OLD | NEW |
---|---|
1 // Copyright 2015 The Chromium Authors. All rights reserved. | 1 // Copyright 2015 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "core/css/parser/CSSPropertyParser.h" | 5 #include "core/css/parser/CSSPropertyParser.h" |
6 | 6 |
7 #include "core/StylePropertyShorthand.h" | 7 #include "core/StylePropertyShorthand.h" |
8 #include "core/css/CSSBasicShapeValues.h" | 8 #include "core/css/CSSBasicShapeValues.h" |
9 #include "core/css/CSSBorderImage.h" | 9 #include "core/css/CSSBorderImage.h" |
10 #include "core/css/CSSContentDistributionValue.h" | 10 #include "core/css/CSSContentDistributionValue.h" |
(...skipping 3091 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
3102 return nullptr; | 3102 return nullptr; |
3103 range = rangeCopy; | 3103 range = rangeCopy; |
3104 RawPtr<CSSFunctionValue> result = CSSFunctionValue::create(CSSValueMinma x); | 3104 RawPtr<CSSFunctionValue> result = CSSFunctionValue::create(CSSValueMinma x); |
3105 result->append(minTrackBreadth.release()); | 3105 result->append(minTrackBreadth.release()); |
3106 result->append(maxTrackBreadth.release()); | 3106 result->append(maxTrackBreadth.release()); |
3107 return result.release(); | 3107 return result.release(); |
3108 } | 3108 } |
3109 return consumeGridBreadth(range, cssParserMode, restriction); | 3109 return consumeGridBreadth(range, cssParserMode, restriction); |
3110 } | 3110 } |
3111 | 3111 |
3112 static RawPtr<CSSGridLineNamesValue> consumeGridLineNames(CSSParserTokenRange& r ange) | 3112 // Appends to the passed in CSSGridLineNamesValue if any, otherwise creates a ne w one. |
3113 static CSSGridLineNamesValue* consumeGridLineNames(CSSParserTokenRange& range, C SSGridLineNamesValue* lineNames = nullptr) | |
3113 { | 3114 { |
3114 CSSParserTokenRange rangeCopy = range; | 3115 CSSParserTokenRange rangeCopy = range; |
3115 if (rangeCopy.consumeIncludingWhitespace().type() != LeftBracketToken) | 3116 if (rangeCopy.consumeIncludingWhitespace().type() != LeftBracketToken) |
3116 return nullptr; | 3117 return nullptr; |
3117 RawPtr<CSSGridLineNamesValue> lineNames = CSSGridLineNamesValue::create(); | 3118 if (!lineNames) |
3119 lineNames = CSSGridLineNamesValue::create(); | |
3118 while (RawPtr<CSSCustomIdentValue> lineName = consumeCustomIdentForGridLine( rangeCopy)) | 3120 while (RawPtr<CSSCustomIdentValue> lineName = consumeCustomIdentForGridLine( rangeCopy)) |
3119 lineNames->append(lineName.release()); | 3121 lineNames->append(lineName.release()); |
3120 if (rangeCopy.consumeIncludingWhitespace().type() != RightBracketToken) | 3122 if (rangeCopy.consumeIncludingWhitespace().type() != RightBracketToken) |
3121 return nullptr; | 3123 return nullptr; |
3122 range = rangeCopy; | 3124 range = rangeCopy; |
3123 return lineNames.release(); | 3125 return lineNames; |
3124 } | 3126 } |
3125 | 3127 |
3126 static bool consumeGridTrackRepeatFunction(CSSParserTokenRange& range, CSSParser Mode cssParserMode, CSSValueList& list, bool& isAutoRepeat) | 3128 static bool consumeGridTrackRepeatFunction(CSSParserTokenRange& range, CSSParser Mode cssParserMode, CSSValueList& list, bool& isAutoRepeat) |
3127 { | 3129 { |
3128 CSSParserTokenRange args = consumeFunction(range); | 3130 CSSParserTokenRange args = consumeFunction(range); |
3129 // The number of repetitions for <auto-repeat> is not important at parsing l evel | 3131 // The number of repetitions for <auto-repeat> is not important at parsing l evel |
3130 // because it will be computed later, let's set it to 1. | 3132 // because it will be computed later, let's set it to 1. |
3131 size_t repetitions = 1; | 3133 size_t repetitions = 1; |
3132 isAutoRepeat = identMatches<CSSValueAutoFill, CSSValueAutoFit>(args.peek().i d()); | 3134 isAutoRepeat = identMatches<CSSValueAutoFill, CSSValueAutoFit>(args.peek().i d()); |
3133 RawPtr<CSSValueList> repeatedValues; | 3135 RawPtr<CSSValueList> repeatedValues; |
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
3171 // We clamp the repetitions to a multiple of the repeat() track list's s ize, while staying below the max grid size. | 3173 // We clamp the repetitions to a multiple of the repeat() track list's s ize, while staying below the max grid size. |
3172 repetitions = std::min(repetitions, kGridMaxTracks / numberOfTracks); | 3174 repetitions = std::min(repetitions, kGridMaxTracks / numberOfTracks); |
3173 for (size_t i = 0; i < repetitions; ++i) { | 3175 for (size_t i = 0; i < repetitions; ++i) { |
3174 for (size_t j = 0; j < repeatedValues->length(); ++j) | 3176 for (size_t j = 0; j < repeatedValues->length(); ++j) |
3175 list.append(repeatedValues->item(j)); | 3177 list.append(repeatedValues->item(j)); |
3176 } | 3178 } |
3177 } | 3179 } |
3178 return true; | 3180 return true; |
3179 } | 3181 } |
3180 | 3182 |
3183 static bool allTracksAreFixedSized(CSSValueList& valueList) | |
3184 { | |
3185 for (auto value : valueList) { | |
3186 if (value->isGridLineNamesValue()) | |
3187 continue; | |
3188 // The auto-repeat value holds a <fixed-size> = <fixed-breadth> | minmax ( <fixed-breadth>, <track-breadth> ) | |
3189 if (value->isGridAutoRepeatValue()) { | |
3190 if (!allTracksAreFixedSized(toCSSValueList(*value))) | |
3191 return false; | |
3192 continue; | |
3193 } | |
3194 ASSERT(value->isPrimitiveValue() || (value->isFunctionValue() && toCSSFu nctionValue(*value).item(0))); | |
3195 const CSSPrimitiveValue& primitiveValue = value->isPrimitiveValue() | |
3196 ? toCSSPrimitiveValue(*value) | |
3197 : toCSSPrimitiveValue(*toCSSFunctionValue(*value).item(0)); | |
3198 CSSValueID valueID = primitiveValue.getValueID(); | |
3199 if (valueID == CSSValueMinContent || valueID == CSSValueMaxContent || va lueID == CSSValueAuto || primitiveValue.isFlex()) | |
3200 return false; | |
3201 } | |
3202 return true; | |
3203 } | |
3204 | |
3181 static RawPtr<CSSValue> consumeGridTrackList(CSSParserTokenRange& range, CSSPars erMode cssParserMode) | 3205 static RawPtr<CSSValue> consumeGridTrackList(CSSParserTokenRange& range, CSSPars erMode cssParserMode) |
3182 { | 3206 { |
3183 RawPtr<CSSValueList> values = CSSValueList::createSpaceSeparated(); | 3207 RawPtr<CSSValueList> values = CSSValueList::createSpaceSeparated(); |
3184 RawPtr<CSSGridLineNamesValue> lineNames = consumeGridLineNames(range); | 3208 RawPtr<CSSGridLineNamesValue> lineNames = consumeGridLineNames(range); |
3185 if (lineNames) | 3209 if (lineNames) |
3186 values->append(lineNames.release()); | 3210 values->append(lineNames.release()); |
3187 | 3211 |
3188 bool seenAutoRepeat = false; | 3212 bool seenAutoRepeat = false; |
3189 // TODO(rob.buis): <line-names> should not be able to directly precede <auto -repeat>. | 3213 // TODO(rob.buis): <line-names> should not be able to directly precede <auto -repeat>. |
3190 do { | 3214 do { |
(...skipping 20 matching lines...) Expand all Loading... | |
3211 return values.release(); | 3235 return values.release(); |
3212 } | 3236 } |
3213 | 3237 |
3214 static RawPtr<CSSValue> consumeGridTemplatesRowsOrColumns(CSSParserTokenRange& r ange, CSSParserMode cssParserMode) | 3238 static RawPtr<CSSValue> consumeGridTemplatesRowsOrColumns(CSSParserTokenRange& r ange, CSSParserMode cssParserMode) |
3215 { | 3239 { |
3216 if (range.peek().id() == CSSValueNone) | 3240 if (range.peek().id() == CSSValueNone) |
3217 return consumeIdent(range); | 3241 return consumeIdent(range); |
3218 return consumeGridTrackList(range, cssParserMode); | 3242 return consumeGridTrackList(range, cssParserMode); |
3219 } | 3243 } |
3220 | 3244 |
3245 static Vector<String> consumeGridTemplateAreasColumnNames(const String& gridRowN ames) | |
3246 { | |
3247 ASSERT(!gridRowNames.isEmpty()); | |
3248 Vector<String> columnNames; | |
3249 // Using StringImpl to avoid checks and indirection in every call to String: :operator[]. | |
3250 StringImpl& text = *gridRowNames.impl(); | |
3251 | |
3252 StringBuilder areaName; | |
3253 for (unsigned i = 0; i < text.length(); ++i) { | |
3254 if (text[i] == ' ') { | |
3255 if (!areaName.isEmpty()) { | |
3256 columnNames.append(areaName.toString()); | |
3257 areaName.clear(); | |
3258 } | |
3259 continue; | |
3260 } | |
3261 if (text[i] == '.') { | |
3262 if (areaName == ".") | |
3263 continue; | |
3264 if (!areaName.isEmpty()) { | |
3265 columnNames.append(areaName.toString()); | |
3266 areaName.clear(); | |
3267 } | |
3268 } else { | |
3269 if (areaName == ".") { | |
3270 columnNames.append(areaName.toString()); | |
3271 areaName.clear(); | |
3272 } | |
3273 } | |
3274 | |
3275 areaName.append(text[i]); | |
3276 } | |
3277 | |
3278 if (!areaName.isEmpty()) | |
3279 columnNames.append(areaName.toString()); | |
3280 | |
3281 return columnNames; | |
3282 } | |
3283 | |
3284 static bool consumeGridTemplateAreasRow(const String& gridRowNames, NamedGridAre aMap& gridAreaMap, const size_t rowCount, size_t& columnCount) | |
3285 { | |
3286 if (gridRowNames.isEmpty() || gridRowNames.containsOnlyWhitespace()) | |
3287 return false; | |
3288 | |
3289 Vector<String> columnNames = consumeGridTemplateAreasColumnNames(gridRowName s); | |
3290 if (!columnCount) { | |
3291 columnCount = columnNames.size(); | |
3292 ASSERT(columnCount); | |
3293 } else if (columnCount != columnNames.size()) { | |
3294 // The declaration is invalid is all the rows don't have the number of c olumns. | |
3295 return false; | |
3296 } | |
3297 | |
3298 for (size_t currentCol = 0; currentCol < columnCount; ++currentCol) { | |
3299 const String& gridAreaName = columnNames[currentCol]; | |
3300 | |
3301 // Unamed areas are always valid (we consider them to be 1x1). | |
3302 if (gridAreaName == ".") | |
3303 continue; | |
3304 | |
3305 // We handle several grid areas with the same name at once to simplify t he validation code. | |
3306 size_t lookAheadCol; | |
3307 for (lookAheadCol = currentCol + 1; lookAheadCol < columnCount; ++lookAh eadCol) { | |
3308 if (columnNames[lookAheadCol] != gridAreaName) | |
3309 break; | |
3310 } | |
3311 | |
3312 NamedGridAreaMap::iterator gridAreaIt = gridAreaMap.find(gridAreaName); | |
3313 if (gridAreaIt == gridAreaMap.end()) { | |
3314 gridAreaMap.add(gridAreaName, GridArea(GridSpan::translatedDefiniteG ridSpan(rowCount, rowCount + 1), GridSpan::translatedDefiniteGridSpan(currentCol , lookAheadCol))); | |
3315 } else { | |
3316 GridArea& gridArea = gridAreaIt->value; | |
3317 | |
3318 // The following checks test that the grid area is a single filled-i n rectangle. | |
3319 // 1. The new row is adjacent to the previously parsed row. | |
3320 if (rowCount != gridArea.rows.endLine()) | |
3321 return false; | |
3322 | |
3323 // 2. The new area starts at the same position as the previously par sed area. | |
3324 if (currentCol != gridArea.columns.startLine()) | |
3325 return false; | |
3326 | |
3327 // 3. The new area ends at the same position as the previously parse d area. | |
3328 if (lookAheadCol != gridArea.columns.endLine()) | |
3329 return false; | |
3330 | |
3331 gridArea.rows = GridSpan::translatedDefiniteGridSpan(gridArea.rows.s tartLine(), gridArea.rows.endLine() + 1); | |
3332 } | |
3333 currentCol = lookAheadCol - 1; | |
3334 } | |
3335 | |
3336 return true; | |
3337 } | |
3338 | |
3221 static RawPtr<CSSValue> consumeGridTemplateAreas(CSSParserTokenRange& range) | 3339 static RawPtr<CSSValue> consumeGridTemplateAreas(CSSParserTokenRange& range) |
3222 { | 3340 { |
3223 if (range.peek().id() == CSSValueNone) | 3341 if (range.peek().id() == CSSValueNone) |
3224 return consumeIdent(range); | 3342 return consumeIdent(range); |
3225 | 3343 |
3226 NamedGridAreaMap gridAreaMap; | 3344 NamedGridAreaMap gridAreaMap; |
3227 size_t rowCount = 0; | 3345 size_t rowCount = 0; |
3228 size_t columnCount = 0; | 3346 size_t columnCount = 0; |
3229 | 3347 |
3230 while (range.peek().type() == StringToken) { | 3348 while (range.peek().type() == StringToken) { |
3231 if (!parseGridTemplateAreasRow(range.consumeIncludingWhitespace().value( ), gridAreaMap, rowCount, columnCount)) | 3349 if (!consumeGridTemplateAreasRow(range.consumeIncludingWhitespace().valu e(), gridAreaMap, rowCount, columnCount)) |
3232 return nullptr; | 3350 return nullptr; |
3233 ++rowCount; | 3351 ++rowCount; |
3234 } | 3352 } |
3235 | 3353 |
3236 if (rowCount == 0) | 3354 if (rowCount == 0) |
3237 return nullptr; | 3355 return nullptr; |
3238 ASSERT(columnCount); | 3356 ASSERT(columnCount); |
3239 return CSSGridTemplateAreasValue::create(gridAreaMap, rowCount, columnCount) ; | 3357 return CSSGridTemplateAreasValue::create(gridAreaMap, rowCount, columnCount) ; |
3240 } | 3358 } |
3241 | 3359 |
(...skipping 1189 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
4431 if (!columnEndValue) | 4549 if (!columnEndValue) |
4432 columnEndValue = columnStartValue->isCustomIdentValue() ? columnStartVal ue : cssValuePool().createIdentifierValue(CSSValueAuto); | 4550 columnEndValue = columnStartValue->isCustomIdentValue() ? columnStartVal ue : cssValuePool().createIdentifierValue(CSSValueAuto); |
4433 | 4551 |
4434 addProperty(CSSPropertyGridRowStart, rowStartValue, important); | 4552 addProperty(CSSPropertyGridRowStart, rowStartValue, important); |
4435 addProperty(CSSPropertyGridColumnStart, columnStartValue, important); | 4553 addProperty(CSSPropertyGridColumnStart, columnStartValue, important); |
4436 addProperty(CSSPropertyGridRowEnd, rowEndValue, important); | 4554 addProperty(CSSPropertyGridRowEnd, rowEndValue, important); |
4437 addProperty(CSSPropertyGridColumnEnd, columnEndValue, important); | 4555 addProperty(CSSPropertyGridColumnEnd, columnEndValue, important); |
4438 return true; | 4556 return true; |
4439 } | 4557 } |
4440 | 4558 |
4559 bool CSSPropertyParser::consumeGridTemplateRowsAndAreasAndColumns(bool important ) | |
4560 { | |
4561 NamedGridAreaMap gridAreaMap; | |
4562 size_t rowCount = 0; | |
4563 size_t columnCount = 0; | |
4564 RawPtr<CSSValueList> templateRows = CSSValueList::createSpaceSeparated(); | |
4565 | |
4566 // Persists between loop iterations so we can use the same value for | |
4567 // consecutive <line-names> values | |
4568 CSSGridLineNamesValue* lineNames = nullptr; | |
4569 | |
4570 do { | |
4571 // Handle leading <custom-ident>*. | |
4572 bool hasPreviousLineNames = lineNames; | |
4573 lineNames = consumeGridLineNames(m_range, lineNames); | |
4574 if (lineNames && !hasPreviousLineNames) | |
4575 templateRows->append(lineNames); | |
4576 | |
4577 // Handle a template-area's row. | |
4578 if (m_range.peek().type() != StringToken || !consumeGridTemplateAreasRow (m_range.consumeIncludingWhitespace().value(), gridAreaMap, rowCount, columnCoun t)) | |
4579 return false; | |
4580 ++rowCount; | |
4581 | |
4582 // Handle template-rows's track-size. | |
4583 RawPtr<CSSValue> value = consumeGridTrackSize(m_range, m_context.mode()) ; | |
4584 if (!value) | |
4585 value = cssValuePool().createIdentifierValue(CSSValueAuto); | |
4586 templateRows->append(value.release()); | |
4587 | |
4588 // This will handle the trailing/leading <custom-ident>* in the grammar. | |
4589 lineNames = consumeGridLineNames(m_range); | |
4590 if (lineNames) | |
4591 templateRows->append(lineNames); | |
4592 } while (!m_range.atEnd() && !(m_range.peek().type() == DelimiterToken && m_ range.peek().delimiter() == '/')); | |
4593 | |
4594 RawPtr<CSSValue> columnsValue = nullptr; | |
4595 if (!m_range.atEnd()) { | |
4596 if (!consumeSlashIncludingWhitespace(m_range)) | |
4597 return false; | |
4598 columnsValue = consumeGridTrackList(m_range, m_context.mode()); | |
4599 if (!columnsValue || !m_range.atEnd()) | |
4600 return false; | |
4601 } else { | |
4602 columnsValue = cssValuePool().createIdentifierValue(CSSValueNone); | |
4603 } | |
4604 addProperty(CSSPropertyGridTemplateRows, templateRows.release(), important); | |
4605 addProperty(CSSPropertyGridTemplateColumns, columnsValue.release(), importan t); | |
4606 addProperty(CSSPropertyGridTemplateAreas, CSSGridTemplateAreasValue::create( gridAreaMap, rowCount, columnCount), important); | |
4607 return true; | |
4608 } | |
4609 | |
4610 bool CSSPropertyParser::consumeGridTemplateShorthand(bool important) | |
4611 { | |
4612 ASSERT(RuntimeEnabledFeatures::cssGridLayoutEnabled()); | |
4613 ASSERT(gridTemplateShorthand().length() == 3); | |
4614 | |
4615 CSSParserTokenRange rangeCopy = m_range; | |
4616 RawPtr<CSSValue> rowsValue = consumeIdent<CSSValueNone>(m_range); | |
4617 | |
4618 // 1- 'none' case. | |
4619 if (rowsValue && m_range.atEnd()) { | |
4620 addProperty(CSSPropertyGridTemplateRows, cssValuePool().createIdentifier Value(CSSValueNone), important); | |
4621 addProperty(CSSPropertyGridTemplateColumns, cssValuePool().createIdentif ierValue(CSSValueNone), important); | |
4622 addProperty(CSSPropertyGridTemplateAreas, cssValuePool().createIdentifie rValue(CSSValueNone), important); | |
4623 return true; | |
4624 } | |
4625 | |
4626 // 2- <grid-template-rows> / <grid-template-columns> | |
4627 if (!rowsValue) | |
4628 rowsValue = consumeGridTrackList(m_range, m_context.mode()); | |
4629 | |
4630 if (rowsValue) { | |
4631 if (!consumeSlashIncludingWhitespace(m_range)) | |
4632 return false; | |
4633 RawPtr<CSSValue> columnsValue = consumeGridTemplatesRowsOrColumns(m_rang e, m_context.mode()); | |
4634 if (!columnsValue || !m_range.atEnd()) | |
4635 return false; | |
4636 | |
4637 addProperty(CSSPropertyGridTemplateRows, rowsValue.release(), important) ; | |
4638 addProperty(CSSPropertyGridTemplateColumns, columnsValue.release(), impo rtant); | |
4639 addProperty(CSSPropertyGridTemplateAreas, cssValuePool().createIdentifie rValue(CSSValueNone), important); | |
4640 return true; | |
4641 } | |
4642 | |
4643 // 3- [<line-names>? <string> <track-size>? <line-names>? ]+ syntax. | |
Timothy Loh
2016/04/07 06:48:22
might as well just write it out completely
[ <lin
rwlbuis
2016/04/07 19:51:22
Done.
| |
4644 m_range = rangeCopy; | |
4645 return consumeGridTemplateRowsAndAreasAndColumns(important); | |
4646 } | |
4647 | |
4441 bool CSSPropertyParser::parseShorthand(CSSPropertyID unresolvedProperty, bool im portant) | 4648 bool CSSPropertyParser::parseShorthand(CSSPropertyID unresolvedProperty, bool im portant) |
4442 { | 4649 { |
4443 CSSPropertyID property = resolveCSSPropertyID(unresolvedProperty); | 4650 CSSPropertyID property = resolveCSSPropertyID(unresolvedProperty); |
4444 | 4651 |
4445 CSSPropertyID oldShorthand = m_currentShorthand; | 4652 CSSPropertyID oldShorthand = m_currentShorthand; |
4446 // TODO(rob.buis): Remove this when the legacy property parser is gone | 4653 // TODO(rob.buis): Remove this when the legacy property parser is gone |
4447 m_currentShorthand = property; | 4654 m_currentShorthand = property; |
4448 switch (property) { | 4655 switch (property) { |
4449 case CSSPropertyWebkitMarginCollapse: { | 4656 case CSSPropertyWebkitMarginCollapse: { |
4450 CSSValueID id = m_range.consumeIncludingWhitespace().id(); | 4657 CSSValueID id = m_range.consumeIncludingWhitespace().id(); |
(...skipping 162 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
4613 columnGap = rowGap; | 4820 columnGap = rowGap; |
4614 addProperty(CSSPropertyGridRowGap, rowGap.release(), important); | 4821 addProperty(CSSPropertyGridRowGap, rowGap.release(), important); |
4615 addProperty(CSSPropertyGridColumnGap, columnGap.release(), important); | 4822 addProperty(CSSPropertyGridColumnGap, columnGap.release(), important); |
4616 return true; | 4823 return true; |
4617 } | 4824 } |
4618 case CSSPropertyGridColumn: | 4825 case CSSPropertyGridColumn: |
4619 case CSSPropertyGridRow: | 4826 case CSSPropertyGridRow: |
4620 return consumeGridItemPositionShorthand(property, important); | 4827 return consumeGridItemPositionShorthand(property, important); |
4621 case CSSPropertyGridArea: | 4828 case CSSPropertyGridArea: |
4622 return consumeGridAreaShorthand(important); | 4829 return consumeGridAreaShorthand(important); |
4830 case CSSPropertyGridTemplate: | |
4831 return consumeGridTemplateShorthand(important); | |
4623 default: | 4832 default: |
4624 m_currentShorthand = oldShorthand; | 4833 m_currentShorthand = oldShorthand; |
4625 CSSParserValueList valueList(m_range); | 4834 CSSParserValueList valueList(m_range); |
4626 if (!valueList.size()) | 4835 if (!valueList.size()) |
4627 return false; | 4836 return false; |
4628 m_valueList = &valueList; | 4837 m_valueList = &valueList; |
4629 return legacyParseShorthand(unresolvedProperty, important); | 4838 return legacyParseShorthand(unresolvedProperty, important); |
4630 } | 4839 } |
4631 } | 4840 } |
4632 | 4841 |
4633 } // namespace blink | 4842 } // namespace blink |
OLD | NEW |