| Index: third_party/WebKit/Source/core/css/parser/LegacyCSSPropertyParser.cpp
|
| diff --git a/third_party/WebKit/Source/core/css/parser/LegacyCSSPropertyParser.cpp b/third_party/WebKit/Source/core/css/parser/LegacyCSSPropertyParser.cpp
|
| index 2535a3874e1bb31d6f3b0e5b7ad3c94d78622bb7..9c5669227e8d6c538aee9084a83e61c502adf79d 100644
|
| --- a/third_party/WebKit/Source/core/css/parser/LegacyCSSPropertyParser.cpp
|
| +++ b/third_party/WebKit/Source/core/css/parser/LegacyCSSPropertyParser.cpp
|
| @@ -27,16 +27,13 @@
|
| #include "core/css/parser/CSSPropertyParser.h"
|
|
|
| #include "core/StylePropertyShorthand.h"
|
| -#include "core/css/CSSCrossfadeValue.h"
|
| #include "core/css/CSSCustomIdentValue.h"
|
| #include "core/css/CSSFunctionValue.h"
|
| #include "core/css/CSSGridLineNamesValue.h"
|
| -#include "core/css/CSSImageSetValue.h"
|
| #include "core/css/CSSPrimitiveValueMappings.h"
|
| #include "core/css/CSSValuePair.h"
|
| #include "core/css/CSSValuePool.h"
|
| #include "core/css/parser/CSSParserValues.h"
|
| -#include "core/frame/UseCounter.h"
|
| #include "core/style/GridArea.h"
|
| #include "platform/RuntimeEnabledFeatures.h"
|
|
|
| @@ -220,15 +217,6 @@ static inline bool isComma(CSSParserValue* value)
|
| return value->m_unit == CSSParserValue::Operator && value->iValue == ',';
|
| }
|
|
|
| -static bool consumeComma(CSSParserValueList* valueList)
|
| -{
|
| - CSSParserValue* value = valueList->current();
|
| - if (!value || !isComma(value))
|
| - return false;
|
| - valueList->next();
|
| - return true;
|
| -}
|
| -
|
| static inline bool isForwardSlashOperator(CSSParserValue* value)
|
| {
|
| ASSERT(value);
|
| @@ -368,2714 +356,875 @@ bool CSSPropertyParser::legacyParseShorthand(CSSPropertyID propertyID, bool impo
|
| }
|
| }
|
|
|
| -void CSSPropertyParser::addFillValue(RefPtrWillBeRawPtr<CSSValue>& lval, PassRefPtrWillBeRawPtr<CSSValue> rval)
|
| +static inline bool isCSSWideKeyword(const CSSParserValue& value)
|
| {
|
| - if (lval) {
|
| - if (lval->isBaseValueList())
|
| - toCSSValueList(lval.get())->append(rval);
|
| - else {
|
| - PassRefPtrWillBeRawPtr<CSSValue> oldlVal(lval.release());
|
| - PassRefPtrWillBeRawPtr<CSSValueList> list = CSSValueList::createCommaSeparated();
|
| - list->append(oldlVal);
|
| - list->append(rval);
|
| - lval = list;
|
| - }
|
| - }
|
| - else
|
| - lval = rval;
|
| + return value.id == CSSValueInitial || value.id == CSSValueInherit || value.id == CSSValueUnset || value.id == CSSValueDefault;
|
| }
|
|
|
| -static bool parseBackgroundClip(CSSParserValue* parserValue, RefPtrWillBeRawPtr<CSSValue>& cssValue)
|
| +static inline bool isValidCustomIdentForGridPositions(const CSSParserValue& value)
|
| {
|
| - if (parserValue->id == CSSValueBorderBox || parserValue->id == CSSValuePaddingBox
|
| - || parserValue->id == CSSValueContentBox) {
|
| - cssValue = cssValuePool().createIdentifierValue(parserValue->id);
|
| - return true;
|
| - }
|
| - return false;
|
| + // FIXME: we need a more general solution for <custom-ident> in all properties.
|
| + return value.m_unit == CSSParserValue::Identifier && value.id != CSSValueSpan && value.id != CSSValueAuto && !isCSSWideKeyword(value);
|
| }
|
|
|
| -const int cMaxFillProperties = 9;
|
| -
|
| -bool CSSPropertyParser::parseFillShorthand(CSSPropertyID propId, const CSSPropertyID* properties, int numProperties, bool important)
|
| +// The function parses [ <integer> || <custom-ident> ] in <grid-line> (which can be stand alone or with 'span').
|
| +bool CSSPropertyParser::parseIntegerOrCustomIdentFromGridPosition(RefPtrWillBeRawPtr<CSSPrimitiveValue>& numericValue, RefPtrWillBeRawPtr<CSSCustomIdentValue>& gridLineName)
|
| {
|
| - ASSERT(numProperties <= cMaxFillProperties);
|
| - if (numProperties > cMaxFillProperties)
|
| - return false;
|
| -
|
| - ShorthandScope scope(this, propId);
|
| -
|
| - bool parsedProperty[cMaxFillProperties] = { false };
|
| - RefPtrWillBeRawPtr<CSSValue> values[cMaxFillProperties];
|
| -#if ENABLE(OILPAN)
|
| - // Zero initialize the array of raw pointers.
|
| - memset(&values, 0, sizeof(values));
|
| -#endif
|
| - RefPtrWillBeRawPtr<CSSValue> clipValue = nullptr;
|
| - RefPtrWillBeRawPtr<CSSValue> positionYValue = nullptr;
|
| - RefPtrWillBeRawPtr<CSSValue> repeatYValue = nullptr;
|
| - bool foundClip = false;
|
| - int i;
|
| - bool foundPositionCSSProperty = false;
|
| -
|
| - while (m_valueList->current()) {
|
| - CSSParserValue* val = m_valueList->current();
|
| - if (isComma(val)) {
|
| - // We hit the end. Fill in all remaining values with the initial value.
|
| - m_valueList->next();
|
| - for (i = 0; i < numProperties; ++i) {
|
| - if (properties[i] == CSSPropertyBackgroundColor && parsedProperty[i])
|
| - // Color is not allowed except as the last item in a list for backgrounds.
|
| - // Reject the entire property.
|
| - return false;
|
| -
|
| - if (!parsedProperty[i] && properties[i] != CSSPropertyBackgroundColor) {
|
| - addFillValue(values[i], cssValuePool().createImplicitInitialValue());
|
| - if (properties[i] == CSSPropertyBackgroundPosition || properties[i] == CSSPropertyWebkitMaskPosition)
|
| - addFillValue(positionYValue, cssValuePool().createImplicitInitialValue());
|
| - if (properties[i] == CSSPropertyBackgroundRepeat || properties[i] == CSSPropertyWebkitMaskRepeat)
|
| - addFillValue(repeatYValue, cssValuePool().createImplicitInitialValue());
|
| - if ((properties[i] == CSSPropertyBackgroundOrigin || properties[i] == CSSPropertyWebkitMaskOrigin) && !parsedProperty[i]) {
|
| - // If background-origin wasn't present, then reset background-clip also.
|
| - addFillValue(clipValue, cssValuePool().createImplicitInitialValue());
|
| - }
|
| - }
|
| - parsedProperty[i] = false;
|
| - }
|
| - if (!m_valueList->current())
|
| - break;
|
| - }
|
| -
|
| - bool sizeCSSPropertyExpected = false;
|
| - if (isForwardSlashOperator(val) && foundPositionCSSProperty) {
|
| - sizeCSSPropertyExpected = true;
|
| + CSSParserValue* value = m_valueList->current();
|
| + if (validUnit(value, FInteger) && value->fValue) {
|
| + numericValue = createPrimitiveNumericValue(value);
|
| + value = m_valueList->next();
|
| + if (value && isValidCustomIdentForGridPositions(*value)) {
|
| + gridLineName = createPrimitiveCustomIdentValue(m_valueList->current());
|
| m_valueList->next();
|
| }
|
| -
|
| - foundPositionCSSProperty = false;
|
| - bool found = false;
|
| - for (i = 0; !found && i < numProperties; ++i) {
|
| -
|
| - if (sizeCSSPropertyExpected && (properties[i] != CSSPropertyBackgroundSize && properties[i] != CSSPropertyWebkitMaskSize))
|
| - continue;
|
| - if (!sizeCSSPropertyExpected && (properties[i] == CSSPropertyBackgroundSize || properties[i] == CSSPropertyWebkitMaskSize))
|
| - continue;
|
| -
|
| - if (!parsedProperty[i]) {
|
| - RefPtrWillBeRawPtr<CSSValue> val1 = nullptr;
|
| - RefPtrWillBeRawPtr<CSSValue> val2 = nullptr;
|
| - CSSPropertyID propId1, propId2;
|
| - CSSParserValue* parserValue = m_valueList->current();
|
| - // parseFillProperty() may modify m_implicitShorthand, so we MUST reset it
|
| - // before EACH return below.
|
| - if (parserValue && parseFillProperty(properties[i], propId1, propId2, val1, val2)) {
|
| - parsedProperty[i] = found = true;
|
| - addFillValue(values[i], val1.release());
|
| - if (properties[i] == CSSPropertyBackgroundPosition || properties[i] == CSSPropertyWebkitMaskPosition)
|
| - addFillValue(positionYValue, val2.release());
|
| - if (properties[i] == CSSPropertyBackgroundRepeat || properties[i] == CSSPropertyWebkitMaskRepeat)
|
| - addFillValue(repeatYValue, val2.release());
|
| - if (properties[i] == CSSPropertyBackgroundOrigin || properties[i] == CSSPropertyWebkitMaskOrigin) {
|
| - // Reparse the value as a clip, and see if we succeed.
|
| - if (parseBackgroundClip(parserValue, val1))
|
| - addFillValue(clipValue, val1.release()); // The property parsed successfully.
|
| - else
|
| - addFillValue(clipValue, cssValuePool().createImplicitInitialValue()); // Some value was used for origin that is not supported by clip. Just reset clip instead.
|
| - }
|
| - if (properties[i] == CSSPropertyBackgroundClip || properties[i] == CSSPropertyWebkitMaskClip) {
|
| - // Update clipValue
|
| - addFillValue(clipValue, val1.release());
|
| - foundClip = true;
|
| - }
|
| - if (properties[i] == CSSPropertyBackgroundPosition || properties[i] == CSSPropertyWebkitMaskPosition)
|
| - foundPositionCSSProperty = true;
|
| - }
|
| - }
|
| - }
|
| -
|
| - // if we didn't find at least one match, this is an
|
| - // invalid shorthand and we have to ignore it
|
| - if (!found) {
|
| - m_implicitShorthand = false;
|
| - return false;
|
| - }
|
| - }
|
| -
|
| - // Now add all of the properties we found.
|
| - for (i = 0; i < numProperties; i++) {
|
| - // Fill in any remaining properties with the initial value.
|
| - if (!parsedProperty[i]) {
|
| - addFillValue(values[i], cssValuePool().createImplicitInitialValue());
|
| - if (properties[i] == CSSPropertyBackgroundPosition || properties[i] == CSSPropertyWebkitMaskPosition)
|
| - addFillValue(positionYValue, cssValuePool().createImplicitInitialValue());
|
| - if (properties[i] == CSSPropertyBackgroundRepeat || properties[i] == CSSPropertyWebkitMaskRepeat)
|
| - addFillValue(repeatYValue, cssValuePool().createImplicitInitialValue());
|
| - if (properties[i] == CSSPropertyBackgroundOrigin || properties[i] == CSSPropertyWebkitMaskOrigin) {
|
| - // If background-origin wasn't present, then reset background-clip also.
|
| - addFillValue(clipValue, cssValuePool().createImplicitInitialValue());
|
| - }
|
| - }
|
| - if (properties[i] == CSSPropertyBackgroundPosition) {
|
| - addProperty(CSSPropertyBackgroundPositionX, values[i].release(), important);
|
| - // it's OK to call positionYValue.release() since we only see CSSPropertyBackgroundPosition once
|
| - addProperty(CSSPropertyBackgroundPositionY, positionYValue.release(), important);
|
| - } else if (properties[i] == CSSPropertyWebkitMaskPosition) {
|
| - addProperty(CSSPropertyWebkitMaskPositionX, values[i].release(), important);
|
| - // it's OK to call positionYValue.release() since we only see CSSPropertyWebkitMaskPosition once
|
| - addProperty(CSSPropertyWebkitMaskPositionY, positionYValue.release(), important);
|
| - } else if (properties[i] == CSSPropertyBackgroundRepeat) {
|
| - addProperty(CSSPropertyBackgroundRepeatX, values[i].release(), important);
|
| - // it's OK to call repeatYValue.release() since we only see CSSPropertyBackgroundPosition once
|
| - addProperty(CSSPropertyBackgroundRepeatY, repeatYValue.release(), important);
|
| - } else if (properties[i] == CSSPropertyWebkitMaskRepeat) {
|
| - addProperty(CSSPropertyWebkitMaskRepeatX, values[i].release(), important);
|
| - // it's OK to call repeatYValue.release() since we only see CSSPropertyBackgroundPosition once
|
| - addProperty(CSSPropertyWebkitMaskRepeatY, repeatYValue.release(), important);
|
| - } else if ((properties[i] == CSSPropertyBackgroundClip || properties[i] == CSSPropertyWebkitMaskClip) && !foundClip)
|
| - // Value is already set while updating origin
|
| - continue;
|
| - else if (properties[i] == CSSPropertyBackgroundSize && !parsedProperty[i] && m_context.useLegacyBackgroundSizeShorthandBehavior())
|
| - continue;
|
| - else
|
| - addProperty(properties[i], values[i].release(), important);
|
| -
|
| - // Add in clip values when we hit the corresponding origin property.
|
| - if (properties[i] == CSSPropertyBackgroundOrigin && !foundClip)
|
| - addProperty(CSSPropertyBackgroundClip, clipValue.release(), important);
|
| - else if (properties[i] == CSSPropertyWebkitMaskOrigin && !foundClip)
|
| - addProperty(CSSPropertyWebkitMaskClip, clipValue.release(), important);
|
| - }
|
| -
|
| - m_implicitShorthand = false;
|
| - return true;
|
| -}
|
| -
|
| -PassRefPtrWillBeRawPtr<CSSValue> CSSPropertyParser::parseColor(const CSSParserValue* value, bool acceptQuirkyColors)
|
| -{
|
| - CSSValueID id = value->id;
|
| - if (isColorKeyword(id)) {
|
| - if (!isValueAllowedInMode(id, m_context.mode()))
|
| - return nullptr;
|
| - return cssValuePool().createIdentifierValue(id);
|
| - }
|
| - RGBA32 c = Color::transparent;
|
| - if (!parseColorFromValue(value, c, acceptQuirkyColors))
|
| - return nullptr;
|
| - return cssValuePool().createColorValue(c);
|
| -}
|
| -
|
| -bool CSSPropertyParser::parseFillImage(CSSParserValueList* valueList, RefPtrWillBeRawPtr<CSSValue>& value)
|
| -{
|
| - if (valueList->current()->id == CSSValueNone) {
|
| - value = cssValuePool().createIdentifierValue(CSSValueNone);
|
| - return true;
|
| - }
|
| - if (valueList->current()->m_unit == CSSParserValue::URI) {
|
| - value = createCSSImageValueWithReferrer(valueList->current()->string, m_context);
|
| return true;
|
| }
|
|
|
| - if (valueList->current()->m_unit == CSSParserValue::Function) {
|
| - if (CSSPropertyParser::isGeneratedImage(valueList->current()->function->id))
|
| - return parseGeneratedImage(valueList, value);
|
| -
|
| - if (valueList->current()->function->id == CSSValueWebkitImageSet) {
|
| - value = parseImageSet(m_valueList);
|
| - if (value)
|
| - return true;
|
| + if (isValidCustomIdentForGridPositions(*value)) {
|
| + gridLineName = createPrimitiveCustomIdentValue(m_valueList->current());
|
| + value = m_valueList->next();
|
| + if (value && validUnit(value, FInteger) && value->fValue) {
|
| + numericValue = createPrimitiveNumericValue(value);
|
| + m_valueList->next();
|
| }
|
| + return true;
|
| }
|
|
|
| return false;
|
| }
|
|
|
| -PassRefPtrWillBeRawPtr<CSSValue> CSSPropertyParser::parseFillPositionX(CSSParserValueList* valueList)
|
| +PassRefPtrWillBeRawPtr<CSSValue> CSSPropertyParser::parseGridPosition()
|
| {
|
| - int id = valueList->current()->id;
|
| - if (id == CSSValueLeft || id == CSSValueRight || id == CSSValueCenter) {
|
| - int percent = 0;
|
| - if (id == CSSValueRight)
|
| - percent = 100;
|
| - else if (id == CSSValueCenter)
|
| - percent = 50;
|
| - return cssValuePool().createValue(percent, CSSPrimitiveValue::UnitType::Percentage);
|
| - }
|
| - if (validUnit(valueList->current(), FPercent | FLength))
|
| - return createPrimitiveNumericValue(valueList->current());
|
| - return nullptr;
|
| -}
|
| + ASSERT(RuntimeEnabledFeatures::cssGridLayoutEnabled());
|
|
|
| -PassRefPtrWillBeRawPtr<CSSValue> CSSPropertyParser::parseFillPositionY(CSSParserValueList* valueList)
|
| -{
|
| - int id = valueList->current()->id;
|
| - if (id == CSSValueTop || id == CSSValueBottom || id == CSSValueCenter) {
|
| - int percent = 0;
|
| - if (id == CSSValueBottom)
|
| - percent = 100;
|
| - else if (id == CSSValueCenter)
|
| - percent = 50;
|
| - return cssValuePool().createValue(percent, CSSPrimitiveValue::UnitType::Percentage);
|
| + CSSParserValue* value = m_valueList->current();
|
| + if (value->id == CSSValueAuto) {
|
| + m_valueList->next();
|
| + return cssValuePool().createIdentifierValue(CSSValueAuto);
|
| }
|
| - if (validUnit(valueList->current(), FPercent | FLength))
|
| - return createPrimitiveNumericValue(valueList->current());
|
| - return nullptr;
|
| -}
|
|
|
| -PassRefPtrWillBeRawPtr<CSSPrimitiveValue> CSSPropertyParser::parseFillPositionComponent(CSSParserValueList* valueList, unsigned& cumulativeFlags, FillPositionFlag& individualFlag, FillPositionParsingMode parsingMode, Units unitless)
|
| -{
|
| - CSSValueID id = valueList->current()->id;
|
| - if (id == CSSValueLeft || id == CSSValueTop || id == CSSValueRight || id == CSSValueBottom || id == CSSValueCenter) {
|
| - int percent = 0;
|
| - if (id == CSSValueLeft || id == CSSValueRight) {
|
| - if (cumulativeFlags & XFillPosition)
|
| - return nullptr;
|
| - cumulativeFlags |= XFillPosition;
|
| - individualFlag = XFillPosition;
|
| - if (id == CSSValueRight)
|
| - percent = 100;
|
| + RefPtrWillBeRawPtr<CSSPrimitiveValue> numericValue = nullptr;
|
| + RefPtrWillBeRawPtr<CSSCustomIdentValue> gridLineName = nullptr;
|
| + bool hasSeenSpanKeyword = false;
|
| +
|
| + if (parseIntegerOrCustomIdentFromGridPosition(numericValue, gridLineName)) {
|
| + value = m_valueList->current();
|
| + if (value && value->id == CSSValueSpan) {
|
| + hasSeenSpanKeyword = true;
|
| + m_valueList->next();
|
| }
|
| - else if (id == CSSValueTop || id == CSSValueBottom) {
|
| - if (cumulativeFlags & YFillPosition)
|
| + } else if (value->id == CSSValueSpan) {
|
| + hasSeenSpanKeyword = true;
|
| + if (CSSParserValue* nextValue = m_valueList->next()) {
|
| + if (!isForwardSlashOperator(nextValue) && !parseIntegerOrCustomIdentFromGridPosition(numericValue, gridLineName))
|
| return nullptr;
|
| - cumulativeFlags |= YFillPosition;
|
| - individualFlag = YFillPosition;
|
| - if (id == CSSValueBottom)
|
| - percent = 100;
|
| - } else if (id == CSSValueCenter) {
|
| - // Center is ambiguous, so we're not sure which position we've found yet, an x or a y.
|
| - percent = 50;
|
| - cumulativeFlags |= AmbiguousFillPosition;
|
| - individualFlag = AmbiguousFillPosition;
|
| }
|
| + }
|
|
|
| - if (parsingMode == ResolveValuesAsKeyword)
|
| - return cssValuePool().createIdentifierValue(id);
|
| + // Check that we have consumed all the value list. For shorthands, the parser will pass
|
| + // the whole value list (including the opposite position).
|
| + if (m_valueList->current() && !isForwardSlashOperator(m_valueList->current()))
|
| + return nullptr;
|
|
|
| - return cssValuePool().createValue(percent, CSSPrimitiveValue::UnitType::Percentage);
|
| - }
|
| - if (validUnit(valueList->current(), FPercent | FLength | unitless)) {
|
| - if (!cumulativeFlags) {
|
| - cumulativeFlags |= XFillPosition;
|
| - individualFlag = XFillPosition;
|
| - } else if (cumulativeFlags & (XFillPosition | AmbiguousFillPosition)) {
|
| - cumulativeFlags |= YFillPosition;
|
| - individualFlag = YFillPosition;
|
| - } else {
|
| - if (m_parsedCalculation)
|
| - m_parsedCalculation.release();
|
| - return nullptr;
|
| - }
|
| - return createPrimitiveNumericValue(valueList->current());
|
| - }
|
| - return nullptr;
|
| -}
|
| + // If we didn't parse anything, this is not a valid grid position.
|
| + if (!hasSeenSpanKeyword && !gridLineName && !numericValue)
|
| + return nullptr;
|
|
|
| -static bool isValueConflictingWithCurrentEdge(int value1, int value2)
|
| -{
|
| - if ((value1 == CSSValueLeft || value1 == CSSValueRight) && (value2 == CSSValueLeft || value2 == CSSValueRight))
|
| - return true;
|
| + // Negative numbers are not allowed for span (but are for <integer>).
|
| + if (hasSeenSpanKeyword && numericValue && numericValue->getIntValue() < 0)
|
| + return nullptr;
|
|
|
| - if ((value1 == CSSValueTop || value1 == CSSValueBottom) && (value2 == CSSValueTop || value2 == CSSValueBottom))
|
| - return true;
|
| + // For the <custom-ident> case.
|
| + if (gridLineName && !numericValue && !hasSeenSpanKeyword)
|
| + return CSSCustomIdentValue::create(gridLineName->value());
|
|
|
| - return false;
|
| + RefPtrWillBeRawPtr<CSSValueList> values = CSSValueList::createSpaceSeparated();
|
| + if (hasSeenSpanKeyword)
|
| + values->append(cssValuePool().createIdentifierValue(CSSValueSpan));
|
| + if (numericValue)
|
| + values->append(numericValue.release());
|
| + if (gridLineName)
|
| + values->append(gridLineName.release());
|
| + ASSERT(values->length());
|
| + return values.release();
|
| }
|
|
|
| -static bool isFillPositionKeyword(CSSValueID value)
|
| +static PassRefPtrWillBeRawPtr<CSSValue> gridMissingGridPositionValue(CSSValue* value)
|
| {
|
| - return value == CSSValueLeft || value == CSSValueTop || value == CSSValueBottom || value == CSSValueRight || value == CSSValueCenter;
|
| + if (value->isCustomIdentValue())
|
| + return value;
|
| +
|
| + return cssValuePool().createIdentifierValue(CSSValueAuto);
|
| }
|
|
|
| -void CSSPropertyParser::parse4ValuesFillPosition(CSSParserValueList* valueList, RefPtrWillBeRawPtr<CSSValue>& value1, RefPtrWillBeRawPtr<CSSValue>& value2, PassRefPtrWillBeRawPtr<CSSPrimitiveValue> parsedValue1, PassRefPtrWillBeRawPtr<CSSPrimitiveValue> parsedValue2)
|
| +bool CSSPropertyParser::parseGridItemPositionShorthand(CSSPropertyID shorthandId, bool important)
|
| {
|
| - // [ left | right ] [ <percentage] | <length> ] && [ top | bottom ] [ <percentage> | <length> ]
|
| - // In the case of 4 values <position> requires the second value to be a length or a percentage.
|
| - if (isFillPositionKeyword(parsedValue2->getValueID()))
|
| - return;
|
| -
|
| - unsigned cumulativeFlags = 0;
|
| - FillPositionFlag value3Flag = InvalidFillPosition;
|
| - RefPtrWillBeRawPtr<CSSPrimitiveValue> value3 = parseFillPositionComponent(valueList, cumulativeFlags, value3Flag, ResolveValuesAsKeyword);
|
| - if (!value3)
|
| - return;
|
| -
|
| - CSSValueID ident1 = parsedValue1->getValueID();
|
| - CSSValueID ident3 = value3->getValueID();
|
| -
|
| - if (ident1 == CSSValueCenter)
|
| - return;
|
| -
|
| - if (!isFillPositionKeyword(ident3) || ident3 == CSSValueCenter)
|
| - return;
|
| -
|
| - // We need to check if the values are not conflicting, e.g. they are not on the same edge. It is
|
| - // needed as the second call to parseFillPositionComponent was on purpose not checking it. In the
|
| - // case of two values top 20px is invalid but in the case of 4 values it becomes valid.
|
| - if (isValueConflictingWithCurrentEdge(ident1, ident3))
|
| - return;
|
| -
|
| - valueList->next();
|
| + ShorthandScope scope(this, shorthandId);
|
| + const StylePropertyShorthand& shorthand = shorthandForProperty(shorthandId);
|
| + ASSERT(shorthand.length() == 2);
|
|
|
| - cumulativeFlags = 0;
|
| - FillPositionFlag value4Flag = InvalidFillPosition;
|
| - RefPtrWillBeRawPtr<CSSPrimitiveValue> value4 = parseFillPositionComponent(valueList, cumulativeFlags, value4Flag, ResolveValuesAsKeyword);
|
| - if (!value4)
|
| - return;
|
| + RefPtrWillBeRawPtr<CSSValue> startValue = parseGridPosition();
|
| + if (!startValue)
|
| + return false;
|
|
|
| - // 4th value must be a length or a percentage.
|
| - if (isFillPositionKeyword(value4->getValueID()))
|
| - return;
|
| + RefPtrWillBeRawPtr<CSSValue> endValue = nullptr;
|
| + if (m_valueList->current()) {
|
| + if (!isForwardSlashOperator(m_valueList->current()))
|
| + return false;
|
|
|
| - value1 = CSSValuePair::create(parsedValue1, parsedValue2, CSSValuePair::DropIdenticalValues);
|
| - value2 = CSSValuePair::create(value3, value4, CSSValuePair::DropIdenticalValues);
|
| + if (!m_valueList->next())
|
| + return false;
|
|
|
| - if (ident1 == CSSValueTop || ident1 == CSSValueBottom)
|
| - value1.swap(value2);
|
| + endValue = parseGridPosition();
|
| + if (!endValue || m_valueList->current())
|
| + return false;
|
| + } else {
|
| + endValue = gridMissingGridPositionValue(startValue.get());
|
| + }
|
|
|
| - valueList->next();
|
| + addProperty(shorthand.properties()[0], startValue, important);
|
| + addProperty(shorthand.properties()[1], endValue, important);
|
| + return true;
|
| }
|
| -void CSSPropertyParser::parse3ValuesFillPosition(CSSParserValueList* valueList, RefPtrWillBeRawPtr<CSSValue>& value1, RefPtrWillBeRawPtr<CSSValue>& value2, PassRefPtrWillBeRawPtr<CSSPrimitiveValue> parsedValue1, PassRefPtrWillBeRawPtr<CSSPrimitiveValue> parsedValue2)
|
| -{
|
| - unsigned cumulativeFlags = 0;
|
| - FillPositionFlag value3Flag = InvalidFillPosition;
|
| - RefPtrWillBeRawPtr<CSSPrimitiveValue> value3 = parseFillPositionComponent(valueList, cumulativeFlags, value3Flag, ResolveValuesAsKeyword);
|
| -
|
| - // value3 is not an expected value, we return.
|
| - if (!value3)
|
| - return;
|
|
|
| - valueList->next();
|
| +bool CSSPropertyParser::parseGridGapShorthand(bool important)
|
| +{
|
| + ShorthandScope scope(this, CSSPropertyGridGap);
|
| + ASSERT(shorthandForProperty(CSSPropertyGridGap).length() == 2);
|
|
|
| - bool swapNeeded = false;
|
| - CSSValueID ident1 = parsedValue1->getValueID();
|
| - CSSValueID ident2 = parsedValue2->getValueID();
|
| - CSSValueID ident3 = value3->getValueID();
|
| + CSSParserValue* value = m_valueList->current();
|
| + if (!value)
|
| + return false;
|
|
|
| - CSSValueID firstPositionKeyword;
|
| - CSSValueID secondPositionKeyword;
|
| + if (!validUnit(value, FLength | FNonNeg))
|
| + return false;
|
|
|
| - if (ident1 == CSSValueCenter) {
|
| - // <position> requires the first 'center' to be followed by a keyword.
|
| - if (!isFillPositionKeyword(ident2))
|
| - return;
|
| + RefPtrWillBeRawPtr<CSSPrimitiveValue> rowGap = createPrimitiveNumericValue(value);
|
| + RefPtrWillBeRawPtr<CSSPrimitiveValue> columnGap = nullptr;
|
|
|
| - // If 'center' is the first keyword then the last one needs to be a length.
|
| - if (isFillPositionKeyword(ident3))
|
| - return;
|
| + value = m_valueList->next();
|
| + if (value) {
|
| + if (!validUnit(value, FLength | FNonNeg))
|
| + return false;
|
|
|
| - firstPositionKeyword = CSSValueLeft;
|
| - if (ident2 == CSSValueLeft || ident2 == CSSValueRight) {
|
| - firstPositionKeyword = CSSValueTop;
|
| - swapNeeded = true;
|
| - }
|
| - value1 = CSSValuePair::create(cssValuePool().createIdentifierValue(firstPositionKeyword), cssValuePool().createValue(50, CSSPrimitiveValue::UnitType::Percentage), CSSValuePair::DropIdenticalValues);
|
| - value2 = CSSValuePair::create(parsedValue2, value3, CSSValuePair::DropIdenticalValues);
|
| - } else if (ident3 == CSSValueCenter) {
|
| - if (isFillPositionKeyword(ident2))
|
| - return;
|
| -
|
| - secondPositionKeyword = CSSValueTop;
|
| - if (ident1 == CSSValueTop || ident1 == CSSValueBottom) {
|
| - secondPositionKeyword = CSSValueLeft;
|
| - swapNeeded = true;
|
| - }
|
| - value1 = CSSValuePair::create(parsedValue1, parsedValue2, CSSValuePair::DropIdenticalValues);
|
| - value2 = CSSValuePair::create(cssValuePool().createIdentifierValue(secondPositionKeyword), cssValuePool().createValue(50, CSSPrimitiveValue::UnitType::Percentage), CSSValuePair::DropIdenticalValues);
|
| + columnGap = createPrimitiveNumericValue(value);
|
| + if (m_valueList->next())
|
| + return false;
|
| } else {
|
| - RefPtrWillBeRawPtr<CSSPrimitiveValue> firstPositionValue = nullptr;
|
| - RefPtrWillBeRawPtr<CSSPrimitiveValue> secondPositionValue = nullptr;
|
| -
|
| - if (isFillPositionKeyword(ident2)) {
|
| - // To match CSS grammar, we should only accept: [ center | left | right | bottom | top ] [ left | right | top | bottom ] [ <percentage> | <length> ].
|
| - ASSERT(ident2 != CSSValueCenter);
|
| -
|
| - if (isFillPositionKeyword(ident3))
|
| - return;
|
| -
|
| - secondPositionValue = value3;
|
| - secondPositionKeyword = ident2;
|
| - firstPositionValue = cssValuePool().createValue(0, CSSPrimitiveValue::UnitType::Percentage);
|
| - } else {
|
| - // Per CSS, we should only accept: [ right | left | top | bottom ] [ <percentage> | <length> ] [ center | left | right | bottom | top ].
|
| - if (!isFillPositionKeyword(ident3))
|
| - return;
|
| -
|
| - firstPositionValue = parsedValue2;
|
| - secondPositionKeyword = ident3;
|
| - secondPositionValue = cssValuePool().createValue(0, CSSPrimitiveValue::UnitType::Percentage);
|
| - }
|
| -
|
| - if (isValueConflictingWithCurrentEdge(ident1, secondPositionKeyword))
|
| - return;
|
| -
|
| - value1 = CSSValuePair::create(parsedValue1, firstPositionValue, CSSValuePair::DropIdenticalValues);
|
| - value2 = CSSValuePair::create(cssValuePool().createIdentifierValue(secondPositionKeyword), secondPositionValue, CSSValuePair::DropIdenticalValues);
|
| + columnGap = rowGap;
|
| }
|
|
|
| - if (ident1 == CSSValueTop || ident1 == CSSValueBottom || swapNeeded)
|
| - value1.swap(value2);
|
| -
|
| -#if ENABLE(ASSERT)
|
| - const CSSValuePair& first = toCSSValuePair(*value1);
|
| - const CSSValuePair& second = toCSSValuePair(*value2);
|
| - ident1 = toCSSPrimitiveValue(first.first()).getValueID();
|
| - ident2 = toCSSPrimitiveValue(second.first()).getValueID();
|
| - ASSERT(ident1 == CSSValueLeft || ident1 == CSSValueRight);
|
| - ASSERT(ident2 == CSSValueBottom || ident2 == CSSValueTop);
|
| -#endif
|
| -}
|
| + addProperty(CSSPropertyGridRowGap, rowGap, important);
|
| + addProperty(CSSPropertyGridColumnGap, columnGap, important);
|
|
|
| -inline bool CSSPropertyParser::isPotentialPositionValue(CSSParserValue* value)
|
| -{
|
| - return isFillPositionKeyword(value->id) || validUnit(value, FPercent | FLength, ReleaseParsedCalcValue);
|
| + return true;
|
| }
|
|
|
| -void CSSPropertyParser::parseFillPosition(CSSParserValueList* valueList, RefPtrWillBeRawPtr<CSSValue>& value1, RefPtrWillBeRawPtr<CSSValue>& value2, Units unitless)
|
| +PassRefPtrWillBeRawPtr<CSSValue> CSSPropertyParser::parseGridTemplateColumns(bool important)
|
| {
|
| - unsigned numberOfValues = 0;
|
| - for (unsigned i = valueList->currentIndex(); i < valueList->size(); ++i, ++numberOfValues) {
|
| - CSSParserValue* current = valueList->valueAt(i);
|
| - if (!current || isComma(current) || isForwardSlashOperator(current) || !isPotentialPositionValue(current))
|
| - break;
|
| - }
|
| -
|
| - if (numberOfValues > 4)
|
| - return;
|
| -
|
| - // If we are parsing two values, we can safely call the CSS 2.1 parsing function and return.
|
| - if (numberOfValues <= 2) {
|
| - parse2ValuesFillPosition(valueList, value1, value2, unitless);
|
| - return;
|
| - }
|
| -
|
| - ASSERT(numberOfValues > 2 && numberOfValues <= 4);
|
| -
|
| - CSSParserValue* value = valueList->current();
|
| -
|
| - // <position> requires the first value to be a background keyword.
|
| - if (!isFillPositionKeyword(value->id))
|
| - return;
|
| -
|
| - // Parse the first value. We're just making sure that it is one of the valid keywords or a percentage/length.
|
| - unsigned cumulativeFlags = 0;
|
| - FillPositionFlag value1Flag = InvalidFillPosition;
|
| - FillPositionFlag value2Flag = InvalidFillPosition;
|
| - value1 = parseFillPositionComponent(valueList, cumulativeFlags, value1Flag, ResolveValuesAsKeyword);
|
| - if (!value1)
|
| - return;
|
| -
|
| - valueList->next();
|
| -
|
| - // In case we are parsing more than two values, relax the check inside of parseFillPositionComponent. top 20px is
|
| - // a valid start for <position>.
|
| - cumulativeFlags = AmbiguousFillPosition;
|
| - value2 = parseFillPositionComponent(valueList, cumulativeFlags, value2Flag, ResolveValuesAsKeyword);
|
| - if (value2)
|
| - valueList->next();
|
| - else {
|
| - value1.clear();
|
| - return;
|
| + if (!(m_valueList->current() && isForwardSlashOperator(m_valueList->current()) && m_valueList->next()))
|
| + return nullptr;
|
| + if (RefPtrWillBeRawPtr<CSSValue> columnsValue = parseGridTrackList()) {
|
| + if (m_valueList->current())
|
| + return nullptr;
|
| + return columnsValue;
|
| }
|
|
|
| - RefPtrWillBeRawPtr<CSSPrimitiveValue> parsedValue1 = toCSSPrimitiveValue(value1.get());
|
| - RefPtrWillBeRawPtr<CSSPrimitiveValue> parsedValue2 = toCSSPrimitiveValue(value2.get());
|
| -
|
| - value1.clear();
|
| - value2.clear();
|
| -
|
| - // Per CSS3 syntax, <position> can't have 'center' as its second keyword as we have more arguments to follow.
|
| - if (parsedValue2->getValueID() == CSSValueCenter)
|
| - return;
|
| -
|
| - if (numberOfValues == 3)
|
| - parse3ValuesFillPosition(valueList, value1, value2, parsedValue1.release(), parsedValue2.release());
|
| - else
|
| - parse4ValuesFillPosition(valueList, value1, value2, parsedValue1.release(), parsedValue2.release());
|
| + return nullptr;
|
| }
|
|
|
| -void CSSPropertyParser::parse2ValuesFillPosition(CSSParserValueList* valueList, RefPtrWillBeRawPtr<CSSValue>& value1, RefPtrWillBeRawPtr<CSSValue>& value2, Units unitless)
|
| +bool CSSPropertyParser::parseGridTemplateRowsAndAreasAndColumns(bool important)
|
| {
|
| - // Parse the first value. We're just making sure that it is one of the valid keywords or a percentage/length.
|
| - unsigned cumulativeFlags = 0;
|
| - FillPositionFlag value1Flag = InvalidFillPosition;
|
| - FillPositionFlag value2Flag = InvalidFillPosition;
|
| - value1 = parseFillPositionComponent(valueList, cumulativeFlags, value1Flag, ResolveValuesAsPercent, unitless);
|
| - if (!value1)
|
| - return;
|
| + NamedGridAreaMap gridAreaMap;
|
| + size_t rowCount = 0;
|
| + size_t columnCount = 0;
|
| + bool trailingIdentWasAdded = false;
|
| + RefPtrWillBeRawPtr<CSSValueList> templateRows = CSSValueList::createSpaceSeparated();
|
|
|
| - // It only takes one value for background-position to be correctly parsed if it was specified in a shorthand (since we
|
| - // can assume that any other values belong to the rest of the shorthand). If we're not parsing a shorthand, though, the
|
| - // value was explicitly specified for our property.
|
| - CSSParserValue* value = valueList->next();
|
| + // At least template-areas strings must be defined.
|
| + if (!m_valueList->current() || isForwardSlashOperator(m_valueList->current()))
|
| + return false;
|
|
|
| - // First check for the comma. If so, we are finished parsing this value or value pair.
|
| - if (value && isComma(value))
|
| - value = 0;
|
| + while (m_valueList->current() && !isForwardSlashOperator(m_valueList->current())) {
|
| + // Handle leading <custom-ident>*.
|
| + if (!parseGridLineNames(*m_valueList, *templateRows, trailingIdentWasAdded ? toCSSGridLineNamesValue(templateRows->item(templateRows->length() - 1)) : nullptr))
|
| + return false;
|
|
|
| - if (value) {
|
| - value2 = parseFillPositionComponent(valueList, cumulativeFlags, value2Flag, ResolveValuesAsPercent, unitless);
|
| - if (value2)
|
| - valueList->next();
|
| - else {
|
| - if (!inShorthand()) {
|
| - value1.clear();
|
| - return;
|
| - }
|
| - }
|
| - }
|
| -
|
| - if (!value2) {
|
| - // Only one value was specified. If that value was not a keyword, then it sets the x position, and the y position
|
| - // is simply 50%. This is our default.
|
| - // For keywords, the keyword was either an x-keyword (left/right), a y-keyword (top/bottom), or an ambiguous keyword (center).
|
| - // For left/right/center, the default of 50% in the y is still correct.
|
| - value2 = cssValuePool().createValue(50, CSSPrimitiveValue::UnitType::Percentage);
|
| - }
|
| -
|
| - if (value1Flag == YFillPosition || value2Flag == XFillPosition)
|
| - value1.swap(value2);
|
| -}
|
| -
|
| -void CSSPropertyParser::parseFillRepeat(RefPtrWillBeRawPtr<CSSValue>& value1, RefPtrWillBeRawPtr<CSSValue>& value2)
|
| -{
|
| - CSSValueID id = m_valueList->current()->id;
|
| - if (id == CSSValueRepeatX) {
|
| - m_implicitShorthand = true;
|
| - value1 = cssValuePool().createIdentifierValue(CSSValueRepeat);
|
| - value2 = cssValuePool().createIdentifierValue(CSSValueNoRepeat);
|
| - m_valueList->next();
|
| - return;
|
| - }
|
| - if (id == CSSValueRepeatY) {
|
| - m_implicitShorthand = true;
|
| - value1 = cssValuePool().createIdentifierValue(CSSValueNoRepeat);
|
| - value2 = cssValuePool().createIdentifierValue(CSSValueRepeat);
|
| - m_valueList->next();
|
| - return;
|
| - }
|
| - if (id == CSSValueRepeat || id == CSSValueNoRepeat || id == CSSValueRound || id == CSSValueSpace)
|
| - value1 = cssValuePool().createIdentifierValue(id);
|
| - else {
|
| - value1 = nullptr;
|
| - return;
|
| - }
|
| -
|
| - CSSParserValue* value = m_valueList->next();
|
| -
|
| - // Parse the second value if one is available
|
| - if (value && !isComma(value)) {
|
| - id = value->id;
|
| - if (id == CSSValueRepeat || id == CSSValueNoRepeat || id == CSSValueRound || id == CSSValueSpace) {
|
| - value2 = cssValuePool().createIdentifierValue(id);
|
| - m_valueList->next();
|
| - return;
|
| - }
|
| - }
|
| -
|
| - // If only one value was specified, value2 is the same as value1.
|
| - m_implicitShorthand = true;
|
| - value2 = cssValuePool().createIdentifierValue(toCSSPrimitiveValue(value1.get())->getValueID());
|
| -}
|
| -
|
| -PassRefPtrWillBeRawPtr<CSSValue> CSSPropertyParser::parseFillSize(CSSPropertyID unresolvedProperty)
|
| -{
|
| - CSSParserValue* value = m_valueList->current();
|
| - m_valueList->next();
|
| -
|
| - if (value->id == CSSValueContain || value->id == CSSValueCover)
|
| - return cssValuePool().createIdentifierValue(value->id);
|
| -
|
| - RefPtrWillBeRawPtr<CSSPrimitiveValue> parsedValue1 = nullptr;
|
| -
|
| - if (value->id == CSSValueAuto)
|
| - parsedValue1 = cssValuePool().createIdentifierValue(CSSValueAuto);
|
| - else {
|
| - if (!validUnit(value, FLength | FPercent))
|
| - return nullptr;
|
| - parsedValue1 = createPrimitiveNumericValue(value);
|
| - }
|
| -
|
| - RefPtrWillBeRawPtr<CSSPrimitiveValue> parsedValue2 = nullptr;
|
| - value = m_valueList->current();
|
| - if (value) {
|
| - if (value->id == CSSValueAuto) {
|
| - // `auto' is the default
|
| - m_valueList->next();
|
| - } else if (validUnit(value, FLength | FPercent)) {
|
| - parsedValue2 = createPrimitiveNumericValue(value);
|
| - m_valueList->next();
|
| - }
|
| - } else if (unresolvedProperty == CSSPropertyAliasWebkitBackgroundSize) {
|
| - // For backwards compatibility we set the second value to the first if it is omitted.
|
| - // We only need to do this for -webkit-background-size. It should be safe to let masks match
|
| - // the real property.
|
| - parsedValue2 = parsedValue1;
|
| - }
|
| -
|
| - if (!parsedValue2)
|
| - return parsedValue1;
|
| -
|
| - return CSSValuePair::create(parsedValue1.release(), parsedValue2.release(), CSSValuePair::KeepIdenticalValues);
|
| -}
|
| -
|
| -bool CSSPropertyParser::parseFillProperty(CSSPropertyID propId, CSSPropertyID& propId1, CSSPropertyID& propId2,
|
| - RefPtrWillBeRawPtr<CSSValue>& retValue1, RefPtrWillBeRawPtr<CSSValue>& retValue2)
|
| -{
|
| - // We initially store the first value in value/value2, and only create
|
| - // CSSValueLists if we have more values.
|
| - RefPtrWillBeRawPtr<CSSValueList> values = nullptr;
|
| - RefPtrWillBeRawPtr<CSSValueList> values2 = nullptr;
|
| - RefPtrWillBeRawPtr<CSSValue> value = nullptr;
|
| - RefPtrWillBeRawPtr<CSSValue> value2 = nullptr;
|
| -
|
| - retValue1 = retValue2 = nullptr;
|
| - propId1 = resolveCSSPropertyID(propId);
|
| - propId2 = propId1;
|
| - if (propId == CSSPropertyBackgroundPosition) {
|
| - propId1 = CSSPropertyBackgroundPositionX;
|
| - propId2 = CSSPropertyBackgroundPositionY;
|
| - } else if (propId == CSSPropertyWebkitMaskPosition) {
|
| - propId1 = CSSPropertyWebkitMaskPositionX;
|
| - propId2 = CSSPropertyWebkitMaskPositionY;
|
| - } else if (propId == CSSPropertyBackgroundRepeat) {
|
| - propId1 = CSSPropertyBackgroundRepeatX;
|
| - propId2 = CSSPropertyBackgroundRepeatY;
|
| - } else if (propId == CSSPropertyWebkitMaskRepeat) {
|
| - propId1 = CSSPropertyWebkitMaskRepeatX;
|
| - propId2 = CSSPropertyWebkitMaskRepeatY;
|
| - }
|
| -
|
| - while (true) {
|
| - RefPtrWillBeRawPtr<CSSValue> currValue = nullptr;
|
| - RefPtrWillBeRawPtr<CSSValue> currValue2 = nullptr;
|
| -
|
| - Units unitless = FUnknown;
|
| - CSSParserValue* val = m_valueList->current();
|
| - ASSERT(val);
|
| -
|
| - switch (propId) {
|
| - case CSSPropertyBackgroundColor:
|
| - currValue = parseColor(val);
|
| - if (currValue)
|
| - m_valueList->next();
|
| - break;
|
| - case CSSPropertyBackgroundAttachment:
|
| - if (val->id == CSSValueScroll || val->id == CSSValueFixed || val->id == CSSValueLocal) {
|
| - currValue = cssValuePool().createIdentifierValue(val->id);
|
| - m_valueList->next();
|
| - }
|
| - break;
|
| - case CSSPropertyBackgroundImage:
|
| - case CSSPropertyWebkitMaskImage:
|
| - if (parseFillImage(m_valueList, currValue))
|
| - m_valueList->next();
|
| - break;
|
| - case CSSPropertyWebkitBackgroundClip:
|
| - case CSSPropertyWebkitBackgroundOrigin:
|
| - case CSSPropertyWebkitMaskClip:
|
| - case CSSPropertyWebkitMaskOrigin:
|
| - // The first three values here are deprecated and do not apply to the version of the property that has
|
| - // the -webkit- prefix removed.
|
| - if (val->id == CSSValueBorder || val->id == CSSValuePadding || val->id == CSSValueContent
|
| - || val->id == CSSValueBorderBox || val->id == CSSValuePaddingBox || val->id == CSSValueContentBox
|
| - || ((propId == CSSPropertyWebkitBackgroundClip || propId == CSSPropertyWebkitMaskClip)
|
| - && val->id == CSSValueText)) {
|
| - currValue = cssValuePool().createIdentifierValue(val->id);
|
| - m_valueList->next();
|
| - }
|
| - break;
|
| - case CSSPropertyBackgroundClip:
|
| - if (parseBackgroundClip(val, currValue))
|
| - m_valueList->next();
|
| - break;
|
| - case CSSPropertyBackgroundOrigin:
|
| - if (val->id == CSSValueBorderBox || val->id == CSSValuePaddingBox || val->id == CSSValueContentBox) {
|
| - currValue = cssValuePool().createIdentifierValue(val->id);
|
| - m_valueList->next();
|
| - }
|
| - break;
|
| - case CSSPropertyBackgroundPosition:
|
| - if (!inShorthand())
|
| - unitless = FUnitlessQuirk;
|
| - // fall-through
|
| - case CSSPropertyWebkitMaskPosition:
|
| - parseFillPosition(m_valueList, currValue, currValue2, unitless);
|
| - // parseFillPosition advances the m_valueList pointer.
|
| - break;
|
| - case CSSPropertyBackgroundPositionX:
|
| - case CSSPropertyWebkitMaskPositionX: {
|
| - currValue = parseFillPositionX(m_valueList);
|
| - if (currValue)
|
| - m_valueList->next();
|
| - break;
|
| - }
|
| - case CSSPropertyBackgroundPositionY:
|
| - case CSSPropertyWebkitMaskPositionY: {
|
| - currValue = parseFillPositionY(m_valueList);
|
| - if (currValue)
|
| - m_valueList->next();
|
| - break;
|
| - }
|
| - case CSSPropertyWebkitMaskComposite:
|
| - if (val->id >= CSSValueClear && val->id <= CSSValuePlusLighter) {
|
| - currValue = cssValuePool().createIdentifierValue(val->id);
|
| - m_valueList->next();
|
| - }
|
| - break;
|
| - case CSSPropertyBackgroundBlendMode:
|
| - if (val->id == CSSValueNormal || val->id == CSSValueMultiply
|
| - || val->id == CSSValueScreen || val->id == CSSValueOverlay || val->id == CSSValueDarken
|
| - || val->id == CSSValueLighten || val->id == CSSValueColorDodge || val->id == CSSValueColorBurn
|
| - || val->id == CSSValueHardLight || val->id == CSSValueSoftLight || val->id == CSSValueDifference
|
| - || val->id == CSSValueExclusion || val->id == CSSValueHue || val->id == CSSValueSaturation
|
| - || val->id == CSSValueColor || val->id == CSSValueLuminosity) {
|
| - currValue = cssValuePool().createIdentifierValue(val->id);
|
| - m_valueList->next();
|
| - }
|
| - break;
|
| - case CSSPropertyBackgroundRepeat:
|
| - case CSSPropertyWebkitMaskRepeat:
|
| - parseFillRepeat(currValue, currValue2);
|
| - // parseFillRepeat advances the m_valueList pointer
|
| - break;
|
| - case CSSPropertyBackgroundSize:
|
| - case CSSPropertyAliasWebkitBackgroundSize:
|
| - case CSSPropertyWebkitMaskSize: {
|
| - currValue = parseFillSize(propId);
|
| - break;
|
| - }
|
| - case CSSPropertyMaskSourceType: {
|
| - ASSERT(RuntimeEnabledFeatures::cssMaskSourceTypeEnabled());
|
| - if (val->id == CSSValueAuto || val->id == CSSValueAlpha || val->id == CSSValueLuminance) {
|
| - currValue = cssValuePool().createIdentifierValue(val->id);
|
| - m_valueList->next();
|
| - } else {
|
| - currValue = nullptr;
|
| - }
|
| - break;
|
| - }
|
| - default:
|
| - break;
|
| - }
|
| - if (!currValue)
|
| - return false;
|
| -
|
| - if (value && !values) {
|
| - values = CSSValueList::createCommaSeparated();
|
| - values->append(value.release());
|
| - }
|
| -
|
| - if (value2 && !values2) {
|
| - values2 = CSSValueList::createCommaSeparated();
|
| - values2->append(value2.release());
|
| - }
|
| -
|
| - if (values)
|
| - values->append(currValue.release());
|
| - else
|
| - value = currValue.release();
|
| - if (currValue2) {
|
| - if (values2)
|
| - values2->append(currValue2.release());
|
| - else
|
| - value2 = currValue2.release();
|
| - }
|
| -
|
| - // When parsing any fill shorthand property, we let it handle building up the lists for all
|
| - // properties.
|
| - if (inShorthand())
|
| - break;
|
| -
|
| - if (!m_valueList->current())
|
| - break;
|
| - if (!consumeComma(m_valueList) || !m_valueList->current())
|
| - return false;
|
| - }
|
| -
|
| - if (values) {
|
| - ASSERT(values->length());
|
| - retValue1 = values.release();
|
| - if (values2) {
|
| - ASSERT(values2->length());
|
| - retValue2 = values2.release();
|
| - }
|
| - } else {
|
| - ASSERT(value);
|
| - retValue1 = value.release();
|
| - retValue2 = value2.release();
|
| - }
|
| -
|
| - return true;
|
| -}
|
| -
|
| -static inline bool isCSSWideKeyword(const CSSParserValue& value)
|
| -{
|
| - return value.id == CSSValueInitial || value.id == CSSValueInherit || value.id == CSSValueUnset || value.id == CSSValueDefault;
|
| -}
|
| -
|
| -static inline bool isValidCustomIdentForGridPositions(const CSSParserValue& value)
|
| -{
|
| - // FIXME: we need a more general solution for <custom-ident> in all properties.
|
| - return value.m_unit == CSSParserValue::Identifier && value.id != CSSValueSpan && value.id != CSSValueAuto && !isCSSWideKeyword(value);
|
| -}
|
| -
|
| -// The function parses [ <integer> || <custom-ident> ] in <grid-line> (which can be stand alone or with 'span').
|
| -bool CSSPropertyParser::parseIntegerOrCustomIdentFromGridPosition(RefPtrWillBeRawPtr<CSSPrimitiveValue>& numericValue, RefPtrWillBeRawPtr<CSSCustomIdentValue>& gridLineName)
|
| -{
|
| - CSSParserValue* value = m_valueList->current();
|
| - if (validUnit(value, FInteger) && value->fValue) {
|
| - numericValue = createPrimitiveNumericValue(value);
|
| - value = m_valueList->next();
|
| - if (value && isValidCustomIdentForGridPositions(*value)) {
|
| - gridLineName = createPrimitiveCustomIdentValue(m_valueList->current());
|
| - m_valueList->next();
|
| - }
|
| - return true;
|
| - }
|
| -
|
| - if (isValidCustomIdentForGridPositions(*value)) {
|
| - gridLineName = createPrimitiveCustomIdentValue(m_valueList->current());
|
| - value = m_valueList->next();
|
| - if (value && validUnit(value, FInteger) && value->fValue) {
|
| - numericValue = createPrimitiveNumericValue(value);
|
| - m_valueList->next();
|
| - }
|
| - return true;
|
| - }
|
| -
|
| - return false;
|
| -}
|
| -
|
| -PassRefPtrWillBeRawPtr<CSSValue> CSSPropertyParser::parseGridPosition()
|
| -{
|
| - ASSERT(RuntimeEnabledFeatures::cssGridLayoutEnabled());
|
| -
|
| - CSSParserValue* value = m_valueList->current();
|
| - if (value->id == CSSValueAuto) {
|
| - m_valueList->next();
|
| - return cssValuePool().createIdentifierValue(CSSValueAuto);
|
| - }
|
| -
|
| - RefPtrWillBeRawPtr<CSSPrimitiveValue> numericValue = nullptr;
|
| - RefPtrWillBeRawPtr<CSSCustomIdentValue> gridLineName = nullptr;
|
| - bool hasSeenSpanKeyword = false;
|
| -
|
| - if (parseIntegerOrCustomIdentFromGridPosition(numericValue, gridLineName)) {
|
| - value = m_valueList->current();
|
| - if (value && value->id == CSSValueSpan) {
|
| - hasSeenSpanKeyword = true;
|
| - m_valueList->next();
|
| - }
|
| - } else if (value->id == CSSValueSpan) {
|
| - hasSeenSpanKeyword = true;
|
| - if (CSSParserValue* nextValue = m_valueList->next()) {
|
| - if (!isForwardSlashOperator(nextValue) && !parseIntegerOrCustomIdentFromGridPosition(numericValue, gridLineName))
|
| - return nullptr;
|
| - }
|
| - }
|
| -
|
| - // Check that we have consumed all the value list. For shorthands, the parser will pass
|
| - // the whole value list (including the opposite position).
|
| - if (m_valueList->current() && !isForwardSlashOperator(m_valueList->current()))
|
| - return nullptr;
|
| -
|
| - // If we didn't parse anything, this is not a valid grid position.
|
| - if (!hasSeenSpanKeyword && !gridLineName && !numericValue)
|
| - return nullptr;
|
| -
|
| - // Negative numbers are not allowed for span (but are for <integer>).
|
| - if (hasSeenSpanKeyword && numericValue && numericValue->getIntValue() < 0)
|
| - return nullptr;
|
| -
|
| - // For the <custom-ident> case.
|
| - if (gridLineName && !numericValue && !hasSeenSpanKeyword)
|
| - return CSSCustomIdentValue::create(gridLineName->value());
|
| -
|
| - RefPtrWillBeRawPtr<CSSValueList> values = CSSValueList::createSpaceSeparated();
|
| - if (hasSeenSpanKeyword)
|
| - values->append(cssValuePool().createIdentifierValue(CSSValueSpan));
|
| - if (numericValue)
|
| - values->append(numericValue.release());
|
| - if (gridLineName)
|
| - values->append(gridLineName.release());
|
| - ASSERT(values->length());
|
| - return values.release();
|
| -}
|
| -
|
| -static PassRefPtrWillBeRawPtr<CSSValue> gridMissingGridPositionValue(CSSValue* value)
|
| -{
|
| - if (value->isCustomIdentValue())
|
| - return value;
|
| -
|
| - return cssValuePool().createIdentifierValue(CSSValueAuto);
|
| -}
|
| -
|
| -bool CSSPropertyParser::parseGridItemPositionShorthand(CSSPropertyID shorthandId, bool important)
|
| -{
|
| - ShorthandScope scope(this, shorthandId);
|
| - const StylePropertyShorthand& shorthand = shorthandForProperty(shorthandId);
|
| - ASSERT(shorthand.length() == 2);
|
| -
|
| - RefPtrWillBeRawPtr<CSSValue> startValue = parseGridPosition();
|
| - if (!startValue)
|
| - return false;
|
| -
|
| - RefPtrWillBeRawPtr<CSSValue> endValue = nullptr;
|
| - if (m_valueList->current()) {
|
| - if (!isForwardSlashOperator(m_valueList->current()))
|
| - return false;
|
| -
|
| - if (!m_valueList->next())
|
| - return false;
|
| -
|
| - endValue = parseGridPosition();
|
| - if (!endValue || m_valueList->current())
|
| - return false;
|
| - } else {
|
| - endValue = gridMissingGridPositionValue(startValue.get());
|
| - }
|
| -
|
| - addProperty(shorthand.properties()[0], startValue, important);
|
| - addProperty(shorthand.properties()[1], endValue, important);
|
| - return true;
|
| -}
|
| -
|
| -bool CSSPropertyParser::parseGridGapShorthand(bool important)
|
| -{
|
| - ShorthandScope scope(this, CSSPropertyGridGap);
|
| - ASSERT(shorthandForProperty(CSSPropertyGridGap).length() == 2);
|
| -
|
| - CSSParserValue* value = m_valueList->current();
|
| - if (!value)
|
| - return false;
|
| -
|
| - if (!validUnit(value, FLength | FNonNeg))
|
| - return false;
|
| -
|
| - RefPtrWillBeRawPtr<CSSPrimitiveValue> rowGap = createPrimitiveNumericValue(value);
|
| - RefPtrWillBeRawPtr<CSSPrimitiveValue> columnGap = nullptr;
|
| -
|
| - value = m_valueList->next();
|
| - if (value) {
|
| - if (!validUnit(value, FLength | FNonNeg))
|
| - return false;
|
| -
|
| - columnGap = createPrimitiveNumericValue(value);
|
| - if (m_valueList->next())
|
| - return false;
|
| - } else {
|
| - columnGap = rowGap;
|
| - }
|
| -
|
| - addProperty(CSSPropertyGridRowGap, rowGap, important);
|
| - addProperty(CSSPropertyGridColumnGap, columnGap, important);
|
| -
|
| - return true;
|
| -}
|
| -
|
| -PassRefPtrWillBeRawPtr<CSSValue> CSSPropertyParser::parseGridTemplateColumns(bool important)
|
| -{
|
| - if (!(m_valueList->current() && isForwardSlashOperator(m_valueList->current()) && m_valueList->next()))
|
| - return nullptr;
|
| - if (RefPtrWillBeRawPtr<CSSValue> columnsValue = parseGridTrackList()) {
|
| - if (m_valueList->current())
|
| - return nullptr;
|
| - return columnsValue;
|
| - }
|
| -
|
| - return nullptr;
|
| -}
|
| -
|
| -bool CSSPropertyParser::parseGridTemplateRowsAndAreasAndColumns(bool important)
|
| -{
|
| - NamedGridAreaMap gridAreaMap;
|
| - size_t rowCount = 0;
|
| - size_t columnCount = 0;
|
| - bool trailingIdentWasAdded = false;
|
| - RefPtrWillBeRawPtr<CSSValueList> templateRows = CSSValueList::createSpaceSeparated();
|
| -
|
| - // At least template-areas strings must be defined.
|
| - if (!m_valueList->current() || isForwardSlashOperator(m_valueList->current()))
|
| - return false;
|
| -
|
| - while (m_valueList->current() && !isForwardSlashOperator(m_valueList->current())) {
|
| - // Handle leading <custom-ident>*.
|
| - if (!parseGridLineNames(*m_valueList, *templateRows, trailingIdentWasAdded ? toCSSGridLineNamesValue(templateRows->item(templateRows->length() - 1)) : nullptr))
|
| - return false;
|
| -
|
| - // Handle a template-area's row.
|
| - if (!parseGridTemplateAreasRow(gridAreaMap, rowCount, columnCount))
|
| - return false;
|
| - ++rowCount;
|
| -
|
| - // Handle template-rows's track-size.
|
| - if (m_valueList->current() && m_valueList->current()->m_unit != CSSParserValue::Operator && m_valueList->current()->m_unit != CSSParserValue::String) {
|
| - RefPtrWillBeRawPtr<CSSValue> value = parseGridTrackSize(*m_valueList);
|
| - if (!value)
|
| - return false;
|
| - templateRows->append(value);
|
| - } else {
|
| - templateRows->append(cssValuePool().createIdentifierValue(CSSValueAuto));
|
| - }
|
| -
|
| - // This will handle the trailing/leading <custom-ident>* in the grammar.
|
| - if (!parseGridLineNames(*m_valueList, *templateRows))
|
| - return false;
|
| - trailingIdentWasAdded = templateRows->item(templateRows->length() - 1)->isGridLineNamesValue();
|
| - }
|
| -
|
| - RefPtrWillBeRawPtr<CSSValue> columnsValue = nullptr;
|
| - if (m_valueList->current()) {
|
| - ASSERT(isForwardSlashOperator(m_valueList->current()));
|
| - columnsValue = parseGridTemplateColumns(important);
|
| - if (!columnsValue)
|
| - return false;
|
| - // The template-columns <track-list> can't be 'none'.
|
| - if (columnsValue->isPrimitiveValue() && toCSSPrimitiveValue(*columnsValue).getValueID() == CSSValueNone)
|
| - return false;
|
| - }
|
| -
|
| - addProperty(CSSPropertyGridTemplateRows, templateRows.release(), important);
|
| - addProperty(CSSPropertyGridTemplateColumns, columnsValue ? columnsValue.release() : cssValuePool().createIdentifierValue(CSSValueNone), important);
|
| -
|
| - RefPtrWillBeRawPtr<CSSValue> templateAreas = CSSGridTemplateAreasValue::create(gridAreaMap, rowCount, columnCount);
|
| - addProperty(CSSPropertyGridTemplateAreas, templateAreas.release(), important);
|
| -
|
| - return true;
|
| -}
|
| -
|
| -
|
| -bool CSSPropertyParser::parseGridTemplateShorthand(bool important)
|
| -{
|
| - ASSERT(RuntimeEnabledFeatures::cssGridLayoutEnabled());
|
| -
|
| - ShorthandScope scope(this, CSSPropertyGridTemplate);
|
| - ASSERT(gridTemplateShorthand().length() == 3);
|
| -
|
| - // At least "none" must be defined.
|
| - if (!m_valueList->current())
|
| - return false;
|
| -
|
| - bool firstValueIsNone = m_valueList->current()->id == CSSValueNone;
|
| -
|
| - // 1- 'none' case.
|
| - if (firstValueIsNone && !m_valueList->next()) {
|
| - addProperty(CSSPropertyGridTemplateColumns, cssValuePool().createIdentifierValue(CSSValueNone), important);
|
| - addProperty(CSSPropertyGridTemplateRows, cssValuePool().createIdentifierValue(CSSValueNone), important);
|
| - addProperty(CSSPropertyGridTemplateAreas, cssValuePool().createIdentifierValue(CSSValueNone), important);
|
| - return true;
|
| - }
|
| -
|
| - // 2- <grid-template-rows> / <grid-template-columns>
|
| - RefPtrWillBeRawPtr<CSSValue> rowsValue = nullptr;
|
| - if (firstValueIsNone) {
|
| - rowsValue = cssValuePool().createIdentifierValue(CSSValueNone);
|
| - } else {
|
| - rowsValue = parseGridTrackList();
|
| - }
|
| -
|
| - if (rowsValue) {
|
| - RefPtrWillBeRawPtr<CSSValue> columnsValue = parseGridTemplateColumns(important);
|
| - if (!columnsValue)
|
| - return false;
|
| -
|
| - addProperty(CSSPropertyGridTemplateRows, rowsValue.release(), important);
|
| - addProperty(CSSPropertyGridTemplateColumns, columnsValue.release(), important);
|
| - addProperty(CSSPropertyGridTemplateAreas, cssValuePool().createIdentifierValue(CSSValueNone), important);
|
| - return true;
|
| - }
|
| -
|
| - // 3- [<line-names>? <string> <track-size>? <line-names>? ]+ syntax.
|
| - // It requires to rewind parsing due to previous syntax failures.
|
| - m_valueList->setCurrentIndex(0);
|
| - return parseGridTemplateRowsAndAreasAndColumns(important);
|
| -}
|
| -
|
| -bool CSSPropertyParser::parseGridShorthand(bool important)
|
| -{
|
| - ShorthandScope scope(this, CSSPropertyGrid);
|
| - ASSERT(shorthandForProperty(CSSPropertyGrid).length() == 8);
|
| -
|
| - // 1- <grid-template>
|
| - if (parseGridTemplateShorthand(important)) {
|
| - // It can only be specified the explicit or the implicit grid properties in a single grid declaration.
|
| - // The sub-properties not specified are set to their initial value, as normal for shorthands.
|
| - addProperty(CSSPropertyGridAutoFlow, cssValuePool().createImplicitInitialValue(), important);
|
| - addProperty(CSSPropertyGridAutoColumns, cssValuePool().createImplicitInitialValue(), important);
|
| - addProperty(CSSPropertyGridAutoRows, cssValuePool().createImplicitInitialValue(), important);
|
| - addProperty(CSSPropertyGridColumnGap, cssValuePool().createImplicitInitialValue(), important);
|
| - addProperty(CSSPropertyGridRowGap, cssValuePool().createImplicitInitialValue(), important);
|
| - return true;
|
| - }
|
| -
|
| - // Need to rewind parsing to explore the alternative syntax of this shorthand.
|
| - m_valueList->setCurrentIndex(0);
|
| -
|
| - // 2- <grid-auto-flow> [ <grid-auto-rows> [ / <grid-auto-columns> ]? ]
|
| - if (!legacyParseAndApplyValue(CSSPropertyGridAutoFlow, important))
|
| - return false;
|
| -
|
| - RefPtrWillBeRawPtr<CSSValue> autoColumnsValue = nullptr;
|
| - RefPtrWillBeRawPtr<CSSValue> autoRowsValue = nullptr;
|
| -
|
| - if (m_valueList->current()) {
|
| - autoRowsValue = parseGridTrackSize(*m_valueList);
|
| - if (!autoRowsValue)
|
| - return false;
|
| - if (m_valueList->current()) {
|
| - if (!isForwardSlashOperator(m_valueList->current()) || !m_valueList->next())
|
| - return false;
|
| - autoColumnsValue = parseGridTrackSize(*m_valueList);
|
| - if (!autoColumnsValue)
|
| - return false;
|
| - }
|
| - if (m_valueList->current())
|
| - return false;
|
| - } else {
|
| - // Other omitted values are set to their initial values.
|
| - autoColumnsValue = cssValuePool().createImplicitInitialValue();
|
| - autoRowsValue = cssValuePool().createImplicitInitialValue();
|
| - }
|
| -
|
| - // if <grid-auto-columns> value is omitted, it is set to the value specified for grid-auto-rows.
|
| - if (!autoColumnsValue)
|
| - autoColumnsValue = autoRowsValue;
|
| -
|
| - addProperty(CSSPropertyGridAutoColumns, autoColumnsValue, important);
|
| - addProperty(CSSPropertyGridAutoRows, autoRowsValue, important);
|
| -
|
| - // It can only be specified the explicit or the implicit grid properties in a single grid declaration.
|
| - // The sub-properties not specified are set to their initial value, as normal for shorthands.
|
| - addProperty(CSSPropertyGridTemplateColumns, cssValuePool().createImplicitInitialValue(), important);
|
| - addProperty(CSSPropertyGridTemplateRows, cssValuePool().createImplicitInitialValue(), important);
|
| - addProperty(CSSPropertyGridTemplateAreas, cssValuePool().createImplicitInitialValue(), important);
|
| - addProperty(CSSPropertyGridColumnGap, cssValuePool().createImplicitInitialValue(), important);
|
| - addProperty(CSSPropertyGridRowGap, cssValuePool().createImplicitInitialValue(), important);
|
| -
|
| - return true;
|
| -}
|
| -
|
| -bool CSSPropertyParser::parseGridAreaShorthand(bool important)
|
| -{
|
| - ASSERT(RuntimeEnabledFeatures::cssGridLayoutEnabled());
|
| -
|
| - ShorthandScope scope(this, CSSPropertyGridArea);
|
| - const StylePropertyShorthand& shorthand = gridAreaShorthand();
|
| - ASSERT_UNUSED(shorthand, shorthand.length() == 4);
|
| -
|
| - RefPtrWillBeRawPtr<CSSValue> rowStartValue = parseGridPosition();
|
| - if (!rowStartValue)
|
| - return false;
|
| -
|
| - RefPtrWillBeRawPtr<CSSValue> columnStartValue = nullptr;
|
| - if (!parseSingleGridAreaLonghand(columnStartValue))
|
| - return false;
|
| -
|
| - RefPtrWillBeRawPtr<CSSValue> rowEndValue = nullptr;
|
| - if (!parseSingleGridAreaLonghand(rowEndValue))
|
| - return false;
|
| -
|
| - RefPtrWillBeRawPtr<CSSValue> columnEndValue = nullptr;
|
| - if (!parseSingleGridAreaLonghand(columnEndValue))
|
| - return false;
|
| -
|
| - if (!columnStartValue)
|
| - columnStartValue = gridMissingGridPositionValue(rowStartValue.get());
|
| -
|
| - if (!rowEndValue)
|
| - rowEndValue = gridMissingGridPositionValue(rowStartValue.get());
|
| -
|
| - if (!columnEndValue)
|
| - columnEndValue = gridMissingGridPositionValue(columnStartValue.get());
|
| -
|
| - addProperty(CSSPropertyGridRowStart, rowStartValue, important);
|
| - addProperty(CSSPropertyGridColumnStart, columnStartValue, important);
|
| - addProperty(CSSPropertyGridRowEnd, rowEndValue, important);
|
| - addProperty(CSSPropertyGridColumnEnd, columnEndValue, important);
|
| - return true;
|
| -}
|
| -
|
| -bool CSSPropertyParser::parseSingleGridAreaLonghand(RefPtrWillBeRawPtr<CSSValue>& property)
|
| -{
|
| - if (!m_valueList->current())
|
| - return true;
|
| -
|
| - if (!isForwardSlashOperator(m_valueList->current()))
|
| - return false;
|
| -
|
| - if (!m_valueList->next())
|
| - return false;
|
| -
|
| - property = parseGridPosition();
|
| - return true;
|
| -}
|
| -
|
| -static inline bool isClosingBracket(const CSSParserValue& value)
|
| -{
|
| - return value.m_unit == CSSParserValue::Operator && value.iValue == ']';
|
| -}
|
| -
|
| -bool CSSPropertyParser::parseGridLineNames(CSSParserValueList& inputList, CSSValueList& valueList, CSSGridLineNamesValue* previousNamedAreaTrailingLineNames)
|
| -{
|
| - if (!inputList.current() || inputList.current()->m_unit != CSSParserValue::Operator || inputList.current()->iValue != '[')
|
| - return true;
|
| -
|
| - // Skip '['
|
| - inputList.next();
|
| -
|
| - RefPtrWillBeRawPtr<CSSGridLineNamesValue> lineNames = previousNamedAreaTrailingLineNames;
|
| - if (!lineNames)
|
| - lineNames = CSSGridLineNamesValue::create();
|
| -
|
| - while (CSSParserValue* identValue = inputList.current()) {
|
| - if (isClosingBracket(*identValue))
|
| - break;
|
| -
|
| - if (!isValidCustomIdentForGridPositions(*identValue))
|
| - return false;
|
| -
|
| - RefPtrWillBeRawPtr<CSSCustomIdentValue> lineName = createPrimitiveCustomIdentValue(identValue);
|
| - lineNames->append(lineName.release());
|
| - inputList.next();
|
| - }
|
| -
|
| - if (!inputList.current() || !isClosingBracket(*inputList.current()))
|
| - return false;
|
| -
|
| - if (!previousNamedAreaTrailingLineNames)
|
| - valueList.append(lineNames.release());
|
| -
|
| - // Consume ']'
|
| - inputList.next();
|
| - return true;
|
| -}
|
| -
|
| -PassRefPtrWillBeRawPtr<CSSValue> CSSPropertyParser::parseGridTrackList()
|
| -{
|
| - ASSERT(RuntimeEnabledFeatures::cssGridLayoutEnabled());
|
| -
|
| - CSSParserValue* value = m_valueList->current();
|
| - if (value->id == CSSValueNone) {
|
| - m_valueList->next();
|
| - return cssValuePool().createIdentifierValue(CSSValueNone);
|
| - }
|
| -
|
| - RefPtrWillBeRawPtr<CSSValueList> values = CSSValueList::createSpaceSeparated();
|
| - // Handle leading <custom-ident>*.
|
| - if (!parseGridLineNames(*m_valueList, *values))
|
| - return nullptr;
|
| -
|
| - bool seenTrackSizeOrRepeatFunction = false;
|
| - bool seenAutoRepeat = false;
|
| - while (CSSParserValue* currentValue = m_valueList->current()) {
|
| - if (isForwardSlashOperator(currentValue))
|
| - break;
|
| - if (currentValue->m_unit == CSSParserValue::Function && currentValue->function->id == CSSValueRepeat) {
|
| - bool isAutoRepeat;
|
| - if (!parseGridTrackRepeatFunction(*values, isAutoRepeat))
|
| - return nullptr;
|
| - if (isAutoRepeat && seenAutoRepeat)
|
| - return nullptr;
|
| - seenTrackSizeOrRepeatFunction = true;
|
| - seenAutoRepeat = seenAutoRepeat || isAutoRepeat;
|
| - } else {
|
| - RefPtrWillBeRawPtr<CSSValue> value = parseGridTrackSize(*m_valueList, seenAutoRepeat ? FixedSizeOnly : AllowAll);
|
| - if (!value)
|
| - return nullptr;
|
| - values->append(value);
|
| - seenTrackSizeOrRepeatFunction = true;
|
| - }
|
| - // This will handle the trailing <custom-ident>* in the grammar.
|
| - if (!parseGridLineNames(*m_valueList, *values))
|
| - return nullptr;
|
| - }
|
| -
|
| - // We should have found a <track-size> or else it is not a valid <track-list>
|
| - if (!seenTrackSizeOrRepeatFunction)
|
| - return nullptr;
|
| -
|
| - // <auto-repeat> requires definite minimum track sizes in order to compute the number of repetitions.
|
| - // The above while loop detects those appearances after the <auto-repeat> but not the ones before.
|
| - if (seenAutoRepeat) {
|
| - for (auto value : *values) {
|
| - if (value->isGridLineNamesValue())
|
| - continue;
|
| - ASSERT(value->isPrimitiveValue() || (value->isFunctionValue() && toCSSFunctionValue(*value).item(0)));
|
| - const CSSPrimitiveValue& primitiveValue = value->isPrimitiveValue()
|
| - ? toCSSPrimitiveValue(*value)
|
| - : toCSSPrimitiveValue(*toCSSFunctionValue(*value).item(0));
|
| - CSSValueID valueID = primitiveValue.getValueID();
|
| - if (valueID == CSSValueMinContent || valueID == CSSValueMaxContent || valueID == CSSValueAuto || primitiveValue.isFlex())
|
| - return nullptr;
|
| - }
|
| - }
|
| -
|
| - return values;
|
| -}
|
| -
|
| -bool CSSPropertyParser::parseGridTrackRepeatFunction(CSSValueList& list, bool& isAutoRepeat)
|
| -{
|
| - CSSParserValueList* arguments = m_valueList->current()->function->args.get();
|
| - if (!arguments || arguments->size() < 3 || !isComma(arguments->valueAt(1)))
|
| - return false;
|
| -
|
| - CSSParserValue* currentValue = arguments->valueAt(0);
|
| - isAutoRepeat = currentValue->id == CSSValueAutoFill || currentValue->id == CSSValueAutoFit;
|
| - if (!isAutoRepeat && !validUnit(currentValue, FPositiveInteger))
|
| - return false;
|
| -
|
| - // The number of repetitions for <auto-repeat> is not important at parsing level
|
| - // because it will be computed later, let's set it to 1.
|
| - size_t repetitions = isAutoRepeat ? 1 : clampTo<size_t>(currentValue->fValue, 0, kGridMaxTracks);
|
| -
|
| - RefPtrWillBeRawPtr<CSSValueList> repeatedValues = CSSValueList::createSpaceSeparated();
|
| - arguments->next(); // Skip the repetition count.
|
| - arguments->next(); // Skip the comma.
|
| -
|
| - // Handle leading <custom-ident>*.
|
| - if (!parseGridLineNames(*arguments, *repeatedValues))
|
| - return false;
|
| -
|
| - size_t numberOfTracks = 0;
|
| - TrackSizeRestriction restriction = isAutoRepeat ? FixedSizeOnly : AllowAll;
|
| - while (arguments->current()) {
|
| - if (isAutoRepeat && numberOfTracks)
|
| - return false;
|
| -
|
| - RefPtrWillBeRawPtr<CSSValue> trackSize = parseGridTrackSize(*arguments, restriction);
|
| - if (!trackSize)
|
| - return false;
|
| -
|
| - repeatedValues->append(trackSize);
|
| - ++numberOfTracks;
|
| -
|
| - // This takes care of any trailing <custom-ident>* in the grammar.
|
| - if (!parseGridLineNames(*arguments, *repeatedValues))
|
| - return false;
|
| - }
|
| -
|
| - // We should have found at least one <track-size> or else it is not a valid <track-list>.
|
| - if (!numberOfTracks)
|
| - return false;
|
| -
|
| - // We clamp the number of repetitions to a multiple of the repeat() track list's size, while staying below the max
|
| - // grid size.
|
| - repetitions = std::min(repetitions, kGridMaxTracks / numberOfTracks);
|
| -
|
| - for (size_t i = 0; i < repetitions; ++i) {
|
| - for (size_t j = 0; j < repeatedValues->length(); ++j)
|
| - list.append(repeatedValues->item(j));
|
| - }
|
| -
|
| - // parseGridTrackSize iterated over the repeat arguments, move to the next value.
|
| - m_valueList->next();
|
| - return true;
|
| -}
|
| -
|
| -
|
| -PassRefPtrWillBeRawPtr<CSSValue> CSSPropertyParser::parseGridTrackSize(CSSParserValueList& inputList, TrackSizeRestriction restriction)
|
| -{
|
| - ASSERT(RuntimeEnabledFeatures::cssGridLayoutEnabled());
|
| -
|
| - CSSParserValue* currentValue = inputList.current();
|
| - inputList.next();
|
| -
|
| - if (currentValue->id == CSSValueAuto)
|
| - return restriction == AllowAll ? cssValuePool().createIdentifierValue(CSSValueAuto) : nullptr;
|
| -
|
| - if (currentValue->m_unit == CSSParserValue::Function && currentValue->function->id == CSSValueMinmax) {
|
| - // The spec defines the following grammar: minmax( <track-breadth> , <track-breadth> )
|
| - CSSParserValueList* arguments = currentValue->function->args.get();
|
| - if (!arguments || arguments->size() != 3 || !isComma(arguments->valueAt(1)))
|
| - return nullptr;
|
| -
|
| - RefPtrWillBeRawPtr<CSSPrimitiveValue> minTrackBreadth = parseGridBreadth(arguments->valueAt(0), restriction);
|
| - if (!minTrackBreadth)
|
| - return nullptr;
|
| -
|
| - RefPtrWillBeRawPtr<CSSPrimitiveValue> maxTrackBreadth = parseGridBreadth(arguments->valueAt(2));
|
| - if (!maxTrackBreadth)
|
| - return nullptr;
|
| -
|
| - RefPtrWillBeRawPtr<CSSFunctionValue> result = CSSFunctionValue::create(CSSValueMinmax);
|
| - result->append(minTrackBreadth);
|
| - result->append(maxTrackBreadth);
|
| - return result.release();
|
| - }
|
| -
|
| - return parseGridBreadth(currentValue, restriction);
|
| -}
|
| -
|
| -PassRefPtrWillBeRawPtr<CSSPrimitiveValue> CSSPropertyParser::parseGridBreadth(CSSParserValue* currentValue, TrackSizeRestriction restriction)
|
| -{
|
| - if (currentValue->id == CSSValueMinContent || currentValue->id == CSSValueMaxContent || currentValue->id == CSSValueAuto)
|
| - return restriction == AllowAll ? cssValuePool().createIdentifierValue(currentValue->id) : nullptr;
|
| -
|
| - if (currentValue->unit() == CSSPrimitiveValue::UnitType::Fraction) {
|
| - if (restriction == FixedSizeOnly)
|
| - return nullptr;
|
| -
|
| - double flexValue = currentValue->fValue;
|
| -
|
| - // Fractional unit is a non-negative dimension.
|
| - if (flexValue < 0)
|
| - return nullptr;
|
| -
|
| - return cssValuePool().createValue(flexValue, CSSPrimitiveValue::UnitType::Fraction);
|
| - }
|
| -
|
| - if (!validUnit(currentValue, FNonNeg | FLength | FPercent))
|
| - return nullptr;
|
| -
|
| - return createPrimitiveNumericValue(currentValue);
|
| -}
|
| -
|
| -static Vector<String> parseGridTemplateAreasColumnNames(const String& gridRowNames)
|
| -{
|
| - ASSERT(!gridRowNames.isEmpty());
|
| - Vector<String> columnNames;
|
| - // Using StringImpl to avoid checks and indirection in every call to String::operator[].
|
| - StringImpl& text = *gridRowNames.impl();
|
| -
|
| - StringBuilder areaName;
|
| - for (unsigned i = 0; i < text.length(); ++i) {
|
| - if (text[i] == ' ') {
|
| - if (!areaName.isEmpty()) {
|
| - columnNames.append(areaName.toString());
|
| - areaName.clear();
|
| - }
|
| - continue;
|
| - }
|
| - if (text[i] == '.') {
|
| - if (areaName == ".")
|
| - continue;
|
| - if (!areaName.isEmpty()) {
|
| - columnNames.append(areaName.toString());
|
| - areaName.clear();
|
| - }
|
| - } else {
|
| - if (areaName == ".") {
|
| - columnNames.append(areaName.toString());
|
| - areaName.clear();
|
| - }
|
| - }
|
| -
|
| - areaName.append(text[i]);
|
| - }
|
| -
|
| - if (!areaName.isEmpty())
|
| - columnNames.append(areaName.toString());
|
| -
|
| - return columnNames;
|
| -}
|
| -
|
| -bool CSSPropertyParser::parseGridTemplateAreasRow(NamedGridAreaMap& gridAreaMap, const size_t rowCount, size_t& columnCount)
|
| -{
|
| - CSSParserValue* currentValue = m_valueList->current();
|
| - if (!currentValue || currentValue->m_unit != CSSParserValue::String)
|
| - return false;
|
| -
|
| - String gridRowNames = currentValue->string;
|
| - if (gridRowNames.isEmpty() || gridRowNames.containsOnlyWhitespace())
|
| - return false;
|
| -
|
| - Vector<String> columnNames = parseGridTemplateAreasColumnNames(gridRowNames);
|
| - if (!columnCount) {
|
| - columnCount = columnNames.size();
|
| - ASSERT(columnCount);
|
| - } else if (columnCount != columnNames.size()) {
|
| - // The declaration is invalid is all the rows don't have the number of columns.
|
| - return false;
|
| - }
|
| -
|
| - for (size_t currentCol = 0; currentCol < columnCount; ++currentCol) {
|
| - const String& gridAreaName = columnNames[currentCol];
|
| -
|
| - // Unamed areas are always valid (we consider them to be 1x1).
|
| - if (gridAreaName == ".")
|
| - continue;
|
| -
|
| - // We handle several grid areas with the same name at once to simplify the validation code.
|
| - size_t lookAheadCol;
|
| - for (lookAheadCol = currentCol + 1; lookAheadCol < columnCount; ++lookAheadCol) {
|
| - if (columnNames[lookAheadCol] != gridAreaName)
|
| - break;
|
| - }
|
| -
|
| - NamedGridAreaMap::iterator gridAreaIt = gridAreaMap.find(gridAreaName);
|
| - if (gridAreaIt == gridAreaMap.end()) {
|
| - gridAreaMap.add(gridAreaName, GridArea(GridSpan::translatedDefiniteGridSpan(rowCount, rowCount + 1), GridSpan::translatedDefiniteGridSpan(currentCol, lookAheadCol)));
|
| - } else {
|
| - GridArea& gridArea = gridAreaIt->value;
|
| -
|
| - // The following checks test that the grid area is a single filled-in rectangle.
|
| - // 1. The new row is adjacent to the previously parsed row.
|
| - if (rowCount != gridArea.rows.resolvedFinalPosition())
|
| - return false;
|
| -
|
| - // 2. The new area starts at the same position as the previously parsed area.
|
| - if (currentCol != gridArea.columns.resolvedInitialPosition())
|
| - return false;
|
| -
|
| - // 3. The new area ends at the same position as the previously parsed area.
|
| - if (lookAheadCol != gridArea.columns.resolvedFinalPosition())
|
| - return false;
|
| -
|
| - gridArea.rows = GridSpan::translatedDefiniteGridSpan(gridArea.rows.resolvedInitialPosition(), gridArea.rows.resolvedFinalPosition() + 1);
|
| - }
|
| - currentCol = lookAheadCol - 1;
|
| - }
|
| -
|
| - m_valueList->next();
|
| - return true;
|
| -}
|
| -
|
| -PassRefPtrWillBeRawPtr<CSSValue> CSSPropertyParser::parseGridTemplateAreas()
|
| -{
|
| - if (m_valueList->current() && m_valueList->current()->id == CSSValueNone) {
|
| - m_valueList->next();
|
| - return cssValuePool().createIdentifierValue(CSSValueNone);
|
| - }
|
| -
|
| - NamedGridAreaMap gridAreaMap;
|
| - size_t rowCount = 0;
|
| - size_t columnCount = 0;
|
| -
|
| - while (m_valueList->current()) {
|
| - if (!parseGridTemplateAreasRow(gridAreaMap, rowCount, columnCount))
|
| - return nullptr;
|
| - ++rowCount;
|
| - }
|
| -
|
| - if (!rowCount || !columnCount)
|
| - return nullptr;
|
| -
|
| - return CSSGridTemplateAreasValue::create(gridAreaMap, rowCount, columnCount);
|
| -}
|
| -
|
| -PassRefPtrWillBeRawPtr<CSSValue> CSSPropertyParser::parseGridAutoFlow(CSSParserValueList& list)
|
| -{
|
| - // [ row | column ] || dense
|
| - ASSERT(RuntimeEnabledFeatures::cssGridLayoutEnabled());
|
| -
|
| - CSSParserValue* value = list.current();
|
| - if (!value)
|
| - return nullptr;
|
| -
|
| - RefPtrWillBeRawPtr<CSSValueList> parsedValues = CSSValueList::createSpaceSeparated();
|
| -
|
| - // First parameter.
|
| - CSSValueID firstId = value->id;
|
| - if (firstId != CSSValueRow && firstId != CSSValueColumn && firstId != CSSValueDense)
|
| - return nullptr;
|
| - parsedValues->append(cssValuePool().createIdentifierValue(firstId));
|
| -
|
| - // Second parameter, if any.
|
| - value = list.next();
|
| - if (value) {
|
| - switch (firstId) {
|
| - case CSSValueRow:
|
| - case CSSValueColumn:
|
| - if (value->id != CSSValueDense)
|
| - return parsedValues;
|
| - break;
|
| - case CSSValueDense:
|
| - if (value->id != CSSValueRow && value->id != CSSValueColumn)
|
| - return parsedValues;
|
| - break;
|
| - default:
|
| - return parsedValues;
|
| - }
|
| - parsedValues->append(cssValuePool().createIdentifierValue(value->id));
|
| - list.next();
|
| - }
|
| -
|
| - return parsedValues;
|
| -}
|
| -
|
| -static bool isBaselinePositionKeyword(CSSValueID id)
|
| -{
|
| - return id == CSSValueBaseline || id == CSSValueLastBaseline;
|
| -}
|
| -
|
| -static bool isAlignmentOverflowKeyword(CSSValueID id)
|
| -{
|
| - return id == CSSValueUnsafe || id == CSSValueSafe;
|
| -}
|
| -
|
| -static bool isItemPositionKeyword(CSSValueID id)
|
| -{
|
| - return id == CSSValueStart || id == CSSValueEnd || id == CSSValueCenter
|
| - || id == CSSValueSelfStart || id == CSSValueSelfEnd || id == CSSValueFlexStart
|
| - || id == CSSValueFlexEnd || id == CSSValueLeft || id == CSSValueRight;
|
| -}
|
| -
|
| -PassRefPtrWillBeRawPtr<CSSValue> CSSPropertyParser::parseLegacyPosition()
|
| -{
|
| - // [ legacy && [ left | right | center ]
|
| -
|
| - CSSParserValue* value = m_valueList->current();
|
| - ASSERT(value);
|
| -
|
| - if (value->id == CSSValueLegacy) {
|
| - value = m_valueList->next();
|
| - if (!value)
|
| - return nullptr;
|
| - if (value->id != CSSValueCenter && value->id != CSSValueLeft && value->id != CSSValueRight)
|
| - return nullptr;
|
| - } else if (value->id == CSSValueCenter || value->id == CSSValueLeft || value->id == CSSValueRight) {
|
| - if (!m_valueList->next() || m_valueList->current()->id != CSSValueLegacy)
|
| - return nullptr;
|
| - } else {
|
| - return nullptr;
|
| - }
|
| -
|
| - m_valueList->next();
|
| - return CSSValuePair::create(cssValuePool().createIdentifierValue(CSSValueLegacy), cssValuePool().createIdentifierValue(value->id), CSSValuePair::DropIdenticalValues);
|
| -}
|
| -
|
| -PassRefPtrWillBeRawPtr<CSSValue> CSSPropertyParser::parseItemPositionOverflowPosition()
|
| -{
|
| - // auto | stretch | <baseline-position> | [<item-position> && <overflow-position>? ]
|
| - // <baseline-position> = baseline | last-baseline;
|
| - // <item-position> = center | start | end | self-start | self-end | flex-start | flex-end | left | right;
|
| - // <overflow-position> = unsafe | safe
|
| -
|
| - CSSParserValue* value = m_valueList->current();
|
| - ASSERT(value);
|
| -
|
| - if (value->id == CSSValueAuto || value->id == CSSValueStretch || isBaselinePositionKeyword(value->id)) {
|
| - m_valueList->next();
|
| - return cssValuePool().createIdentifierValue(value->id);
|
| - }
|
| + // Handle a template-area's row.
|
| + if (!parseGridTemplateAreasRow(gridAreaMap, rowCount, columnCount))
|
| + return false;
|
| + ++rowCount;
|
|
|
| - RefPtrWillBeRawPtr<CSSPrimitiveValue> position = nullptr;
|
| - RefPtrWillBeRawPtr<CSSPrimitiveValue> overflowAlignmentKeyword = nullptr;
|
| - if (isItemPositionKeyword(value->id)) {
|
| - position = cssValuePool().createIdentifierValue(value->id);
|
| - value = m_valueList->next();
|
| - if (value) {
|
| - if (isAlignmentOverflowKeyword(value->id))
|
| - overflowAlignmentKeyword = cssValuePool().createIdentifierValue(value->id);
|
| - else
|
| - return nullptr;
|
| + // Handle template-rows's track-size.
|
| + if (m_valueList->current() && m_valueList->current()->m_unit != CSSParserValue::Operator && m_valueList->current()->m_unit != CSSParserValue::String) {
|
| + RefPtrWillBeRawPtr<CSSValue> value = parseGridTrackSize(*m_valueList);
|
| + if (!value)
|
| + return false;
|
| + templateRows->append(value);
|
| + } else {
|
| + templateRows->append(cssValuePool().createIdentifierValue(CSSValueAuto));
|
| }
|
| - } else if (isAlignmentOverflowKeyword(value->id)) {
|
| - overflowAlignmentKeyword = cssValuePool().createIdentifierValue(value->id);
|
| - value = m_valueList->next();
|
| - if (value && isItemPositionKeyword(value->id))
|
| - position = cssValuePool().createIdentifierValue(value->id);
|
| - else
|
| - return nullptr;
|
| - } else {
|
| - return nullptr;
|
| - }
|
| -
|
| - m_valueList->next();
|
| -
|
| - ASSERT(position);
|
| - if (overflowAlignmentKeyword)
|
| - return CSSValuePair::create(position, overflowAlignmentKeyword, CSSValuePair::DropIdenticalValues);
|
| - return position.release();
|
| -}
|
|
|
| -inline int CSSPropertyParser::colorIntFromValue(CSSParserValue* v)
|
| -{
|
| - bool isPercent;
|
| - double value;
|
| -
|
| - if (m_parsedCalculation) {
|
| - isPercent = m_parsedCalculation->category() == CalcPercent;
|
| - value = m_parsedCalculation->doubleValue();
|
| - m_parsedCalculation.release();
|
| - } else {
|
| - isPercent = v->unit() == CSSPrimitiveValue::UnitType::Percentage;
|
| - value = v->fValue;
|
| - }
|
| -
|
| - if (value <= 0.0)
|
| - return 0;
|
| -
|
| - if (isPercent) {
|
| - if (value >= 100.0)
|
| - return 255;
|
| - return static_cast<int>(value * 256.0 / 100.0);
|
| - }
|
| -
|
| - if (value >= 255.0)
|
| - return 255;
|
| -
|
| - return static_cast<int>(value);
|
| -}
|
| -
|
| -bool CSSPropertyParser::parseColorParameters(const CSSParserValue* value, int* colorArray, bool parseAlpha)
|
| -{
|
| - CSSParserValueList* args = value->function->args.get();
|
| - CSSParserValue* v = args->current();
|
| - Units unitType = FUnknown;
|
| - // Get the first value and its type
|
| - if (validUnit(v, FInteger))
|
| - unitType = FInteger;
|
| - else if (validUnit(v, FPercent))
|
| - unitType = FPercent;
|
| - else
|
| - return false;
|
| -
|
| - colorArray[0] = colorIntFromValue(v);
|
| - for (int i = 1; i < 3; i++) {
|
| - args->next();
|
| - if (!consumeComma(args))
|
| - return false;
|
| - v = args->current();
|
| - if (!validUnit(v, unitType))
|
| - return false;
|
| - colorArray[i] = colorIntFromValue(v);
|
| - }
|
| - if (parseAlpha) {
|
| - args->next();
|
| - if (!consumeComma(args))
|
| - return false;
|
| - v = args->current();
|
| - if (!validUnit(v, FNumber))
|
| + // This will handle the trailing/leading <custom-ident>* in the grammar.
|
| + if (!parseGridLineNames(*m_valueList, *templateRows))
|
| return false;
|
| - // Convert the floating pointer number of alpha to an integer in the range [0, 256),
|
| - // with an equal distribution across all 256 values.
|
| - colorArray[3] = static_cast<int>(std::max(0.0, std::min(1.0, v->fValue)) * nextafter(256.0, 0.0));
|
| + trailingIdentWasAdded = templateRows->item(templateRows->length() - 1)->isGridLineNamesValue();
|
| }
|
| - return true;
|
| -}
|
|
|
| -// The CSS3 specification defines the format of a HSL color as
|
| -// hsl(<number>, <percent>, <percent>)
|
| -// and with alpha, the format is
|
| -// hsla(<number>, <percent>, <percent>, <number>)
|
| -// The first value, HUE, is in an angle with a value between 0 and 360
|
| -bool CSSPropertyParser::parseHSLParameters(const CSSParserValue* value, double* colorArray, bool parseAlpha)
|
| -{
|
| - CSSParserValueList* args = value->function->args.get();
|
| - CSSParserValue* v = args->current();
|
| - // Get the first value
|
| - if (!validUnit(v, FNumber))
|
| - return false;
|
| - // normalize the Hue value and change it to be between 0 and 1.0
|
| - colorArray[0] = (((static_cast<int>(v->fValue) % 360) + 360) % 360) / 360.0;
|
| - for (int i = 1; i < 3; i++) {
|
| - args->next();
|
| - if (!consumeComma(args))
|
| - return false;
|
| - v = args->current();
|
| - if (!validUnit(v, FPercent))
|
| - return false;
|
| - double percentValue = m_parsedCalculation ? m_parsedCalculation.release()->doubleValue() : v->fValue;
|
| - colorArray[i] = std::max(0.0, std::min(100.0, percentValue)) / 100.0; // needs to be value between 0 and 1.0
|
| - }
|
| - if (parseAlpha) {
|
| - args->next();
|
| - if (!consumeComma(args))
|
| + RefPtrWillBeRawPtr<CSSValue> columnsValue = nullptr;
|
| + if (m_valueList->current()) {
|
| + ASSERT(isForwardSlashOperator(m_valueList->current()));
|
| + columnsValue = parseGridTemplateColumns(important);
|
| + if (!columnsValue)
|
| return false;
|
| - v = args->current();
|
| - if (!validUnit(v, FNumber))
|
| + // The template-columns <track-list> can't be 'none'.
|
| + if (columnsValue->isPrimitiveValue() && toCSSPrimitiveValue(*columnsValue).getValueID() == CSSValueNone)
|
| return false;
|
| - colorArray[3] = std::max(0.0, std::min(1.0, v->fValue));
|
| }
|
| - return true;
|
| -}
|
|
|
| -bool CSSPropertyParser::parseColorFromValue(const CSSParserValue* value, RGBA32& result, bool acceptQuirkyColors)
|
| -{
|
| - if (acceptQuirkyColors && value->unit() == CSSPrimitiveValue::UnitType::Number
|
| - && value->fValue >= 0. && value->fValue < 1000000. && value->isInt) {
|
| - String str = String::format("%06d", static_cast<int>(value->fValue));
|
| - return Color::parseHexColor(str, result);
|
| - }
|
| - if (acceptQuirkyColors && value->m_unit == CSSParserValue::DimensionList) {
|
| - CSSParserValue* numberToken = value->valueList->valueAt(0);
|
| - CSSParserValue* unitToken = value->valueList->valueAt(1);
|
| - ASSERT(numberToken->unit() == CSSPrimitiveValue::UnitType::Number);
|
| - ASSERT(unitToken->m_unit == CSSParserValue::Identifier);
|
| - if (!numberToken->isInt || numberToken->fValue < 0)
|
| - return false;
|
| - String color = String::number(numberToken->fValue) + String(unitToken->string);
|
| - if (color.length() > 6)
|
| - return false;
|
| - while (color.length() < 6)
|
| - color = "0" + color;
|
| - return Color::parseHexColor(color, result);
|
| - }
|
| - if (value->m_unit == CSSParserValue::Identifier) {
|
| - Color color;
|
| - if (!color.setNamedColor(value->string))
|
| - return acceptQuirkyColors && Color::parseHexColor(value->string, result);
|
| - result = color.rgb();
|
| - return true;
|
| - }
|
| - if (value->m_unit == CSSParserValue::HexColor) {
|
| - if (value->string.is8Bit())
|
| - return Color::parseHexColor(value->string.characters8(), value->string.length(), result);
|
| - return Color::parseHexColor(value->string.characters16(), value->string.length(), result);
|
| - }
|
| + addProperty(CSSPropertyGridTemplateRows, templateRows.release(), important);
|
| + addProperty(CSSPropertyGridTemplateColumns, columnsValue ? columnsValue.release() : cssValuePool().createIdentifierValue(CSSValueNone), important);
|
|
|
| - if (value->m_unit == CSSParserValue::Function
|
| - && value->function->args != 0
|
| - && value->function->args->size() == 5 /* rgb + two commas */
|
| - && value->function->id == CSSValueRgb) {
|
| - int colorValues[3];
|
| - if (!parseColorParameters(value, colorValues, false))
|
| - return false;
|
| - result = makeRGB(colorValues[0], colorValues[1], colorValues[2]);
|
| - } else {
|
| - if (value->m_unit == CSSParserValue::Function
|
| - && value->function->args != 0
|
| - && value->function->args->size() == 7 /* rgba + three commas */
|
| - && value->function->id == CSSValueRgba) {
|
| - int colorValues[4];
|
| - if (!parseColorParameters(value, colorValues, true))
|
| - return false;
|
| - result = makeRGBA(colorValues[0], colorValues[1], colorValues[2], colorValues[3]);
|
| - } else if (value->m_unit == CSSParserValue::Function
|
| - && value->function->args != 0
|
| - && value->function->args->size() == 5 /* hsl + two commas */
|
| - && value->function->id == CSSValueHsl) {
|
| - double colorValues[3];
|
| - if (!parseHSLParameters(value, colorValues, false))
|
| - return false;
|
| - result = makeRGBAFromHSLA(colorValues[0], colorValues[1], colorValues[2], 1.0);
|
| - } else if (value->m_unit == CSSParserValue::Function
|
| - && value->function->args != 0
|
| - && value->function->args->size() == 7 /* hsla + three commas */
|
| - && value->function->id == CSSValueHsla) {
|
| - double colorValues[4];
|
| - if (!parseHSLParameters(value, colorValues, true))
|
| - return false;
|
| - result = makeRGBAFromHSLA(colorValues[0], colorValues[1], colorValues[2], colorValues[3]);
|
| - } else {
|
| - return false;
|
| - }
|
| - }
|
| + RefPtrWillBeRawPtr<CSSValue> templateAreas = CSSGridTemplateAreasValue::create(gridAreaMap, rowCount, columnCount);
|
| + addProperty(CSSPropertyGridTemplateAreas, templateAreas.release(), important);
|
|
|
| return true;
|
| }
|
|
|
| -// This should go away once we drop support for -webkit-gradient
|
| -static PassRefPtrWillBeRawPtr<CSSPrimitiveValue> parseDeprecatedGradientPoint(CSSParserValue* a, bool horizontal)
|
| -{
|
| - RefPtrWillBeRawPtr<CSSPrimitiveValue> result = nullptr;
|
| - if (a->m_unit == CSSParserValue::Identifier) {
|
| - if ((a->id == CSSValueLeft && horizontal)
|
| - || (a->id == CSSValueTop && !horizontal))
|
| - result = cssValuePool().createValue(0., CSSPrimitiveValue::UnitType::Percentage);
|
| - else if ((a->id == CSSValueRight && horizontal)
|
| - || (a->id == CSSValueBottom && !horizontal))
|
| - result = cssValuePool().createValue(100., CSSPrimitiveValue::UnitType::Percentage);
|
| - else if (a->id == CSSValueCenter)
|
| - result = cssValuePool().createValue(50., CSSPrimitiveValue::UnitType::Percentage);
|
| - } else if (a->unit() == CSSPrimitiveValue::UnitType::Number || a->unit() == CSSPrimitiveValue::UnitType::Percentage) {
|
| - result = cssValuePool().createValue(a->fValue, a->unit());
|
| - }
|
| - return result;
|
| -}
|
| -
|
| -// Used to parse colors for -webkit-gradient(...).
|
| -PassRefPtrWillBeRawPtr<CSSValue> CSSPropertyParser::parseDeprecatedGradientStopColor(const CSSParserValue* value)
|
| -{
|
| - // Disallow currentcolor.
|
| - if (value->id == CSSValueCurrentcolor)
|
| - return nullptr;
|
| - return parseColor(value);
|
| -}
|
|
|
| -bool CSSPropertyParser::parseDeprecatedGradientColorStop(CSSParserValue* a, CSSGradientColorStop& stop)
|
| +bool CSSPropertyParser::parseGridTemplateShorthand(bool important)
|
| {
|
| - if (a->m_unit != CSSParserValue::Function)
|
| - return false;
|
| + ASSERT(RuntimeEnabledFeatures::cssGridLayoutEnabled());
|
|
|
| - if (a->function->id != CSSValueFrom
|
| - && a->function->id != CSSValueTo
|
| - && a->function->id != CSSValueColorStop)
|
| - return false;
|
| + ShorthandScope scope(this, CSSPropertyGridTemplate);
|
| + ASSERT(gridTemplateShorthand().length() == 3);
|
|
|
| - CSSParserValueList* args = a->function->args.get();
|
| - if (!args)
|
| + // At least "none" must be defined.
|
| + if (!m_valueList->current())
|
| return false;
|
|
|
| - if (a->function->id == CSSValueFrom || a->function->id == CSSValueTo) {
|
| - // The "from" and "to" stops expect 1 argument.
|
| - if (args->size() != 1)
|
| - return false;
|
| -
|
| - if (a->function->id == CSSValueFrom)
|
| - stop.m_position = cssValuePool().createValue(0, CSSPrimitiveValue::UnitType::Number);
|
| - else
|
| - stop.m_position = cssValuePool().createValue(1, CSSPrimitiveValue::UnitType::Number);
|
| + bool firstValueIsNone = m_valueList->current()->id == CSSValueNone;
|
|
|
| - stop.m_color = parseDeprecatedGradientStopColor(args->current());
|
| - if (!stop.m_color)
|
| - return false;
|
| + // 1- 'none' case.
|
| + if (firstValueIsNone && !m_valueList->next()) {
|
| + addProperty(CSSPropertyGridTemplateColumns, cssValuePool().createIdentifierValue(CSSValueNone), important);
|
| + addProperty(CSSPropertyGridTemplateRows, cssValuePool().createIdentifierValue(CSSValueNone), important);
|
| + addProperty(CSSPropertyGridTemplateAreas, cssValuePool().createIdentifierValue(CSSValueNone), important);
|
| + return true;
|
| }
|
|
|
| - // The "color-stop" function expects 3 arguments.
|
| - if (a->function->id == CSSValueColorStop) {
|
| - if (args->size() != 3)
|
| - return false;
|
| -
|
| - CSSParserValue* stopArg = args->current();
|
| - if (stopArg->unit() == CSSPrimitiveValue::UnitType::Percentage)
|
| - stop.m_position = cssValuePool().createValue(stopArg->fValue / 100, CSSPrimitiveValue::UnitType::Number);
|
| - else if (stopArg->unit() == CSSPrimitiveValue::UnitType::Number)
|
| - stop.m_position = cssValuePool().createValue(stopArg->fValue, CSSPrimitiveValue::UnitType::Number);
|
| - else
|
| - return false;
|
| + // 2- <grid-template-rows> / <grid-template-columns>
|
| + RefPtrWillBeRawPtr<CSSValue> rowsValue = nullptr;
|
| + if (firstValueIsNone) {
|
| + rowsValue = cssValuePool().createIdentifierValue(CSSValueNone);
|
| + } else {
|
| + rowsValue = parseGridTrackList();
|
| + }
|
|
|
| - args->next();
|
| - if (!consumeComma(args))
|
| + if (rowsValue) {
|
| + RefPtrWillBeRawPtr<CSSValue> columnsValue = parseGridTemplateColumns(important);
|
| + if (!columnsValue)
|
| return false;
|
|
|
| - stop.m_color = parseDeprecatedGradientStopColor(args->current());
|
| - if (!stop.m_color)
|
| - return false;
|
| + addProperty(CSSPropertyGridTemplateRows, rowsValue.release(), important);
|
| + addProperty(CSSPropertyGridTemplateColumns, columnsValue.release(), important);
|
| + addProperty(CSSPropertyGridTemplateAreas, cssValuePool().createIdentifierValue(CSSValueNone), important);
|
| + return true;
|
| }
|
|
|
| - return true;
|
| + // 3- [<line-names>? <string> <track-size>? <line-names>? ]+ syntax.
|
| + // It requires to rewind parsing due to previous syntax failures.
|
| + m_valueList->setCurrentIndex(0);
|
| + return parseGridTemplateRowsAndAreasAndColumns(important);
|
| }
|
|
|
| -bool CSSPropertyParser::parseDeprecatedGradient(CSSParserValueList* valueList, RefPtrWillBeRawPtr<CSSValue>& gradient)
|
| +bool CSSPropertyParser::parseGridShorthand(bool important)
|
| {
|
| - // Walk the arguments.
|
| - CSSParserValueList* args = valueList->current()->function->args.get();
|
| - if (!args || args->size() == 0)
|
| - return false;
|
| -
|
| - // The first argument is the gradient type. It is an identifier.
|
| - CSSGradientType gradientType;
|
| - CSSParserValue* a = args->current();
|
| - if (!a || a->m_unit != CSSParserValue::Identifier)
|
| - return false;
|
| - if (a->id == CSSValueLinear)
|
| - gradientType = CSSDeprecatedLinearGradient;
|
| - else if (a->id == CSSValueRadial)
|
| - gradientType = CSSDeprecatedRadialGradient;
|
| - else
|
| - return false;
|
| + ShorthandScope scope(this, CSSPropertyGrid);
|
| + ASSERT(shorthandForProperty(CSSPropertyGrid).length() == 8);
|
|
|
| - RefPtrWillBeRawPtr<CSSGradientValue> result = nullptr;
|
| - switch (gradientType) {
|
| - case CSSDeprecatedLinearGradient:
|
| - result = CSSLinearGradientValue::create(NonRepeating, gradientType);
|
| - break;
|
| - case CSSDeprecatedRadialGradient:
|
| - result = CSSRadialGradientValue::create(NonRepeating, gradientType);
|
| - break;
|
| - default:
|
| - // The rest of the gradient types shouldn't appear here.
|
| - ASSERT_NOT_REACHED();
|
| + // 1- <grid-template>
|
| + if (parseGridTemplateShorthand(important)) {
|
| + // It can only be specified the explicit or the implicit grid properties in a single grid declaration.
|
| + // The sub-properties not specified are set to their initial value, as normal for shorthands.
|
| + addProperty(CSSPropertyGridAutoFlow, cssValuePool().createImplicitInitialValue(), important);
|
| + addProperty(CSSPropertyGridAutoColumns, cssValuePool().createImplicitInitialValue(), important);
|
| + addProperty(CSSPropertyGridAutoRows, cssValuePool().createImplicitInitialValue(), important);
|
| + addProperty(CSSPropertyGridColumnGap, cssValuePool().createImplicitInitialValue(), important);
|
| + addProperty(CSSPropertyGridRowGap, cssValuePool().createImplicitInitialValue(), important);
|
| + return true;
|
| }
|
| - args->next();
|
| -
|
| - if (!consumeComma(args))
|
| - return false;
|
| -
|
| - // Next comes the starting point for the gradient as an x y pair. There is no
|
| - // comma between the x and the y values.
|
| - // First X. It can be left, right, number or percent.
|
| - a = args->current();
|
| - if (!a)
|
| - return false;
|
| - RefPtrWillBeRawPtr<CSSPrimitiveValue> point = parseDeprecatedGradientPoint(a, true);
|
| - if (!point)
|
| - return false;
|
| - result->setFirstX(point.release());
|
| -
|
| - // First Y. It can be top, bottom, number or percent.
|
| - a = args->next();
|
| - if (!a)
|
| - return false;
|
| - point = parseDeprecatedGradientPoint(a, false);
|
| - if (!point)
|
| - return false;
|
| - result->setFirstY(point.release());
|
| -
|
| - // Comma after the first point.
|
| - args->next();
|
| - if (!consumeComma(args))
|
| - return false;
|
|
|
| - // For radial gradients only, we now expect a numeric radius.
|
| - if (gradientType == CSSDeprecatedRadialGradient) {
|
| - a = args->current();
|
| - if (!a || a->unit() != CSSPrimitiveValue::UnitType::Number)
|
| - return false;
|
| - toCSSRadialGradientValue(result.get())->setFirstRadius(createPrimitiveNumericValue(a));
|
| -
|
| - // Comma after the first radius.
|
| - args->next();
|
| - if (!consumeComma(args))
|
| - return false;
|
| - }
|
| + // Need to rewind parsing to explore the alternative syntax of this shorthand.
|
| + m_valueList->setCurrentIndex(0);
|
|
|
| - // Next is the ending point for the gradient as an x, y pair.
|
| - // Second X. It can be left, right, number or percent.
|
| - a = args->current();
|
| - if (!a)
|
| - return false;
|
| - point = parseDeprecatedGradientPoint(a, true);
|
| - if (!point)
|
| + // 2- <grid-auto-flow> [ <grid-auto-rows> [ / <grid-auto-columns> ]? ]
|
| + if (!legacyParseAndApplyValue(CSSPropertyGridAutoFlow, important))
|
| return false;
|
| - result->setSecondX(point.release());
|
|
|
| - // Second Y. It can be top, bottom, number or percent.
|
| - a = args->next();
|
| - if (!a)
|
| - return false;
|
| - point = parseDeprecatedGradientPoint(a, false);
|
| - if (!point)
|
| - return false;
|
| - result->setSecondY(point.release());
|
| - args->next();
|
| + RefPtrWillBeRawPtr<CSSValue> autoColumnsValue = nullptr;
|
| + RefPtrWillBeRawPtr<CSSValue> autoRowsValue = nullptr;
|
|
|
| - // For radial gradients only, we now expect the second radius.
|
| - if (gradientType == CSSDeprecatedRadialGradient) {
|
| - // Comma after the second point.
|
| - if (!consumeComma(args))
|
| + if (m_valueList->current()) {
|
| + autoRowsValue = parseGridTrackSize(*m_valueList);
|
| + if (!autoRowsValue)
|
| return false;
|
| -
|
| - a = args->current();
|
| - if (!a || a->unit() != CSSPrimitiveValue::UnitType::Number)
|
| + if (m_valueList->current()) {
|
| + if (!isForwardSlashOperator(m_valueList->current()) || !m_valueList->next())
|
| + return false;
|
| + autoColumnsValue = parseGridTrackSize(*m_valueList);
|
| + if (!autoColumnsValue)
|
| + return false;
|
| + }
|
| + if (m_valueList->current())
|
| return false;
|
| - toCSSRadialGradientValue(result.get())->setSecondRadius(createPrimitiveNumericValue(a));
|
| - args->next();
|
| + } else {
|
| + // Other omitted values are set to their initial values.
|
| + autoColumnsValue = cssValuePool().createImplicitInitialValue();
|
| + autoRowsValue = cssValuePool().createImplicitInitialValue();
|
| }
|
|
|
| - // We now will accept any number of stops (0 or more).
|
| - a = args->current();
|
| - while (a) {
|
| - // Look for the comma before the next stop.
|
| - if (!consumeComma(args))
|
| - return false;
|
| -
|
| - // Now examine the stop itself.
|
| - a = args->current();
|
| - if (!a)
|
| - return false;
|
| + // if <grid-auto-columns> value is omitted, it is set to the value specified for grid-auto-rows.
|
| + if (!autoColumnsValue)
|
| + autoColumnsValue = autoRowsValue;
|
|
|
| - // The function name needs to be one of "from", "to", or "color-stop."
|
| - CSSGradientColorStop stop;
|
| - if (!parseDeprecatedGradientColorStop(a, stop))
|
| - return false;
|
| - result->addStop(stop);
|
| + addProperty(CSSPropertyGridAutoColumns, autoColumnsValue, important);
|
| + addProperty(CSSPropertyGridAutoRows, autoRowsValue, important);
|
|
|
| - // Advance
|
| - a = args->next();
|
| - }
|
| + // It can only be specified the explicit or the implicit grid properties in a single grid declaration.
|
| + // The sub-properties not specified are set to their initial value, as normal for shorthands.
|
| + addProperty(CSSPropertyGridTemplateColumns, cssValuePool().createImplicitInitialValue(), important);
|
| + addProperty(CSSPropertyGridTemplateRows, cssValuePool().createImplicitInitialValue(), important);
|
| + addProperty(CSSPropertyGridTemplateAreas, cssValuePool().createImplicitInitialValue(), important);
|
| + addProperty(CSSPropertyGridColumnGap, cssValuePool().createImplicitInitialValue(), important);
|
| + addProperty(CSSPropertyGridRowGap, cssValuePool().createImplicitInitialValue(), important);
|
|
|
| - gradient = result.release();
|
| return true;
|
| }
|
|
|
| -static PassRefPtrWillBeRawPtr<CSSPrimitiveValue> valueFromSideKeyword(CSSParserValue* a, bool& isHorizontal)
|
| +bool CSSPropertyParser::parseGridAreaShorthand(bool important)
|
| {
|
| - if (a->m_unit != CSSParserValue::Identifier)
|
| - return nullptr;
|
| -
|
| - switch (a->id) {
|
| - case CSSValueLeft:
|
| - case CSSValueRight:
|
| - isHorizontal = true;
|
| - break;
|
| - case CSSValueTop:
|
| - case CSSValueBottom:
|
| - isHorizontal = false;
|
| - break;
|
| - default:
|
| - return nullptr;
|
| - }
|
| - return cssValuePool().createIdentifierValue(a->id);
|
| -}
|
| + ASSERT(RuntimeEnabledFeatures::cssGridLayoutEnabled());
|
|
|
| -bool CSSPropertyParser::parseDeprecatedLinearGradient(CSSParserValueList* valueList, RefPtrWillBeRawPtr<CSSValue>& gradient, CSSGradientRepeat repeating)
|
| -{
|
| - RefPtrWillBeRawPtr<CSSLinearGradientValue> result = CSSLinearGradientValue::create(repeating, CSSPrefixedLinearGradient);
|
| + ShorthandScope scope(this, CSSPropertyGridArea);
|
| + const StylePropertyShorthand& shorthand = gridAreaShorthand();
|
| + ASSERT_UNUSED(shorthand, shorthand.length() == 4);
|
|
|
| - // Walk the arguments.
|
| - CSSParserValueList* args = valueList->current()->function->args.get();
|
| - if (!args || !args->size())
|
| + RefPtrWillBeRawPtr<CSSValue> rowStartValue = parseGridPosition();
|
| + if (!rowStartValue)
|
| return false;
|
|
|
| - CSSParserValue* a = args->current();
|
| - if (!a)
|
| + RefPtrWillBeRawPtr<CSSValue> columnStartValue = nullptr;
|
| + if (!parseSingleGridAreaLonghand(columnStartValue))
|
| return false;
|
|
|
| - bool expectComma = false;
|
| - // Look for angle.
|
| - if (validUnit(a, FAngle, HTMLStandardMode)) {
|
| - result->setAngle(createPrimitiveNumericValue(a));
|
| -
|
| - args->next();
|
| - expectComma = true;
|
| - } else {
|
| - // Look one or two optional keywords that indicate a side or corner.
|
| - RefPtrWillBeRawPtr<CSSPrimitiveValue> startX = nullptr;
|
| - RefPtrWillBeRawPtr<CSSPrimitiveValue> startY = nullptr;
|
| -
|
| - RefPtrWillBeRawPtr<CSSPrimitiveValue> location = nullptr;
|
| - bool isHorizontal = false;
|
| - if ((location = valueFromSideKeyword(a, isHorizontal))) {
|
| - if (isHorizontal)
|
| - startX = location;
|
| - else
|
| - startY = location;
|
| -
|
| - a = args->next();
|
| - if (a) {
|
| - if ((location = valueFromSideKeyword(a, isHorizontal))) {
|
| - if (isHorizontal) {
|
| - if (startX)
|
| - return false;
|
| - startX = location;
|
| - } else {
|
| - if (startY)
|
| - return false;
|
| - startY = location;
|
| - }
|
| -
|
| - args->next();
|
| - }
|
| - }
|
| -
|
| - expectComma = true;
|
| - }
|
| + RefPtrWillBeRawPtr<CSSValue> rowEndValue = nullptr;
|
| + if (!parseSingleGridAreaLonghand(rowEndValue))
|
| + return false;
|
|
|
| - if (!startX && !startY)
|
| - startY = cssValuePool().createIdentifierValue(CSSValueTop);
|
| + RefPtrWillBeRawPtr<CSSValue> columnEndValue = nullptr;
|
| + if (!parseSingleGridAreaLonghand(columnEndValue))
|
| + return false;
|
|
|
| - result->setFirstX(startX.release());
|
| - result->setFirstY(startY.release());
|
| - }
|
| + if (!columnStartValue)
|
| + columnStartValue = gridMissingGridPositionValue(rowStartValue.get());
|
|
|
| - if (!parseGradientColorStops(args, result.get(), expectComma))
|
| - return false;
|
| + if (!rowEndValue)
|
| + rowEndValue = gridMissingGridPositionValue(rowStartValue.get());
|
|
|
| - if (!result->stopCount())
|
| - return false;
|
| + if (!columnEndValue)
|
| + columnEndValue = gridMissingGridPositionValue(columnStartValue.get());
|
|
|
| - gradient = result.release();
|
| + addProperty(CSSPropertyGridRowStart, rowStartValue, important);
|
| + addProperty(CSSPropertyGridColumnStart, columnStartValue, important);
|
| + addProperty(CSSPropertyGridRowEnd, rowEndValue, important);
|
| + addProperty(CSSPropertyGridColumnEnd, columnEndValue, important);
|
| return true;
|
| }
|
|
|
| -bool CSSPropertyParser::parseDeprecatedRadialGradient(CSSParserValueList* valueList, RefPtrWillBeRawPtr<CSSValue>& gradient, CSSGradientRepeat repeating)
|
| +bool CSSPropertyParser::parseSingleGridAreaLonghand(RefPtrWillBeRawPtr<CSSValue>& property)
|
| {
|
| - RefPtrWillBeRawPtr<CSSRadialGradientValue> result = CSSRadialGradientValue::create(repeating, CSSPrefixedRadialGradient);
|
| + if (!m_valueList->current())
|
| + return true;
|
|
|
| - // Walk the arguments.
|
| - CSSParserValueList* args = valueList->current()->function->args.get();
|
| - if (!args || !args->size())
|
| + if (!isForwardSlashOperator(m_valueList->current()))
|
| return false;
|
|
|
| - CSSParserValue* a = args->current();
|
| - if (!a)
|
| + if (!m_valueList->next())
|
| return false;
|
|
|
| - bool expectComma = false;
|
| -
|
| - // Optional background-position
|
| - RefPtrWillBeRawPtr<CSSValue> centerX = nullptr;
|
| - RefPtrWillBeRawPtr<CSSValue> centerY = nullptr;
|
| - // parse2ValuesFillPosition advances the args next pointer.
|
| - parse2ValuesFillPosition(args, centerX, centerY);
|
| -
|
| - if ((centerX || centerY) && !consumeComma(args))
|
| - return false;
|
| + property = parseGridPosition();
|
| + return true;
|
| +}
|
|
|
| - a = args->current();
|
| - if (!a)
|
| - return false;
|
| +static inline bool isClosingBracket(const CSSParserValue& value)
|
| +{
|
| + return value.m_unit == CSSParserValue::Operator && value.iValue == ']';
|
| +}
|
|
|
| - result->setFirstX(toCSSPrimitiveValue(centerX.get()));
|
| - result->setSecondX(toCSSPrimitiveValue(centerX.get()));
|
| - // CSS3 radial gradients always share the same start and end point.
|
| - result->setFirstY(toCSSPrimitiveValue(centerY.get()));
|
| - result->setSecondY(toCSSPrimitiveValue(centerY.get()));
|
| +bool CSSPropertyParser::parseGridLineNames(CSSParserValueList& inputList, CSSValueList& valueList, CSSGridLineNamesValue* previousNamedAreaTrailingLineNames)
|
| +{
|
| + if (!inputList.current() || inputList.current()->m_unit != CSSParserValue::Operator || inputList.current()->iValue != '[')
|
| + return true;
|
|
|
| - RefPtrWillBeRawPtr<CSSPrimitiveValue> shapeValue = nullptr;
|
| - RefPtrWillBeRawPtr<CSSPrimitiveValue> sizeValue = nullptr;
|
| + // Skip '['
|
| + inputList.next();
|
|
|
| - // Optional shape and/or size in any order.
|
| - for (int i = 0; i < 2; ++i) {
|
| - if (a->m_unit != CSSParserValue::Identifier)
|
| - break;
|
| + RefPtrWillBeRawPtr<CSSGridLineNamesValue> lineNames = previousNamedAreaTrailingLineNames;
|
| + if (!lineNames)
|
| + lineNames = CSSGridLineNamesValue::create();
|
|
|
| - bool foundValue = false;
|
| - switch (a->id) {
|
| - case CSSValueCircle:
|
| - case CSSValueEllipse:
|
| - shapeValue = cssValuePool().createIdentifierValue(a->id);
|
| - foundValue = true;
|
| - break;
|
| - case CSSValueClosestSide:
|
| - case CSSValueClosestCorner:
|
| - case CSSValueFarthestSide:
|
| - case CSSValueFarthestCorner:
|
| - case CSSValueContain:
|
| - case CSSValueCover:
|
| - sizeValue = cssValuePool().createIdentifierValue(a->id);
|
| - foundValue = true;
|
| - break;
|
| - default:
|
| + while (CSSParserValue* identValue = inputList.current()) {
|
| + if (isClosingBracket(*identValue))
|
| break;
|
| - }
|
|
|
| - if (foundValue) {
|
| - a = args->next();
|
| - if (!a)
|
| - return false;
|
| + if (!isValidCustomIdentForGridPositions(*identValue))
|
| + return false;
|
|
|
| - expectComma = true;
|
| - }
|
| + RefPtrWillBeRawPtr<CSSCustomIdentValue> lineName = createPrimitiveCustomIdentValue(identValue);
|
| + lineNames->append(lineName.release());
|
| + inputList.next();
|
| }
|
|
|
| - result->setShape(shapeValue);
|
| - result->setSizingBehavior(sizeValue);
|
| + if (!inputList.current() || !isClosingBracket(*inputList.current()))
|
| + return false;
|
|
|
| - // Or, two lengths or percentages
|
| - RefPtrWillBeRawPtr<CSSPrimitiveValue> horizontalSize = nullptr;
|
| - RefPtrWillBeRawPtr<CSSPrimitiveValue> verticalSize = nullptr;
|
| + if (!previousNamedAreaTrailingLineNames)
|
| + valueList.append(lineNames.release());
|
|
|
| - if (!shapeValue && !sizeValue) {
|
| - if (validUnit(a, FLength | FPercent)) {
|
| - horizontalSize = createPrimitiveNumericValue(a);
|
| - a = args->next();
|
| - if (!a)
|
| - return false;
|
| + // Consume ']'
|
| + inputList.next();
|
| + return true;
|
| +}
|
|
|
| - expectComma = true;
|
| - }
|
| +PassRefPtrWillBeRawPtr<CSSValue> CSSPropertyParser::parseGridTrackList()
|
| +{
|
| + ASSERT(RuntimeEnabledFeatures::cssGridLayoutEnabled());
|
|
|
| - if (validUnit(a, FLength | FPercent)) {
|
| - verticalSize = createPrimitiveNumericValue(a);
|
| + CSSParserValue* value = m_valueList->current();
|
| + if (value->id == CSSValueNone) {
|
| + m_valueList->next();
|
| + return cssValuePool().createIdentifierValue(CSSValueNone);
|
| + }
|
|
|
| - a = args->next();
|
| - if (!a)
|
| - return false;
|
| - expectComma = true;
|
| + RefPtrWillBeRawPtr<CSSValueList> values = CSSValueList::createSpaceSeparated();
|
| + // Handle leading <custom-ident>*.
|
| + if (!parseGridLineNames(*m_valueList, *values))
|
| + return nullptr;
|
| +
|
| + bool seenTrackSizeOrRepeatFunction = false;
|
| + bool seenAutoRepeat = false;
|
| + while (CSSParserValue* currentValue = m_valueList->current()) {
|
| + if (isForwardSlashOperator(currentValue))
|
| + break;
|
| + if (currentValue->m_unit == CSSParserValue::Function && currentValue->function->id == CSSValueRepeat) {
|
| + bool isAutoRepeat;
|
| + if (!parseGridTrackRepeatFunction(*values, isAutoRepeat))
|
| + return nullptr;
|
| + if (isAutoRepeat && seenAutoRepeat)
|
| + return nullptr;
|
| + seenTrackSizeOrRepeatFunction = true;
|
| + seenAutoRepeat = seenAutoRepeat || isAutoRepeat;
|
| + } else {
|
| + RefPtrWillBeRawPtr<CSSValue> value = parseGridTrackSize(*m_valueList, seenAutoRepeat ? FixedSizeOnly : AllowAll);
|
| + if (!value)
|
| + return nullptr;
|
| + values->append(value);
|
| + seenTrackSizeOrRepeatFunction = true;
|
| }
|
| + // This will handle the trailing <custom-ident>* in the grammar.
|
| + if (!parseGridLineNames(*m_valueList, *values))
|
| + return nullptr;
|
| }
|
|
|
| - // Must have neither or both.
|
| - if (!horizontalSize != !verticalSize)
|
| - return false;
|
| -
|
| - result->setEndHorizontalSize(horizontalSize);
|
| - result->setEndVerticalSize(verticalSize);
|
| + // We should have found a <track-size> or else it is not a valid <track-list>
|
| + if (!seenTrackSizeOrRepeatFunction)
|
| + return nullptr;
|
|
|
| - if (!parseGradientColorStops(args, result.get(), expectComma))
|
| - return false;
|
| + // <auto-repeat> requires definite minimum track sizes in order to compute the number of repetitions.
|
| + // The above while loop detects those appearances after the <auto-repeat> but not the ones before.
|
| + if (seenAutoRepeat) {
|
| + for (auto value : *values) {
|
| + if (value->isGridLineNamesValue())
|
| + continue;
|
| + ASSERT(value->isPrimitiveValue() || (value->isFunctionValue() && toCSSFunctionValue(*value).item(0)));
|
| + const CSSPrimitiveValue& primitiveValue = value->isPrimitiveValue()
|
| + ? toCSSPrimitiveValue(*value)
|
| + : toCSSPrimitiveValue(*toCSSFunctionValue(*value).item(0));
|
| + CSSValueID valueID = primitiveValue.getValueID();
|
| + if (valueID == CSSValueMinContent || valueID == CSSValueMaxContent || valueID == CSSValueAuto || primitiveValue.isFlex())
|
| + return nullptr;
|
| + }
|
| + }
|
|
|
| - gradient = result.release();
|
| - return true;
|
| + return values;
|
| }
|
|
|
| -bool CSSPropertyParser::parseLinearGradient(CSSParserValueList* valueList, RefPtrWillBeRawPtr<CSSValue>& gradient, CSSGradientRepeat repeating)
|
| +bool CSSPropertyParser::parseGridTrackRepeatFunction(CSSValueList& list, bool& isAutoRepeat)
|
| {
|
| - RefPtrWillBeRawPtr<CSSLinearGradientValue> result = CSSLinearGradientValue::create(repeating, CSSLinearGradient);
|
| -
|
| - CSSParserFunction* function = valueList->current()->function;
|
| - CSSParserValueList* args = function->args.get();
|
| - if (!args || !args->size())
|
| + CSSParserValueList* arguments = m_valueList->current()->function->args.get();
|
| + if (!arguments || arguments->size() < 3 || !isComma(arguments->valueAt(1)))
|
| return false;
|
|
|
| - CSSParserValue* a = args->current();
|
| - if (!a)
|
| + CSSParserValue* currentValue = arguments->valueAt(0);
|
| + isAutoRepeat = currentValue->id == CSSValueAutoFill || currentValue->id == CSSValueAutoFit;
|
| + if (!isAutoRepeat && !validUnit(currentValue, FPositiveInteger))
|
| return false;
|
|
|
| - bool expectComma = false;
|
| - // Look for angle.
|
| - if (validUnit(a, FAngle, HTMLStandardMode)) {
|
| - result->setAngle(createPrimitiveNumericValue(a));
|
| -
|
| - args->next();
|
| - expectComma = true;
|
| - } else if (a->m_unit == CSSParserValue::Identifier && a->id == CSSValueTo) {
|
| - // to [ [left | right] || [top | bottom] ]
|
| - a = args->next();
|
| - if (!a)
|
| - return false;
|
| -
|
| - RefPtrWillBeRawPtr<CSSPrimitiveValue> endX = nullptr;
|
| - RefPtrWillBeRawPtr<CSSPrimitiveValue> endY = nullptr;
|
| - RefPtrWillBeRawPtr<CSSPrimitiveValue> location = nullptr;
|
| - bool isHorizontal = false;
|
| + // The number of repetitions for <auto-repeat> is not important at parsing level
|
| + // because it will be computed later, let's set it to 1.
|
| + size_t repetitions = isAutoRepeat ? 1 : clampTo<size_t>(currentValue->fValue, 0, kGridMaxTracks);
|
|
|
| - location = valueFromSideKeyword(a, isHorizontal);
|
| - if (!location)
|
| - return false;
|
| + RefPtrWillBeRawPtr<CSSValueList> repeatedValues = CSSValueList::createSpaceSeparated();
|
| + arguments->next(); // Skip the repetition count.
|
| + arguments->next(); // Skip the comma.
|
|
|
| - if (isHorizontal)
|
| - endX = location;
|
| - else
|
| - endY = location;
|
| + // Handle leading <custom-ident>*.
|
| + if (!parseGridLineNames(*arguments, *repeatedValues))
|
| + return false;
|
|
|
| - a = args->next();
|
| - if (!a)
|
| + size_t numberOfTracks = 0;
|
| + TrackSizeRestriction restriction = isAutoRepeat ? FixedSizeOnly : AllowAll;
|
| + while (arguments->current()) {
|
| + if (isAutoRepeat && numberOfTracks)
|
| return false;
|
|
|
| - location = valueFromSideKeyword(a, isHorizontal);
|
| - if (location) {
|
| - if (isHorizontal) {
|
| - if (endX)
|
| - return false;
|
| - endX = location;
|
| - } else {
|
| - if (endY)
|
| - return false;
|
| - endY = location;
|
| - }
|
| + RefPtrWillBeRawPtr<CSSValue> trackSize = parseGridTrackSize(*arguments, restriction);
|
| + if (!trackSize)
|
| + return false;
|
|
|
| - args->next();
|
| - }
|
| + repeatedValues->append(trackSize);
|
| + ++numberOfTracks;
|
|
|
| - expectComma = true;
|
| - result->setFirstX(endX.release());
|
| - result->setFirstY(endY.release());
|
| + // This takes care of any trailing <custom-ident>* in the grammar.
|
| + if (!parseGridLineNames(*arguments, *repeatedValues))
|
| + return false;
|
| }
|
|
|
| - if (!parseGradientColorStops(args, result.get(), expectComma))
|
| + // We should have found at least one <track-size> or else it is not a valid <track-list>.
|
| + if (!numberOfTracks)
|
| return false;
|
|
|
| - if (!result->stopCount())
|
| - return false;
|
| + // We clamp the number of repetitions to a multiple of the repeat() track list's size, while staying below the max
|
| + // grid size.
|
| + repetitions = std::min(repetitions, kGridMaxTracks / numberOfTracks);
|
| +
|
| + for (size_t i = 0; i < repetitions; ++i) {
|
| + for (size_t j = 0; j < repeatedValues->length(); ++j)
|
| + list.append(repeatedValues->item(j));
|
| + }
|
|
|
| - gradient = result.release();
|
| + // parseGridTrackSize iterated over the repeat arguments, move to the next value.
|
| + m_valueList->next();
|
| return true;
|
| }
|
|
|
| -bool CSSPropertyParser::parseRadialGradient(CSSParserValueList* valueList, RefPtrWillBeRawPtr<CSSValue>& gradient, CSSGradientRepeat repeating)
|
| +
|
| +PassRefPtrWillBeRawPtr<CSSValue> CSSPropertyParser::parseGridTrackSize(CSSParserValueList& inputList, TrackSizeRestriction restriction)
|
| {
|
| - RefPtrWillBeRawPtr<CSSRadialGradientValue> result = CSSRadialGradientValue::create(repeating, CSSRadialGradient);
|
| + ASSERT(RuntimeEnabledFeatures::cssGridLayoutEnabled());
|
|
|
| - CSSParserValueList* args = valueList->current()->function->args.get();
|
| - if (!args || !args->size())
|
| - return false;
|
| + CSSParserValue* currentValue = inputList.current();
|
| + inputList.next();
|
|
|
| - CSSParserValue* a = args->current();
|
| - if (!a)
|
| - return false;
|
| + if (currentValue->id == CSSValueAuto)
|
| + return restriction == AllowAll ? cssValuePool().createIdentifierValue(CSSValueAuto) : nullptr;
|
|
|
| - bool expectComma = false;
|
| -
|
| - RefPtrWillBeRawPtr<CSSPrimitiveValue> shapeValue = nullptr;
|
| - 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 (a->m_unit == CSSParserValue::Identifier) {
|
| - bool badIdent = false;
|
| - switch (a->id) {
|
| - case CSSValueCircle:
|
| - case CSSValueEllipse:
|
| - if (shapeValue)
|
| - return false;
|
| - shapeValue = cssValuePool().createIdentifierValue(a->id);
|
| - break;
|
| - case CSSValueClosestSide:
|
| - case CSSValueClosestCorner:
|
| - case CSSValueFarthestSide:
|
| - case CSSValueFarthestCorner:
|
| - if (sizeValue || horizontalSize)
|
| - return false;
|
| - sizeValue = cssValuePool().createIdentifierValue(a->id);
|
| - break;
|
| - default:
|
| - badIdent = true;
|
| - }
|
| + if (currentValue->m_unit == CSSParserValue::Function && currentValue->function->id == CSSValueMinmax) {
|
| + // The spec defines the following grammar: minmax( <track-breadth> , <track-breadth> )
|
| + CSSParserValueList* arguments = currentValue->function->args.get();
|
| + if (!arguments || arguments->size() != 3 || !isComma(arguments->valueAt(1)))
|
| + return nullptr;
|
|
|
| - if (badIdent)
|
| - break;
|
| + RefPtrWillBeRawPtr<CSSPrimitiveValue> minTrackBreadth = parseGridBreadth(arguments->valueAt(0), restriction);
|
| + if (!minTrackBreadth)
|
| + return nullptr;
|
|
|
| - a = args->next();
|
| - if (!a)
|
| - return false;
|
| - } else if (validUnit(a, FLength | FPercent)) {
|
| + RefPtrWillBeRawPtr<CSSPrimitiveValue> maxTrackBreadth = parseGridBreadth(arguments->valueAt(2));
|
| + if (!maxTrackBreadth)
|
| + return nullptr;
|
|
|
| - if (sizeValue || horizontalSize)
|
| - return false;
|
| - horizontalSize = createPrimitiveNumericValue(a);
|
| + RefPtrWillBeRawPtr<CSSFunctionValue> result = CSSFunctionValue::create(CSSValueMinmax);
|
| + result->append(minTrackBreadth);
|
| + result->append(maxTrackBreadth);
|
| + return result.release();
|
| + }
|
|
|
| - a = args->next();
|
| - if (!a)
|
| - return false;
|
| + return parseGridBreadth(currentValue, restriction);
|
| +}
|
|
|
| - if (validUnit(a, FLength | FPercent)) {
|
| - verticalSize = createPrimitiveNumericValue(a);
|
| - ++i;
|
| - a = args->next();
|
| - if (!a)
|
| - return false;
|
| - }
|
| - } else
|
| - break;
|
| - }
|
| +PassRefPtrWillBeRawPtr<CSSPrimitiveValue> CSSPropertyParser::parseGridBreadth(CSSParserValue* currentValue, TrackSizeRestriction restriction)
|
| +{
|
| + if (currentValue->id == CSSValueMinContent || currentValue->id == CSSValueMaxContent || currentValue->id == CSSValueAuto)
|
| + return restriction == AllowAll ? cssValuePool().createIdentifierValue(currentValue->id) : nullptr;
|
|
|
| - // You can specify size as a keyword or a length/percentage, not both.
|
| - if (sizeValue && horizontalSize)
|
| - return false;
|
| - // Circles must have 0 or 1 lengths.
|
| - if (shapeValue && shapeValue->getValueID() == CSSValueCircle && verticalSize)
|
| - return false;
|
| - // Ellipses must have 0 or 2 length/percentages.
|
| - if (shapeValue && shapeValue->getValueID() == CSSValueEllipse && horizontalSize && !verticalSize)
|
| - return false;
|
| - // If there's only one size, it must be a length.
|
| - if (!verticalSize && horizontalSize && horizontalSize->isPercentage())
|
| - return false;
|
| + if (currentValue->unit() == CSSPrimitiveValue::UnitType::Fraction) {
|
| + if (restriction == FixedSizeOnly)
|
| + return nullptr;
|
|
|
| - result->setShape(shapeValue);
|
| - result->setSizingBehavior(sizeValue);
|
| - result->setEndHorizontalSize(horizontalSize);
|
| - result->setEndVerticalSize(verticalSize);
|
| -
|
| - // Second part of grammar, the center-position clause:
|
| - // at <position>
|
| - RefPtrWillBeRawPtr<CSSValue> centerX = nullptr;
|
| - RefPtrWillBeRawPtr<CSSValue> centerY = nullptr;
|
| - if (a->m_unit == CSSParserValue::Identifier && a->id == CSSValueAt) {
|
| - a = args->next();
|
| - if (!a)
|
| - return false;
|
| + double flexValue = currentValue->fValue;
|
|
|
| - parseFillPosition(args, centerX, centerY);
|
| - if (!(centerX && centerY))
|
| - return false;
|
| + // Fractional unit is a non-negative dimension.
|
| + if (flexValue < 0)
|
| + return nullptr;
|
|
|
| - a = args->current();
|
| - if (!a)
|
| - return false;
|
| - result->setFirstX(centerX);
|
| - result->setFirstY(centerY);
|
| - // Right now, CSS radial gradients have the same start and end centers.
|
| - result->setSecondX(centerX);
|
| - result->setSecondY(centerY);
|
| + return cssValuePool().createValue(flexValue, CSSPrimitiveValue::UnitType::Fraction);
|
| }
|
|
|
| - if (shapeValue || sizeValue || horizontalSize || centerX || centerY)
|
| - expectComma = true;
|
| -
|
| - if (!parseGradientColorStops(args, result.get(), expectComma))
|
| - return false;
|
| + if (!validUnit(currentValue, FNonNeg | FLength | FPercent))
|
| + return nullptr;
|
|
|
| - gradient = result.release();
|
| - return true;
|
| + return createPrimitiveNumericValue(currentValue);
|
| }
|
|
|
| -bool CSSPropertyParser::parseGradientColorStops(CSSParserValueList* valueList, CSSGradientValue* gradient, bool expectComma)
|
| +static Vector<String> parseGridTemplateAreasColumnNames(const String& gridRowNames)
|
| {
|
| - CSSParserValue* a = valueList->current();
|
| -
|
| - // Now look for color stops.
|
| - // <color-stop-list> = [ <color-stop> , <color-hint>? ]# , <color-stop>
|
| - bool supportsColorHints = gradient->gradientType() == CSSLinearGradient
|
| - || gradient->gradientType() == CSSRadialGradient;
|
| -
|
| - // The first color stop cannot be a color hint.
|
| - bool previousStopWasColorHint = true;
|
| - while (a) {
|
| - // Look for the comma before the next stop.
|
| - if (expectComma) {
|
| - if (!isComma(a))
|
| - return false;
|
| + ASSERT(!gridRowNames.isEmpty());
|
| + Vector<String> columnNames;
|
| + // Using StringImpl to avoid checks and indirection in every call to String::operator[].
|
| + StringImpl& text = *gridRowNames.impl();
|
|
|
| - a = valueList->next();
|
| - if (!a)
|
| - return false;
|
| + StringBuilder areaName;
|
| + for (unsigned i = 0; i < text.length(); ++i) {
|
| + if (text[i] == ' ') {
|
| + if (!areaName.isEmpty()) {
|
| + columnNames.append(areaName.toString());
|
| + areaName.clear();
|
| + }
|
| + continue;
|
| }
|
| -
|
| - // <color-stop> = <color> [ <percentage> | <length> ]?
|
| - // <color-hint> = <length> | <percentage>
|
| - CSSGradientColorStop stop;
|
| - stop.m_color = parseColor(a);
|
| -
|
| - // Two hints in a row are not allowed.
|
| - if (!stop.m_color && (!supportsColorHints || previousStopWasColorHint))
|
| - return false;
|
| - previousStopWasColorHint = !stop.m_color;
|
| -
|
| - if (stop.m_color)
|
| - a = valueList->next();
|
| -
|
| - if (a) {
|
| - if (validUnit(a, FLength | FPercent)) {
|
| - stop.m_position = createPrimitiveNumericValue(a);
|
| - a = valueList->next();
|
| + if (text[i] == '.') {
|
| + if (areaName == ".")
|
| + continue;
|
| + if (!areaName.isEmpty()) {
|
| + columnNames.append(areaName.toString());
|
| + areaName.clear();
|
| + }
|
| + } else {
|
| + if (areaName == ".") {
|
| + columnNames.append(areaName.toString());
|
| + areaName.clear();
|
| }
|
| }
|
|
|
| - if (!stop.m_color && !stop.m_position)
|
| - return false;
|
| -
|
| - gradient->addStop(stop);
|
| - expectComma = true;
|
| + areaName.append(text[i]);
|
| }
|
|
|
| - // The last color stop cannot be a color hint.
|
| - if (previousStopWasColorHint)
|
| - return false;
|
| + if (!areaName.isEmpty())
|
| + columnNames.append(areaName.toString());
|
|
|
| - // Must have 2 or more stops to be valid.
|
| - return gradient->stopCount() >= 2;
|
| + return columnNames;
|
| }
|
|
|
| -bool CSSPropertyParser::parseGeneratedImage(CSSParserValueList* valueList, RefPtrWillBeRawPtr<CSSValue>& value)
|
| +bool CSSPropertyParser::parseGridTemplateAreasRow(NamedGridAreaMap& gridAreaMap, const size_t rowCount, size_t& columnCount)
|
| {
|
| - CSSParserValue* val = valueList->current();
|
| -
|
| - if (val->m_unit != CSSParserValue::Function)
|
| + CSSParserValue* currentValue = m_valueList->current();
|
| + if (!currentValue || currentValue->m_unit != CSSParserValue::String)
|
| return false;
|
|
|
| - if (val->function->id == CSSValueWebkitGradient) {
|
| - // FIXME: This should send a deprecation message.
|
| - if (m_context.useCounter())
|
| - m_context.useCounter()->count(UseCounter::DeprecatedWebKitGradient);
|
| - return parseDeprecatedGradient(valueList, value);
|
| - }
|
| + String gridRowNames = currentValue->string;
|
| + if (gridRowNames.isEmpty() || gridRowNames.containsOnlyWhitespace())
|
| + return false;
|
|
|
| - if (val->function->id == CSSValueWebkitLinearGradient) {
|
| - // FIXME: This should send a deprecation message.
|
| - if (m_context.useCounter())
|
| - m_context.useCounter()->count(UseCounter::DeprecatedWebKitLinearGradient);
|
| - return parseDeprecatedLinearGradient(valueList, value, NonRepeating);
|
| + Vector<String> columnNames = parseGridTemplateAreasColumnNames(gridRowNames);
|
| + if (!columnCount) {
|
| + columnCount = columnNames.size();
|
| + ASSERT(columnCount);
|
| + } else if (columnCount != columnNames.size()) {
|
| + // The declaration is invalid is all the rows don't have the number of columns.
|
| + return false;
|
| }
|
|
|
| - if (val->function->id == CSSValueLinearGradient)
|
| - return parseLinearGradient(valueList, value, NonRepeating);
|
| + for (size_t currentCol = 0; currentCol < columnCount; ++currentCol) {
|
| + const String& gridAreaName = columnNames[currentCol];
|
|
|
| - if (val->function->id == CSSValueWebkitRepeatingLinearGradient) {
|
| - // FIXME: This should send a deprecation message.
|
| - if (m_context.useCounter())
|
| - m_context.useCounter()->count(UseCounter::DeprecatedWebKitRepeatingLinearGradient);
|
| - return parseDeprecatedLinearGradient(valueList, value, Repeating);
|
| - }
|
| + // Unamed areas are always valid (we consider them to be 1x1).
|
| + if (gridAreaName == ".")
|
| + continue;
|
|
|
| - if (val->function->id == CSSValueRepeatingLinearGradient)
|
| - return parseLinearGradient(valueList, value, Repeating);
|
| + // We handle several grid areas with the same name at once to simplify the validation code.
|
| + size_t lookAheadCol;
|
| + for (lookAheadCol = currentCol + 1; lookAheadCol < columnCount; ++lookAheadCol) {
|
| + if (columnNames[lookAheadCol] != gridAreaName)
|
| + break;
|
| + }
|
|
|
| - if (val->function->id == CSSValueWebkitRadialGradient) {
|
| - // FIXME: This should send a deprecation message.
|
| - if (m_context.useCounter())
|
| - m_context.useCounter()->count(UseCounter::DeprecatedWebKitRadialGradient);
|
| - return parseDeprecatedRadialGradient(valueList, value, NonRepeating);
|
| - }
|
| + NamedGridAreaMap::iterator gridAreaIt = gridAreaMap.find(gridAreaName);
|
| + if (gridAreaIt == gridAreaMap.end()) {
|
| + gridAreaMap.add(gridAreaName, GridArea(GridSpan::translatedDefiniteGridSpan(rowCount, rowCount + 1), GridSpan::translatedDefiniteGridSpan(currentCol, lookAheadCol)));
|
| + } else {
|
| + GridArea& gridArea = gridAreaIt->value;
|
|
|
| - if (val->function->id == CSSValueRadialGradient)
|
| - return parseRadialGradient(valueList, value, NonRepeating);
|
| + // The following checks test that the grid area is a single filled-in rectangle.
|
| + // 1. The new row is adjacent to the previously parsed row.
|
| + if (rowCount != gridArea.rows.resolvedFinalPosition())
|
| + return false;
|
|
|
| - if (val->function->id == CSSValueWebkitRepeatingRadialGradient) {
|
| - if (m_context.useCounter())
|
| - m_context.useCounter()->count(UseCounter::DeprecatedWebKitRepeatingRadialGradient);
|
| - return parseDeprecatedRadialGradient(valueList, value, Repeating);
|
| - }
|
| + // 2. The new area starts at the same position as the previously parsed area.
|
| + if (currentCol != gridArea.columns.resolvedInitialPosition())
|
| + return false;
|
|
|
| - if (val->function->id == CSSValueRepeatingRadialGradient)
|
| - return parseRadialGradient(valueList, value, Repeating);
|
| + // 3. The new area ends at the same position as the previously parsed area.
|
| + if (lookAheadCol != gridArea.columns.resolvedFinalPosition())
|
| + return false;
|
|
|
| - if (val->function->id == CSSValueWebkitCrossFade)
|
| - return parseCrossfade(valueList, value);
|
| + gridArea.rows = GridSpan::translatedDefiniteGridSpan(gridArea.rows.resolvedInitialPosition(), gridArea.rows.resolvedFinalPosition() + 1);
|
| + }
|
| + currentCol = lookAheadCol - 1;
|
| + }
|
|
|
| - return false;
|
| + m_valueList->next();
|
| + return true;
|
| }
|
|
|
| -bool CSSPropertyParser::parseCrossfade(CSSParserValueList* valueList, RefPtrWillBeRawPtr<CSSValue>& crossfade)
|
| +PassRefPtrWillBeRawPtr<CSSValue> CSSPropertyParser::parseGridTemplateAreas()
|
| {
|
| - // Walk the arguments.
|
| - CSSParserValueList* args = valueList->current()->function->args.get();
|
| - if (!args || args->size() != 5)
|
| - return false;
|
| - RefPtrWillBeRawPtr<CSSValue> fromImageValue = nullptr;
|
| - RefPtrWillBeRawPtr<CSSValue> toImageValue = nullptr;
|
| + if (m_valueList->current() && m_valueList->current()->id == CSSValueNone) {
|
| + m_valueList->next();
|
| + return cssValuePool().createIdentifierValue(CSSValueNone);
|
| + }
|
|
|
| - // The first argument is the "from" image. It is a fill image.
|
| - if (!args->current() || !parseFillImage(args, fromImageValue))
|
| - return false;
|
| - args->next();
|
| + NamedGridAreaMap gridAreaMap;
|
| + size_t rowCount = 0;
|
| + size_t columnCount = 0;
|
|
|
| - if (!consumeComma(args))
|
| - return false;
|
| + while (m_valueList->current()) {
|
| + if (!parseGridTemplateAreasRow(gridAreaMap, rowCount, columnCount))
|
| + return nullptr;
|
| + ++rowCount;
|
| + }
|
|
|
| - // The second argument is the "to" image. It is a fill image.
|
| - if (!args->current() || !parseFillImage(args, toImageValue))
|
| - return false;
|
| - args->next();
|
| + if (!rowCount || !columnCount)
|
| + return nullptr;
|
|
|
| - if (!consumeComma(args))
|
| - return false;
|
| + return CSSGridTemplateAreasValue::create(gridAreaMap, rowCount, columnCount);
|
| +}
|
| +
|
| +PassRefPtrWillBeRawPtr<CSSValue> CSSPropertyParser::parseGridAutoFlow(CSSParserValueList& list)
|
| +{
|
| + // [ row | column ] || dense
|
| + ASSERT(RuntimeEnabledFeatures::cssGridLayoutEnabled());
|
|
|
| - // The third argument is the crossfade value. It is a percentage or a fractional number.
|
| - RefPtrWillBeRawPtr<CSSPrimitiveValue> percentage = nullptr;
|
| - CSSParserValue* value = args->current();
|
| + CSSParserValue* value = list.current();
|
| if (!value)
|
| - return false;
|
| + return nullptr;
|
|
|
| - if (value->unit() == CSSPrimitiveValue::UnitType::Percentage)
|
| - percentage = cssValuePool().createValue(clampTo<double>(value->fValue / 100, 0, 1), CSSPrimitiveValue::UnitType::Number);
|
| - else if (value->unit() == CSSPrimitiveValue::UnitType::Number)
|
| - percentage = cssValuePool().createValue(clampTo<double>(value->fValue, 0, 1), CSSPrimitiveValue::UnitType::Number);
|
| - else
|
| - return false;
|
| + RefPtrWillBeRawPtr<CSSValueList> parsedValues = CSSValueList::createSpaceSeparated();
|
|
|
| - crossfade = CSSCrossfadeValue::create(fromImageValue, toImageValue, percentage);
|
| + // First parameter.
|
| + CSSValueID firstId = value->id;
|
| + if (firstId != CSSValueRow && firstId != CSSValueColumn && firstId != CSSValueDense)
|
| + return nullptr;
|
| + parsedValues->append(cssValuePool().createIdentifierValue(firstId));
|
|
|
| - return true;
|
| + // Second parameter, if any.
|
| + value = list.next();
|
| + if (value) {
|
| + switch (firstId) {
|
| + case CSSValueRow:
|
| + case CSSValueColumn:
|
| + if (value->id != CSSValueDense)
|
| + return parsedValues;
|
| + break;
|
| + case CSSValueDense:
|
| + if (value->id != CSSValueRow && value->id != CSSValueColumn)
|
| + return parsedValues;
|
| + break;
|
| + default:
|
| + return parsedValues;
|
| + }
|
| + parsedValues->append(cssValuePool().createIdentifierValue(value->id));
|
| + list.next();
|
| + }
|
| +
|
| + return parsedValues;
|
| }
|
|
|
| -PassRefPtrWillBeRawPtr<CSSValue> CSSPropertyParser::parseImageSet(CSSParserValueList* valueList)
|
| +static bool isBaselinePositionKeyword(CSSValueID id)
|
| {
|
| - CSSParserValue* function = valueList->current();
|
| -
|
| - if (function->m_unit != CSSParserValue::Function)
|
| - return nullptr;
|
| -
|
| - CSSParserValueList* functionArgs = valueList->current()->function->args.get();
|
| - if (!functionArgs || !functionArgs->size() || !functionArgs->current())
|
| - return nullptr;
|
| + return id == CSSValueBaseline || id == CSSValueLastBaseline;
|
| +}
|
|
|
| - RefPtrWillBeRawPtr<CSSImageSetValue> imageSet = CSSImageSetValue::create();
|
| +static bool isAlignmentOverflowKeyword(CSSValueID id)
|
| +{
|
| + return id == CSSValueUnsafe || id == CSSValueSafe;
|
| +}
|
|
|
| - while (functionArgs->current()) {
|
| - CSSParserValue* arg = functionArgs->current();
|
| - if (arg->m_unit != CSSParserValue::URI)
|
| - return nullptr;
|
| +static bool isItemPositionKeyword(CSSValueID id)
|
| +{
|
| + return id == CSSValueStart || id == CSSValueEnd || id == CSSValueCenter
|
| + || id == CSSValueSelfStart || id == CSSValueSelfEnd || id == CSSValueFlexStart
|
| + || id == CSSValueFlexEnd || id == CSSValueLeft || id == CSSValueRight;
|
| +}
|
|
|
| - RefPtrWillBeRawPtr<CSSValue> image = createCSSImageValueWithReferrer(arg->string, m_context);
|
| - imageSet->append(image);
|
| +PassRefPtrWillBeRawPtr<CSSValue> CSSPropertyParser::parseLegacyPosition()
|
| +{
|
| + // [ legacy && [ left | right | center ]
|
|
|
| - arg = functionArgs->next();
|
| - if (!arg)
|
| - return nullptr;
|
| + CSSParserValue* value = m_valueList->current();
|
| + ASSERT(value);
|
|
|
| - if (arg->m_unit != CSSParserValue::DimensionList)
|
| + if (value->id == CSSValueLegacy) {
|
| + value = m_valueList->next();
|
| + if (!value)
|
| return nullptr;
|
| - ASSERT(arg->valueList->valueAt(0)->unit() == CSSPrimitiveValue::UnitType::Number);
|
| - ASSERT(arg->valueList->valueAt(1)->m_unit == CSSParserValue::Identifier);
|
| - if (String(arg->valueList->valueAt(1)->string) != "x")
|
| + if (value->id != CSSValueCenter && value->id != CSSValueLeft && value->id != CSSValueRight)
|
| return nullptr;
|
| - double imageScaleFactor = arg->valueList->valueAt(0)->fValue;
|
| - if (imageScaleFactor <= 0)
|
| + } else if (value->id == CSSValueCenter || value->id == CSSValueLeft || value->id == CSSValueRight) {
|
| + if (!m_valueList->next() || m_valueList->current()->id != CSSValueLegacy)
|
| return nullptr;
|
| - imageSet->append(cssValuePool().createValue(imageScaleFactor, CSSPrimitiveValue::UnitType::Number));
|
| - functionArgs->next();
|
| + } else {
|
| + return nullptr;
|
| + }
|
|
|
| - // If there are no more arguments, we're done.
|
| - if (!functionArgs->current())
|
| - break;
|
| + m_valueList->next();
|
| + return CSSValuePair::create(cssValuePool().createIdentifierValue(CSSValueLegacy), cssValuePool().createIdentifierValue(value->id), CSSValuePair::DropIdenticalValues);
|
| +}
|
| +
|
| +PassRefPtrWillBeRawPtr<CSSValue> CSSPropertyParser::parseItemPositionOverflowPosition()
|
| +{
|
| + // auto | stretch | <baseline-position> | [<item-position> && <overflow-position>? ]
|
| + // <baseline-position> = baseline | last-baseline;
|
| + // <item-position> = center | start | end | self-start | self-end | flex-start | flex-end | left | right;
|
| + // <overflow-position> = unsafe | safe
|
| +
|
| + CSSParserValue* value = m_valueList->current();
|
| + ASSERT(value);
|
| +
|
| + if (value->id == CSSValueAuto || value->id == CSSValueStretch || isBaselinePositionKeyword(value->id)) {
|
| + m_valueList->next();
|
| + return cssValuePool().createIdentifierValue(value->id);
|
| + }
|
|
|
| - // If there are more arguments, they should be after a comma.
|
| - if (!consumeComma(functionArgs))
|
| + RefPtrWillBeRawPtr<CSSPrimitiveValue> position = nullptr;
|
| + RefPtrWillBeRawPtr<CSSPrimitiveValue> overflowAlignmentKeyword = nullptr;
|
| + if (isItemPositionKeyword(value->id)) {
|
| + position = cssValuePool().createIdentifierValue(value->id);
|
| + value = m_valueList->next();
|
| + if (value) {
|
| + if (isAlignmentOverflowKeyword(value->id))
|
| + overflowAlignmentKeyword = cssValuePool().createIdentifierValue(value->id);
|
| + else
|
| + return nullptr;
|
| + }
|
| + } else if (isAlignmentOverflowKeyword(value->id)) {
|
| + overflowAlignmentKeyword = cssValuePool().createIdentifierValue(value->id);
|
| + value = m_valueList->next();
|
| + if (value && isItemPositionKeyword(value->id))
|
| + position = cssValuePool().createIdentifierValue(value->id);
|
| + else
|
| return nullptr;
|
| + } else {
|
| + return nullptr;
|
| }
|
|
|
| - return imageSet.release();
|
| + m_valueList->next();
|
| +
|
| + ASSERT(position);
|
| + if (overflowAlignmentKeyword)
|
| + return CSSValuePair::create(position, overflowAlignmentKeyword, CSSValuePair::DropIdenticalValues);
|
| + return position.release();
|
| }
|
|
|
| bool CSSPropertyParser::parseCalculation(CSSParserValue* value, ValueRange range)
|
|
|