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

Side by Side Diff: Source/core/css/parser/BisonCSSParser-in.cpp

Issue 149373004: [CSS Grid Layout] Implementation of the grid-template shorthand. (Closed) Base URL: https://chromium.googlesource.com/chromium/blink.git@grid-template-working
Patch Set: Adding checks and layout tests to verify misplaced 'none' arguments. Created 6 years, 10 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 unified diff | Download patch
OLDNEW
1 /* 1 /*
2 * Copyright (C) 2003 Lars Knoll (knoll@kde.org) 2 * Copyright (C) 2003 Lars Knoll (knoll@kde.org)
3 * Copyright (C) 2005 Allan Sandfeld Jensen (kde@carewolf.com) 3 * Copyright (C) 2005 Allan Sandfeld Jensen (kde@carewolf.com)
4 * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012 Apple Inc. All rights reserved. 4 * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012 Apple Inc. All rights reserved.
5 * Copyright (C) 2007 Nicholas Shanks <webkit@nickshanks.com> 5 * Copyright (C) 2007 Nicholas Shanks <webkit@nickshanks.com>
6 * Copyright (C) 2008 Eric Seidel <eric@webkit.org> 6 * Copyright (C) 2008 Eric Seidel <eric@webkit.org>
7 * Copyright (C) 2009 Torch Mobile Inc. All rights reserved. (http://www.torchmo bile.com/) 7 * Copyright (C) 2009 Torch Mobile Inc. All rights reserved. (http://www.torchmo bile.com/)
8 * Copyright (C) 2012 Adobe Systems Incorporated. All rights reserved. 8 * Copyright (C) 2012 Adobe Systems Incorporated. All rights reserved.
9 * Copyright (C) 2012 Intel Corporation. All rights reserved. 9 * Copyright (C) 2012 Intel Corporation. All rights reserved.
10 * 10 *
(...skipping 2394 matching lines...) Expand 10 before | Expand all | Expand 10 after
2405 if (!RuntimeEnabledFeatures::cssGridLayoutEnabled()) 2405 if (!RuntimeEnabledFeatures::cssGridLayoutEnabled())
2406 return false; 2406 return false;
2407 return parseGridAreaShorthand(important); 2407 return parseGridAreaShorthand(important);
2408 2408
2409 case CSSPropertyGridTemplateAreas: 2409 case CSSPropertyGridTemplateAreas:
2410 if (!RuntimeEnabledFeatures::cssGridLayoutEnabled()) 2410 if (!RuntimeEnabledFeatures::cssGridLayoutEnabled())
2411 return false; 2411 return false;
2412 parsedValue = parseGridTemplateAreas(); 2412 parsedValue = parseGridTemplateAreas();
2413 break; 2413 break;
2414 2414
2415 case CSSPropertyGridTemplate:
2416 if (!RuntimeEnabledFeatures::cssGridLayoutEnabled())
2417 return false;
2418 return parseGridTemplateShorthand(important);
2419
2415 case CSSPropertyWebkitMarginCollapse: { 2420 case CSSPropertyWebkitMarginCollapse: {
2416 if (num == 1) { 2421 if (num == 1) {
2417 ShorthandScope scope(this, CSSPropertyWebkitMarginCollapse); 2422 ShorthandScope scope(this, CSSPropertyWebkitMarginCollapse);
2418 if (!parseValue(webkitMarginCollapseShorthand().properties()[0], imp ortant)) 2423 if (!parseValue(webkitMarginCollapseShorthand().properties()[0], imp ortant))
2419 return false; 2424 return false;
2420 CSSValue* value = m_parsedProperties.last().value(); 2425 CSSValue* value = m_parsedProperties.last().value();
2421 addProperty(webkitMarginCollapseShorthand().properties()[1], value, important); 2426 addProperty(webkitMarginCollapseShorthand().properties()[1], value, important);
2422 return true; 2427 return true;
2423 } 2428 }
2424 else if (num == 2) { 2429 else if (num == 2) {
(...skipping 2168 matching lines...) Expand 10 before | Expand all | Expand 10 after
4593 return false; 4598 return false;
4594 } else { 4599 } else {
4595 endValue = gridMissingGridPositionValue(startValue.get()); 4600 endValue = gridMissingGridPositionValue(startValue.get());
4596 } 4601 }
4597 4602
4598 addProperty(shorthand.properties()[0], startValue, important); 4603 addProperty(shorthand.properties()[0], startValue, important);
4599 addProperty(shorthand.properties()[1], endValue, important); 4604 addProperty(shorthand.properties()[1], endValue, important);
4600 return true; 4605 return true;
4601 } 4606 }
4602 4607
4608 bool BisonCSSParser::parseGridTemplateShorthand(bool important)
4609 {
4610 ASSERT(RuntimeEnabledFeatures::cssGridLayoutEnabled());
4611
4612 ShorthandScope scope(this, CSSPropertyGridTemplate);
4613 const StylePropertyShorthand& shorthand = gridTemplateShorthand();
4614 ASSERT_UNUSED(shorthand, shorthand.length() == 3);
Julien - ping for review 2014/02/21 20:04:50 ASSERT(gridTemplateShorthand().length() == 3) ?
4615
4616 if (!m_valueList->current())
4617 return false;
4618
4619 RefPtr<CSSValue> columnsValue;
4620 RefPtr<CSSValue> rowsValue;
4621 RefPtr<CSSValue> areasValue;
4622 NamedGridAreaMap gridAreaMap;
4623 size_t areaRowCount = 0;
4624 size_t areaColumnCount = 0;
4625 size_t numberOfClauses = 1;
Julien - ping for review 2014/02/21 20:04:50 This really should be a state, not a plain int. Yo
4626 bool seenTemplateAreas = false;
4627 bool seenTrackSizeOrRepeat = false;
Julien - ping for review 2014/02/21 20:04:50 Per our style guide, this should be hasSeenTrackSi
4628
4629 RefPtr<CSSValueList> values = CSSValueList::createSpaceSeparated();
4630
4631 while (m_valueList->current()) {
4632 if (isForwardSlashOperator(m_valueList->current())) {
4633 // Slash not allowed in the second clause. Two clauses are required if slash used.
4634 if (++numberOfClauses > 2 || !m_valueList->next())
4635 return false;
4636 if (values->length() > 0)
4637 columnsValue = values.release();
4638 else
4639 columnsValue = cssValuePool().createIdentifierValue(CSSValueNone );
4640 values = CSSValueList::createSpaceSeparated();
4641 seenTrackSizeOrRepeat = false;
4642 }
4643
4644 if (m_valueList->current()->id == CSSValueNone) {
4645 if (seenTemplateAreas)
4646 return false; // The 'none' value is not allowed in complex form .
4647 if (seenTrackSizeOrRepeat)
4648 return false; // The 'none' value is not allowed as part of a tr ack-size list.
4649 if (m_valueList->next()) {
4650 if (!isForwardSlashOperator(m_valueList->current()))
4651 return false;
4652 continue;
4653 }
4654 break;
4655 }
4656
4657 // Handle leading <ident>*.
Julien - ping for review 2014/02/21 20:04:50 Let's be precise here. First the specification cal
4658 if (m_valueList->current()->unit == CSSParserValue::ValueList)
4659 parseGridLineNames(m_valueList.get(), *values);
4660
4661 // Handle a template-area's row.
4662 if (m_valueList->current() && m_valueList->current()->unit == CSSPrimiti veValue::CSS_STRING) {
4663 if (!parseGridTemplateAreasRow(gridAreaMap, areaRowCount, areaColumn Count))
4664 return false;
4665 if (!areaRowCount && seenTrackSizeOrRepeat)
4666 return false; // No TrackSize allowed before the area's first ro w definition.
4667 ++areaRowCount;
4668 seenTemplateAreas = true;
4669 }
4670
4671 // Handle template-{columns/rows}'s track-size, repeat or auto.
Julien - ping for review 2014/02/21 20:04:50 I am concerned by that. We have now effectively du
4672 if (m_valueList->current() && m_valueList->current()->unit == CSSParserV alue::Function && equalIgnoringCase(m_valueList->current()->function->name, "rep eat(")) {
4673 if (seenTemplateAreas)
4674 return false; // Not allowed for template-row in complex form.
4675 if (!parseGridTrackRepeatFunction(*values))
4676 return false;
4677 seenTrackSizeOrRepeat = true;
4678 } else if (m_valueList->current() && m_valueList->current()->unit != CSS ParserValue::ValueList && m_valueList->current()->unit != CSSPrimitiveValue::CSS _STRING) {
4679 RefPtr<CSSValue> value = parseGridTrackSize(*m_valueList);
4680 if (!value)
4681 return false;
4682 values->append(value);
4683 seenTrackSizeOrRepeat = true;
4684 } else {
4685 if (!seenTemplateAreas)
4686 return false; // track-size mandatory in template-columns, "auto " otherwise.
4687 values->append(cssValuePool().createIdentifierValue(CSSValueAuto));
4688 }
4689
4690 // This will handle the trailing <ident>* in the grammar.
4691 if (m_valueList->current() && m_valueList->current()->unit == CSSParserV alue::ValueList) {
4692 parseGridLineNames(m_valueList.get(), *values);
4693 if (m_valueList->current() && m_valueList->current()->unit == CSSPar serValue::ValueList) {
4694 if (!seenTemplateAreas)
4695 return false;
4696 // Concat the last row's <ident>* with the new row's line name.
4697 parseGridLineNames(m_valueList.get(), *values, static_cast<CSSGr idLineNamesValue*>(values->item(values->length() - 1)));
4698 }
4699 if (seenTemplateAreas && m_valueList->current() && m_valueList->curr ent()->unit != CSSPrimitiveValue::CSS_STRING)
4700 return false; // area string mandatory (if additional elements) after line-name in complex form.
4701 }
4702 }
4703
4704 // Handle template-areas property value.
4705 if (areaRowCount > 0)
4706 areasValue = CSSGridTemplateAreasValue::create(gridAreaMap, areaRowCount , areaColumnCount);
4707 else
4708 areasValue = cssValuePool().createIdentifierValue(CSSValueNone);
4709
4710 // Handle template-columns property value.
4711 if (numberOfClauses == 1) {
4712 if (!areaRowCount && values->length() > 0)
4713 return false;
4714 columnsValue = cssValuePool().createIdentifierValue(CSSValueNone);
4715 }
4716
4717 // Handle template-rows property value.
4718 if (values->length() > 0)
4719 rowsValue = values.release();
4720 else if (areaRowCount > 0)
4721 return false;
4722 else
4723 rowsValue = cssValuePool().createIdentifierValue(CSSValueNone);
4724
4725 addProperty(CSSPropertyGridTemplateColumns, columnsValue, important);
4726 addProperty(CSSPropertyGridTemplateRows, rowsValue, important);
4727 addProperty(CSSPropertyGridTemplateAreas, areasValue, important);
4728
4729 return true;
4730 }
4731
4603 bool BisonCSSParser::parseGridAreaShorthand(bool important) 4732 bool BisonCSSParser::parseGridAreaShorthand(bool important)
4604 { 4733 {
4605 ASSERT(RuntimeEnabledFeatures::cssGridLayoutEnabled()); 4734 ASSERT(RuntimeEnabledFeatures::cssGridLayoutEnabled());
4606 4735
4607 ShorthandScope scope(this, CSSPropertyGridArea); 4736 ShorthandScope scope(this, CSSPropertyGridArea);
4608 const StylePropertyShorthand& shorthand = gridAreaShorthand(); 4737 const StylePropertyShorthand& shorthand = gridAreaShorthand();
4609 ASSERT_UNUSED(shorthand, shorthand.length() == 4); 4738 ASSERT_UNUSED(shorthand, shorthand.length() == 4);
4610 4739
4611 RefPtr<CSSValue> rowStartValue = parseGridPosition(); 4740 RefPtr<CSSValue> rowStartValue = parseGridPosition();
4612 if (!rowStartValue) 4741 if (!rowStartValue)
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after
4648 if (!isForwardSlashOperator(m_valueList->current())) 4777 if (!isForwardSlashOperator(m_valueList->current()))
4649 return false; 4778 return false;
4650 4779
4651 if (!m_valueList->next()) 4780 if (!m_valueList->next())
4652 return false; 4781 return false;
4653 4782
4654 property = parseGridPosition(); 4783 property = parseGridPosition();
4655 return true; 4784 return true;
4656 } 4785 }
4657 4786
4658 void BisonCSSParser::parseGridLineNames(CSSParserValueList* parserValueList, CSS ValueList& valueList) 4787 void BisonCSSParser::parseGridLineNames(CSSParserValueList* parserValueList, CSS ValueList& valueList, CSSGridLineNamesValue* lineNamesToConcat)
4659 { 4788 {
4660 ASSERT(parserValueList->current() && parserValueList->current()->unit == CSS ParserValue::ValueList); 4789 ASSERT(parserValueList->current() && parserValueList->current()->unit == CSS ParserValue::ValueList);
4661 4790
4662 CSSParserValueList* identList = parserValueList->current()->valueList; 4791 CSSParserValueList* identList = parserValueList->current()->valueList;
4663 if (!identList->size()) { 4792 if (!identList->size()) {
4664 parserValueList->next(); 4793 parserValueList->next();
4665 return; 4794 return;
4666 } 4795 }
4667 4796
4668 RefPtrWillBeRawPtr<CSSGridLineNamesValue> lineNames = CSSGridLineNamesValue: :create(); 4797 RefPtr<CSSGridLineNamesValue> lineNames = lineNamesToConcat ? lineNamesToCon cat : CSSGridLineNamesValue::create();
4669 while (CSSParserValue* identValue = identList->current()) { 4798 while (CSSParserValue* identValue = identList->current()) {
4670 ASSERT(identValue->unit == CSSPrimitiveValue::CSS_IDENT); 4799 ASSERT(identValue->unit == CSSPrimitiveValue::CSS_IDENT);
4671 RefPtrWillBeRawPtr<CSSPrimitiveValue> lineName = createPrimitiveStringVa lue(identValue); 4800 RefPtrWillBeRawPtr<CSSPrimitiveValue> lineName = createPrimitiveStringVa lue(identValue);
4672 lineNames->append(lineName.release()); 4801 lineNames->append(lineName.release());
4673 identList->next(); 4802 identList->next();
4674 } 4803 }
4675 valueList.append(lineNames.release()); 4804 if (!lineNamesToConcat)
4805 valueList.append(lineNames.release());
4676 4806
4677 parserValueList->next(); 4807 parserValueList->next();
4678 } 4808 }
4679 4809
4680 bool BisonCSSParser::parseGridTrackList(CSSPropertyID propId, bool important) 4810 bool BisonCSSParser::parseGridTrackList(CSSPropertyID propId, bool important)
4681 { 4811 {
4682 ASSERT(RuntimeEnabledFeatures::cssGridLayoutEnabled()); 4812 ASSERT(RuntimeEnabledFeatures::cssGridLayoutEnabled());
4683 4813
4684 CSSParserValue* value = m_valueList->current(); 4814 CSSParserValue* value = m_valueList->current();
4685 if (value->id == CSSValueNone) { 4815 if (value->id == CSSValueNone) {
(...skipping 124 matching lines...) Expand 10 before | Expand all | Expand 10 after
4810 4940
4811 return cssValuePool().createValue(flexValue, CSSPrimitiveValue::CSS_FR); 4941 return cssValuePool().createValue(flexValue, CSSPrimitiveValue::CSS_FR);
4812 } 4942 }
4813 4943
4814 if (!validUnit(currentValue, FNonNeg | FLength | FPercent)) 4944 if (!validUnit(currentValue, FNonNeg | FLength | FPercent))
4815 return 0; 4945 return 0;
4816 4946
4817 return createPrimitiveNumericValue(currentValue); 4947 return createPrimitiveNumericValue(currentValue);
4818 } 4948 }
4819 4949
4950 bool BisonCSSParser::parseGridTemplateAreasRow(NamedGridAreaMap& gridAreaMap, co nst size_t rowCount, size_t& columnCount)
4951 {
4952 CSSParserValue* currentValue = m_valueList->current();
4953 if (!currentValue || currentValue->unit != CSSPrimitiveValue::CSS_STRING)
4954 return false;
4955
4956 String gridRowNames = currentValue->string;
4957 if (!gridRowNames.length())
4958 return false;
4959
4960 Vector<String> columnNames;
4961 gridRowNames.split(' ', columnNames);
4962
4963 if (!columnCount) {
4964 columnCount = columnNames.size();
4965 ASSERT(columnCount);
4966 } else if (columnCount != columnNames.size()) {
4967 // The declaration is invalid is all the rows don't have the number of c olumns.
4968 return false;
4969 }
4970
4971 for (size_t currentCol = 0; currentCol < columnCount; ++currentCol) {
4972 const String& gridAreaName = columnNames[currentCol];
4973
4974 // Unamed areas are always valid (we consider them to be 1x1).
4975 if (gridAreaName == ".")
4976 continue;
4977
4978 // We handle several grid areas with the same name at once to simplify t he validation code.
4979 size_t lookAheadCol;
4980 for (lookAheadCol = currentCol; lookAheadCol < (columnCount - 1); ++look AheadCol) {
4981 if (columnNames[lookAheadCol + 1] != gridAreaName)
4982 break;
4983 }
4984
4985 NamedGridAreaMap::iterator gridAreaIt = gridAreaMap.find(gridAreaName);
4986 if (gridAreaIt == gridAreaMap.end()) {
4987 gridAreaMap.add(gridAreaName, GridCoordinate(GridSpan(rowCount, rowC ount), GridSpan(currentCol, lookAheadCol)));
4988 } else {
4989 GridCoordinate& gridCoordinate = gridAreaIt->value;
4990
4991 // The following checks test that the grid area is a single filled-i n rectangle.
4992 // 1. The new row is adjacent to the previously parsed row.
4993 if (rowCount != gridCoordinate.rows.initialPositionIndex + 1)
4994 return false;
4995
4996 // 2. The new area starts at the same position as the previously par sed area.
4997 if (currentCol != gridCoordinate.columns.initialPositionIndex)
4998 return false;
4999
5000 // 3. The new area ends at the same position as the previously parse d area.
5001 if (lookAheadCol != gridCoordinate.columns.finalPositionIndex)
5002 return false;
5003
5004 ++gridCoordinate.rows.finalPositionIndex;
5005 }
5006 currentCol = lookAheadCol;
5007 }
5008
5009 m_valueList->next();
5010 return true;
5011 }
5012
4820 PassRefPtr<CSSValue> BisonCSSParser::parseGridTemplateAreas() 5013 PassRefPtr<CSSValue> BisonCSSParser::parseGridTemplateAreas()
4821 { 5014 {
4822 NamedGridAreaMap gridAreaMap; 5015 NamedGridAreaMap gridAreaMap;
4823 size_t rowCount = 0; 5016 size_t rowCount = 0;
4824 size_t columnCount = 0; 5017 size_t columnCount = 0;
4825 5018
4826 while (CSSParserValue* currentValue = m_valueList->current()) { 5019 while (m_valueList->current()) {
4827 if (currentValue->unit != CSSPrimitiveValue::CSS_STRING) 5020 if (!parseGridTemplateAreasRow(gridAreaMap, rowCount, columnCount))
4828 return 0; 5021 return 0;
4829
4830 String gridRowNames = currentValue->string;
4831 if (!gridRowNames.length())
4832 return 0;
4833
4834 Vector<String> columnNames;
4835 gridRowNames.split(' ', columnNames);
4836
4837 if (!columnCount) {
4838 columnCount = columnNames.size();
4839 ASSERT(columnCount);
4840 } else if (columnCount != columnNames.size()) {
4841 // The declaration is invalid is all the rows don't have the number of columns.
4842 return 0;
4843 }
4844
4845 for (size_t currentCol = 0; currentCol < columnCount; ++currentCol) {
4846 const String& gridAreaName = columnNames[currentCol];
4847
4848 // Unamed areas are always valid (we consider them to be 1x1).
4849 if (gridAreaName == ".")
4850 continue;
4851
4852 // We handle several grid areas with the same name at once to simpli fy the validation code.
4853 size_t lookAheadCol;
4854 for (lookAheadCol = currentCol; lookAheadCol < (columnCount - 1); ++ lookAheadCol) {
4855 if (columnNames[lookAheadCol + 1] != gridAreaName)
4856 break;
4857 }
4858
4859 NamedGridAreaMap::iterator gridAreaIt = gridAreaMap.find(gridAreaNam e);
4860 if (gridAreaIt == gridAreaMap.end()) {
4861 gridAreaMap.add(gridAreaName, GridCoordinate(GridSpan(rowCount, rowCount), GridSpan(currentCol, lookAheadCol)));
4862 } else {
4863 GridCoordinate& gridCoordinate = gridAreaIt->value;
4864
4865 // The following checks test that the grid area is a single fill ed-in rectangle.
4866 // 1. The new row is adjacent to the previously parsed row.
4867 if (rowCount != gridCoordinate.rows.initialPositionIndex + 1)
4868 return 0;
4869
4870 // 2. The new area starts at the same position as the previously parsed area.
4871 if (currentCol != gridCoordinate.columns.initialPositionIndex)
4872 return 0;
4873
4874 // 3. The new area ends at the same position as the previously p arsed area.
4875 if (lookAheadCol != gridCoordinate.columns.finalPositionIndex)
4876 return 0;
4877
4878 ++gridCoordinate.rows.finalPositionIndex;
4879 }
4880 currentCol = lookAheadCol;
4881 }
4882
4883 ++rowCount; 5022 ++rowCount;
4884 m_valueList->next();
4885 } 5023 }
4886 5024
4887 if (!rowCount || !columnCount) 5025 if (!rowCount || !columnCount)
4888 return 0; 5026 return 0;
4889 5027
4890 return CSSGridTemplateAreasValue::create(gridAreaMap, rowCount, columnCount) ; 5028 return CSSGridTemplateAreasValue::create(gridAreaMap, rowCount, columnCount) ;
4891 } 5029 }
4892 5030
4893 PassRefPtr<CSSValue> BisonCSSParser::parseCounterContent(CSSParserValueList* arg s, bool counters) 5031 PassRefPtr<CSSValue> BisonCSSParser::parseCounterContent(CSSParserValueList* arg s, bool counters)
4894 { 5032 {
(...skipping 5201 matching lines...) Expand 10 before | Expand all | Expand 10 after
10096 { 10234 {
10097 // The tokenizer checks for the construct of an+b. 10235 // The tokenizer checks for the construct of an+b.
10098 // However, since the {ident} rule precedes the {nth} rule, some of those 10236 // However, since the {ident} rule precedes the {nth} rule, some of those
10099 // tokens are identified as string literal. Furthermore we need to accept 10237 // tokens are identified as string literal. Furthermore we need to accept
10100 // "odd" and "even" which does not match to an+b. 10238 // "odd" and "even" which does not match to an+b.
10101 return equalIgnoringCase(token, "odd") || equalIgnoringCase(token, "even") 10239 return equalIgnoringCase(token, "odd") || equalIgnoringCase(token, "even")
10102 || equalIgnoringCase(token, "n") || equalIgnoringCase(token, "-n"); 10240 || equalIgnoringCase(token, "n") || equalIgnoringCase(token, "-n");
10103 } 10241 }
10104 10242
10105 } 10243 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698