| 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
 | 
| 
 |