Index: third_party/WebKit/Source/core/css/parser/CSSPropertyParser.cpp |
diff --git a/third_party/WebKit/Source/core/css/parser/CSSPropertyParser.cpp b/third_party/WebKit/Source/core/css/parser/CSSPropertyParser.cpp |
index 0d0289de215d787aff3cce61cc940094fc764aff..e13ebebdc9da4990a27d59308295605921767dbb 100644 |
--- a/third_party/WebKit/Source/core/css/parser/CSSPropertyParser.cpp |
+++ b/third_party/WebKit/Source/core/css/parser/CSSPropertyParser.cpp |
@@ -5,6 +5,7 @@ |
#include "core/css/parser/CSSPropertyParser.h" |
#include "core/StylePropertyShorthand.h" |
+#include "core/css/CSSBasicShapeValues.h" |
#include "core/css/CSSCalculationValue.h" |
#include "core/css/CSSCounterValue.h" |
#include "core/css/CSSCrossfadeValue.h" |
@@ -2741,6 +2742,8 @@ static PassRefPtrWillBeRawPtr<CSSValue> consumeGeneratedImage(CSSParserTokenRang |
if (context.useCounter()) |
context.useCounter()->count(UseCounter::DeprecatedWebKitRepeatingLinearGradient); |
result = consumeLinearGradient(args, context.mode(), Repeating, CSSPrefixedLinearGradient); |
+ } else if (id == CSSValueRepeatingLinearGradient) { |
+ result = consumeLinearGradient(args, context.mode(), Repeating, CSSLinearGradient); |
} else if (id == CSSValueLinearGradient) { |
result = consumeLinearGradient(args, context.mode(), NonRepeating, CSSLinearGradient); |
} else if (id == CSSValueWebkitGradient) { |
@@ -2934,6 +2937,216 @@ static PassRefPtrWillBeRawPtr<CSSPrimitiveValue> consumeVerticalAlign(CSSParserT |
return parsedValue.release(); |
} |
+static PassRefPtrWillBeRawPtr<CSSPrimitiveValue> consumeShapeRadius(CSSParserTokenRange& args, CSSParserMode cssParserMode) |
+{ |
+ if (identMatches<CSSValueClosestSide, CSSValueFarthestSide>(args.peek().id())) |
+ return consumeIdent(args); |
+ return consumeLengthOrPercent(args, cssParserMode, ValueRangeNonNegative); |
+} |
+ |
+static PassRefPtrWillBeRawPtr<CSSBasicShapeCircleValue> consumeBasicShapeCircle(CSSParserTokenRange& args, const CSSParserContext& context) |
+{ |
+ // spec: https://drafts.csswg.org/css-shapes/#supported-basic-shapes |
+ // circle( [<shape-radius>]? [at <position>]? ) |
+ RefPtrWillBeRawPtr<CSSBasicShapeCircleValue> shape = CSSBasicShapeCircleValue::create(); |
+ if (RefPtrWillBeRawPtr<CSSPrimitiveValue> radius = consumeShapeRadius(args, context.mode())) |
+ shape->setRadius(radius.release()); |
+ if (consumeIdent<CSSValueAt>(args)) { |
+ RefPtrWillBeRawPtr<CSSValue> centerX = nullptr; |
+ RefPtrWillBeRawPtr<CSSValue> centerY = nullptr; |
+ if (!consumePosition(args, context.mode(), UnitlessQuirk::Forbid, centerX, centerY)) |
+ return nullptr; |
+ shape->setCenterX(centerX); |
+ shape->setCenterY(centerY); |
+ } |
+ return shape.release(); |
+} |
+ |
+static PassRefPtrWillBeRawPtr<CSSBasicShapeEllipseValue> consumeBasicShapeEllipse(CSSParserTokenRange& args, const CSSParserContext& context) |
+{ |
+ // spec: https://drafts.csswg.org/css-shapes/#supported-basic-shapes |
+ // ellipse( [<shape-radius>{2}]? [at <position>]? ) |
+ RefPtrWillBeRawPtr<CSSBasicShapeEllipseValue> shape = CSSBasicShapeEllipseValue::create(); |
+ if (RefPtrWillBeRawPtr<CSSPrimitiveValue> radiusX = consumeShapeRadius(args, context.mode())) { |
+ shape->setRadiusX(radiusX); |
+ if (RefPtrWillBeRawPtr<CSSPrimitiveValue> radiusY = consumeShapeRadius(args, context.mode())) |
+ shape->setRadiusY(radiusY); |
+ } |
+ if (consumeIdent<CSSValueAt>(args)) { |
+ RefPtrWillBeRawPtr<CSSValue> centerX = nullptr; |
+ RefPtrWillBeRawPtr<CSSValue> centerY = nullptr; |
+ if (!consumePosition(args, context.mode(), UnitlessQuirk::Forbid, centerX, centerY)) |
+ return nullptr; |
+ shape->setCenterX(centerX); |
+ shape->setCenterY(centerY); |
+ } |
+ return shape.release(); |
+} |
+ |
+static PassRefPtrWillBeRawPtr<CSSBasicShapePolygonValue> consumeBasicShapePolygon(CSSParserTokenRange& args, const CSSParserContext& context) |
+{ |
+ RefPtrWillBeRawPtr<CSSBasicShapePolygonValue> shape = CSSBasicShapePolygonValue::create(); |
+ if (identMatches<CSSValueEvenodd, CSSValueNonzero>(args.peek().id())) { |
+ shape->setWindRule(args.consumeIncludingWhitespace().id() == CSSValueEvenodd ? RULE_EVENODD : RULE_NONZERO); |
+ if (!consumeCommaIncludingWhitespace(args)) |
+ return nullptr; |
+ } |
+ |
+ do { |
+ RefPtrWillBeRawPtr<CSSPrimitiveValue> xLength = consumeLengthOrPercent(args, context.mode(), ValueRangeAll); |
+ if (!xLength) |
+ return nullptr; |
+ RefPtrWillBeRawPtr<CSSPrimitiveValue> yLength = consumeLengthOrPercent(args, context.mode(), ValueRangeAll); |
+ if (!yLength) |
+ return nullptr; |
+ shape->appendPoint(xLength.release(), yLength.release()); |
+ } while (consumeCommaIncludingWhitespace(args)); |
+ return shape.release(); |
+} |
+ |
+static void completeBorderRadii(RefPtrWillBeRawPtr<CSSPrimitiveValue> radii[4]) |
+{ |
+ if (radii[3]) |
+ return; |
+ if (!radii[2]) { |
+ if (!radii[1]) |
+ radii[1] = radii[0]; |
+ radii[2] = radii[0]; |
+ } |
+ radii[3] = radii[1]; |
+} |
+ |
+static bool consumeRadii(RefPtrWillBeRawPtr<CSSPrimitiveValue> horizontalRadii[4], RefPtrWillBeRawPtr<CSSPrimitiveValue> verticalRadii[4], CSSParserTokenRange& range, CSSParserMode cssParserMode, bool useLegacyParsing) |
+{ |
+#if ENABLE(OILPAN) |
+ // Unconditionally zero initialize the arrays of raw pointers. |
+ memset(horizontalRadii, 0, 4 * sizeof(horizontalRadii[0])); |
+ memset(verticalRadii, 0, 4 * sizeof(verticalRadii[0])); |
+#endif |
+ unsigned i = 0; |
+ for (; i < 4 && !range.atEnd() && range.peek().type() != DelimiterToken; ++i) { |
+ horizontalRadii[i] = consumeLengthOrPercent(range, cssParserMode, ValueRangeNonNegative); |
+ if (!horizontalRadii[i]) |
+ return false; |
+ } |
+ if (!horizontalRadii[0]) |
+ return false; |
+ if (range.atEnd()) { |
+ // Legacy syntax: -webkit-border-radius: l1 l2; is equivalent to border-radius: l1 / l2; |
+ if (useLegacyParsing && i == 2) { |
+ verticalRadii[0] = horizontalRadii[1]; |
+ horizontalRadii[1] = nullptr; |
+ } else { |
+ completeBorderRadii(horizontalRadii); |
+ for (unsigned i = 0; i < 4; ++i) |
+ verticalRadii[i] = horizontalRadii[i]; |
+ return true; |
+ } |
+ } else { |
+ if (range.peek().type() != DelimiterToken || range.peek().delimiter() != '/') |
+ return false; |
+ range.consumeIncludingWhitespace(); |
+ for (i = 0; i < 4 && !range.atEnd(); ++i) { |
+ verticalRadii[i] = consumeLengthOrPercent(range, cssParserMode, ValueRangeNonNegative); |
+ if (!verticalRadii[i]) |
+ return false; |
+ } |
+ if (!verticalRadii[0] || !range.atEnd()) |
+ return false; |
+ } |
+ completeBorderRadii(horizontalRadii); |
+ completeBorderRadii(verticalRadii); |
+ return true; |
+} |
+ |
+static PassRefPtrWillBeRawPtr<CSSBasicShapeInsetValue> consumeBasicShapeInset(CSSParserTokenRange& args, const CSSParserContext& context) |
+{ |
+ RefPtrWillBeRawPtr<CSSBasicShapeInsetValue> shape = CSSBasicShapeInsetValue::create(); |
+ RefPtrWillBeRawPtr<CSSPrimitiveValue> top = consumeLengthOrPercent(args, context.mode(), ValueRangeAll); |
+ if (!top) |
+ return nullptr; |
+ RefPtrWillBeRawPtr<CSSPrimitiveValue> right = nullptr; |
+ RefPtrWillBeRawPtr<CSSPrimitiveValue> bottom = nullptr; |
+ RefPtrWillBeRawPtr<CSSPrimitiveValue> left = nullptr; |
+ if ((right = consumeLengthOrPercent(args, context.mode(), ValueRangeAll))) { |
+ if ((bottom = consumeLengthOrPercent(args, context.mode(), ValueRangeAll))) |
+ left = consumeLengthOrPercent(args, context.mode(), ValueRangeAll); |
+ } |
+ if (left) |
+ shape->updateShapeSize4Values(top.get(), right.get(), bottom.get(), left.get()); |
+ else if (bottom) |
+ shape->updateShapeSize3Values(top.get(), right.get(), bottom.get()); |
+ else if (right) |
+ shape->updateShapeSize2Values(top.get(), right.get()); |
+ else |
+ shape->updateShapeSize1Value(top.get()); |
+ |
+ if (consumeIdent<CSSValueRound>(args)) { |
+ RefPtrWillBeRawPtr<CSSPrimitiveValue> horizontalRadii[4]; |
+ RefPtrWillBeRawPtr<CSSPrimitiveValue> verticalRadii[4]; |
+ if (!consumeRadii(horizontalRadii, verticalRadii, args, context.mode(), false)) |
+ return nullptr; |
+ shape->setTopLeftRadius(CSSValuePair::create(horizontalRadii[0].release(), verticalRadii[0].release(), CSSValuePair::DropIdenticalValues)); |
+ shape->setTopRightRadius(CSSValuePair::create(horizontalRadii[1].release(), verticalRadii[1].release(), CSSValuePair::DropIdenticalValues)); |
+ shape->setBottomRightRadius(CSSValuePair::create(horizontalRadii[2].release(), verticalRadii[2].release(), CSSValuePair::DropIdenticalValues)); |
+ shape->setBottomLeftRadius(CSSValuePair::create(horizontalRadii[3].release(), verticalRadii[3].release(), CSSValuePair::DropIdenticalValues)); |
+ } |
+ return shape.release(); |
+} |
+ |
+static PassRefPtrWillBeRawPtr<CSSValue> consumeBasicShape(CSSParserTokenRange& range, const CSSParserContext& context) |
+{ |
+ RefPtrWillBeRawPtr<CSSValue> shape = nullptr; |
+ if (range.peek().type() != FunctionToken) |
+ return nullptr; |
+ CSSValueID id = range.peek().functionId(); |
+ CSSParserTokenRange rangeCopy = range; |
+ CSSParserTokenRange args = consumeFunction(rangeCopy); |
+ if (id == CSSValueCircle) |
+ shape = consumeBasicShapeCircle(args, context); |
+ else if (id == CSSValueEllipse) |
+ shape = consumeBasicShapeEllipse(args, context); |
+ else if (id == CSSValuePolygon) |
+ shape = consumeBasicShapePolygon(args, context); |
+ else if (id == CSSValueInset) |
+ shape = consumeBasicShapeInset(args, context); |
+ if (!shape || !args.atEnd()) |
+ return nullptr; |
+ range = rangeCopy; |
+ return shape.release(); |
+} |
+ |
+static PassRefPtrWillBeRawPtr<CSSValue> consumeClipPath(CSSParserTokenRange& range, const CSSParserContext& context) |
+{ |
+ if (range.peek().id() == CSSValueNone) |
+ return consumeIdent(range); |
+ String url = consumeUrl(range); |
+ if (!url.isNull()) |
+ return CSSURIValue::create(url); |
+ return consumeBasicShape(range, context); |
+} |
+ |
+static PassRefPtrWillBeRawPtr<CSSValue> consumeShapeOutside(CSSParserTokenRange& range, const CSSParserContext& context) |
+{ |
+ if (range.peek().id() == CSSValueNone) |
+ return consumeIdent(range); |
+ if (RefPtrWillBeRawPtr<CSSValue> imageValue = consumeImage(range, context)) |
+ return imageValue.release(); |
+ RefPtrWillBeRawPtr<CSSValueList> list = CSSValueList::createSpaceSeparated(); |
+ if (RefPtrWillBeRawPtr<CSSValue> boxValue = consumeIdent<CSSValueContentBox, CSSValuePaddingBox, CSSValueBorderBox, CSSValueMarginBox>(range)) |
+ list->append(boxValue.release()); |
+ if (RefPtrWillBeRawPtr<CSSValue> shapeValue = consumeBasicShape(range, context)) { |
+ list->append(shapeValue.release()); |
+ if (list->length() < 2) { |
+ if (RefPtrWillBeRawPtr<CSSValue> boxValue = consumeIdent<CSSValueContentBox, CSSValuePaddingBox, CSSValueBorderBox, CSSValueMarginBox>(range)) |
+ list->append(boxValue.release()); |
+ } |
+ } |
+ if (!list->length()) |
+ return nullptr; |
+ return list.release(); |
+} |
+ |
PassRefPtrWillBeRawPtr<CSSValue> CSSPropertyParser::parseSingleValue(CSSPropertyID unresolvedProperty) |
{ |
CSSPropertyID property = resolveCSSPropertyID(unresolvedProperty); |
@@ -3230,6 +3443,10 @@ PassRefPtrWillBeRawPtr<CSSValue> CSSPropertyParser::parseSingleValue(CSSProperty |
return consumeIdent<CSSValueAuto, CSSValueUnder>(m_range); |
case CSSPropertyVerticalAlign: |
return consumeVerticalAlign(m_range, m_context.mode()); |
+ case CSSPropertyShapeOutside: |
+ return consumeShapeOutside(m_range, m_context); |
+ case CSSPropertyWebkitClipPath: |
+ return consumeClipPath(m_range, m_context); |
default: |
CSSParserValueList valueList(m_range); |
if (valueList.size()) { |
@@ -3748,49 +3965,6 @@ bool CSSPropertyParser::consume4Values(const StylePropertyShorthand& shorthand, |
return m_range.atEnd(); |
} |
-static bool consumeRadii(RefPtrWillBeRawPtr<CSSPrimitiveValue> horizontalRadii[4], RefPtrWillBeRawPtr<CSSPrimitiveValue> verticalRadii[4], CSSParserTokenRange& range, CSSParserMode cssParserMode, bool useLegacyParsing) |
-{ |
-#if ENABLE(OILPAN) |
- // Unconditionally zero initialize the arrays of raw pointers. |
- memset(horizontalRadii, 0, 4 * sizeof(horizontalRadii[0])); |
- memset(verticalRadii, 0, 4 * sizeof(verticalRadii[0])); |
-#endif |
- unsigned i = 0; |
- for (; i < 4 && !range.atEnd() && range.peek().type() != DelimiterToken; ++i) { |
- horizontalRadii[i] = consumeLengthOrPercent(range, cssParserMode, ValueRangeNonNegative); |
- if (!horizontalRadii[i]) |
- return false; |
- } |
- if (!horizontalRadii[0]) |
- return false; |
- if (range.atEnd()) { |
- // Legacy syntax: -webkit-border-radius: l1 l2; is equivalent to border-radius: l1 / l2; |
- if (useLegacyParsing && i == 2) { |
- verticalRadii[0] = horizontalRadii[1]; |
- horizontalRadii[1] = nullptr; |
- } else { |
- completeBorderRadii(horizontalRadii); |
- for (unsigned i = 0; i < 4; ++i) |
- verticalRadii[i] = horizontalRadii[i]; |
- return true; |
- } |
- } else { |
- if (range.peek().type() != DelimiterToken || range.peek().delimiter() != '/') |
- return false; |
- range.consumeIncludingWhitespace(); |
- for (i = 0; i < 4 && !range.atEnd(); ++i) { |
- verticalRadii[i] = consumeLengthOrPercent(range, cssParserMode, ValueRangeNonNegative); |
- if (!verticalRadii[i]) |
- return false; |
- } |
- if (!verticalRadii[0] || !range.atEnd()) |
- return false; |
- } |
- completeBorderRadii(horizontalRadii); |
- completeBorderRadii(verticalRadii); |
- return true; |
-} |
- |
bool CSSPropertyParser::parseShorthand(CSSPropertyID unresolvedProperty, bool important) |
{ |
CSSPropertyID property = resolveCSSPropertyID(unresolvedProperty); |