internal bool ParseRadialGradient(ref nsCSSValue aValue, bool aIsRepeating, bool aIsLegacy) { nsCSSValueGradient cssGradient = new nsCSSValueGradient(true, aIsRepeating); // [ <shape> || <size> ] bool haveShape = ParseVariant(cssGradient.GetRadialShape(), cssGradient.SetRadialShape, VARIANT_KEYWORD, nsCSSProps.kRadialGradientShapeKTable); bool haveSize = ParseVariant(cssGradient.GetRadialSize(), cssGradient.SetRadialSize, VARIANT_KEYWORD, aIsLegacy ? nsCSSProps.kRadialGradientLegacySizeKTable : nsCSSProps.kRadialGradientSizeKTable); if (haveSize) { if (!haveShape) { // <size> <shape> haveShape = ParseVariant(cssGradient.GetRadialShape(), cssGradient.SetRadialShape, VARIANT_KEYWORD, nsCSSProps.kRadialGradientShapeKTable); } } else if (!aIsLegacy) { // <length> | [<length> | <percentage>]{2} haveSize = ParseNonNegativeVariant(cssGradient.GetRadiusX(), cssGradient.SetRadiusX, VARIANT_LP, null); if (haveSize) { // vertical extent is optional bool haveYSize = ParseNonNegativeVariant(cssGradient.GetRadiusY(), cssGradient.SetRadiusY, VARIANT_LP, null); if (!haveShape) { var shapeValue = new nsCSSValue(); haveShape = ParseVariant(ref shapeValue, VARIANT_KEYWORD, nsCSSProps.kRadialGradientShapeKTable); } int32_t shape = cssGradient.GetRadialShape().GetUnit() == nsCSSUnit.Enumerated ? cssGradient.GetRadialShape().GetIntValue() : -1; if (haveYSize ? shape == nsStyle.GRADIENT_SHAPE_CIRCULAR : cssGradient.GetRadiusX().GetUnit() == nsCSSUnit.Percent || shape == nsStyle.GRADIENT_SHAPE_ELLIPTICAL) { SkipUntil(')'); return false; } cssGradient.mIsExplicitSize = true; } } if ((haveShape || haveSize) && ExpectSymbol(',', true)) { // [ <shape> || <size> ] , return ParseGradientColorStops(cssGradient, ref aValue); } if (!GetToken(true)) { return false; } if (!aIsLegacy) { if (mToken.mType == nsCSSTokenType.Ident && mToken.mIdentStr.LowerCaseEqualsLiteral("at")) { // [ <shape> || <size> ]? at <position> , if (!ParseBoxPositionValues(ref cssGradient.mBgPos, false) || !ExpectSymbol(',', true)) { SkipUntil(')'); return false; } return ParseGradientColorStops(cssGradient, ref aValue); } // <color-stops> only UngetToken(); return ParseGradientColorStops(cssGradient, ref aValue); } Debug.Assert(!cssGradient.mIsExplicitSize); nsCSSTokenType ty = mToken.mType; string id = mToken.mIdentStr; UngetToken(); // <legacy-gradient-line> bool haveGradientLine = false; // if we already encountered a shape or size, // we can not have a gradient-line in legacy syntax if (!haveShape && !haveSize) { haveGradientLine = IsLegacyGradientLine(ty, id); } if (haveGradientLine) { bool haveAngle = ParseVariant(ref cssGradient.mAngle, VARIANT_ANGLE, null); // if we got an angle, we might now have a comma, ending the gradient-line if (!haveAngle || !ExpectSymbol(',', true)) { if (!ParseBoxPositionValues(ref cssGradient.mBgPos, false)) { SkipUntil(')'); return false; } if (!ExpectSymbol(',', true) && // if we didn't already get an angle, we might have one now, // otherwise it's an error (haveAngle || !ParseVariant(ref cssGradient.mAngle, VARIANT_ANGLE, null) || // now we better have a comma !ExpectSymbol(',', true))) { SkipUntil(')'); return false; } } if (cssGradient.mAngle.GetUnit() != nsCSSUnit.None) { cssGradient.mIsLegacySyntax = true; } } // radial gradients might have a shape and size here for legacy syntax if (!haveShape && !haveSize) { haveShape = ParseVariant(cssGradient.GetRadialShape(), cssGradient.SetRadialShape, VARIANT_KEYWORD, nsCSSProps.kRadialGradientShapeKTable); haveSize = ParseVariant(cssGradient.GetRadialSize(), cssGradient.SetRadialSize, VARIANT_KEYWORD, nsCSSProps.kRadialGradientLegacySizeKTable); // could be in either order if (!haveShape) { haveShape = ParseVariant(cssGradient.GetRadialShape(), cssGradient.SetRadialShape, VARIANT_KEYWORD, nsCSSProps.kRadialGradientShapeKTable); } } if ((haveShape || haveSize) && !ExpectSymbol(',', true)) { SkipUntil(')'); return false; } return ParseGradientColorStops(cssGradient, ref aValue); }
// <gradient> // : linear-gradient( <linear-gradient-line>? <color-stops> ')' // | radial-gradient( <radial-gradient-line>? <color-stops> ')' // // <linear-gradient-line> : [ to [left | right] || [top | bottom] ] , // | <legacy-gradient-line> // <radial-gradient-line> : [ <shape> || <size> ] [ at <position> ]? , // | [ at <position> ] , // | <legacy-gradient-line>? <legacy-shape-size>? // <shape> : circle | ellipse // <size> : closest-side | closest-corner | farthest-side | farthest-corner // | <length> | [<length> | <percentage>]{2} // // <legacy-gradient-line> : [ <position> || <angle>] , // // <legacy-shape-size> : [ <shape> || <legacy-size> ] , // <legacy-size> : closest-side | closest-corner | farthest-side // | farthest-corner | contain | cover // // <color-stops> : <color-stop> , <color-stop> [, <color-stop>]* internal bool ParseLinearGradient(ref nsCSSValue aValue, bool aIsRepeating, bool aIsLegacy) { nsCSSValueGradient cssGradient = new nsCSSValueGradient(false, aIsRepeating); if (!GetToken(true)) { return false; } if (mToken.mType == nsCSSTokenType.Ident && mToken.mIdentStr.LowerCaseEqualsLiteral("to")) { // "to" syntax doesn't allow explicit "center" if (!ParseBoxPositionValues(ref cssGradient.mBgPos, false, false)) { SkipUntil(')'); return false; } // [ to [left | right] || [top | bottom] ] , nsCSSValue xValue = cssGradient.mBgPos.mXValue; nsCSSValue yValue = cssGradient.mBgPos.mYValue; if (xValue.GetUnit() != nsCSSUnit.Enumerated || 0 == (xValue.GetIntValue() & (nsStyle.BG_POSITION_LEFT | nsStyle.BG_POSITION_CENTER | nsStyle.BG_POSITION_RIGHT)) || yValue.GetUnit() != nsCSSUnit.Enumerated || 0 == (yValue.GetIntValue() & (nsStyle.BG_POSITION_TOP | nsStyle.BG_POSITION_CENTER | nsStyle.BG_POSITION_BOTTOM))) { SkipUntil(')'); return false; } if (!ExpectSymbol(',', true)) { SkipUntil(')'); return false; } return ParseGradientColorStops(cssGradient, ref aValue); } if (!aIsLegacy) { UngetToken(); // <angle> , if (ParseVariant(ref cssGradient.mAngle, VARIANT_ANGLE, null) && !ExpectSymbol(',', true)) { SkipUntil(')'); return false; } return ParseGradientColorStops(cssGradient, ref aValue); } nsCSSTokenType ty = mToken.mType; string id = mToken.mIdentStr; UngetToken(); // <legacy-gradient-line> bool haveGradientLine = IsLegacyGradientLine(ty, id); if (haveGradientLine) { cssGradient.mIsLegacySyntax = true; bool haveAngle = ParseVariant(ref cssGradient.mAngle, VARIANT_ANGLE, null); // if we got an angle, we might now have a comma, ending the gradient-line if (!haveAngle || !ExpectSymbol(',', true)) { if (!ParseBoxPositionValues(ref cssGradient.mBgPos, false)) { SkipUntil(')'); return false; } if (!ExpectSymbol(',', true) && // if we didn't already get an angle, we might have one now, // otherwise it's an error (haveAngle || !ParseVariant(ref cssGradient.mAngle, VARIANT_ANGLE, null) || // now we better have a comma !ExpectSymbol(',', true))) { SkipUntil(')'); return false; } } } return ParseGradientColorStops(cssGradient, ref aValue); }
// <color-stop> : <color> [ <percentage> | <length> ]? internal bool ParseColorStop(nsCSSValueGradient aGradient) { nsCSSValueGradientStop stop = aGradient.mStops.AppendElement(); if (!ParseVariant(ref stop.mColor, VARIANT_COLOR, null)) { return false; } // Stop positions do not have to fall between the starting-point and // ending-point, so we don't use ParseNonNegativeVariant. if (!ParseVariant(ref stop.mLocation, VARIANT_LP | VARIANT_CALC, null)) { stop.mLocation.SetNoneValue(); } return true; }
internal bool ParseGradientColorStops(nsCSSValueGradient aGradient, ref nsCSSValue aValue) { // At least two color stops are required if (!ParseColorStop(aGradient) || !ExpectSymbol(',', true) || !ParseColorStop(aGradient)) { SkipUntil(')'); return false; } // Additional color stops while (ExpectSymbol(',', true)) { if (!ParseColorStop(aGradient)) { SkipUntil(')'); return false; } } if (!ExpectSymbol(')', true)) { SkipUntil(')'); return false; } aValue.SetGradientValue(aGradient); return true; }
internal void SetGradientValue(CssValueGradient aValue) { mUnit = CssUnit.Gradient; mValue = aValue; }