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

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

Issue 2200313002: Move consumeImage to CSSPropertyParserHelpers (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Rename enum Created 4 years, 4 months 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 | « third_party/WebKit/Source/core/css/parser/CSSPropertyParserHelpers.h ('k') | 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/CSSPropertyParserHelpers.cpp
diff --git a/third_party/WebKit/Source/core/css/parser/CSSPropertyParserHelpers.cpp b/third_party/WebKit/Source/core/css/parser/CSSPropertyParserHelpers.cpp
index 40202f650e10a4a060301a61258c614503d9657a..d383afc447c6a0771de7fe248e1134040189c2ab 100644
--- a/third_party/WebKit/Source/core/css/parser/CSSPropertyParserHelpers.cpp
+++ b/third_party/WebKit/Source/core/css/parser/CSSPropertyParserHelpers.cpp
@@ -6,8 +6,14 @@
#include "core/css/CSSCalculationValue.h"
#include "core/css/CSSColorValue.h"
+#include "core/css/CSSCrossfadeValue.h"
+#include "core/css/CSSGradientValue.h"
+#include "core/css/CSSImageSetValue.h"
+#include "core/css/CSSImageValue.h"
+#include "core/css/CSSPaintValue.h"
#include "core/css/CSSStringValue.h"
#include "core/css/CSSValuePair.h"
+#include "core/frame/UseCounter.h"
namespace blink {
@@ -613,6 +619,457 @@ bool consumeOneOrTwoValuedPosition(CSSParserTokenRange& range, CSSParserMode css
return positionFromTwoValues(value1, value2, resultX, resultY);
}
+// This should go away once we drop support for -webkit-gradient
+static CSSPrimitiveValue* consumeDeprecatedGradientPoint(CSSParserTokenRange& args, bool horizontal)
+{
+ if (args.peek().type() == IdentToken) {
+ if ((horizontal && consumeIdent<CSSValueLeft>(args)) || (!horizontal && consumeIdent<CSSValueTop>(args)))
+ return CSSPrimitiveValue::create(0., CSSPrimitiveValue::UnitType::Percentage);
+ if ((horizontal && consumeIdent<CSSValueRight>(args)) || (!horizontal && consumeIdent<CSSValueBottom>(args)))
+ return CSSPrimitiveValue::create(100., CSSPrimitiveValue::UnitType::Percentage);
+ if (consumeIdent<CSSValueCenter>(args))
+ return CSSPrimitiveValue::create(50., CSSPrimitiveValue::UnitType::Percentage);
+ return nullptr;
+ }
+ CSSPrimitiveValue* result = consumePercent(args, ValueRangeAll);
+ if (!result)
+ result = consumeNumber(args, ValueRangeAll);
+ return result;
+}
+
+// Used to parse colors for -webkit-gradient(...).
+static CSSValue* consumeDeprecatedGradientStopColor(CSSParserTokenRange& args, CSSParserMode cssParserMode)
+{
+ if (args.peek().id() == CSSValueCurrentcolor)
+ return nullptr;
+ return consumeColor(args, cssParserMode);
+}
+
+static bool consumeDeprecatedGradientColorStop(CSSParserTokenRange& range, CSSGradientColorStop& stop, CSSParserMode cssParserMode)
+{
+ CSSValueID id = range.peek().functionId();
+ if (id != CSSValueFrom && id != CSSValueTo && id != CSSValueColorStop)
+ return false;
+
+ CSSParserTokenRange args = consumeFunction(range);
+ double position;
+ if (id == CSSValueFrom || id == CSSValueTo) {
+ position = (id == CSSValueFrom) ? 0 : 1;
+ } else {
+ DCHECK(id == CSSValueColorStop);
+ const CSSParserToken& arg = args.consumeIncludingWhitespace();
+ if (arg.type() == PercentageToken)
+ position = arg.numericValue() / 100.0;
+ else if (arg.type() == NumberToken)
+ position = arg.numericValue();
+ else
+ return false;
+
+ if (!consumeCommaIncludingWhitespace(args))
+ return false;
+ }
+
+ stop.m_position = CSSPrimitiveValue::create(position, CSSPrimitiveValue::UnitType::Number);
+ stop.m_color = consumeDeprecatedGradientStopColor(args, cssParserMode);
+ return stop.m_color && args.atEnd();
+}
+
+static CSSValue* consumeDeprecatedGradient(CSSParserTokenRange& args, CSSParserMode cssParserMode)
+{
+ CSSGradientValue* result = nullptr;
+ CSSValueID id = args.consumeIncludingWhitespace().id();
+ bool isDeprecatedRadialGradient = (id == CSSValueRadial);
+ if (isDeprecatedRadialGradient)
+ result = CSSRadialGradientValue::create(NonRepeating, CSSDeprecatedRadialGradient);
+ else if (id == CSSValueLinear)
+ result = CSSLinearGradientValue::create(NonRepeating, CSSDeprecatedLinearGradient);
+ if (!result || !consumeCommaIncludingWhitespace(args))
+ return nullptr;
+
+ CSSPrimitiveValue* point = consumeDeprecatedGradientPoint(args, true);
+ if (!point)
+ return nullptr;
+ result->setFirstX(point);
+ point = consumeDeprecatedGradientPoint(args, false);
+ if (!point)
+ return nullptr;
+ result->setFirstY(point);
+
+ if (!consumeCommaIncludingWhitespace(args))
+ return nullptr;
+
+ // For radial gradients only, we now expect a numeric radius.
+ if (isDeprecatedRadialGradient) {
+ CSSPrimitiveValue* radius = consumeNumber(args, ValueRangeAll);
+ if (!radius || !consumeCommaIncludingWhitespace(args))
+ return nullptr;
+ toCSSRadialGradientValue(result)->setFirstRadius(radius);
+ }
+
+ point = consumeDeprecatedGradientPoint(args, true);
+ if (!point)
+ return nullptr;
+ result->setSecondX(point);
+ point = consumeDeprecatedGradientPoint(args, false);
+ if (!point)
+ return nullptr;
+ result->setSecondY(point);
+
+ // For radial gradients only, we now expect the second radius.
+ if (isDeprecatedRadialGradient) {
+ if (!consumeCommaIncludingWhitespace(args))
+ return nullptr;
+ CSSPrimitiveValue* radius = consumeNumber(args, ValueRangeAll);
+ if (!radius)
+ return nullptr;
+ toCSSRadialGradientValue(result)->setSecondRadius(radius);
+ }
+
+ CSSGradientColorStop stop;
+ while (consumeCommaIncludingWhitespace(args)) {
+ if (!consumeDeprecatedGradientColorStop(args, stop, cssParserMode))
+ return nullptr;
+ result->addStop(stop);
+ }
+
+ return result;
+}
+
+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 CSSValue* consumeDeprecatedRadialGradient(CSSParserTokenRange& args, CSSParserMode cssParserMode, CSSGradientRepeat repeating)
+{
+ CSSRadialGradientValue* result = CSSRadialGradientValue::create(repeating, CSSPrefixedRadialGradient);
+ CSSValue* centerX = nullptr;
+ CSSValue* centerY = nullptr;
+ consumeOneOrTwoValuedPosition(args, cssParserMode, UnitlessQuirk::Forbid, centerX, centerY);
+ if ((centerX || centerY) && !consumeCommaIncludingWhitespace(args))
+ return nullptr;
+
+ result->setFirstX(toCSSPrimitiveValue(centerX));
+ result->setSecondX(toCSSPrimitiveValue(centerX));
+ result->setFirstY(toCSSPrimitiveValue(centerY));
+ result->setSecondY(toCSSPrimitiveValue(centerY));
+
+ CSSPrimitiveValue* shape = consumeIdent<CSSValueCircle, CSSValueEllipse>(args);
+ CSSPrimitiveValue* sizeKeyword = consumeIdent<CSSValueClosestSide, CSSValueClosestCorner, CSSValueFarthestSide, CSSValueFarthestCorner, CSSValueContain, CSSValueCover>(args);
+ if (!shape)
+ shape = consumeIdent<CSSValueCircle, CSSValueEllipse>(args);
+ result->setShape(shape);
+ result->setSizingBehavior(sizeKeyword);
+
+ // Or, two lengths or percentages
+ if (!shape && !sizeKeyword) {
+ CSSPrimitiveValue* horizontalSize = consumeLengthOrPercent(args, cssParserMode, ValueRangeAll);
+ CSSPrimitiveValue* verticalSize = nullptr;
+ if (horizontalSize) {
+ verticalSize = consumeLengthOrPercent(args, cssParserMode, ValueRangeAll);
+ if (!verticalSize)
+ return nullptr;
+ consumeCommaIncludingWhitespace(args);
+ result->setEndHorizontalSize(horizontalSize);
+ result->setEndVerticalSize(verticalSize);
+ }
+ } else {
+ consumeCommaIncludingWhitespace(args);
+ }
+ if (!consumeGradientColorStops(args, cssParserMode, result))
+ return nullptr;
+
+ return result;
+}
+
+static CSSValue* consumeRadialGradient(CSSParserTokenRange& args, CSSParserMode cssParserMode, CSSGradientRepeat repeating)
+{
+ CSSRadialGradientValue* result = CSSRadialGradientValue::create(repeating, CSSRadialGradient);
+
+ CSSPrimitiveValue* shape = nullptr;
+ CSSPrimitiveValue* sizeKeyword = nullptr;
+ CSSPrimitiveValue* horizontalSize = nullptr;
+ 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 {
+ CSSPrimitiveValue* center = consumeLengthOrPercent(args, cssParserMode, ValueRangeAll);
+ if (!center)
+ break;
+ if (horizontalSize)
+ return nullptr;
+ horizontalSize = center;
+ center = consumeLengthOrPercent(args, cssParserMode, ValueRangeAll);
+ if (center) {
+ verticalSize = center;
+ ++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.
+ if (!verticalSize && horizontalSize && horizontalSize->isPercentage())
+ return nullptr;
+ if ((horizontalSize && horizontalSize->isCalculatedPercentageWithLength())
+ || (verticalSize && verticalSize->isCalculatedPercentageWithLength()))
+ return nullptr;
+
+ result->setShape(shape);
+ result->setSizingBehavior(sizeKeyword);
+ result->setEndHorizontalSize(horizontalSize);
+ result->setEndVerticalSize(verticalSize);
+
+ CSSValue* centerX = nullptr;
+ 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))
+ return nullptr;
+ return result;
+}
+
+static CSSValue* consumeLinearGradient(CSSParserTokenRange& args, CSSParserMode cssParserMode, CSSGradientRepeat repeating, CSSGradientType gradientType)
+{
+ CSSLinearGradientValue* result = CSSLinearGradientValue::create(repeating, gradientType);
+
+ bool expectComma = true;
+ CSSPrimitiveValue* angle = consumeAngle(args);
+ if (angle) {
+ result->setAngle(angle);
+ } else if (gradientType == CSSPrefixedLinearGradient || consumeIdent<CSSValueTo>(args)) {
+ CSSPrimitiveValue* endX = consumeIdent<CSSValueLeft, CSSValueRight>(args);
+ CSSPrimitiveValue* endY = consumeIdent<CSSValueBottom, CSSValueTop>(args);
+ if (!endX && !endY) {
+ if (gradientType == CSSLinearGradient)
+ return nullptr;
+ endY = CSSPrimitiveValue::createIdentifier(CSSValueTop);
+ expectComma = false;
+ } else if (!endX) {
+ endX = consumeIdent<CSSValueLeft, CSSValueRight>(args);
+ }
+
+ result->setFirstX(endX);
+ result->setFirstY(endY);
+ } else {
+ expectComma = false;
+ }
+
+ if (expectComma && !consumeCommaIncludingWhitespace(args))
+ return nullptr;
+ if (!consumeGradientColorStops(args, cssParserMode, result))
+ return nullptr;
+ return result;
+}
+
+CSSValue* consumeImageOrNone(CSSParserTokenRange& range, CSSParserContext context)
+{
+ if (range.peek().id() == CSSValueNone)
+ return consumeIdent(range);
+ return consumeImage(range, context);
+}
+
+static CSSValue* consumeCrossFade(CSSParserTokenRange& args, CSSParserContext context)
+{
+ CSSValue* fromImageValue = consumeImageOrNone(args, context);
+ if (!fromImageValue || !consumeCommaIncludingWhitespace(args))
+ return nullptr;
+ CSSValue* toImageValue = consumeImageOrNone(args, context);
+ if (!toImageValue || !consumeCommaIncludingWhitespace(args))
+ return nullptr;
+
+ CSSPrimitiveValue* percentage = nullptr;
+ const CSSParserToken& percentageArg = args.consumeIncludingWhitespace();
+ if (percentageArg.type() == PercentageToken)
+ percentage = CSSPrimitiveValue::create(clampTo<double>(percentageArg.numericValue() / 100, 0, 1), CSSPrimitiveValue::UnitType::Number);
+ else if (percentageArg.type() == NumberToken)
+ percentage = CSSPrimitiveValue::create(clampTo<double>(percentageArg.numericValue(), 0, 1), CSSPrimitiveValue::UnitType::Number);
+
+ if (!percentage)
+ return nullptr;
+ return CSSCrossfadeValue::create(fromImageValue, toImageValue, percentage);
+}
+
+static CSSValue* consumePaint(CSSParserTokenRange& args, CSSParserContext context)
+{
+ DCHECK(RuntimeEnabledFeatures::cssPaintAPIEnabled());
+
+ CSSCustomIdentValue* name = consumeCustomIdent(args);
+ if (!name)
+ return nullptr;
+
+ return CSSPaintValue::create(name);
+}
+
+static CSSValue* consumeGeneratedImage(CSSParserTokenRange& range, CSSParserContext context)
+{
+ CSSValueID id = range.peek().functionId();
+ CSSParserTokenRange rangeCopy = range;
+ CSSParserTokenRange args = consumeFunction(rangeCopy);
+ CSSValue* result = nullptr;
+ if (id == CSSValueRadialGradient) {
+ result = consumeRadialGradient(args, context.mode(), NonRepeating);
+ } else if (id == CSSValueRepeatingRadialGradient) {
+ result = consumeRadialGradient(args, context.mode(), Repeating);
+ } 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 == CSSValueRepeatingLinearGradient) {
+ result = consumeLinearGradient(args, context.mode(), Repeating, CSSLinearGradient);
+ } else if (id == CSSValueLinearGradient) {
+ result = consumeLinearGradient(args, context.mode(), NonRepeating, CSSLinearGradient);
+ } else if (id == CSSValueWebkitGradient) {
+ // FIXME: This should send a deprecation message.
+ if (context.useCounter())
+ context.useCounter()->count(UseCounter::DeprecatedWebKitGradient);
+ result = consumeDeprecatedGradient(args, context.mode());
+ } else if (id == CSSValueWebkitRadialGradient) {
+ // FIXME: This should send a deprecation message.
+ if (context.useCounter())
+ context.useCounter()->count(UseCounter::DeprecatedWebKitRadialGradient);
+ result = consumeDeprecatedRadialGradient(args, context.mode(), NonRepeating);
+ } else if (id == CSSValueWebkitRepeatingRadialGradient) {
+ if (context.useCounter())
+ context.useCounter()->count(UseCounter::DeprecatedWebKitRepeatingRadialGradient);
+ result = consumeDeprecatedRadialGradient(args, context.mode(), Repeating);
+ } else if (id == CSSValueWebkitCrossFade) {
+ result = consumeCrossFade(args, context);
+ } else if (id == CSSValuePaint) {
+ result = RuntimeEnabledFeatures::cssPaintAPIEnabled() ? consumePaint(args, context) : nullptr;
+ }
+ if (!result || !args.atEnd())
+ return nullptr;
+ range = rangeCopy;
+ return result;
+}
+
+static CSSValue* createCSSImageValueWithReferrer(const AtomicString& rawValue, const CSSParserContext& context)
+{
+ CSSValue* imageValue = CSSImageValue::create(rawValue, context.completeURL(rawValue));
+ toCSSImageValue(imageValue)->setReferrer(context.referrer());
+ return imageValue;
+}
+
+static CSSValue* consumeImageSet(CSSParserTokenRange& range, const CSSParserContext& context)
+{
+ CSSParserTokenRange rangeCopy = range;
+ CSSParserTokenRange args = consumeFunction(rangeCopy);
+ CSSImageSetValue* imageSet = CSSImageSetValue::create();
+ do {
+ AtomicString urlValue = consumeUrl(args).toAtomicString();
+ if (urlValue.isNull())
+ return nullptr;
+
+ CSSValue* image = createCSSImageValueWithReferrer(urlValue, context);
+ imageSet->append(*image);
+
+ const CSSParserToken& token = args.consumeIncludingWhitespace();
+ if (token.type() != DimensionToken)
+ return nullptr;
+ if (token.value() != "x")
+ return nullptr;
+ DCHECK(token.unitType() == CSSPrimitiveValue::UnitType::Unknown);
+ double imageScaleFactor = token.numericValue();
+ if (imageScaleFactor <= 0)
+ return nullptr;
+ imageSet->append(*CSSPrimitiveValue::create(imageScaleFactor, CSSPrimitiveValue::UnitType::Number));
+ } while (consumeCommaIncludingWhitespace(args));
+ if (!args.atEnd())
+ return nullptr;
+ range = rangeCopy;
+ return imageSet;
+}
+
+static bool isGeneratedImage(CSSValueID id)
+{
+ return id == CSSValueLinearGradient || id == CSSValueRadialGradient
+ || id == CSSValueRepeatingLinearGradient || id == CSSValueRepeatingRadialGradient
+ || id == CSSValueWebkitLinearGradient || id == CSSValueWebkitRadialGradient
+ || id == CSSValueWebkitRepeatingLinearGradient || id == CSSValueWebkitRepeatingRadialGradient
+ || id == CSSValueWebkitGradient || id == CSSValueWebkitCrossFade || id == CSSValuePaint;
+}
+
+CSSValue* consumeImage(CSSParserTokenRange& range, CSSParserContext context, ConsumeGeneratedImage generatedImage)
+{
+ AtomicString uri = consumeUrl(range).toAtomicString();
+ if (!uri.isNull())
+ return createCSSImageValueWithReferrer(uri, context);
+ if (range.peek().type() == FunctionToken) {
+ CSSValueID id = range.peek().functionId();
+ if (id == CSSValueWebkitImageSet)
+ return consumeImageSet(range, context);
+ if (generatedImage == ConsumeGeneratedImage::Allow && isGeneratedImage(id))
+ return consumeGeneratedImage(range, context);
+ }
+ return nullptr;
+}
+
} // namespace CSSPropertyParserHelpers
} // namespace blink
« no previous file with comments | « third_party/WebKit/Source/core/css/parser/CSSPropertyParserHelpers.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698