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

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: Add deprecated linear gradient support 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 6e2b2211d22e2763058d7ae3233c3358c86d817f..a2ef560f4c6edbdc74aeb6f2cf6295a280a63a7f 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,227 @@ static PassRefPtrWillBeRawPtr<CSSValue> consumeCursor(CSSParserTokenRange& range
return list.release();
}
+static bool consumeGradientColorStops(CSSParserTokenRange& range, CSSParserContext context, CSSGradientValue* gradient, bool expectComma)
+{
+ bool supportsColorHints = gradient->gradientType() == CSSLinearGradient || gradient->gradientType() == CSSRadialGradient;
+
+ // The first color stop cannot be a color hint.
+ bool previousStopWasColorHint = true;
+ while (!range.atEnd()) {
Timothy Loh 2015/12/09 06:59:57 Can we just use a regular do-while loop here and m
rwlbuis 2015/12/09 21:31:13 Done.
+ if (expectComma && !consumeCommaIncludingWhitespace(range))
+ return false;
+
+ CSSGradientColorStop stop;
+ stop.m_color = consumeColor(range, context);
+
+ // 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, context.mode(), ValueRangeAll);
+ if (!stop.m_color && !stop.m_position)
+ return false;
+
+ gradient->addStop(stop);
+ expectComma = true;
+ }
+
+ // 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, CSSParserContext context, CSSGradientRepeat repeating)
+{
+ RefPtrWillBeRawPtr<CSSRadialGradientValue> result = CSSRadialGradientValue::create(repeating, CSSRadialGradient);
+
+ RefPtrWillBeRawPtr<CSSPrimitiveValue> shapeValue = nullptr;
Timothy Loh 2015/12/09 06:59:57 imo shapeValue -> shape, sizeValue -> sizeKeyword
rwlbuis 2015/12/09 21:31:13 Done.
+ RefPtrWillBeRawPtr<CSSPrimitiveValue> sizeValue = 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 (shapeValue)
+ return nullptr;
+ shapeValue = consumeIdent(args);
+ } else if (id == CSSValueClosestSide || id == CSSValueClosestCorner || id == CSSValueFarthestSide || id == CSSValueFarthestCorner) {
+ if (sizeValue || horizontalSize)
Timothy Loh 2015/12/09 06:59:57 Probably nicer to leave out the horizontalSize che
rwlbuis 2015/12/09 21:31:14 Done.
+ return nullptr;
+ sizeValue = consumeIdent(args);
+ } else {
+ break;
+ }
+ } else {
+ RefPtrWillBeRawPtr<CSSPrimitiveValue> center = consumeLengthOrPercent(args, context.mode(), ValueRangeAll);
+ if (!center)
+ break;
+ if (sizeValue || horizontalSize)
Timothy Loh 2015/12/09 06:59:57 and leave out the sizeValue check here
rwlbuis 2015/12/09 21:31:14 Done.
+ return nullptr;
+ horizontalSize = center;
+
+ if ((center = consumeLengthOrPercent(args, context.mode(), ValueRangeAll))) {
+ verticalSize = center.release();
+ ++i;
+ }
+ }
+ }
+
+ // You can specify size as a keyword or a length/percentage, not both.
+ if (sizeValue && horizontalSize)
+ return nullptr;
+ // Circles must have 0 or 1 lengths.
+ if (shapeValue && shapeValue->getValueID() == CSSValueCircle && verticalSize)
+ return nullptr;
+ // Ellipses must have 0 or 2 length/percentages.
+ if (shapeValue && shapeValue->getValueID() == CSSValueEllipse && horizontalSize && !verticalSize)
+ return nullptr;
+ // If there's only one size, it must be a length.
+ if (!verticalSize && horizontalSize && horizontalSize->isPercentage())
Timothy Loh 2015/12/09 06:59:57 // TODO(timloh): Calcs with both lengths and perce
rwlbuis 2015/12/09 21:31:13 Done.
+ return nullptr;
+
+ result->setShape(shapeValue);
+ result->setSizingBehavior(sizeValue);
+ result->setEndHorizontalSize(horizontalSize);
+ result->setEndVerticalSize(verticalSize);
+
+ RefPtrWillBeRawPtr<CSSValue> centerX = nullptr;
+ RefPtrWillBeRawPtr<CSSValue> centerY = nullptr;
+ if (args.peek().id() == CSSValueAt) {
+ args.consumeIncludingWhitespace();
+
+ consumePosition(args, context.mode(), 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);
+ }
+
+ bool expectComma = shapeValue || sizeValue || horizontalSize || centerX || centerY;
+ if (!consumeGradientColorStops(args, context, result.get(), expectComma) || !args.atEnd())
+ return nullptr;
+
+ return result.release();
+}
+
+static PassRefPtrWillBeRawPtr<CSSValue> consumeLinearGradient(CSSParserTokenRange args, CSSParserContext context, CSSGradientRepeat repeating, CSSGradientType gradientType)
+{
+ RefPtrWillBeRawPtr<CSSLinearGradientValue> result = CSSLinearGradientValue::create(repeating, gradientType);
+
+ bool expectComma = true;
+ RefPtrWillBeRawPtr<CSSPrimitiveValue> angle = consumeAngle(args, context.mode());
+ 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)
+ return nullptr;
+ RefPtrWillBeRawPtr<CSSPrimitiveValue> location = consumeIdent<CSSValueLeft, CSSValueRight>(args);
Timothy Loh 2015/12/09 06:59:57 Should be enough to just write if (!endX) end
rwlbuis 2015/12/09 21:31:13 I think endX and location have to be separate. Oth
rwlbuis 2015/12/09 23:08:46 Oh, I see why you mean here too now, should be fix
+ if (location) {
+ if (endX)
+ return nullptr;
+ endX = location;
+ } else if ((location = consumeIdent<CSSValueBottom, CSSValueTop>(args))) {
+ if (endY)
+ return nullptr;
+ endY = location;
+ }
+
+ if (!endX && !endY) {
+ endY = cssValuePool().createIdentifierValue(CSSValueTop);
Timothy Loh 2015/12/09 06:59:57 Unreachable?
rwlbuis 2015/12/09 21:31:13 Sorry, I merged a patch wrong, this is still neede
+ expectComma = false;
+ }
+
+ result->setFirstX(endX.release());
+ result->setFirstY(endY.release());
+ }
+
+ if (!consumeGradientColorStops(args, context, result.get(), expectComma) || !args.atEnd())
+ 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 || !args.atEnd())
+ return nullptr;
+
+ return CSSCrossfadeValue::create(fromImageValue, toImageValue, percentage);
+}
+
+static PassRefPtrWillBeRawPtr<CSSValue> consumeGeneratedImage(CSSParserTokenRange& range, CSSParserContext context)
Timothy Loh 2015/12/09 06:59:57 As usual, we need to make sure this doesn't accide
rwlbuis 2015/12/09 21:31:14 Done.
Timothy Loh 2015/12/10 04:20:07 Any reason to not use else if here? (which imo mak
+{
+ CSSValueID id = range.peek().functionId();
+ if (id == CSSValueRadialGradient)
+ return consumeRadialGradient(consumeFunction(range), context, NonRepeating);
+ if (id == CSSValueWebkitLinearGradient) {
+ // FIXME: This should send a deprecation message.
+ if (context.useCounter())
+ context.useCounter()->count(UseCounter::DeprecatedWebKitLinearGradient);
+ return consumeLinearGradient(consumeFunction(range), context, NonRepeating, CSSPrefixedLinearGradient);
+ }
+ if (id == CSSValueWebkitRepeatingLinearGradient) {
+ // FIXME: This should send a deprecation message.
+ if (context.useCounter())
+ context.useCounter()->count(UseCounter::DeprecatedWebKitRepeatingLinearGradient);
+ return consumeLinearGradient(consumeFunction(range), context, Repeating, CSSPrefixedLinearGradient);
+ }
+ if (id == CSSValueLinearGradient)
+ return consumeLinearGradient(consumeFunction(range), context, NonRepeating, CSSLinearGradient);
+ if (id == CSSValueWebkitCrossFade)
+ return consumeCrossFade(consumeFunction(range), context);
+ return nullptr;
+}
+
+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