Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(222)

Unified Diff: third_party/WebKit/Source/core/css/parser/CSSPropertyParser.cpp

Issue 1508913002: Add support for <image> type parsing using CSSParserTokens (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Patch for landing Created 5 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « no previous file | no next file » | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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 db7cdba5f2faa52e27f976644b9a87fe5e5d2bd1..6432b846e62d74e23d9fd369d8c4ff6327c26caa 100644
--- a/third_party/WebKit/Source/core/css/parser/CSSPropertyParser.cpp
+++ b/third_party/WebKit/Source/core/css/parser/CSSPropertyParser.cpp
@@ -7,6 +7,7 @@
#include "core/StylePropertyShorthand.h"
#include "core/css/CSSCalculationValue.h"
+#include "core/css/CSSCrossfadeValue.h"
#include "core/css/CSSCursorImageValue.h"
#include "core/css/CSSCustomIdentValue.h"
#include "core/css/CSSFontFaceSrcValue.h"
@@ -2405,6 +2406,217 @@ static PassRefPtrWillBeRawPtr<CSSValue> consumeCursor(CSSParserTokenRange& range
return list.release();
}
+static bool consumeGradientColorStops(CSSParserTokenRange& range, CSSParserMode cssParserMode, CSSGradientValue* gradient)
+{
+ bool supportsColorHints = gradient->gradientType() == CSSLinearGradient || gradient->gradientType() == CSSRadialGradient;
+
+ // The first color stop cannot be a color hint.
+ bool previousStopWasColorHint = true;
+ do {
+ CSSGradientColorStop stop;
+ stop.m_color = consumeColor(range, cssParserMode);
+ // Two hints in a row are not allowed.
+ if (!stop.m_color && (!supportsColorHints || previousStopWasColorHint))
+ return false;
+ previousStopWasColorHint = !stop.m_color;
+ stop.m_position = consumeLengthOrPercent(range, cssParserMode, ValueRangeAll);
+ if (!stop.m_color && !stop.m_position)
+ return false;
+ gradient->addStop(stop);
+ } while (consumeCommaIncludingWhitespace(range));
+
+ // The last color stop cannot be a color hint.
+ if (previousStopWasColorHint)
+ return false;
+
+ // Must have 2 or more stops to be valid.
+ return gradient->stopCount() >= 2;
+}
+
+static PassRefPtrWillBeRawPtr<CSSValue> consumeRadialGradient(CSSParserTokenRange& args, CSSParserMode cssParserMode, CSSGradientRepeat repeating)
+{
+ RefPtrWillBeRawPtr<CSSRadialGradientValue> result = CSSRadialGradientValue::create(repeating, CSSRadialGradient);
+
+ RefPtrWillBeRawPtr<CSSPrimitiveValue> shape = nullptr;
+ RefPtrWillBeRawPtr<CSSPrimitiveValue> sizeKeyword = nullptr;
+ RefPtrWillBeRawPtr<CSSPrimitiveValue> horizontalSize = nullptr;
+ RefPtrWillBeRawPtr<CSSPrimitiveValue> verticalSize = nullptr;
+
+ // First part of grammar, the size/shape clause:
+ // [ circle || <length> ] |
+ // [ ellipse || [ <length> | <percentage> ]{2} ] |
+ // [ [ circle | ellipse] || <size-keyword> ]
+ for (int i = 0; i < 3; ++i) {
+ if (args.peek().type() == IdentToken) {
+ CSSValueID id = args.peek().id();
+ if (id == CSSValueCircle || id == CSSValueEllipse) {
+ if (shape)
+ return nullptr;
+ shape = consumeIdent(args);
+ } else if (id == CSSValueClosestSide || id == CSSValueClosestCorner || id == CSSValueFarthestSide || id == CSSValueFarthestCorner) {
+ if (sizeKeyword)
+ return nullptr;
+ sizeKeyword = consumeIdent(args);
+ } else {
+ break;
+ }
+ } else {
+ RefPtrWillBeRawPtr<CSSPrimitiveValue> center = consumeLengthOrPercent(args, cssParserMode, ValueRangeAll);
+ if (!center)
+ break;
+ if (horizontalSize)
+ return nullptr;
+ horizontalSize = center;
+ if ((center = consumeLengthOrPercent(args, cssParserMode, ValueRangeAll))) {
+ verticalSize = center.release();
+ ++i;
+ }
+ }
+ }
+
+ // You can specify size as a keyword or a length/percentage, not both.
+ if (sizeKeyword && horizontalSize)
+ return nullptr;
+ // Circles must have 0 or 1 lengths.
+ if (shape && shape->getValueID() == CSSValueCircle && verticalSize)
+ return nullptr;
+ // Ellipses must have 0 or 2 length/percentages.
+ if (shape && shape->getValueID() == CSSValueEllipse && horizontalSize && !verticalSize)
+ return nullptr;
+ // If there's only one size, it must be a length.
+ // TODO(timloh): Calcs with both lengths and percentages should be rejected.
+ if (!verticalSize && horizontalSize && horizontalSize->isPercentage())
+ return nullptr;
+
+ result->setShape(shape);
+ result->setSizingBehavior(sizeKeyword);
+ result->setEndHorizontalSize(horizontalSize);
+ result->setEndVerticalSize(verticalSize);
+
+ RefPtrWillBeRawPtr<CSSValue> centerX = nullptr;
+ RefPtrWillBeRawPtr<CSSValue> centerY = nullptr;
+ if (args.peek().id() == CSSValueAt) {
+ args.consumeIncludingWhitespace();
+ consumePosition(args, cssParserMode, UnitlessQuirk::Forbid, centerX, centerY);
+ if (!(centerX && centerY))
+ return nullptr;
+ result->setFirstX(centerX);
+ result->setFirstY(centerY);
+ // Right now, CSS radial gradients have the same start and end centers.
+ result->setSecondX(centerX);
+ result->setSecondY(centerY);
+ }
+
+ if ((shape || sizeKeyword || horizontalSize || centerX || centerY) && !consumeCommaIncludingWhitespace(args))
+ return nullptr;
+ if (!consumeGradientColorStops(args, cssParserMode, result.get()))
+ return nullptr;
+ return result.release();
+}
+
+static PassRefPtrWillBeRawPtr<CSSValue> consumeLinearGradient(CSSParserTokenRange& args, CSSParserMode cssParserMode, CSSGradientRepeat repeating, CSSGradientType gradientType)
+{
+ RefPtrWillBeRawPtr<CSSLinearGradientValue> result = CSSLinearGradientValue::create(repeating, gradientType);
+
+ bool expectComma = true;
+ RefPtrWillBeRawPtr<CSSPrimitiveValue> angle = consumeAngle(args, cssParserMode);
+ if (angle) {
+ result->setAngle(angle.release());
+ } else if (gradientType == CSSPrefixedLinearGradient || consumeIdent<CSSValueTo>(args)) {
+ RefPtrWillBeRawPtr<CSSPrimitiveValue> endX = consumeIdent<CSSValueLeft, CSSValueRight>(args);
+ RefPtrWillBeRawPtr<CSSPrimitiveValue> endY = consumeIdent<CSSValueBottom, CSSValueTop>(args);
+ if (!endX && !endY) {
+ if (gradientType == CSSLinearGradient)
+ return nullptr;
+ endY = cssValuePool().createIdentifierValue(CSSValueTop);
+ expectComma = false;
+ } else if (!endX) {
+ endX = consumeIdent<CSSValueLeft, CSSValueRight>(args);
+ }
+
+ result->setFirstX(endX.release());
+ result->setFirstY(endY.release());
+ } else {
+ expectComma = false;
+ }
+
+ if (expectComma && !consumeCommaIncludingWhitespace(args))
+ return nullptr;
+ if (!consumeGradientColorStops(args, cssParserMode, result.get()))
+ return nullptr;
+ return result.release();
+}
+
+static PassRefPtrWillBeRawPtr<CSSValue> consumeImage(CSSParserTokenRange&, CSSParserContext);
+
+static PassRefPtrWillBeRawPtr<CSSValue> consumeCrossFade(CSSParserTokenRange& args, CSSParserContext context)
+{
+ RefPtrWillBeRawPtr<CSSValue> fromImageValue = consumeImage(args, context);
+ if (!fromImageValue || !consumeCommaIncludingWhitespace(args))
+ return nullptr;
+ RefPtrWillBeRawPtr<CSSValue> toImageValue = consumeImage(args, context);
+ if (!toImageValue || !consumeCommaIncludingWhitespace(args))
+ return nullptr;
+
+ RefPtrWillBeRawPtr<CSSPrimitiveValue> percentage = nullptr;
+ const CSSParserToken& percentageArg = args.consumeIncludingWhitespace();
+ if (percentageArg.type() == PercentageToken)
+ percentage = cssValuePool().createValue(clampTo<double>(percentageArg.numericValue() / 100, 0, 1), CSSPrimitiveValue::UnitType::Number);
+ else if (percentageArg.type() == NumberToken)
+ percentage = cssValuePool().createValue(clampTo<double>(percentageArg.numericValue(), 0, 1), CSSPrimitiveValue::UnitType::Number);
+
+ if (!percentage)
+ return nullptr;
+ return CSSCrossfadeValue::create(fromImageValue, toImageValue, percentage);
+}
+
+static PassRefPtrWillBeRawPtr<CSSValue> consumeGeneratedImage(CSSParserTokenRange& range, CSSParserContext context)
+{
+ CSSValueID id = range.peek().functionId();
+ CSSParserTokenRange rangeCopy = range;
+ CSSParserTokenRange args = consumeFunction(rangeCopy);
+ RefPtrWillBeRawPtr<CSSValue> result = nullptr;
+ if (id == CSSValueRadialGradient) {
+ result = consumeRadialGradient(args, context.mode(), NonRepeating);
+ } else if (id == CSSValueWebkitLinearGradient) {
+ // FIXME: This should send a deprecation message.
+ if (context.useCounter())
+ context.useCounter()->count(UseCounter::DeprecatedWebKitLinearGradient);
+ result = consumeLinearGradient(args, context.mode(), NonRepeating, CSSPrefixedLinearGradient);
+ } else if (id == CSSValueWebkitRepeatingLinearGradient) {
+ // FIXME: This should send a deprecation message.
+ if (context.useCounter())
+ context.useCounter()->count(UseCounter::DeprecatedWebKitRepeatingLinearGradient);
+ result = consumeLinearGradient(args, context.mode(), Repeating, CSSPrefixedLinearGradient);
+ } else if (id == CSSValueLinearGradient) {
+ result = consumeLinearGradient(args, context.mode(), NonRepeating, CSSLinearGradient);
+ } else if (id == CSSValueWebkitCrossFade) {
+ result = consumeCrossFade(args, context);
+ }
+ if (!result || !args.atEnd())
+ return nullptr;
+ range = rangeCopy;
+ return result;
+}
+
+static PassRefPtrWillBeRawPtr<CSSValue> consumeImage(CSSParserTokenRange& range, CSSParserContext context)
+{
+ if (range.peek().id() == CSSValueNone)
+ return consumeIdent(range);
+
+ AtomicString uri(consumeUrl(range));
+ if (!uri.isNull())
+ return CSSPropertyParser::createCSSImageValueWithReferrer(uri, context);
+ if (range.peek().type() == FunctionToken) {
+ CSSValueID id = range.peek().functionId();
+ if (id == CSSValueWebkitImageSet)
+ return consumeImageSet(range, context);
+ if (CSSPropertyParser::isGeneratedImage(id))
+ return consumeGeneratedImage(range, context);
+ }
+ return nullptr;
+}
+
PassRefPtrWillBeRawPtr<CSSValue> CSSPropertyParser::parseSingleValue(CSSPropertyID unresolvedProperty)
{
CSSPropertyID property = resolveCSSPropertyID(unresolvedProperty);
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698