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

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

Issue 1736763003: Cleanup CSSPropertyParser (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: V3 Created 4 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « third_party/WebKit/Source/core/css/parser/CSSPropertyParser.cpp ('k') | no next file » | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: third_party/WebKit/Source/core/css/parser/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)
« no previous file with comments | « third_party/WebKit/Source/core/css/parser/CSSPropertyParser.cpp ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698