// 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 bool ParseBackground() { using (/*var compound = */new nsAutoParseCompoundProperty(this)) { // background-color can only be set once, so it's not a list. var color = new nsCSSValue(); // Check first for inherit/initial. if (ParseVariant(ref color, VARIANT_INHERIT, null)) { // must be alone if (!ExpectEndProperty()) { return false; } AppendValues(nsCSSProps.SubpropertyEntryFor(nsCSSProperty.Background), color); return true; } nsCSSValue image = new nsCSSValue(), repeat = new nsCSSValue(), attachment = new nsCSSValue(), clip = new nsCSSValue(), origin = new nsCSSValue(), position = new nsCSSValue(), size = new nsCSSValue(); var state = new BackgroundParseState(color, image.SetListValue(), repeat.SetPairListValue(), attachment.SetListValue(), clip.SetListValue(), origin.SetListValue(), position.SetListValue(), size.SetPairListValue()); for (;;) { if (!ParseBackgroundItem(state)) { return false; } if (CheckEndProperty()) { break; } // If we saw a color, this must be the last item. if (color.GetUnit() != nsCSSUnit.Null) { { if (!mSuppressErrors) mReporter.ReportUnexpected("PEExpectEndValue", mToken); }; return false; } // Otherwise, a comma is mandatory. if (!ExpectSymbol(',', true)) { return false; } // Chain another entry on all the lists. state.mImage.mNext = new nsCSSValueList(); state.mImage = state.mImage.mNext; state.mRepeat.mNext = new nsCSSValuePairList(); state.mRepeat = state.mRepeat.mNext; state.mAttachment.mNext = new nsCSSValueList(); state.mAttachment = state.mAttachment.mNext; state.mClip.mNext = new nsCSSValueList(); state.mClip = state.mClip.mNext; state.mOrigin.mNext = new nsCSSValueList(); state.mOrigin = state.mOrigin.mNext; state.mPosition.mNext = new nsCSSValueList(); state.mPosition = state.mPosition.mNext; state.mSize.mNext = new nsCSSValuePairList(); state.mSize = state.mSize.mNext; } // If we get to this point without seeing a color, provide a default. if (color.GetUnit() == nsCSSUnit.Null) { color.SetColorValue(nscolor.RGBA(0,0,0,0)); } AppendValue(nsCSSProperty.BackgroundImage, image); AppendValue(nsCSSProperty.BackgroundRepeat, repeat); AppendValue(nsCSSProperty.BackgroundAttachment, attachment); AppendValue(nsCSSProperty.BackgroundClip, clip); AppendValue(nsCSSProperty.BackgroundOrigin, origin); AppendValue(nsCSSProperty.BackgroundPosition, position); AppendValue(nsCSSProperty.BackgroundSize, size); AppendValue(nsCSSProperty.BackgroundColor, color); return true; } }