/** * BoxPositionMaskToCSSValue and ParseBoxPositionValues are used * for parsing the CSS 2.1 background-position syntax (which has at * most two values). (Compare to the css3-background syntax which * takes up to four values.) Some current CSS specifications that * use background-position-like syntax still use this old syntax. ** * Parses two values that correspond to positions in a box. These can be * values corresponding to percentages of the box, raw offsets, or keywords * like "top," "left center," etc. * * @param aOut The nsCSSValuePair in which to place the result. * @param aAcceptsInherit If true, 'inherit' and 'initial' are legal values * @param aAllowExplicitCenter If true, 'center' is a legal value * @return Whether or not the operation succeeded. */ bool ParseBoxPositionValues(ref nsCSSValuePair aOut, bool aAcceptsInherit, bool aAllowExplicitCenter = true) { // First try a percentage or a length value nsCSSValue xValue = aOut.mXValue, yValue = aOut.mYValue; int32_t variantMask = (aAcceptsInherit ? VARIANT_INHERIT : 0) | VARIANT_LP | VARIANT_CALC; if (ParseVariant(ref xValue, variantMask, null)) { if (nsCSSUnit.Inherit == xValue.GetUnit() || nsCSSUnit.Initial == xValue.GetUnit()) { // both are inherited or both are set to initial yValue = xValue; return true; } // We have one percentage/length/calc. Get the optional second // percentage/length/calc/keyword. if (ParseVariant(ref yValue, VARIANT_LP | VARIANT_CALC, null)) { // We have two numbers return true; } if (ParseEnum(ref yValue, nsCSSProps.kBackgroundPositionKTable)) { int32_t yVal = yValue.GetIntValue(); if (!((yVal & BG_CTB) != 0)) { // The second keyword can only be 'center', 'top', or 'bottom' return false; } yValue = BoxPositionMaskToCSSValue(yVal, false); return true; } // If only one percentage or length value is given, it sets the // horizontal position only, and the vertical position will be 50%. yValue.SetPercentValue(0.5f); return true; } // Now try keywords. We do this manually to allow for the first // appearance of "center" to apply to the either the x or y // position (it's ambiguous so we have to disambiguate). Each // allowed keyword value is assigned it's own bit. We don't allow // any duplicate keywords other than center. We try to get two // keywords but it's okay if there is only one. int32_t mask = 0; if (ParseEnum(ref xValue, nsCSSProps.kBackgroundPositionKTable)) { int32_t bit = xValue.GetIntValue(); mask |= bit; if (ParseEnum(ref xValue, nsCSSProps.kBackgroundPositionKTable)) { bit = xValue.GetIntValue(); if ((mask & (bit & ~BG_CENTER)) != 0) { // Only the 'center' keyword can be duplicated. return false; } mask |= bit; } else { // Only one keyword. See if we have a length, percentage, or calc. if (ParseVariant(ref yValue, VARIANT_LP | VARIANT_CALC, null)) { if (!((mask & BG_CLR) != 0)) { // The first keyword can only be 'center', 'left', or 'right' return false; } xValue = BoxPositionMaskToCSSValue(mask, true); return true; } } } // Check for bad input. Bad input consists of no matching keywords, // or pairs of x keywords or pairs of y keywords. if ((mask == 0) || (mask == (BG_TOP | BG_BOTTOM)) || (mask == (BG_LEFT | BG_RIGHT)) || (!aAllowExplicitCenter && ((mask & BG_CENTER) != 0))) { return false; } // Create style values xValue = BoxPositionMaskToCSSValue(mask, true); yValue = BoxPositionMaskToCSSValue(mask, false); return true; }
bool ParseTransformOrigin(bool aPerspective) { var position = new nsCSSValuePair(); if (!ParseBoxPositionValues(ref position, true)) return false; nsCSSProperty prop = nsCSSProperty.TransformOrigin; if (aPerspective) { if (!ExpectEndProperty()) { return false; } prop = nsCSSProperty.PerspectiveOrigin; } // Unlike many other uses of pairs, this position should always be stored // as a pair, even if the values are the same, so it always serializes as // a pair, and to keep the computation code simple. if (position.mXValue.GetUnit() == nsCSSUnit.Inherit || position.mXValue.GetUnit() == nsCSSUnit.Initial) { Debug.Assert(position.mXValue == position.mYValue, "inherit/initial only half?"); AppendValue(prop, position.mXValue); } else { var value = new nsCSSValue(); if (aPerspective) { value.SetPairValue(position.mXValue, position.mYValue); } else { var depth = new nsCSSValue(); if (!nsLayoutUtils.Are3DTransformsEnabled() || // only try parsing if 3-D transforms are enabled !ParseVariant(ref depth, VARIANT_LENGTH | VARIANT_CALC, null)) { depth.SetFloatValue(0.0f, nsCSSUnit.Pixel); } value.SetTripletValue(position.mXValue, position.mYValue, depth); } AppendValue(prop, value); } return true; }
internal void SetBorderImageInitialValues() { // border-image-source: none var source = new nsCSSValue(); source.SetNoneValue(); AppendValue(nsCSSProperty.BorderImageSource, source); // border-image-slice: 100% var sliceBoxValue = new nsCSSValue(); nsCSSRect sliceBox = sliceBoxValue.SetRectValue(); sliceBox.SetAllSidesTo(new nsCSSValue(1.0f, nsCSSUnit.Percent)); var slice = new nsCSSValue(); nsCSSValueList sliceList = slice.SetListValue(); sliceList.mValue = sliceBoxValue; AppendValue(nsCSSProperty.BorderImageSlice, slice); // border-image-width: 1 var width = new nsCSSValue(); nsCSSRect widthBox = width.SetRectValue(); widthBox.SetAllSidesTo(new nsCSSValue(1.0f, nsCSSUnit.Number)); AppendValue(nsCSSProperty.BorderImageWidth, width); // border-image-outset: 0 var outset = new nsCSSValue(); nsCSSRect outsetBox = outset.SetRectValue(); outsetBox.SetAllSidesTo(new nsCSSValue(0.0f, nsCSSUnit.Number)); AppendValue(nsCSSProperty.BorderImageOutset, outset); // border-image-repeat: repeat var repeat = new nsCSSValue(); var repeatPair = new nsCSSValuePair(); repeatPair.SetBothValuesTo(new nsCSSValue(nsStyle.BORDER_IMAGE_REPEAT_STRETCH, nsCSSUnit.Enumerated)); repeat.SetPairValue(repeatPair); AppendValue(nsCSSProperty.BorderImageRepeat, repeat); }
/** * Parses two values that correspond to lengths for the background-size * property. These can be one or two lengths (or the 'auto' keyword) or * percentages corresponding to the element's dimensions or the single keywords * 'contain' or 'cover'. 'initial' and 'inherit' must be handled by the caller * if desired. * * @param aOut The nsCSSValuePair in which to place the result. * @return Whether or not the operation succeeded. */ bool ParseBackgroundSizeValues(ref nsCSSValuePair aOut) { // First try a percentage or a length value nsCSSValue xValue = aOut.mXValue, yValue = aOut.mYValue; if (ParseNonNegativeVariant(ref xValue, BG_SIZE_VARIANT, null)) { // We have one percentage/length/calc/auto. Get the optional second // percentage/length/calc/keyword. if (ParseNonNegativeVariant(ref yValue, BG_SIZE_VARIANT, null)) { // We have a second percentage/length/calc/auto. return true; } // If only one percentage or length value is given, it sets the // horizontal size only, and the vertical size will be as if by 'auto'. yValue.SetAutoValue(); return true; } // Now address 'contain' and 'cover'. if (!ParseEnum(ref xValue, nsCSSProps.kBackgroundSizeKTable)) return false; yValue.Reset(); return true; }
internal bool ParseBorderImageRepeat(bool aAcceptsInherit) { var value = new nsCSSValue(); if (aAcceptsInherit && ParseVariant(ref value, VARIANT_INHERIT, null)) { // Keyword "inherit" can not be mixed, so we are done. AppendValue(nsCSSProperty.BorderImageRepeat, value); return true; } var result = new nsCSSValuePair(); if (!ParseEnum(ref result.mXValue, nsCSSProps.kBorderImageRepeatKTable)) { return false; } // optional second keyword, defaults to first if (!ParseEnum(ref result.mYValue, nsCSSProps.kBorderImageRepeatKTable)) { result.mYValue = result.mXValue; } value.SetPairValue(result); AppendValue(nsCSSProperty.BorderImageRepeat, value); return true; }
// This function is very similar to ParseBackgroundList and // ParseBackgroundPosition. internal bool ParseBackgroundSize() { var value = new nsCSSValue(); if (ParseVariant(ref value, VARIANT_INHERIT, null)) { // 'initial' and 'inherit' stand alone, no list permitted. if (!ExpectEndProperty()) { return false; } } else { var valuePair = new nsCSSValuePair(); if (!ParseBackgroundSizeValues(ref valuePair)) { return false; } nsCSSValuePairList item = value.SetPairListValue(); for (;;) { item.mXValue = valuePair.mXValue; item.mYValue = valuePair.mYValue; if (CheckEndProperty()) { break; } if (!ExpectSymbol(',', true)) { return false; } if (!ParseBackgroundSizeValues(ref valuePair)) { return false; } item.mNext = new nsCSSValuePairList(); item = item.mNext; } } AppendValue(nsCSSProperty.BackgroundSize, value); return true; }
internal bool ParseBackgroundRepeatValues(ref nsCSSValuePair aValue) { nsCSSValue xValue = aValue.mXValue; nsCSSValue yValue = aValue.mYValue; if (ParseEnum(ref xValue, nsCSSProps.kBackgroundRepeatKTable)) { int32_t value = xValue.GetIntValue(); // For single values set yValue as nsCSSUnit.Null. if (value == nsStyle.BG_REPEAT_REPEAT_X || value == nsStyle.BG_REPEAT_REPEAT_Y || !ParseEnum(ref yValue, nsCSSProps.kBackgroundRepeatPartKTable)) { // the caller will fail cases like "repeat-x no-repeat" // by expecting a list separator or an end property. yValue.Reset(); } return true; } return false; }
// Parse one item of the background shorthand property. internal bool ParseBackgroundItem(BackgroundParseState aState) { // Fill in the values that the shorthand will set if we don't find // other values. aState.mImage.mValue.SetNoneValue(); aState.mRepeat.mXValue.SetIntValue(nsStyle.BG_REPEAT_REPEAT, nsCSSUnit.Enumerated); aState.mRepeat.mYValue.Reset(); aState.mAttachment.mValue.SetIntValue(nsStyle.BG_ATTACHMENT_SCROLL, nsCSSUnit.Enumerated); aState.mClip.mValue.SetIntValue(nsStyle.BG_CLIP_BORDER, nsCSSUnit.Enumerated); aState.mOrigin.mValue.SetIntValue(nsStyle.BG_ORIGIN_PADDING, nsCSSUnit.Enumerated); nsCSSValue[] positionArr = new nsCSSValue[4]; aState.mPosition.mValue.SetArrayValue(positionArr, nsCSSUnit.Array); positionArr[1].SetPercentValue(0.0f); positionArr[3].SetPercentValue(0.0f); aState.mSize.mXValue.SetAutoValue(); aState.mSize.mYValue.SetAutoValue(); bool haveColor = false, haveImage = false, haveRepeat = false, haveAttach = false, havePositionAndSize = false, haveOrigin = false, haveSomething = false; while (GetToken(true)) { nsCSSTokenType tt = mToken.mType; UngetToken(); // ...but we'll still cheat and use mToken if (tt == nsCSSTokenType.Symbol) { // ExpectEndProperty only looks for symbols, and nothing else will // show up as one. break; } if (tt == nsCSSTokenType.Ident) { nsCSSKeyword keyword = nsCSSKeywords.LookupKeyword(mToken.mIdentStr); int32_t dummy = 0; if (keyword == nsCSSKeyword.inherit || keyword == nsCSSKeyword._moz_initial || keyword == nsCSSKeyword.initial) { return false; } else if (keyword == nsCSSKeyword.none) { if (haveImage) return false; haveImage = true; if (!ParseSingleValueProperty(ref aState.mImage.mValue, nsCSSProperty.BackgroundImage)) { Debug.Fail("should be able to parse"); return false; } } else if (nsCSSProps.FindKeyword(keyword, nsCSSProps.kBackgroundAttachmentKTable, ref dummy)) { if (haveAttach) return false; haveAttach = true; if (!ParseSingleValueProperty(ref aState.mAttachment.mValue, nsCSSProperty.BackgroundAttachment)) { Debug.Fail("should be able to parse"); return false; } } else if (nsCSSProps.FindKeyword(keyword, nsCSSProps.kBackgroundRepeatKTable, ref dummy)) { if (haveRepeat) return false; haveRepeat = true; var scratch = new nsCSSValuePair(); if (!ParseBackgroundRepeatValues(ref scratch)) { Debug.Fail("should be able to parse"); return false; } aState.mRepeat.mXValue = scratch.mXValue; aState.mRepeat.mYValue = scratch.mYValue; } else if (nsCSSProps.FindKeyword(keyword, nsCSSProps.kBackgroundPositionKTable, ref dummy)) { if (havePositionAndSize) return false; havePositionAndSize = true; if (!ParseBackgroundPositionValues(ref aState.mPosition.mValue, false)) { return false; } if (ExpectSymbol('/', true)) { var scratch = new nsCSSValuePair(); if (!ParseBackgroundSizeValues(ref scratch)) { return false; } aState.mSize.mXValue = scratch.mXValue; aState.mSize.mYValue = scratch.mYValue; } } else if (nsCSSProps.FindKeyword(keyword, nsCSSProps.kBackgroundOriginKTable, ref dummy)) { if (haveOrigin) return false; haveOrigin = true; if (!ParseSingleValueProperty(ref aState.mOrigin.mValue, nsCSSProperty.BackgroundOrigin)) { Debug.Fail("should be able to parse"); return false; } // The spec allows a second box value (for background-clip), // immediately following the first one (for background-origin). // 'background-clip' and 'background-origin' use the same keyword table Debug.Assert(nsCSSProps.kKeywordTableTable[ (int)nsCSSProperty.BackgroundOrigin] == nsCSSProps.kBackgroundOriginKTable); Debug.Assert(nsCSSProps.kKeywordTableTable[ (int)nsCSSProperty.BackgroundClip] == nsCSSProps.kBackgroundOriginKTable); if (!ParseSingleValueProperty(ref aState.mClip.mValue, nsCSSProperty.BackgroundClip)) { // When exactly one <box> value is set, it is used for both // 'background-origin' and 'background-clip'. // See assertions above showing these values are compatible. aState.mClip.mValue = aState.mOrigin.mValue; } } else { if (haveColor) return false; haveColor = true; if (!ParseSingleValueProperty(ref aState.mColor, nsCSSProperty.BackgroundColor)) { return false; } } } else if (tt == nsCSSTokenType.URL || (tt == nsCSSTokenType.Function && (mToken.mIdentStr.LowerCaseEqualsLiteral("linear-gradient") || mToken.mIdentStr.LowerCaseEqualsLiteral("radial-gradient") || mToken.mIdentStr.LowerCaseEqualsLiteral("repeating-linear-gradient") || mToken.mIdentStr.LowerCaseEqualsLiteral("repeating-radial-gradient") || mToken.mIdentStr.LowerCaseEqualsLiteral("-moz-linear-gradient") || mToken.mIdentStr.LowerCaseEqualsLiteral("-moz-radial-gradient") || mToken.mIdentStr.LowerCaseEqualsLiteral("-moz-repeating-linear-gradient") || mToken.mIdentStr.LowerCaseEqualsLiteral("-moz-repeating-radial-gradient") || mToken.mIdentStr.LowerCaseEqualsLiteral("-moz-image-rect") || mToken.mIdentStr.LowerCaseEqualsLiteral("-moz-element")))) { if (haveImage) return false; haveImage = true; if (!ParseSingleValueProperty(ref aState.mImage.mValue, nsCSSProperty.BackgroundImage)) { return false; } } else if (tt == nsCSSTokenType.Dimension || tt == nsCSSTokenType.Number || tt == nsCSSTokenType.Percentage || (tt == nsCSSTokenType.Function && (mToken.mIdentStr.LowerCaseEqualsLiteral("calc") || mToken.mIdentStr.LowerCaseEqualsLiteral("-moz-calc")))) { if (havePositionAndSize) return false; havePositionAndSize = true; if (!ParseBackgroundPositionValues(ref aState.mPosition.mValue, false)) { return false; } if (ExpectSymbol('/', true)) { var scratch = new nsCSSValuePair(); if (!ParseBackgroundSizeValues(ref scratch)) { return false; } aState.mSize.mXValue = scratch.mXValue; aState.mSize.mYValue = scratch.mYValue; } } else { if (haveColor) return false; haveColor = true; // Note: This parses 'inherit' and 'initial', but // we've already checked for them, so it's ok. if (!ParseSingleValueProperty(ref aState.mColor, nsCSSProperty.BackgroundColor)) { return false; } } haveSomething = true; } return haveSomething; }
internal void SetPairValue(CssValuePair aValue) { mUnit = CssUnit.Pair; mValue = aValue; }