Index: third_party/WebKit/Source/core/css/parser/CSSPropertyParser.cpp |
diff --git a/third_party/WebKit/Source/core/css/parser/CSSPropertyParser.cpp b/third_party/WebKit/Source/core/css/parser/CSSPropertyParser.cpp |
index 419adc0c8689172fb5591fedd15974a368a99914..365a88dee4ca2ec5c7e41bd993ab6401e2962c64 100644 |
--- a/third_party/WebKit/Source/core/css/parser/CSSPropertyParser.cpp |
+++ b/third_party/WebKit/Source/core/css/parser/CSSPropertyParser.cpp |
@@ -18,6 +18,7 @@ |
#include "core/css/CSSGradientValue.h" |
#include "core/css/CSSGridAutoRepeatValue.h" |
#include "core/css/CSSGridLineNamesValue.h" |
+#include "core/css/CSSGridTemplateAreasValue.h" |
#include "core/css/CSSImageSetValue.h" |
#include "core/css/CSSPaintValue.h" |
#include "core/css/CSSPathValue.h" |
@@ -59,6 +60,39 @@ CSSPropertyParser::CSSPropertyParser(const CSSParserTokenRange& range, |
m_range.consumeWhitespace(); |
} |
+void CSSPropertyParser::addProperty(CSSPropertyID property, CSSValue* value, bool important, bool implicit) |
+{ |
+ ASSERT(!isPropertyAlias(property)); |
+ |
+ int shorthandIndex = 0; |
+ bool setFromShorthand = false; |
+ |
+ if (m_currentShorthand) { |
+ Vector<StylePropertyShorthand, 4> shorthands; |
+ getMatchingShorthandsForLonghand(property, &shorthands); |
+ setFromShorthand = true; |
+ if (shorthands.size() > 1) |
+ shorthandIndex = indexOfShorthandForLonghand(m_currentShorthand, shorthands); |
+ } |
+ |
+ m_parsedProperties->append(CSSProperty(property, value, important, setFromShorthand, shorthandIndex, implicit)); |
+} |
+ |
+void CSSPropertyParser::addExpandedPropertyForValue(CSSPropertyID property, CSSValue* value, bool important) |
+{ |
+ const StylePropertyShorthand& shorthand = shorthandForProperty(property); |
+ unsigned shorthandLength = shorthand.length(); |
+ if (!shorthandLength) { |
+ addProperty(property, value, important); |
+ return; |
+ } |
+ |
+ ShorthandScope scope(this, property); |
+ const CSSPropertyID* longhands = shorthand.properties(); |
+ for (unsigned i = 0; i < shorthandLength; ++i) |
+ addProperty(longhands[i], value, important); |
+} |
+ |
static bool hasInvalidNumericValues(const CSSParserTokenRange& range) |
{ |
for (const CSSParserToken& token : range) { |
@@ -2923,7 +2957,7 @@ static CSSValue* consumeBackgroundSize(CSSPropertyID unresolvedProperty, CSSPars |
return CSSValuePair::create(horizontal, vertical, CSSValuePair::KeepIdenticalValues); |
} |
-CSSValueList* consumeGridAutoFlow(CSSParserTokenRange& range) |
+static CSSValueList* consumeGridAutoFlow(CSSParserTokenRange& range) |
{ |
CSSPrimitiveValue* rowOrColumnValue = consumeIdent<CSSValueRow, CSSValueColumn>(range); |
CSSPrimitiveValue* denseAlgorithm = consumeIdent<CSSValueDense>(range); |
@@ -3102,6 +3136,124 @@ static CSSValue* consumeGridLine(CSSParserTokenRange& range) |
return values; |
} |
+static bool allTracksAreFixedSized(CSSValueList& valueList) |
+{ |
+ for (CSSValue* value : valueList) { |
+ if (value->isGridLineNamesValue()) |
+ continue; |
+ // The auto-repeat value holds a <fixed-size> = <fixed-breadth> | minmax( <fixed-breadth>, <track-breadth> ) |
+ if (value->isGridAutoRepeatValue()) { |
+ if (!allTracksAreFixedSized(toCSSValueList(*value))) |
+ return false; |
+ continue; |
+ } |
+ 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 false; |
+ } |
+ return true; |
+} |
+ |
+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) { |
+ // TODO(rob.buis): this whitespace check misses \n and \t. |
+ // https://drafts.csswg.org/css-grid/#valdef-grid-template-areas-string |
+ // https://drafts.csswg.org/css-syntax-3/#whitespace |
+ 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 { |
+ // TODO(rob.buis): only allow name code points here. |
+ if (areaName == ".") { |
+ columnNames.append(areaName.toString()); |
+ areaName.clear(); |
+ } |
+ } |
+ |
+ areaName.append(text[i]); |
+ } |
+ |
+ if (!areaName.isEmpty()) |
+ columnNames.append(areaName.toString()); |
+ |
+ return columnNames; |
+} |
+ |
+static bool parseGridTemplateAreasRow(const String& gridRowNames, NamedGridAreaMap& gridAreaMap, const size_t rowCount, size_t& columnCount) |
+{ |
+ if (gridRowNames.isEmpty() || gridRowNames.containsOnlyWhitespace()) |
+ return false; |
+ |
+ Vector<String> columnNames = parseGridTemplateAreasColumnNames(gridRowNames); |
+ if (rowCount == 0) { |
+ columnCount = columnNames.size(); |
+ ASSERT(columnCount); |
+ } else if (columnCount != columnNames.size()) { |
+ // The declaration is invalid if all the rows don't have the number of columns. |
+ return false; |
+ } |
+ |
+ for (size_t currentColumn = 0; currentColumn < columnCount; ++currentColumn) { |
+ const String& gridAreaName = columnNames[currentColumn]; |
+ |
+ // Unamed areas are always valid (we consider them to be 1x1). |
+ if (gridAreaName == ".") |
+ continue; |
+ |
+ size_t lookAheadColumn = currentColumn + 1; |
+ while (lookAheadColumn < columnCount && columnNames[lookAheadColumn] == gridAreaName) |
+ lookAheadColumn++; |
+ |
+ NamedGridAreaMap::iterator gridAreaIt = gridAreaMap.find(gridAreaName); |
+ if (gridAreaIt == gridAreaMap.end()) { |
+ gridAreaMap.add(gridAreaName, GridArea(GridSpan::translatedDefiniteGridSpan(rowCount, rowCount + 1), GridSpan::translatedDefiniteGridSpan(currentColumn, lookAheadColumn))); |
+ } 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.endLine()) |
+ return false; |
+ |
+ // 2. The new area starts at the same position as the previously parsed area. |
+ if (currentColumn != gridArea.columns.startLine()) |
+ return false; |
+ |
+ // 3. The new area ends at the same position as the previously parsed area. |
+ if (lookAheadColumn != gridArea.columns.endLine()) |
+ return false; |
+ |
+ gridArea.rows = GridSpan::translatedDefiniteGridSpan(gridArea.rows.startLine(), gridArea.rows.endLine() + 1); |
+ } |
+ currentColumn = lookAheadColumn - 1; |
+ } |
+ |
+ return true; |
+} |
+ |
+enum TrackSizeRestriction { FixedSizeOnly, AllowAll }; |
+ |
static CSSPrimitiveValue* consumeGridBreadth(CSSParserTokenRange& range, CSSParserMode cssParserMode, TrackSizeRestriction restriction = AllowAll) |
{ |
if (restriction == AllowAll) { |
@@ -3118,7 +3270,7 @@ static CSSPrimitiveValue* consumeGridBreadth(CSSParserTokenRange& range, CSSPars |
} |
// TODO(rob.buis): This needs a bool parameter so we can disallow <auto-track-list> for the grid shorthand. |
-CSSValue* consumeGridTrackSize(CSSParserTokenRange& range, CSSParserMode cssParserMode, TrackSizeRestriction restriction) |
+static CSSValue* consumeGridTrackSize(CSSParserTokenRange& range, CSSParserMode cssParserMode, TrackSizeRestriction restriction = AllowAll) |
{ |
const CSSParserToken& token = range.peek(); |
if (restriction == AllowAll && identMatches<CSSValueAuto>(token.id())) |
@@ -4563,6 +4715,70 @@ bool CSSPropertyParser::consumeGridTemplateShorthand(bool important) |
return consumeGridTemplateRowsAndAreasAndColumns(important); |
} |
+bool CSSPropertyParser::consumeGridShorthand(bool important) |
+{ |
+ ASSERT(RuntimeEnabledFeatures::cssGridLayoutEnabled()); |
+ ASSERT(shorthandForProperty(CSSPropertyGrid).length() == 8); |
+ |
+ CSSParserTokenRange rangeCopy = m_range; |
+ |
+ // 1- <grid-template> |
+ if (consumeGridTemplateShorthand(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; |
+ } |
+ |
+ m_range = rangeCopy; |
+ |
+ // 2- <grid-auto-flow> [ <grid-auto-rows> [ / <grid-auto-columns> ]? ] |
+ CSSValueList* gridAutoFlow = consumeGridAutoFlow(m_range); |
+ if (!gridAutoFlow) |
+ return false; |
+ |
+ CSSValue* autoColumnsValue = nullptr; |
+ CSSValue* autoRowsValue = nullptr; |
+ |
+ if (!m_range.atEnd()) { |
+ autoRowsValue = consumeGridTrackSize(m_range, m_context.mode()); |
+ if (!autoRowsValue) |
+ return false; |
+ if (consumeSlashIncludingWhitespace(m_range)) { |
+ autoColumnsValue = consumeGridTrackSize(m_range, m_context.mode()); |
+ if (!autoColumnsValue) |
+ return false; |
+ } |
+ if (!m_range.atEnd()) |
+ 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; |
+ |
+ // 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(CSSPropertyGridAutoFlow, gridAutoFlow, important); |
+ addProperty(CSSPropertyGridAutoColumns, autoColumnsValue, important); |
+ addProperty(CSSPropertyGridAutoRows, autoRowsValue, important); |
+ addProperty(CSSPropertyGridColumnGap, cssValuePool().createImplicitInitialValue(), important); |
+ addProperty(CSSPropertyGridRowGap, cssValuePool().createImplicitInitialValue(), important); |
+ |
+ return true; |
+} |
+ |
bool CSSPropertyParser::parseShorthand(CSSPropertyID unresolvedProperty, bool important) |
{ |
CSSPropertyID property = resolveCSSPropertyID(unresolvedProperty); |
@@ -4747,13 +4963,11 @@ bool CSSPropertyParser::parseShorthand(CSSPropertyID unresolvedProperty, bool im |
return consumeGridAreaShorthand(important); |
case CSSPropertyGridTemplate: |
return consumeGridTemplateShorthand(important); |
+ case CSSPropertyGrid: |
+ return consumeGridShorthand(important); |
default: |
m_currentShorthand = oldShorthand; |
- CSSParserValueList valueList(m_range); |
- if (!valueList.size()) |
- return false; |
- m_valueList = &valueList; |
- return legacyParseShorthand(unresolvedProperty, important); |
+ return false; |
} |
} |