Chromium Code Reviews| 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..fe227f6f1278f652b8914c306ca0c75e88a9ed2c 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 propId, CSSValue* value, bool important, bool implicit) |
|
Timothy Loh
2016/04/13 06:09:41
since you're moving this, can you rename propId to
rwlbuis
2016/04/13 22:16:29
Done.
|
| +{ |
| + ASSERT(!isPropertyAlias(propId)); |
| + |
| + int shorthandIndex = 0; |
| + bool setFromShorthand = false; |
| + |
| + if (m_currentShorthand) { |
| + Vector<StylePropertyShorthand, 4> shorthands; |
| + getMatchingShorthandsForLonghand(propId, &shorthands); |
| + setFromShorthand = true; |
| + if (shorthands.size() > 1) |
| + shorthandIndex = indexOfShorthandForLonghand(m_currentShorthand, shorthands); |
| + } |
| + |
| + m_parsedProperties->append(CSSProperty(propId, value, important, setFromShorthand, shorthandIndex, implicit)); |
| +} |
| + |
| +void CSSPropertyParser::addExpandedPropertyForValue(CSSPropertyID propId, CSSValue* value, bool important) |
|
Timothy Loh
2016/04/13 06:09:42
propId -> property
rwlbuis
2016/04/13 22:16:29
Done.
|
| +{ |
| + const StylePropertyShorthand& shorthand = shorthandForProperty(propId); |
| + unsigned shorthandLength = shorthand.length(); |
| + if (!shorthandLength) { |
| + addProperty(propId, value, important); |
| + return; |
| + } |
| + |
| + ShorthandScope scope(this, propId); |
| + 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 (auto value : valueList) { |
|
Timothy Loh
2016/04/13 06:09:42
does it work to write
for (CSSValue* value : valu
rwlbuis
2016/04/13 22:16:29
Done.
|
| + 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; |
| + } |
| + ASSERT(value->isPrimitiveValue() || (value->isFunctionValue() && toCSSFunctionValue(*value).item(0))); |
|
Timothy Loh
2016/04/13 06:09:42
I guess this assertion is unnecessary since the co
rwlbuis
2016/04/13 22:16:29
It is not 100% covered just by that code. In theor
Timothy Loh
2016/04/14 02:04:12
Not sure I follow. Ternary below says:
non-null p
|
| + 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) { |
| + if (text[i] == ' ') { |
|
Timothy Loh
2016/04/13 06:09:42
Needs a TODO that this whitespace check is missing
rwlbuis
2016/04/13 22:16:29
Done.
|
| + 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 { |
|
Timothy Loh
2016/04/13 06:09:42
Needs a TODO to handle trash tokens (should only a
rwlbuis
2016/04/13 22:16:28
Done.
|
| + 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()) |
|
Timothy Loh
2016/04/13 06:09:42
I feel like I had this discussion before... but is
rwlbuis
2016/04/13 22:16:29
Acknowledged.
|
| + return false; |
| + |
| + Vector<String> columnNames = parseGridTemplateAreasColumnNames(gridRowNames); |
| + if (!columnCount) { |
|
Timothy Loh
2016/04/13 06:09:42
IMO more obvious if you write if (rowCount == 0)
rwlbuis
2016/04/13 22:16:29
You meant columnCount == 0, right? Done.
Timothy Loh
2016/04/14 02:04:12
Nope, I meant rowCount. I think it makes more sens
|
| + 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. |
|
Timothy Loh
2016/04/13 06:09:41
invalid is -> invalid if
rwlbuis
2016/04/13 22:16:29
Done.
|
| + return false; |
| + } |
| + |
| + for (size_t currentCol = 0; currentCol < columnCount; ++currentCol) { |
|
Timothy Loh
2016/04/13 06:09:41
currentColumn
rwlbuis
2016/04/13 22:16:29
Done.
|
| + 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. |
|
Timothy Loh
2016/04/13 06:09:42
I'm not really sure what this comment is trying to
rwlbuis
2016/04/13 22:16:29
Done.
|
| + size_t lookAheadCol; |
|
Timothy Loh
2016/04/13 06:09:42
imo more readable as
size_t lookAheadColumn = cur
rwlbuis
2016/04/13 22:16:29
Done.
|
| + 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.endLine()) |
| + return false; |
| + |
| + // 2. The new area starts at the same position as the previously parsed area. |
| + if (currentCol != gridArea.columns.startLine()) |
| + return false; |
| + |
| + // 3. The new area ends at the same position as the previously parsed area. |
| + if (lookAheadCol != gridArea.columns.endLine()) |
| + return false; |
| + |
| + gridArea.rows = GridSpan::translatedDefiniteGridSpan(gridArea.rows.startLine(), gridArea.rows.endLine() + 1); |
| + } |
| + currentCol = lookAheadCol - 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,71 @@ 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; |
| + |
| + addProperty(CSSPropertyGridAutoFlow, gridAutoFlow, important); |
| + 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); |
|
Timothy Loh
2016/04/13 06:09:42
I think it makes sense for the longhands to always
rwlbuis
2016/04/13 22:16:29
Done.
|
| + addProperty(CSSPropertyGridTemplateRows, cssValuePool().createImplicitInitialValue(), important); |
| + addProperty(CSSPropertyGridTemplateAreas, cssValuePool().createImplicitInitialValue(), 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 +4964,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; |
| } |
| } |