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