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

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

Issue 185293006: Move almost all of CSSPropertyParser into CSSPropertyParser.cpp (Closed) Base URL: https://chromium.googlesource.com/chromium/blink.git@master
Patch Set: Fix link errors Created 6 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 unified diff | Download patch
« no previous file with comments | « Source/core/css/parser/BisonCSSParser.h ('k') | Source/core/css/parser/CSSPropertyParser.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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 86 matching lines...) Expand 10 before | Expand all | Expand 10 after
97 #endif 97 #endif
98 98
99 int cssyyparse(WebCore::BisonCSSParser*); 99 int cssyyparse(WebCore::BisonCSSParser*);
100 100
101 using namespace std; 101 using namespace std;
102 using namespace WTF; 102 using namespace WTF;
103 103
104 namespace WebCore { 104 namespace WebCore {
105 105
106 static const unsigned INVALID_NUM_PARSED_PROPERTIES = UINT_MAX; 106 static const unsigned INVALID_NUM_PARSED_PROPERTIES = UINT_MAX;
107 static const double MAX_SCALE = 1000000;
108
109 template <unsigned N>
110 static bool equal(const CSSParserString& a, const char (&b)[N])
111 {
112 unsigned length = N - 1; // Ignore the trailing null character
113 if (a.length() != length)
114 return false;
115
116 return a.is8Bit() ? WTF::equal(a.characters8(), reinterpret_cast<const LChar *>(b), length) : WTF::equal(a.characters16(), reinterpret_cast<const LChar*>(b), length);
117 }
118
119 template <unsigned N>
120 static bool equalIgnoringCase(const CSSParserString& a, const char (&b)[N])
121 {
122 unsigned length = N - 1; // Ignore the trailing null character
123 if (a.length() != length)
124 return false;
125
126 return a.is8Bit() ? WTF::equalIgnoringCase(b, a.characters8(), length) : WTF ::equalIgnoringCase(b, a.characters16(), length);
127 }
128
129 template <unsigned N>
130 static bool equalIgnoringCase(CSSParserValue* value, const char (&b)[N])
131 {
132 ASSERT(value->unit == CSSPrimitiveValue::CSS_IDENT || value->unit == CSSPrim itiveValue::CSS_STRING);
133 return equalIgnoringCase(value->string, b);
134 }
135
136 static PassRefPtrWillBeRawPtr<CSSPrimitiveValue> createPrimitiveValuePair(PassRe fPtrWillBeRawPtr<CSSPrimitiveValue> first, PassRefPtrWillBeRawPtr<CSSPrimitiveVa lue> second, Pair::IdenticalValuesPolicy identicalValuesPolicy = Pair::DropIdent icalValues)
137 {
138 return cssValuePool().createValue(Pair::create(first, second, identicalValue sPolicy));
139 }
140
141 class AnimationParseContext {
142 public:
143 AnimationParseContext()
144 : m_animationPropertyKeywordAllowed(true)
145 , m_firstAnimationCommitted(false)
146 , m_hasSeenAnimationPropertyKeyword(false)
147 {
148 }
149
150 void commitFirstAnimation()
151 {
152 m_firstAnimationCommitted = true;
153 }
154
155 bool hasCommittedFirstAnimation() const
156 {
157 return m_firstAnimationCommitted;
158 }
159
160 void commitAnimationPropertyKeyword()
161 {
162 m_animationPropertyKeywordAllowed = false;
163 }
164
165 bool animationPropertyKeywordAllowed() const
166 {
167 return m_animationPropertyKeywordAllowed;
168 }
169
170 bool hasSeenAnimationPropertyKeyword() const
171 {
172 return m_hasSeenAnimationPropertyKeyword;
173 }
174
175 void sawAnimationPropertyKeyword()
176 {
177 m_hasSeenAnimationPropertyKeyword = true;
178 }
179
180 private:
181 bool m_animationPropertyKeywordAllowed;
182 bool m_firstAnimationCommitted;
183 bool m_hasSeenAnimationPropertyKeyword;
184 };
185 107
186 BisonCSSParser::BisonCSSParser(const CSSParserContext& context) 108 BisonCSSParser::BisonCSSParser(const CSSParserContext& context)
187 : m_context(context) 109 : m_context(context)
188 , m_important(false) 110 , m_important(false)
189 , m_id(CSSPropertyInvalid) 111 , m_id(CSSPropertyInvalid)
190 , m_styleSheet(0) 112 , m_styleSheet(0)
191 , m_supportsCondition(false) 113 , m_supportsCondition(false)
192 , m_selectorListForParseSelector(0) 114 , m_selectorListForParseSelector(0)
193 , m_numParsedPropertiesBeforeMarginBox(INVALID_NUM_PARSED_PROPERTIES) 115 , m_numParsedPropertiesBeforeMarginBox(INVALID_NUM_PARSED_PROPERTIES)
194 , m_hasFontFaceOnlyValues(false) 116 , m_hasFontFaceOnlyValues(false)
(...skipping 239 matching lines...) Expand 10 before | Expand all | Expand 10 after
434 unit = CSSPrimitiveValue::CSS_PX; 356 unit = CSSPrimitiveValue::CSS_PX;
435 } 357 }
436 if (number < 0 && !acceptsNegativeNumbers) 358 if (number < 0 && !acceptsNegativeNumbers)
437 return false; 359 return false;
438 360
439 RefPtrWillBeRawPtr<CSSValue> value = cssValuePool().createValue(number, unit ); 361 RefPtrWillBeRawPtr<CSSValue> value = cssValuePool().createValue(number, unit );
440 declaration->addParsedProperty(CSSProperty(propertyId, value.release(), impo rtant)); 362 declaration->addParsedProperty(CSSProperty(propertyId, value.release(), impo rtant));
441 return true; 363 return true;
442 } 364 }
443 365
444 static inline bool isValidKeywordPropertyAndValue(CSSPropertyID propertyId, int valueID, const CSSParserContext& parserContext) 366 bool isValidKeywordPropertyAndValue(CSSPropertyID propertyId, int valueID, const CSSParserContext& parserContext)
445 { 367 {
446 if (!valueID) 368 if (!valueID)
447 return false; 369 return false;
448 370
449 switch (propertyId) { 371 switch (propertyId) {
450 case CSSPropertyBorderCollapse: // collapse | separate | inherit 372 case CSSPropertyBorderCollapse: // collapse | separate | inherit
451 if (valueID == CSSValueCollapse || valueID == CSSValueSeparate) 373 if (valueID == CSSValueCollapse || valueID == CSSValueSeparate)
452 return true; 374 return true;
453 break; 375 break;
454 case CSSPropertyBorderTopStyle: // <border-style> | inherit 376 case CSSPropertyBorderTopStyle: // <border-style> | inherit
(...skipping 350 matching lines...) Expand 10 before | Expand all | Expand 10 after
805 if (valueID == CSSValueNormal || valueID == CSSValueBreakAll || valueID == CSSValueBreakWord) 727 if (valueID == CSSValueNormal || valueID == CSSValueBreakAll || valueID == CSSValueBreakWord)
806 return true; 728 return true;
807 break; 729 break;
808 default: 730 default:
809 ASSERT_NOT_REACHED(); 731 ASSERT_NOT_REACHED();
810 return false; 732 return false;
811 } 733 }
812 return false; 734 return false;
813 } 735 }
814 736
815 static inline bool isKeywordPropertyID(CSSPropertyID propertyId) 737 bool isKeywordPropertyID(CSSPropertyID propertyId)
816 { 738 {
817 switch (propertyId) { 739 switch (propertyId) {
818 case CSSPropertyMixBlendMode: 740 case CSSPropertyMixBlendMode:
819 case CSSPropertyIsolation: 741 case CSSPropertyIsolation:
820 case CSSPropertyBorderBottomStyle: 742 case CSSPropertyBorderBottomStyle:
821 case CSSPropertyBorderCollapse: 743 case CSSPropertyBorderCollapse:
822 case CSSPropertyBorderLeftStyle: 744 case CSSPropertyBorderLeftStyle:
823 case CSSPropertyBorderRightStyle: 745 case CSSPropertyBorderRightStyle:
824 case CSSPropertyBorderTopStyle: 746 case CSSPropertyBorderTopStyle:
825 case CSSPropertyBoxSizing: 747 case CSSPropertyBoxSizing:
(...skipping 501 matching lines...) Expand 10 before | Expand all | Expand 10 after
1327 filterProperties(true, m_parsedProperties, results, unusedEntries, seenPrope rties); 1249 filterProperties(true, m_parsedProperties, results, unusedEntries, seenPrope rties);
1328 filterProperties(false, m_parsedProperties, results, unusedEntries, seenProp erties); 1250 filterProperties(false, m_parsedProperties, results, unusedEntries, seenProp erties);
1329 if (unusedEntries) 1251 if (unusedEntries)
1330 results.remove(0, unusedEntries); 1252 results.remove(0, unusedEntries);
1331 1253
1332 CSSParserMode mode = inViewport() ? CSSViewportRuleMode : m_context.mode(); 1254 CSSParserMode mode = inViewport() ? CSSViewportRuleMode : m_context.mode();
1333 1255
1334 return ImmutableStylePropertySet::create(results.data(), results.size(), mod e); 1256 return ImmutableStylePropertySet::create(results.data(), results.size(), mod e);
1335 } 1257 }
1336 1258
1337 void CSSPropertyParser::addPropertyWithPrefixingVariant(CSSPropertyID propId, Pa ssRefPtrWillBeRawPtr<CSSValue> value, bool important, bool implicit)
1338 {
1339 RefPtrWillBeRawPtr<CSSValue> val = value.get();
1340 addProperty(propId, value, important, implicit);
1341
1342 CSSPropertyID prefixingVariant = prefixingVariantForPropertyId(propId);
1343 if (prefixingVariant == propId)
1344 return;
1345
1346 if (m_currentShorthand) {
1347 // We can't use ShorthandScope here as we can already be inside one (e.g we are parsing CSSTransition).
1348 m_currentShorthand = prefixingVariantForPropertyId(m_currentShorthand);
1349 addProperty(prefixingVariant, val.release(), important, implicit);
1350 m_currentShorthand = prefixingVariantForPropertyId(m_currentShorthand);
1351 } else {
1352 addProperty(prefixingVariant, val.release(), important, implicit);
1353 }
1354 }
1355
1356 void CSSPropertyParser::addProperty(CSSPropertyID propId, PassRefPtrWillBeRawPtr <CSSValue> value, bool important, bool implicit)
1357 {
1358 // This property doesn't belong to a shorthand.
1359 if (!m_currentShorthand) {
1360 m_parsedProperties.append(CSSProperty(propId, value, important, false, C SSPropertyInvalid, m_implicitShorthand || implicit));
1361 return;
1362 }
1363
1364 Vector<StylePropertyShorthand, 4> shorthands;
1365 getMatchingShorthandsForLonghand(propId, &shorthands);
1366 // The longhand does not belong to multiple shorthands.
1367 if (shorthands.size() == 1)
1368 m_parsedProperties.append(CSSProperty(propId, value, important, true, CS SPropertyInvalid, m_implicitShorthand || implicit));
1369 else
1370 m_parsedProperties.append(CSSProperty(propId, value, important, true, in dexOfShorthandForLonghand(m_currentShorthand, shorthands), m_implicitShorthand | | implicit));
1371 }
1372
1373 void BisonCSSParser::rollbackLastProperties(int num) 1259 void BisonCSSParser::rollbackLastProperties(int num)
1374 { 1260 {
1375 ASSERT(num >= 0); 1261 ASSERT(num >= 0);
1376 ASSERT(m_parsedProperties.size() >= static_cast<unsigned>(num)); 1262 ASSERT(m_parsedProperties.size() >= static_cast<unsigned>(num));
1377 m_parsedProperties.shrink(m_parsedProperties.size() - num); 1263 m_parsedProperties.shrink(m_parsedProperties.size() - num);
1378 } 1264 }
1379 1265
1380 void CSSPropertyParser::rollbackLastProperties(int num)
1381 {
1382 ASSERT(num >= 0);
1383 ASSERT(m_parsedProperties.size() >= static_cast<unsigned>(num));
1384 m_parsedProperties.shrink(m_parsedProperties.size() - num);
1385 }
1386
1387 void BisonCSSParser::clearProperties() 1266 void BisonCSSParser::clearProperties()
1388 { 1267 {
1389 m_parsedProperties.clear(); 1268 m_parsedProperties.clear();
1390 m_numParsedPropertiesBeforeMarginBox = INVALID_NUM_PARSED_PROPERTIES; 1269 m_numParsedPropertiesBeforeMarginBox = INVALID_NUM_PARSED_PROPERTIES;
1391 m_hasFontFaceOnlyValues = false; 1270 m_hasFontFaceOnlyValues = false;
1392 } 1271 }
1393 1272
1394 KURL CSSPropertyParser::completeURL(const String& url) const
1395 {
1396 return m_context.completeURL(url);
1397 }
1398
1399 bool CSSPropertyParser::validCalculationUnit(CSSParserValue* value, Units unitfl ags, ReleaseParsedCalcValueCondition releaseCalc)
1400 {
1401 bool mustBeNonNegative = unitflags & FNonNeg;
1402
1403 if (!parseCalculation(value, mustBeNonNegative ? ValueRangeNonNegative : Val ueRangeAll))
1404 return false;
1405
1406 bool b = false;
1407 switch (m_parsedCalculation->category()) {
1408 case CalcLength:
1409 b = (unitflags & FLength);
1410 break;
1411 case CalcPercent:
1412 b = (unitflags & FPercent);
1413 if (b && mustBeNonNegative && m_parsedCalculation->isNegative())
1414 b = false;
1415 break;
1416 case CalcNumber:
1417 b = (unitflags & FNumber);
1418 if (!b && (unitflags & FInteger) && m_parsedCalculation->isInt())
1419 b = true;
1420 if (b && mustBeNonNegative && m_parsedCalculation->isNegative())
1421 b = false;
1422 break;
1423 case CalcPercentLength:
1424 b = (unitflags & FPercent) && (unitflags & FLength);
1425 break;
1426 case CalcPercentNumber:
1427 b = (unitflags & FPercent) && (unitflags & FNumber);
1428 break;
1429 case CalcOther:
1430 break;
1431 }
1432 if (!b || releaseCalc == ReleaseParsedCalcValue)
1433 m_parsedCalculation.release();
1434 return b;
1435 }
1436
1437 inline bool CSSPropertyParser::shouldAcceptUnitLessValues(CSSParserValue* value, Units unitflags, CSSParserMode cssParserMode)
1438 {
1439 // Quirks mode and presentation attributes accept unit less values.
1440 return (unitflags & (FLength | FAngle | FTime)) && (!value->fValue || isUnit LessLengthParsingEnabledForMode(cssParserMode));
1441 }
1442
1443 bool CSSPropertyParser::validUnit(CSSParserValue* value, Units unitflags, CSSPar serMode cssParserMode, ReleaseParsedCalcValueCondition releaseCalc)
1444 {
1445 if (isCalculation(value))
1446 return validCalculationUnit(value, unitflags, releaseCalc);
1447
1448 bool b = false;
1449 switch (value->unit) {
1450 case CSSPrimitiveValue::CSS_NUMBER:
1451 b = (unitflags & FNumber);
1452 if (!b && shouldAcceptUnitLessValues(value, unitflags, cssParserMode)) {
1453 value->unit = (unitflags & FLength) ? CSSPrimitiveValue::CSS_PX :
1454 ((unitflags & FAngle) ? CSSPrimitiveValue::CSS_DEG : C SSPrimitiveValue::CSS_MS);
1455 b = true;
1456 }
1457 if (!b && (unitflags & FInteger) && value->isInt)
1458 b = true;
1459 if (!b && (unitflags & FPositiveInteger) && value->isInt && value->fValu e > 0)
1460 b = true;
1461 break;
1462 case CSSPrimitiveValue::CSS_PERCENTAGE:
1463 b = (unitflags & FPercent);
1464 break;
1465 case CSSParserValue::Q_EMS:
1466 case CSSPrimitiveValue::CSS_EMS:
1467 case CSSPrimitiveValue::CSS_REMS:
1468 case CSSPrimitiveValue::CSS_CHS:
1469 case CSSPrimitiveValue::CSS_EXS:
1470 case CSSPrimitiveValue::CSS_PX:
1471 case CSSPrimitiveValue::CSS_CM:
1472 case CSSPrimitiveValue::CSS_MM:
1473 case CSSPrimitiveValue::CSS_IN:
1474 case CSSPrimitiveValue::CSS_PT:
1475 case CSSPrimitiveValue::CSS_PC:
1476 case CSSPrimitiveValue::CSS_VW:
1477 case CSSPrimitiveValue::CSS_VH:
1478 case CSSPrimitiveValue::CSS_VMIN:
1479 case CSSPrimitiveValue::CSS_VMAX:
1480 b = (unitflags & FLength);
1481 break;
1482 case CSSPrimitiveValue::CSS_MS:
1483 case CSSPrimitiveValue::CSS_S:
1484 b = (unitflags & FTime);
1485 break;
1486 case CSSPrimitiveValue::CSS_DEG:
1487 case CSSPrimitiveValue::CSS_RAD:
1488 case CSSPrimitiveValue::CSS_GRAD:
1489 case CSSPrimitiveValue::CSS_TURN:
1490 b = (unitflags & FAngle);
1491 break;
1492 case CSSPrimitiveValue::CSS_DPPX:
1493 case CSSPrimitiveValue::CSS_DPI:
1494 case CSSPrimitiveValue::CSS_DPCM:
1495 b = (unitflags & FResolution);
1496 break;
1497 case CSSPrimitiveValue::CSS_HZ:
1498 case CSSPrimitiveValue::CSS_KHZ:
1499 case CSSPrimitiveValue::CSS_DIMENSION:
1500 default:
1501 break;
1502 }
1503 if (b && unitflags & FNonNeg && value->fValue < 0)
1504 b = false;
1505 return b;
1506 }
1507
1508 inline PassRefPtrWillBeRawPtr<CSSPrimitiveValue> CSSPropertyParser::createPrimit iveNumericValue(CSSParserValue* value)
1509 {
1510 if (m_parsedCalculation) {
1511 ASSERT(isCalculation(value));
1512 return CSSPrimitiveValue::create(m_parsedCalculation.release());
1513 }
1514
1515 ASSERT((value->unit >= CSSPrimitiveValue::CSS_NUMBER && value->unit <= CSSPr imitiveValue::CSS_KHZ)
1516 || (value->unit >= CSSPrimitiveValue::CSS_TURN && value->unit <= CSSPrim itiveValue::CSS_CHS)
1517 || (value->unit >= CSSPrimitiveValue::CSS_VW && value->unit <= CSSPrimit iveValue::CSS_VMAX)
1518 || (value->unit >= CSSPrimitiveValue::CSS_DPPX && value->unit <= CSSPrim itiveValue::CSS_DPCM));
1519 return cssValuePool().createValue(value->fValue, static_cast<CSSPrimitiveVal ue::UnitTypes>(value->unit));
1520 }
1521
1522 inline PassRefPtrWillBeRawPtr<CSSPrimitiveValue> CSSPropertyParser::createPrimit iveStringValue(CSSParserValue* value)
1523 {
1524 ASSERT(value->unit == CSSPrimitiveValue::CSS_STRING || value->unit == CSSPri mitiveValue::CSS_IDENT);
1525 return cssValuePool().createValue(value->string, CSSPrimitiveValue::CSS_STRI NG);
1526 }
1527
1528 static inline bool isComma(CSSParserValue* value)
1529 {
1530 return value && value->unit == CSSParserValue::Operator && value->iValue == ',';
1531 }
1532
1533 static inline bool isForwardSlashOperator(CSSParserValue* value)
1534 {
1535 ASSERT(value);
1536 return value->unit == CSSParserValue::Operator && value->iValue == '/';
1537 }
1538
1539 static bool isGeneratedImageValue(CSSParserValue* val)
1540 {
1541 if (val->unit != CSSParserValue::Function)
1542 return false;
1543
1544 return equalIgnoringCase(val->function->name, "-webkit-gradient(")
1545 || equalIgnoringCase(val->function->name, "-webkit-linear-gradient(")
1546 || equalIgnoringCase(val->function->name, "linear-gradient(")
1547 || equalIgnoringCase(val->function->name, "-webkit-repeating-linear-grad ient(")
1548 || equalIgnoringCase(val->function->name, "repeating-linear-gradient(")
1549 || equalIgnoringCase(val->function->name, "-webkit-radial-gradient(")
1550 || equalIgnoringCase(val->function->name, "radial-gradient(")
1551 || equalIgnoringCase(val->function->name, "-webkit-repeating-radial-grad ient(")
1552 || equalIgnoringCase(val->function->name, "repeating-radial-gradient(")
1553 || equalIgnoringCase(val->function->name, "-webkit-canvas(")
1554 || equalIgnoringCase(val->function->name, "-webkit-cross-fade(");
1555 }
1556
1557 bool CSSPropertyParser::validWidthOrHeight(CSSParserValue* value)
1558 {
1559 int id = value->id;
1560 if (id == CSSValueIntrinsic || id == CSSValueMinIntrinsic || id == CSSValueW ebkitMinContent || id == CSSValueWebkitMaxContent || id == CSSValueWebkitFillAva ilable || id == CSSValueWebkitFitContent)
1561 return true;
1562 return !id && validUnit(value, FLength | FPercent | FNonNeg);
1563 }
1564
1565 inline PassRefPtrWillBeRawPtr<CSSPrimitiveValue> CSSPropertyParser::parseValidPr imitive(CSSValueID identifier, CSSParserValue* value)
1566 {
1567 if (identifier)
1568 return cssValuePool().createIdentifierValue(identifier);
1569 if (value->unit == CSSPrimitiveValue::CSS_STRING)
1570 return createPrimitiveStringValue(value);
1571 if (value->unit >= CSSPrimitiveValue::CSS_NUMBER && value->unit <= CSSPrimit iveValue::CSS_KHZ)
1572 return createPrimitiveNumericValue(value);
1573 if (value->unit >= CSSPrimitiveValue::CSS_TURN && value->unit <= CSSPrimitiv eValue::CSS_CHS)
1574 return createPrimitiveNumericValue(value);
1575 if (value->unit >= CSSPrimitiveValue::CSS_VW && value->unit <= CSSPrimitiveV alue::CSS_VMAX)
1576 return createPrimitiveNumericValue(value);
1577 if (value->unit >= CSSPrimitiveValue::CSS_DPPX && value->unit <= CSSPrimitiv eValue::CSS_DPCM)
1578 return createPrimitiveNumericValue(value);
1579 if (value->unit >= CSSParserValue::Q_EMS)
1580 return CSSPrimitiveValue::createAllowingMarginQuirk(value->fValue, CSSPr imitiveValue::CSS_EMS);
1581 if (isCalculation(value))
1582 return CSSPrimitiveValue::create(m_parsedCalculation.release());
1583
1584 return nullptr;
1585 }
1586
1587 void CSSPropertyParser::addExpandedPropertyForValue(CSSPropertyID propId, PassRe fPtrWillBeRawPtr<CSSValue> prpValue, bool important)
1588 {
1589 const StylePropertyShorthand& shorthand = shorthandForProperty(propId);
1590 unsigned shorthandLength = shorthand.length();
1591 if (!shorthandLength) {
1592 addProperty(propId, prpValue, important);
1593 return;
1594 }
1595
1596 RefPtrWillBeRawPtr<CSSValue> value = prpValue;
1597 ShorthandScope scope(this, propId);
1598 const CSSPropertyID* longhands = shorthand.properties();
1599 for (unsigned i = 0; i < shorthandLength; ++i)
1600 addProperty(longhands[i], value, important);
1601 }
1602
1603 void BisonCSSParser::setCurrentProperty(CSSPropertyID propId) 1273 void BisonCSSParser::setCurrentProperty(CSSPropertyID propId)
1604 { 1274 {
1605 m_id = propId; 1275 m_id = propId;
1606 } 1276 }
1607 1277
1608 bool BisonCSSParser::parseValue(CSSPropertyID propId, bool important) 1278 bool BisonCSSParser::parseValue(CSSPropertyID propId, bool important)
1609 { 1279 {
1610 CSSPropertyParser parser(m_valueList, m_context, m_inViewport, m_important, m_parsedProperties, m_hasFontFaceOnlyValues); 1280 CSSPropertyParser parser(m_valueList, m_context, m_inViewport, m_important, m_parsedProperties, m_hasFontFaceOnlyValues);
1611 return parser.parseValue(propId, important); 1281 return parser.parseValue(propId, important);
1612 } 1282 }
1613 1283
1614 bool CSSPropertyParser::parseValue(CSSPropertyID propId, bool important)
1615 {
1616 if (!isInternalPropertyAndValueParsingEnabledForMode(m_context.mode()) && is InternalProperty(propId))
1617 return false;
1618
1619 // We don't count the UA style sheet in our statistics.
1620 if (m_context.useCounter())
1621 m_context.useCounter()->count(m_context, propId);
1622
1623 if (!m_valueList)
1624 return false;
1625
1626 CSSParserValue* value = m_valueList->current();
1627
1628 if (!value)
1629 return false;
1630
1631 if (inViewport()) {
1632 // Allow @viewport rules from UA stylesheets even if the feature is disa bled.
1633 if (!RuntimeEnabledFeatures::cssViewportEnabled() && !isUASheetBehavior( m_context.mode()))
1634 return false;
1635
1636 return parseViewportProperty(propId, important);
1637 }
1638
1639 // Note: m_parsedCalculation is used to pass the calc value to validUnit and then cleared at the end of this function.
1640 // FIXME: This is to avoid having to pass parsedCalc to all validUnit caller s.
1641 ASSERT(!m_parsedCalculation);
1642
1643 CSSValueID id = value->id;
1644
1645 int num = inShorthand() ? 1 : m_valueList->size();
1646
1647 if (id == CSSValueInherit) {
1648 if (num != 1)
1649 return false;
1650 addExpandedPropertyForValue(propId, cssValuePool().createInheritedValue( ), important);
1651 return true;
1652 }
1653 else if (id == CSSValueInitial) {
1654 if (num != 1)
1655 return false;
1656 addExpandedPropertyForValue(propId, cssValuePool().createExplicitInitial Value(), important);
1657 return true;
1658 }
1659
1660 if (isKeywordPropertyID(propId)) {
1661 if (!isValidKeywordPropertyAndValue(propId, id, m_context))
1662 return false;
1663 if (m_valueList->next() && !inShorthand())
1664 return false;
1665 addProperty(propId, cssValuePool().createIdentifierValue(id), important) ;
1666 return true;
1667 }
1668
1669 bool validPrimitive = false;
1670 RefPtrWillBeRawPtr<CSSValue> parsedValue;
1671
1672 switch (propId) {
1673 case CSSPropertySize: // <length>{1,2} | auto | [ <page-size > || [ portrait | landscape] ]
1674 return parseSize(propId, important);
1675
1676 case CSSPropertyQuotes: // [<string> <string>]+ | none | inher it
1677 if (id)
1678 validPrimitive = true;
1679 else
1680 return parseQuotes(propId, important);
1681 break;
1682 case CSSPropertyUnicodeBidi: // normal | embed | bidi-override | isolate | i solate-override | plaintext | inherit
1683 if (id == CSSValueNormal
1684 || id == CSSValueEmbed
1685 || id == CSSValueBidiOverride
1686 || id == CSSValueWebkitIsolate
1687 || id == CSSValueWebkitIsolateOverride
1688 || id == CSSValueWebkitPlaintext)
1689 validPrimitive = true;
1690 break;
1691
1692 case CSSPropertyContent: // [ <string> | <uri> | <counter> | at tr(X) | open-quote |
1693 // close-quote | no-open-quote | no-close-quote ]+ | inherit
1694 return parseContent(propId, important);
1695
1696 case CSSPropertyClip: // <shape> | auto | inherit
1697 if (id == CSSValueAuto)
1698 validPrimitive = true;
1699 else if (value->unit == CSSParserValue::Function)
1700 return parseClipShape(propId, important);
1701 break;
1702
1703 /* Start of supported CSS properties with validation. This is needed for par seShorthand to work
1704 * correctly and allows optimization in WebCore::applyRule(..)
1705 */
1706 case CSSPropertyOverflow: {
1707 ShorthandScope scope(this, propId);
1708 if (num != 1 || !parseValue(CSSPropertyOverflowY, important))
1709 return false;
1710
1711 RefPtrWillBeRawPtr<CSSValue> overflowXValue;
1712
1713 // FIXME: -webkit-paged-x or -webkit-paged-y only apply to overflow-y. I f this value has been
1714 // set using the shorthand, then for now overflow-x will default to auto , but once we implement
1715 // pagination controls, it should default to hidden. If the overflow-y v alue is anything but
1716 // paged-x or paged-y, then overflow-x and overflow-y should have the sa me value.
1717 if (id == CSSValueWebkitPagedX || id == CSSValueWebkitPagedY)
1718 overflowXValue = cssValuePool().createIdentifierValue(CSSValueAuto);
1719 else
1720 overflowXValue = m_parsedProperties.last().value();
1721 addProperty(CSSPropertyOverflowX, overflowXValue.release(), important);
1722 return true;
1723 }
1724
1725 case CSSPropertyTextAlign:
1726 // left | right | center | justify | -webkit-left | -webkit-right | -web kit-center | -webkit-match-parent
1727 // | start | end | <string> | inherit | -webkit-auto (converted to start )
1728 if ((id >= CSSValueWebkitAuto && id <= CSSValueWebkitMatchParent) || id == CSSValueStart || id == CSSValueEnd
1729 || value->unit == CSSPrimitiveValue::CSS_STRING)
1730 validPrimitive = true;
1731 break;
1732
1733 case CSSPropertyFontWeight: { // normal | bold | bolder | lighter | 100 | 2 00 | 300 | 400 | 500 | 600 | 700 | 800 | 900 | inherit
1734 if (m_valueList->size() != 1)
1735 return false;
1736 return parseFontWeight(important);
1737 }
1738 case CSSPropertyBorderSpacing: {
1739 if (num == 1) {
1740 ShorthandScope scope(this, CSSPropertyBorderSpacing);
1741 if (!parseValue(CSSPropertyWebkitBorderHorizontalSpacing, important) )
1742 return false;
1743 CSSValue* value = m_parsedProperties.last().value();
1744 addProperty(CSSPropertyWebkitBorderVerticalSpacing, value, important );
1745 return true;
1746 }
1747 else if (num == 2) {
1748 ShorthandScope scope(this, CSSPropertyBorderSpacing);
1749 if (!parseValue(CSSPropertyWebkitBorderHorizontalSpacing, important) || !parseValue(CSSPropertyWebkitBorderVerticalSpacing, important))
1750 return false;
1751 return true;
1752 }
1753 return false;
1754 }
1755 case CSSPropertyWebkitBorderHorizontalSpacing:
1756 case CSSPropertyWebkitBorderVerticalSpacing:
1757 validPrimitive = validUnit(value, FLength | FNonNeg);
1758 break;
1759 case CSSPropertyOutlineColor: // <color> | invert | inherit
1760 // Outline color has "invert" as additional keyword.
1761 // Also, we want to allow the special focus color even in HTML Standard parsing mode.
1762 if (id == CSSValueInvert || id == CSSValueWebkitFocusRingColor) {
1763 validPrimitive = true;
1764 break;
1765 }
1766 /* nobreak */
1767 case CSSPropertyBackgroundColor: // <color> | inherit
1768 case CSSPropertyBorderTopColor: // <color> | inherit
1769 case CSSPropertyBorderRightColor:
1770 case CSSPropertyBorderBottomColor:
1771 case CSSPropertyBorderLeftColor:
1772 case CSSPropertyWebkitBorderStartColor:
1773 case CSSPropertyWebkitBorderEndColor:
1774 case CSSPropertyWebkitBorderBeforeColor:
1775 case CSSPropertyWebkitBorderAfterColor:
1776 case CSSPropertyColor: // <color> | inherit
1777 case CSSPropertyTextDecorationColor: // CSS3 text decoration colors
1778 case CSSPropertyTextLineThroughColor:
1779 case CSSPropertyTextUnderlineColor:
1780 case CSSPropertyTextOverlineColor:
1781 case CSSPropertyWebkitColumnRuleColor:
1782 case CSSPropertyWebkitTextEmphasisColor:
1783 case CSSPropertyWebkitTextFillColor:
1784 case CSSPropertyWebkitTextStrokeColor:
1785 if (propId == CSSPropertyTextDecorationColor
1786 && !RuntimeEnabledFeatures::css3TextDecorationsEnabled())
1787 return false;
1788
1789 if ((id >= CSSValueAqua && id <= CSSValueWebkitText) || id == CSSValueMe nu) {
1790 validPrimitive = isValueAllowedInMode(id, m_context.mode());
1791 } else {
1792 parsedValue = parseColor();
1793 if (parsedValue)
1794 m_valueList->next();
1795 }
1796 break;
1797
1798 case CSSPropertyCursor: {
1799 // Grammar defined by CSS3 UI and modified by CSS4 images:
1800 // [ [<image> [<x> <y>]?,]*
1801 // [ auto | crosshair | default | pointer | progress | move | e-resize | ne-resize |
1802 // nw-resize | n-resize | se-resize | sw-resize | s-resize | w-resize | ew-resize |
1803 // ns-resize | nesw-resize | nwse-resize | col-resize | row-resize | tex t | wait | help |
1804 // vertical-text | cell | context-menu | alias | copy | no-drop | not-al lowed | -webkit-zoom-in
1805 // -webkit-zoom-out | all-scroll | -webkit-grab | -webkit-grabbing ] ] | inherit
1806 RefPtrWillBeRawPtr<CSSValueList> list;
1807 while (value) {
1808 RefPtrWillBeRawPtr<CSSValue> image = nullptr;
1809 if (value->unit == CSSPrimitiveValue::CSS_URI) {
1810 String uri = value->string;
1811 if (!uri.isNull())
1812 image = CSSImageValue::create(uri, completeURL(uri));
1813 } else if (value->unit == CSSParserValue::Function && equalIgnoringC ase(value->function->name, "-webkit-image-set(")) {
1814 image = parseImageSet(m_valueList.get());
1815 if (!image)
1816 break;
1817 } else
1818 break;
1819
1820 Vector<int> coords;
1821 value = m_valueList->next();
1822 while (value && value->unit == CSSPrimitiveValue::CSS_NUMBER) {
1823 coords.append(int(value->fValue));
1824 value = m_valueList->next();
1825 }
1826 bool hasHotSpot = false;
1827 IntPoint hotSpot(-1, -1);
1828 int nrcoords = coords.size();
1829 if (nrcoords > 0 && nrcoords != 2)
1830 return false;
1831 if (nrcoords == 2) {
1832 hasHotSpot = true;
1833 hotSpot = IntPoint(coords[0], coords[1]);
1834 }
1835
1836 if (!list)
1837 list = CSSValueList::createCommaSeparated();
1838
1839 if (image)
1840 list->append(CSSCursorImageValue::create(image, hasHotSpot, hotS pot));
1841
1842 if (!value || !(value->unit == CSSParserValue::Operator && value->iV alue == ','))
1843 return false;
1844 value = m_valueList->next(); // comma
1845 }
1846 if (list) {
1847 if (!value)
1848 return false;
1849 if (inQuirksMode() && value->id == CSSValueHand) // MSIE 5 compatibi lity :/
1850 list->append(cssValuePool().createIdentifierValue(CSSValuePointe r));
1851 else if ((value->id >= CSSValueAuto && value->id <= CSSValueWebkitGr abbing) || value->id == CSSValueCopy || value->id == CSSValueNone)
1852 list->append(cssValuePool().createIdentifierValue(value->id));
1853 m_valueList->next();
1854 parsedValue = list.release();
1855 break;
1856 } else if (value) {
1857 id = value->id;
1858 if (inQuirksMode() && value->id == CSSValueHand) { // MSIE 5 compati bility :/
1859 id = CSSValuePointer;
1860 validPrimitive = true;
1861 } else if ((value->id >= CSSValueAuto && value->id <= CSSValueWebkit Grabbing) || value->id == CSSValueCopy || value->id == CSSValueNone)
1862 validPrimitive = true;
1863 } else {
1864 ASSERT_NOT_REACHED();
1865 return false;
1866 }
1867 break;
1868 }
1869
1870 case CSSPropertyBackgroundBlendMode:
1871 case CSSPropertyBackgroundAttachment:
1872 case CSSPropertyBackgroundClip:
1873 case CSSPropertyWebkitBackgroundClip:
1874 case CSSPropertyWebkitBackgroundComposite:
1875 case CSSPropertyBackgroundImage:
1876 case CSSPropertyBackgroundOrigin:
1877 case CSSPropertyMaskSourceType:
1878 case CSSPropertyWebkitBackgroundOrigin:
1879 case CSSPropertyBackgroundPosition:
1880 case CSSPropertyBackgroundPositionX:
1881 case CSSPropertyBackgroundPositionY:
1882 case CSSPropertyBackgroundSize:
1883 case CSSPropertyWebkitBackgroundSize:
1884 case CSSPropertyBackgroundRepeat:
1885 case CSSPropertyBackgroundRepeatX:
1886 case CSSPropertyBackgroundRepeatY:
1887 case CSSPropertyWebkitMaskClip:
1888 case CSSPropertyWebkitMaskComposite:
1889 case CSSPropertyWebkitMaskImage:
1890 case CSSPropertyWebkitMaskOrigin:
1891 case CSSPropertyWebkitMaskPosition:
1892 case CSSPropertyWebkitMaskPositionX:
1893 case CSSPropertyWebkitMaskPositionY:
1894 case CSSPropertyWebkitMaskSize:
1895 case CSSPropertyWebkitMaskRepeat:
1896 case CSSPropertyWebkitMaskRepeatX:
1897 case CSSPropertyWebkitMaskRepeatY:
1898 {
1899 RefPtrWillBeRawPtr<CSSValue> val1;
1900 RefPtrWillBeRawPtr<CSSValue> val2;
1901 CSSPropertyID propId1, propId2;
1902 bool result = false;
1903 if (parseFillProperty(propId, propId1, propId2, val1, val2)) {
1904 OwnPtr<ShorthandScope> shorthandScope;
1905 if (propId == CSSPropertyBackgroundPosition ||
1906 propId == CSSPropertyBackgroundRepeat ||
1907 propId == CSSPropertyWebkitMaskPosition ||
1908 propId == CSSPropertyWebkitMaskRepeat) {
1909 shorthandScope = adoptPtr(new ShorthandScope(this, propId));
1910 }
1911 addProperty(propId1, val1.release(), important);
1912 if (val2)
1913 addProperty(propId2, val2.release(), important);
1914 result = true;
1915 }
1916 m_implicitShorthand = false;
1917 return result;
1918 }
1919 case CSSPropertyObjectPosition:
1920 return RuntimeEnabledFeatures::objectFitPositionEnabled() && parseObject Position(important);
1921 case CSSPropertyListStyleImage: // <uri> | none | inherit
1922 case CSSPropertyBorderImageSource:
1923 case CSSPropertyWebkitMaskBoxImageSource:
1924 if (id == CSSValueNone) {
1925 parsedValue = cssValuePool().createIdentifierValue(CSSValueNone);
1926 m_valueList->next();
1927 } else if (value->unit == CSSPrimitiveValue::CSS_URI) {
1928 parsedValue = CSSImageValue::create(value->string, completeURL(value ->string));
1929 m_valueList->next();
1930 } else if (isGeneratedImageValue(value)) {
1931 if (parseGeneratedImage(m_valueList.get(), parsedValue))
1932 m_valueList->next();
1933 else
1934 return false;
1935 }
1936 else if (value->unit == CSSParserValue::Function && equalIgnoringCase(va lue->function->name, "-webkit-image-set(")) {
1937 parsedValue = parseImageSet(m_valueList.get());
1938 if (!parsedValue)
1939 return false;
1940 m_valueList->next();
1941 }
1942 break;
1943
1944 case CSSPropertyWebkitTextStrokeWidth:
1945 case CSSPropertyOutlineWidth: // <border-width> | inherit
1946 case CSSPropertyBorderTopWidth: //// <border-width> | inherit
1947 case CSSPropertyBorderRightWidth: // Which is defined as
1948 case CSSPropertyBorderBottomWidth: // thin | medium | thick | <length>
1949 case CSSPropertyBorderLeftWidth:
1950 case CSSPropertyWebkitBorderStartWidth:
1951 case CSSPropertyWebkitBorderEndWidth:
1952 case CSSPropertyWebkitBorderBeforeWidth:
1953 case CSSPropertyWebkitBorderAfterWidth:
1954 case CSSPropertyWebkitColumnRuleWidth:
1955 if (id == CSSValueThin || id == CSSValueMedium || id == CSSValueThick)
1956 validPrimitive = true;
1957 else
1958 validPrimitive = validUnit(value, FLength | FNonNeg);
1959 break;
1960
1961 case CSSPropertyLetterSpacing: // normal | <length> | inherit
1962 case CSSPropertyWordSpacing: // normal | <length> | inherit
1963 if (id == CSSValueNormal)
1964 validPrimitive = true;
1965 else
1966 validPrimitive = validUnit(value, FLength);
1967 break;
1968
1969 case CSSPropertyTextIndent:
1970 parsedValue = parseTextIndent();
1971 break;
1972
1973 case CSSPropertyPaddingTop: //// <padding-width> | inherit
1974 case CSSPropertyPaddingRight: // Which is defined as
1975 case CSSPropertyPaddingBottom: // <length> | <percentage>
1976 case CSSPropertyPaddingLeft: ////
1977 case CSSPropertyWebkitPaddingStart:
1978 case CSSPropertyWebkitPaddingEnd:
1979 case CSSPropertyWebkitPaddingBefore:
1980 case CSSPropertyWebkitPaddingAfter:
1981 validPrimitive = (!id && validUnit(value, FLength | FPercent | FNonNeg)) ;
1982 break;
1983
1984 case CSSPropertyMaxWidth:
1985 case CSSPropertyWebkitMaxLogicalWidth:
1986 case CSSPropertyMaxHeight:
1987 case CSSPropertyWebkitMaxLogicalHeight:
1988 validPrimitive = (id == CSSValueNone || validWidthOrHeight(value));
1989 break;
1990
1991 case CSSPropertyMinWidth:
1992 case CSSPropertyWebkitMinLogicalWidth:
1993 case CSSPropertyMinHeight:
1994 case CSSPropertyWebkitMinLogicalHeight:
1995 validPrimitive = validWidthOrHeight(value);
1996 break;
1997
1998 case CSSPropertyWidth:
1999 case CSSPropertyWebkitLogicalWidth:
2000 case CSSPropertyHeight:
2001 case CSSPropertyWebkitLogicalHeight:
2002 validPrimitive = (id == CSSValueAuto || validWidthOrHeight(value));
2003 break;
2004
2005 case CSSPropertyFontSize:
2006 return parseFontSize(important);
2007
2008 case CSSPropertyFontVariant: // normal | small-caps | inherit
2009 return parseFontVariant(important);
2010
2011 case CSSPropertyVerticalAlign:
2012 // baseline | sub | super | top | text-top | middle | bottom | text-bott om |
2013 // <percentage> | <length> | inherit
2014
2015 if (id >= CSSValueBaseline && id <= CSSValueWebkitBaselineMiddle)
2016 validPrimitive = true;
2017 else
2018 validPrimitive = (!id && validUnit(value, FLength | FPercent));
2019 break;
2020
2021 case CSSPropertyBottom: // <length> | <percentage> | auto | in herit
2022 case CSSPropertyLeft: // <length> | <percentage> | auto | in herit
2023 case CSSPropertyRight: // <length> | <percentage> | auto | in herit
2024 case CSSPropertyTop: // <length> | <percentage> | auto | in herit
2025 case CSSPropertyMarginTop: //// <margin-width> | inherit
2026 case CSSPropertyMarginRight: // Which is defined as
2027 case CSSPropertyMarginBottom: // <length> | <percentage> | auto | i nherit
2028 case CSSPropertyMarginLeft: ////
2029 case CSSPropertyWebkitMarginStart:
2030 case CSSPropertyWebkitMarginEnd:
2031 case CSSPropertyWebkitMarginBefore:
2032 case CSSPropertyWebkitMarginAfter:
2033 if (id == CSSValueAuto)
2034 validPrimitive = true;
2035 else
2036 validPrimitive = (!id && validUnit(value, FLength | FPercent));
2037 break;
2038
2039 case CSSPropertyOrphans: // <integer> | inherit | auto (We've added support for auto for backwards compatibility)
2040 case CSSPropertyWidows: // <integer> | inherit | auto (Ditto)
2041 if (id == CSSValueAuto)
2042 validPrimitive = true;
2043 else
2044 validPrimitive = (!id && validUnit(value, FPositiveInteger, HTMLQuir ksMode));
2045 break;
2046
2047 case CSSPropertyZIndex: // auto | <integer> | inherit
2048 if (id == CSSValueAuto)
2049 validPrimitive = true;
2050 else
2051 validPrimitive = (!id && validUnit(value, FInteger, HTMLQuirksMode)) ;
2052 break;
2053
2054 case CSSPropertyLineHeight:
2055 return parseLineHeight(important);
2056 case CSSPropertyCounterIncrement: // [ <identifier> <integer>? ]+ | none | inherit
2057 if (id != CSSValueNone)
2058 return parseCounter(propId, 1, important);
2059 validPrimitive = true;
2060 break;
2061 case CSSPropertyCounterReset: // [ <identifier> <integer>? ]+ | none | inherit
2062 if (id != CSSValueNone)
2063 return parseCounter(propId, 0, important);
2064 validPrimitive = true;
2065 break;
2066 case CSSPropertyFontFamily:
2067 // [[ <family-name> | <generic-family> ],]* [<family-name> | <generic-fa mily>] | inherit
2068 {
2069 parsedValue = parseFontFamily();
2070 break;
2071 }
2072
2073 case CSSPropertyTextDecoration:
2074 // Fall through 'text-decoration-line' parsing if CSS 3 Text Decoration
2075 // is disabled to match CSS 2.1 rules for parsing 'text-decoration'.
2076 if (RuntimeEnabledFeatures::css3TextDecorationsEnabled()) {
2077 // [ <text-decoration-line> || <text-decoration-style> || <text-deco ration-color> ] | inherit
2078 return parseShorthand(CSSPropertyTextDecoration, textDecorationShort hand(), important);
2079 }
2080 case CSSPropertyWebkitTextDecorationsInEffect:
2081 case CSSPropertyTextDecorationLine:
2082 // none | [ underline || overline || line-through || blink ] | inherit
2083 return parseTextDecoration(propId, important);
2084
2085 case CSSPropertyTextDecorationStyle:
2086 // solid | double | dotted | dashed | wavy
2087 if (RuntimeEnabledFeatures::css3TextDecorationsEnabled()
2088 && (id == CSSValueSolid || id == CSSValueDouble || id == CSSValueDot ted || id == CSSValueDashed || id == CSSValueWavy))
2089 validPrimitive = true;
2090 break;
2091
2092 case CSSPropertyTextUnderlinePosition:
2093 // auto | under | inherit
2094 if (RuntimeEnabledFeatures::css3TextDecorationsEnabled())
2095 return parseTextUnderlinePosition(important);
2096 return false;
2097
2098 case CSSPropertyZoom: // normal | reset | document | <number> | <pe rcentage> | inherit
2099 if (id == CSSValueNormal || id == CSSValueReset || id == CSSValueDocumen t)
2100 validPrimitive = true;
2101 else
2102 validPrimitive = (!id && validUnit(value, FNumber | FPercent | FNonN eg, HTMLStandardMode));
2103 break;
2104
2105 case CSSPropertySrc: // Only used within @font-face and @-webkit-filter, so cannot use inherit | initial or be !important. This is a list of urls or local r eferences.
2106 return parseFontFaceSrc();
2107
2108 case CSSPropertyUnicodeRange:
2109 return parseFontFaceUnicodeRange();
2110
2111 /* CSS3 properties */
2112
2113 case CSSPropertyBorderImage:
2114 case CSSPropertyWebkitMaskBoxImage:
2115 return parseBorderImageShorthand(propId, important);
2116 case CSSPropertyWebkitBorderImage: {
2117 if (RefPtrWillBeRawPtr<CSSValue> result = parseBorderImage(propId)) {
2118 addProperty(propId, result, important);
2119 return true;
2120 }
2121 return false;
2122 }
2123
2124 case CSSPropertyBorderImageOutset:
2125 case CSSPropertyWebkitMaskBoxImageOutset: {
2126 RefPtrWillBeRawPtr<CSSPrimitiveValue> result;
2127 if (parseBorderImageOutset(result)) {
2128 addProperty(propId, result, important);
2129 return true;
2130 }
2131 break;
2132 }
2133 case CSSPropertyBorderImageRepeat:
2134 case CSSPropertyWebkitMaskBoxImageRepeat: {
2135 RefPtrWillBeRawPtr<CSSValue> result;
2136 if (parseBorderImageRepeat(result)) {
2137 addProperty(propId, result, important);
2138 return true;
2139 }
2140 break;
2141 }
2142 case CSSPropertyBorderImageSlice:
2143 case CSSPropertyWebkitMaskBoxImageSlice: {
2144 RefPtrWillBeRawPtr<CSSBorderImageSliceValue> result;
2145 if (parseBorderImageSlice(propId, result)) {
2146 addProperty(propId, result, important);
2147 return true;
2148 }
2149 break;
2150 }
2151 case CSSPropertyBorderImageWidth:
2152 case CSSPropertyWebkitMaskBoxImageWidth: {
2153 RefPtrWillBeRawPtr<CSSPrimitiveValue> result;
2154 if (parseBorderImageWidth(result)) {
2155 addProperty(propId, result, important);
2156 return true;
2157 }
2158 break;
2159 }
2160 case CSSPropertyBorderTopRightRadius:
2161 case CSSPropertyBorderTopLeftRadius:
2162 case CSSPropertyBorderBottomLeftRadius:
2163 case CSSPropertyBorderBottomRightRadius: {
2164 if (num != 1 && num != 2)
2165 return false;
2166 validPrimitive = validUnit(value, FLength | FPercent | FNonNeg);
2167 if (!validPrimitive)
2168 return false;
2169 RefPtrWillBeRawPtr<CSSPrimitiveValue> parsedValue1 = createPrimitiveNume ricValue(value);
2170 RefPtrWillBeRawPtr<CSSPrimitiveValue> parsedValue2;
2171 if (num == 2) {
2172 value = m_valueList->next();
2173 validPrimitive = validUnit(value, FLength | FPercent | FNonNeg);
2174 if (!validPrimitive)
2175 return false;
2176 parsedValue2 = createPrimitiveNumericValue(value);
2177 } else
2178 parsedValue2 = parsedValue1;
2179
2180 addProperty(propId, createPrimitiveValuePair(parsedValue1.release(), par sedValue2.release()), important);
2181 return true;
2182 }
2183 case CSSPropertyTabSize:
2184 validPrimitive = validUnit(value, FInteger | FNonNeg);
2185 break;
2186 case CSSPropertyWebkitAspectRatio:
2187 return parseAspectRatio(important);
2188 case CSSPropertyBorderRadius:
2189 case CSSPropertyWebkitBorderRadius:
2190 return parseBorderRadius(propId, important);
2191 case CSSPropertyOutlineOffset:
2192 validPrimitive = validUnit(value, FLength);
2193 break;
2194 case CSSPropertyTextShadow: // CSS2 property, dropped in CSS2.1, back in CSS 3, so treat as CSS3
2195 case CSSPropertyBoxShadow:
2196 case CSSPropertyWebkitBoxShadow:
2197 if (id == CSSValueNone)
2198 validPrimitive = true;
2199 else {
2200 RefPtrWillBeRawPtr<CSSValueList> shadowValueList = parseShadow(m_val ueList.get(), propId);
2201 if (shadowValueList) {
2202 addProperty(propId, shadowValueList.release(), important);
2203 m_valueList->next();
2204 return true;
2205 }
2206 return false;
2207 }
2208 break;
2209 case CSSPropertyWebkitBoxReflect:
2210 if (id == CSSValueNone)
2211 validPrimitive = true;
2212 else
2213 return parseReflect(propId, important);
2214 break;
2215 case CSSPropertyOpacity:
2216 validPrimitive = validUnit(value, FNumber);
2217 break;
2218 case CSSPropertyWebkitBoxFlex:
2219 validPrimitive = validUnit(value, FNumber);
2220 break;
2221 case CSSPropertyWebkitBoxFlexGroup:
2222 validPrimitive = validUnit(value, FInteger | FNonNeg, HTMLStandardMode);
2223 break;
2224 case CSSPropertyWebkitBoxOrdinalGroup:
2225 validPrimitive = validUnit(value, FInteger | FNonNeg, HTMLStandardMode) && value->fValue;
2226 break;
2227 case CSSPropertyWebkitFilter:
2228 if (id == CSSValueNone)
2229 validPrimitive = true;
2230 else {
2231 RefPtrWillBeRawPtr<CSSValue> val = parseFilter();
2232 if (val) {
2233 addProperty(propId, val, important);
2234 return true;
2235 }
2236 return false;
2237 }
2238 break;
2239 case CSSPropertyFlex: {
2240 ShorthandScope scope(this, propId);
2241 if (id == CSSValueNone) {
2242 addProperty(CSSPropertyFlexGrow, cssValuePool().createValue(0, CSSPr imitiveValue::CSS_NUMBER), important);
2243 addProperty(CSSPropertyFlexShrink, cssValuePool().createValue(0, CSS PrimitiveValue::CSS_NUMBER), important);
2244 addProperty(CSSPropertyFlexBasis, cssValuePool().createIdentifierVal ue(CSSValueAuto), important);
2245 return true;
2246 }
2247 return parseFlex(m_valueList.get(), important);
2248 }
2249 case CSSPropertyFlexBasis:
2250 // FIXME: Support intrinsic dimensions too.
2251 if (id == CSSValueAuto)
2252 validPrimitive = true;
2253 else
2254 validPrimitive = (!id && validUnit(value, FLength | FPercent | FNonN eg));
2255 break;
2256 case CSSPropertyFlexGrow:
2257 case CSSPropertyFlexShrink:
2258 validPrimitive = validUnit(value, FNumber | FNonNeg);
2259 break;
2260 case CSSPropertyOrder:
2261 validPrimitive = validUnit(value, FInteger, HTMLStandardMode);
2262 break;
2263 case CSSPropertyInternalMarqueeIncrement:
2264 if (id == CSSValueSmall || id == CSSValueLarge || id == CSSValueMedium)
2265 validPrimitive = true;
2266 else
2267 validPrimitive = validUnit(value, FLength | FPercent);
2268 break;
2269 case CSSPropertyInternalMarqueeRepetition:
2270 if (id == CSSValueInfinite)
2271 validPrimitive = true;
2272 else
2273 validPrimitive = validUnit(value, FInteger | FNonNeg);
2274 break;
2275 case CSSPropertyInternalMarqueeSpeed:
2276 if (id == CSSValueNormal || id == CSSValueSlow || id == CSSValueFast)
2277 validPrimitive = true;
2278 else
2279 validPrimitive = validUnit(value, FTime | FInteger | FNonNeg);
2280 break;
2281 case CSSPropertyWebkitTransform:
2282 if (id == CSSValueNone)
2283 validPrimitive = true;
2284 else {
2285 RefPtrWillBeRawPtr<CSSValue> transformValue = parseTransform();
2286 if (transformValue) {
2287 addProperty(propId, transformValue.release(), important);
2288 return true;
2289 }
2290 return false;
2291 }
2292 break;
2293 case CSSPropertyWebkitTransformOrigin:
2294 case CSSPropertyWebkitTransformOriginX:
2295 case CSSPropertyWebkitTransformOriginY:
2296 case CSSPropertyWebkitTransformOriginZ: {
2297 RefPtrWillBeRawPtr<CSSValue> val1;
2298 RefPtrWillBeRawPtr<CSSValue> val2;
2299 RefPtrWillBeRawPtr<CSSValue> val3;
2300 CSSPropertyID propId1, propId2, propId3;
2301 if (parseTransformOrigin(propId, propId1, propId2, propId3, val1, val2, val3)) {
2302 addProperty(propId1, val1.release(), important);
2303 if (val2)
2304 addProperty(propId2, val2.release(), important);
2305 if (val3)
2306 addProperty(propId3, val3.release(), important);
2307 return true;
2308 }
2309 return false;
2310 }
2311 case CSSPropertyWebkitPerspective:
2312 if (id == CSSValueNone)
2313 validPrimitive = true;
2314 else {
2315 // Accepting valueless numbers is a quirk of the -webkit prefixed ve rsion of the property.
2316 if (validUnit(value, FNumber | FLength | FNonNeg)) {
2317 RefPtrWillBeRawPtr<CSSValue> val = createPrimitiveNumericValue(v alue);
2318 if (val) {
2319 addProperty(propId, val.release(), important);
2320 return true;
2321 }
2322 return false;
2323 }
2324 }
2325 break;
2326 case CSSPropertyWebkitPerspectiveOrigin:
2327 case CSSPropertyWebkitPerspectiveOriginX:
2328 case CSSPropertyWebkitPerspectiveOriginY: {
2329 RefPtrWillBeRawPtr<CSSValue> val1;
2330 RefPtrWillBeRawPtr<CSSValue> val2;
2331 CSSPropertyID propId1, propId2;
2332 if (parsePerspectiveOrigin(propId, propId1, propId2, val1, val2)) {
2333 addProperty(propId1, val1.release(), important);
2334 if (val2)
2335 addProperty(propId2, val2.release(), important);
2336 return true;
2337 }
2338 return false;
2339 }
2340 case CSSPropertyAnimationDelay:
2341 case CSSPropertyAnimationDirection:
2342 case CSSPropertyAnimationDuration:
2343 case CSSPropertyAnimationFillMode:
2344 case CSSPropertyAnimationName:
2345 case CSSPropertyAnimationPlayState:
2346 case CSSPropertyAnimationIterationCount:
2347 case CSSPropertyAnimationTimingFunction:
2348 if (!RuntimeEnabledFeatures::cssAnimationUnprefixedEnabled())
2349 break;
2350 case CSSPropertyWebkitAnimationDelay:
2351 case CSSPropertyWebkitAnimationDirection:
2352 case CSSPropertyWebkitAnimationDuration:
2353 case CSSPropertyWebkitAnimationFillMode:
2354 case CSSPropertyWebkitAnimationName:
2355 case CSSPropertyWebkitAnimationPlayState:
2356 case CSSPropertyWebkitAnimationIterationCount:
2357 case CSSPropertyWebkitAnimationTimingFunction:
2358 case CSSPropertyTransitionDelay:
2359 case CSSPropertyTransitionDuration:
2360 case CSSPropertyTransitionTimingFunction:
2361 case CSSPropertyTransitionProperty:
2362 case CSSPropertyWebkitTransitionDelay:
2363 case CSSPropertyWebkitTransitionDuration:
2364 case CSSPropertyWebkitTransitionTimingFunction:
2365 case CSSPropertyWebkitTransitionProperty: {
2366 RefPtrWillBeRawPtr<CSSValue> val;
2367 AnimationParseContext context;
2368 if (parseAnimationProperty(propId, val, context)) {
2369 addPropertyWithPrefixingVariant(propId, val.release(), important);
2370 return true;
2371 }
2372 return false;
2373 }
2374
2375 case CSSPropertyJustifySelf:
2376 if (!RuntimeEnabledFeatures::cssGridLayoutEnabled())
2377 return false;
2378
2379 return parseItemPositionOverflowPosition(propId, important);
2380 case CSSPropertyGridAutoColumns:
2381 case CSSPropertyGridAutoRows:
2382 if (!RuntimeEnabledFeatures::cssGridLayoutEnabled())
2383 return false;
2384 parsedValue = parseGridTrackSize(*m_valueList);
2385 break;
2386
2387 case CSSPropertyGridTemplateColumns:
2388 case CSSPropertyGridTemplateRows:
2389 if (!RuntimeEnabledFeatures::cssGridLayoutEnabled())
2390 return false;
2391 return parseGridTrackList(propId, important);
2392
2393 case CSSPropertyGridColumnEnd:
2394 case CSSPropertyGridColumnStart:
2395 case CSSPropertyGridRowEnd:
2396 case CSSPropertyGridRowStart:
2397 if (!RuntimeEnabledFeatures::cssGridLayoutEnabled())
2398 return false;
2399 parsedValue = parseGridPosition();
2400 break;
2401
2402 case CSSPropertyGridColumn:
2403 case CSSPropertyGridRow:
2404 if (!RuntimeEnabledFeatures::cssGridLayoutEnabled())
2405 return false;
2406 return parseGridItemPositionShorthand(propId, important);
2407
2408 case CSSPropertyGridArea:
2409 if (!RuntimeEnabledFeatures::cssGridLayoutEnabled())
2410 return false;
2411 return parseGridAreaShorthand(important);
2412
2413 case CSSPropertyGridTemplateAreas:
2414 if (!RuntimeEnabledFeatures::cssGridLayoutEnabled())
2415 return false;
2416 parsedValue = parseGridTemplateAreas();
2417 break;
2418
2419 case CSSPropertyWebkitMarginCollapse: {
2420 if (num == 1) {
2421 ShorthandScope scope(this, CSSPropertyWebkitMarginCollapse);
2422 if (!parseValue(webkitMarginCollapseShorthand().properties()[0], imp ortant))
2423 return false;
2424 CSSValue* value = m_parsedProperties.last().value();
2425 addProperty(webkitMarginCollapseShorthand().properties()[1], value, important);
2426 return true;
2427 }
2428 else if (num == 2) {
2429 ShorthandScope scope(this, CSSPropertyWebkitMarginCollapse);
2430 if (!parseValue(webkitMarginCollapseShorthand().properties()[0], imp ortant) || !parseValue(webkitMarginCollapseShorthand().properties()[1], importan t))
2431 return false;
2432 return true;
2433 }
2434 return false;
2435 }
2436 case CSSPropertyTextLineThroughWidth:
2437 case CSSPropertyTextOverlineWidth:
2438 case CSSPropertyTextUnderlineWidth:
2439 if (id == CSSValueAuto || id == CSSValueNormal || id == CSSValueThin ||
2440 id == CSSValueMedium || id == CSSValueThick)
2441 validPrimitive = true;
2442 else
2443 validPrimitive = !id && validUnit(value, FNumber | FLength | FPercen t);
2444 break;
2445 case CSSPropertyWebkitColumnCount:
2446 parsedValue = parseColumnCount();
2447 break;
2448 case CSSPropertyWebkitColumnGap: // normal | <length>
2449 if (id == CSSValueNormal)
2450 validPrimitive = true;
2451 else
2452 validPrimitive = validUnit(value, FLength | FNonNeg);
2453 break;
2454 case CSSPropertyWebkitColumnAxis:
2455 if (id == CSSValueHorizontal || id == CSSValueVertical || id == CSSValue Auto)
2456 validPrimitive = true;
2457 break;
2458 case CSSPropertyWebkitColumnProgression:
2459 if (id == CSSValueNormal || id == CSSValueReverse)
2460 validPrimitive = true;
2461 break;
2462 case CSSPropertyWebkitColumnSpan: // none | all | 1 (will be dropped in the unprefixed property)
2463 if (id == CSSValueAll || id == CSSValueNone)
2464 validPrimitive = true;
2465 else
2466 validPrimitive = validUnit(value, FNumber | FNonNeg) && value->fValu e == 1;
2467 break;
2468 case CSSPropertyWebkitColumnWidth: // auto | <length>
2469 parsedValue = parseColumnWidth();
2470 break;
2471 case CSSPropertyWillChange:
2472 if (!RuntimeEnabledFeatures::cssWillChangeEnabled())
2473 return false;
2474 return parseWillChange(important);
2475 // End of CSS3 properties
2476
2477 // Apple specific properties. These will never be standardized and are pure ly to
2478 // support custom WebKit-based Apple applications.
2479 case CSSPropertyWebkitLineClamp:
2480 // When specifying number of lines, don't allow 0 as a valid value
2481 // When specifying either type of unit, require non-negative integers
2482 validPrimitive = (!id && (value->unit == CSSPrimitiveValue::CSS_PERCENTA GE || value->fValue) && validUnit(value, FInteger | FPercent | FNonNeg, HTMLQuir ksMode));
2483 break;
2484
2485 case CSSPropertyWebkitFontSizeDelta: // <length>
2486 validPrimitive = validUnit(value, FLength);
2487 break;
2488
2489 case CSSPropertyWebkitHighlight:
2490 if (id == CSSValueNone || value->unit == CSSPrimitiveValue::CSS_STRING)
2491 validPrimitive = true;
2492 break;
2493
2494 case CSSPropertyWebkitHyphenateCharacter:
2495 if (id == CSSValueAuto || value->unit == CSSPrimitiveValue::CSS_STRING)
2496 validPrimitive = true;
2497 break;
2498
2499 case CSSPropertyWebkitLocale:
2500 if (id == CSSValueAuto || value->unit == CSSPrimitiveValue::CSS_STRING)
2501 validPrimitive = true;
2502 break;
2503
2504 // End Apple-specific properties
2505
2506 case CSSPropertyWebkitAppRegion:
2507 if (id >= CSSValueDrag && id <= CSSValueNoDrag)
2508 validPrimitive = true;
2509 break;
2510
2511 case CSSPropertyWebkitTapHighlightColor:
2512 if ((id >= CSSValueAqua && id <= CSSValueWindowtext) || id == CSSValueMe nu
2513 || (id >= CSSValueWebkitFocusRingColor && id < CSSValueWebkitText && inQuirksMode())) {
2514 validPrimitive = true;
2515 } else {
2516 parsedValue = parseColor();
2517 if (parsedValue)
2518 m_valueList->next();
2519 }
2520 break;
2521
2522 /* shorthand properties */
2523 case CSSPropertyBackground: {
2524 // Position must come before color in this array because a plain old "0" is a legal color
2525 // in quirks mode but it's usually the X coordinate of a position.
2526 const CSSPropertyID properties[] = { CSSPropertyBackgroundImage, CSSProp ertyBackgroundRepeat,
2527 CSSPropertyBackgroundAttachment, CSSPropertyB ackgroundPosition, CSSPropertyBackgroundOrigin,
2528 CSSPropertyBackgroundClip, CSSPropertyBackgro undColor, CSSPropertyBackgroundSize };
2529 return parseFillShorthand(propId, properties, WTF_ARRAY_LENGTH(propertie s), important);
2530 }
2531 case CSSPropertyWebkitMask: {
2532 const CSSPropertyID properties[] = { CSSPropertyWebkitMaskImage, CSSProp ertyWebkitMaskRepeat,
2533 CSSPropertyWebkitMaskPosition, CSSPropertyWebkitMaskOrigin, CSSPrope rtyWebkitMaskClip, CSSPropertyWebkitMaskSize };
2534 return parseFillShorthand(propId, properties, WTF_ARRAY_LENGTH(propertie s), important);
2535 }
2536 case CSSPropertyBorder:
2537 // [ 'border-width' || 'border-style' || <color> ] | inherit
2538 {
2539 if (parseShorthand(propId, parsingShorthandForProperty(CSSPropertyBorder ), important)) {
2540 // The CSS3 Borders and Backgrounds specification says that border a lso resets border-image. It's as
2541 // though a value of none was specified for the image.
2542 addExpandedPropertyForValue(CSSPropertyBorderImage, cssValuePool().c reateImplicitInitialValue(), important);
2543 return true;
2544 }
2545 return false;
2546 }
2547 case CSSPropertyBorderTop:
2548 // [ 'border-top-width' || 'border-style' || <color> ] | inherit
2549 return parseShorthand(propId, borderTopShorthand(), important);
2550 case CSSPropertyBorderRight:
2551 // [ 'border-right-width' || 'border-style' || <color> ] | inherit
2552 return parseShorthand(propId, borderRightShorthand(), important);
2553 case CSSPropertyBorderBottom:
2554 // [ 'border-bottom-width' || 'border-style' || <color> ] | inherit
2555 return parseShorthand(propId, borderBottomShorthand(), important);
2556 case CSSPropertyBorderLeft:
2557 // [ 'border-left-width' || 'border-style' || <color> ] | inherit
2558 return parseShorthand(propId, borderLeftShorthand(), important);
2559 case CSSPropertyWebkitBorderStart:
2560 return parseShorthand(propId, webkitBorderStartShorthand(), important);
2561 case CSSPropertyWebkitBorderEnd:
2562 return parseShorthand(propId, webkitBorderEndShorthand(), important);
2563 case CSSPropertyWebkitBorderBefore:
2564 return parseShorthand(propId, webkitBorderBeforeShorthand(), important);
2565 case CSSPropertyWebkitBorderAfter:
2566 return parseShorthand(propId, webkitBorderAfterShorthand(), important);
2567 case CSSPropertyOutline:
2568 // [ 'outline-color' || 'outline-style' || 'outline-width' ] | inherit
2569 return parseShorthand(propId, outlineShorthand(), important);
2570 case CSSPropertyBorderColor:
2571 // <color>{1,4} | inherit
2572 return parse4Values(propId, borderColorShorthand().properties(), importa nt);
2573 case CSSPropertyBorderWidth:
2574 // <border-width>{1,4} | inherit
2575 return parse4Values(propId, borderWidthShorthand().properties(), importa nt);
2576 case CSSPropertyBorderStyle:
2577 // <border-style>{1,4} | inherit
2578 return parse4Values(propId, borderStyleShorthand().properties(), importa nt);
2579 case CSSPropertyMargin:
2580 // <margin-width>{1,4} | inherit
2581 return parse4Values(propId, marginShorthand().properties(), important);
2582 case CSSPropertyPadding:
2583 // <padding-width>{1,4} | inherit
2584 return parse4Values(propId, paddingShorthand().properties(), important);
2585 case CSSPropertyFlexFlow:
2586 return parseShorthand(propId, flexFlowShorthand(), important);
2587 case CSSPropertyFont:
2588 // [ [ 'font-style' || 'font-variant' || 'font-weight' ]? 'font-size' [ / 'line-height' ]?
2589 // 'font-family' ] | caption | icon | menu | message-box | small-caption | status-bar | inherit
2590 if (id >= CSSValueCaption && id <= CSSValueStatusBar)
2591 validPrimitive = true;
2592 else
2593 return parseFont(important);
2594 break;
2595 case CSSPropertyListStyle:
2596 return parseShorthand(propId, listStyleShorthand(), important);
2597 case CSSPropertyWebkitColumns:
2598 return parseColumnsShorthand(important);
2599 case CSSPropertyWebkitColumnRule:
2600 return parseShorthand(propId, webkitColumnRuleShorthand(), important);
2601 case CSSPropertyWebkitTextStroke:
2602 return parseShorthand(propId, webkitTextStrokeShorthand(), important);
2603 case CSSPropertyAnimation:
2604 if (!RuntimeEnabledFeatures::cssAnimationUnprefixedEnabled())
2605 break;
2606 case CSSPropertyWebkitAnimation:
2607 return parseAnimationShorthand(propId, important);
2608 case CSSPropertyTransition:
2609 case CSSPropertyWebkitTransition:
2610 return parseTransitionShorthand(propId, important);
2611 case CSSPropertyInvalid:
2612 return false;
2613 case CSSPropertyPage:
2614 return parsePage(propId, important);
2615 case CSSPropertyFontStretch:
2616 return false;
2617 // CSS Text Layout Module Level 3: Vertical writing support
2618 case CSSPropertyWebkitTextEmphasis:
2619 return parseShorthand(propId, webkitTextEmphasisShorthand(), important);
2620
2621 case CSSPropertyWebkitTextEmphasisStyle:
2622 return parseTextEmphasisStyle(important);
2623
2624 case CSSPropertyWebkitTextOrientation:
2625 // FIXME: For now just support sideways, sideways-right, upright and ver tical-right.
2626 if (id == CSSValueSideways || id == CSSValueSidewaysRight || id == CSSVa lueVerticalRight || id == CSSValueUpright)
2627 validPrimitive = true;
2628 break;
2629
2630 case CSSPropertyWebkitLineBoxContain:
2631 if (id == CSSValueNone)
2632 validPrimitive = true;
2633 else
2634 return parseLineBoxContain(important);
2635 break;
2636 case CSSPropertyWebkitFontFeatureSettings:
2637 if (id == CSSValueNormal)
2638 validPrimitive = true;
2639 else
2640 return parseFontFeatureSettings(important);
2641 break;
2642
2643 case CSSPropertyFontVariantLigatures:
2644 if (id == CSSValueNormal)
2645 validPrimitive = true;
2646 else
2647 return parseFontVariantLigatures(important);
2648 break;
2649 case CSSPropertyWebkitClipPath:
2650 if (id == CSSValueNone) {
2651 validPrimitive = true;
2652 } else if (value->unit == CSSParserValue::Function) {
2653 parsedValue = parseBasicShape();
2654 } else if (value->unit == CSSPrimitiveValue::CSS_URI) {
2655 parsedValue = CSSPrimitiveValue::create(value->string, CSSPrimitiveV alue::CSS_URI);
2656 addProperty(propId, parsedValue.release(), important);
2657 return true;
2658 }
2659 break;
2660 case CSSPropertyShapeInside:
2661 case CSSPropertyShapeOutside:
2662 parsedValue = parseShapeProperty(propId);
2663 break;
2664 case CSSPropertyShapeMargin:
2665 case CSSPropertyShapePadding:
2666 validPrimitive = (RuntimeEnabledFeatures::cssShapesEnabled() && !id && v alidUnit(value, FLength | FNonNeg));
2667 break;
2668 case CSSPropertyShapeImageThreshold:
2669 validPrimitive = (RuntimeEnabledFeatures::cssShapesEnabled() && !id && v alidUnit(value, FNumber));
2670 break;
2671
2672 case CSSPropertyTouchAction:
2673 // auto | none | [pan-x || pan-y]
2674 return parseTouchAction(important);
2675
2676 case CSSPropertyAlignSelf:
2677 ASSERT(RuntimeEnabledFeatures::cssGridLayoutEnabled());
2678 return parseItemPositionOverflowPosition(propId, important);
2679
2680 case CSSPropertyAlignItems:
2681 ASSERT(RuntimeEnabledFeatures::cssGridLayoutEnabled());
2682 return parseItemPositionOverflowPosition(propId, important);
2683
2684 case CSSPropertyBorderBottomStyle:
2685 case CSSPropertyBorderCollapse:
2686 case CSSPropertyBorderLeftStyle:
2687 case CSSPropertyBorderRightStyle:
2688 case CSSPropertyBorderTopStyle:
2689 case CSSPropertyBoxSizing:
2690 case CSSPropertyCaptionSide:
2691 case CSSPropertyClear:
2692 case CSSPropertyDirection:
2693 case CSSPropertyDisplay:
2694 case CSSPropertyEmptyCells:
2695 case CSSPropertyFloat:
2696 case CSSPropertyFontStyle:
2697 case CSSPropertyImageRendering:
2698 case CSSPropertyListStylePosition:
2699 case CSSPropertyListStyleType:
2700 case CSSPropertyObjectFit:
2701 case CSSPropertyOutlineStyle:
2702 case CSSPropertyOverflowWrap:
2703 case CSSPropertyOverflowX:
2704 case CSSPropertyOverflowY:
2705 case CSSPropertyPageBreakAfter:
2706 case CSSPropertyPageBreakBefore:
2707 case CSSPropertyPageBreakInside:
2708 case CSSPropertyPointerEvents:
2709 case CSSPropertyPosition:
2710 case CSSPropertyResize:
2711 case CSSPropertySpeak:
2712 case CSSPropertyTableLayout:
2713 case CSSPropertyTextAlignLast:
2714 case CSSPropertyTextJustify:
2715 case CSSPropertyTextLineThroughMode:
2716 case CSSPropertyTextLineThroughStyle:
2717 case CSSPropertyTextOverflow:
2718 case CSSPropertyTextOverlineMode:
2719 case CSSPropertyTextOverlineStyle:
2720 case CSSPropertyTextRendering:
2721 case CSSPropertyTextTransform:
2722 case CSSPropertyTextUnderlineMode:
2723 case CSSPropertyTextUnderlineStyle:
2724 case CSSPropertyTouchActionDelay:
2725 case CSSPropertyVisibility:
2726 case CSSPropertyWebkitAppearance:
2727 case CSSPropertyWebkitBackfaceVisibility:
2728 case CSSPropertyWebkitBorderAfterStyle:
2729 case CSSPropertyWebkitBorderBeforeStyle:
2730 case CSSPropertyWebkitBorderEndStyle:
2731 case CSSPropertyWebkitBorderFit:
2732 case CSSPropertyWebkitBorderStartStyle:
2733 case CSSPropertyWebkitBoxAlign:
2734 case CSSPropertyWebkitBoxDecorationBreak:
2735 case CSSPropertyWebkitBoxDirection:
2736 case CSSPropertyWebkitBoxLines:
2737 case CSSPropertyWebkitBoxOrient:
2738 case CSSPropertyWebkitBoxPack:
2739 case CSSPropertyInternalCallback:
2740 case CSSPropertyWebkitColumnBreakAfter:
2741 case CSSPropertyWebkitColumnBreakBefore:
2742 case CSSPropertyWebkitColumnBreakInside:
2743 case CSSPropertyColumnFill:
2744 case CSSPropertyWebkitColumnRuleStyle:
2745 case CSSPropertyAlignContent:
2746 case CSSPropertyFlexDirection:
2747 case CSSPropertyFlexWrap:
2748 case CSSPropertyJustifyContent:
2749 case CSSPropertyFontKerning:
2750 case CSSPropertyWebkitFontSmoothing:
2751 case CSSPropertyGridAutoFlow:
2752 case CSSPropertyWebkitLineBreak:
2753 case CSSPropertyWebkitMarginAfterCollapse:
2754 case CSSPropertyWebkitMarginBeforeCollapse:
2755 case CSSPropertyWebkitMarginBottomCollapse:
2756 case CSSPropertyWebkitMarginTopCollapse:
2757 case CSSPropertyInternalMarqueeDirection:
2758 case CSSPropertyInternalMarqueeStyle:
2759 case CSSPropertyWebkitPrintColorAdjust:
2760 case CSSPropertyWebkitRtlOrdering:
2761 case CSSPropertyWebkitRubyPosition:
2762 case CSSPropertyWebkitTextCombine:
2763 case CSSPropertyWebkitTextEmphasisPosition:
2764 case CSSPropertyWebkitTextSecurity:
2765 case CSSPropertyWebkitTransformStyle:
2766 case CSSPropertyWebkitUserDrag:
2767 case CSSPropertyWebkitUserModify:
2768 case CSSPropertyWebkitUserSelect:
2769 case CSSPropertyWebkitWrapFlow:
2770 case CSSPropertyWebkitWrapThrough:
2771 case CSSPropertyWebkitWritingMode:
2772 case CSSPropertyWhiteSpace:
2773 case CSSPropertyWordBreak:
2774 case CSSPropertyWordWrap:
2775 case CSSPropertyMixBlendMode:
2776 case CSSPropertyIsolation:
2777 // These properties should be handled before in isValidKeywordPropertyAn dValue().
2778 ASSERT_NOT_REACHED();
2779 return false;
2780 // Properties below are validated inside parseViewportProperty, because we
2781 // check for parser state. We need to invalidate if someone adds them outsid e
2782 // a @viewport rule.
2783 case CSSPropertyMaxZoom:
2784 case CSSPropertyMinZoom:
2785 case CSSPropertyOrientation:
2786 case CSSPropertyUserZoom:
2787 validPrimitive = false;
2788 break;
2789 default:
2790 return parseSVGValue(propId, important);
2791 }
2792
2793 if (validPrimitive) {
2794 parsedValue = parseValidPrimitive(id, value);
2795 m_valueList->next();
2796 }
2797 ASSERT(!m_parsedCalculation);
2798 if (parsedValue) {
2799 if (!m_valueList->current() || inShorthand()) {
2800 addProperty(propId, parsedValue.release(), important);
2801 return true;
2802 }
2803 }
2804 return false;
2805 }
2806
2807 void CSSPropertyParser::addFillValue(RefPtrWillBeRawPtr<CSSValue>& lval, PassRef PtrWillBeRawPtr<CSSValue> rval)
2808 {
2809 if (lval) {
2810 if (lval->isBaseValueList())
2811 toCSSValueList(lval.get())->append(rval);
2812 else {
2813 PassRefPtrWillBeRawPtr<CSSValue> oldlVal(lval.release());
2814 PassRefPtrWillBeRawPtr<CSSValueList> list = CSSValueList::createComm aSeparated();
2815 list->append(oldlVal);
2816 list->append(rval);
2817 lval = list;
2818 }
2819 }
2820 else
2821 lval = rval;
2822 }
2823
2824 static bool parseBackgroundClip(CSSParserValue* parserValue, RefPtrWillBeRawPtr< CSSValue>& cssValue)
2825 {
2826 if (parserValue->id == CSSValueBorderBox || parserValue->id == CSSValuePaddi ngBox
2827 || parserValue->id == CSSValueContentBox || parserValue->id == CSSValueW ebkitText) {
2828 cssValue = cssValuePool().createIdentifierValue(parserValue->id);
2829 return true;
2830 }
2831 return false;
2832 }
2833
2834 const int cMaxFillProperties = 9;
2835
2836 bool CSSPropertyParser::parseFillShorthand(CSSPropertyID propId, const CSSProper tyID* properties, int numProperties, bool important)
2837 {
2838 ASSERT(numProperties <= cMaxFillProperties);
2839 if (numProperties > cMaxFillProperties)
2840 return false;
2841
2842 ShorthandScope scope(this, propId);
2843
2844 bool parsedProperty[cMaxFillProperties] = { false };
2845 RefPtrWillBeRawPtr<CSSValue> values[cMaxFillProperties];
2846 RefPtrWillBeRawPtr<CSSValue> clipValue;
2847 RefPtrWillBeRawPtr<CSSValue> positionYValue;
2848 RefPtrWillBeRawPtr<CSSValue> repeatYValue;
2849 bool foundClip = false;
2850 int i;
2851 bool foundPositionCSSProperty = false;
2852
2853 while (m_valueList->current()) {
2854 CSSParserValue* val = m_valueList->current();
2855 if (val->unit == CSSParserValue::Operator && val->iValue == ',') {
2856 // We hit the end. Fill in all remaining values with the initial va lue.
2857 m_valueList->next();
2858 for (i = 0; i < numProperties; ++i) {
2859 if (properties[i] == CSSPropertyBackgroundColor && parsedPropert y[i])
2860 // Color is not allowed except as the last item in a list fo r backgrounds.
2861 // Reject the entire property.
2862 return false;
2863
2864 if (!parsedProperty[i] && properties[i] != CSSPropertyBackground Color) {
2865 addFillValue(values[i], cssValuePool().createImplicitInitial Value());
2866 if (properties[i] == CSSPropertyBackgroundPosition || proper ties[i] == CSSPropertyWebkitMaskPosition)
2867 addFillValue(positionYValue, cssValuePool().createImplic itInitialValue());
2868 if (properties[i] == CSSPropertyBackgroundRepeat || properti es[i] == CSSPropertyWebkitMaskRepeat)
2869 addFillValue(repeatYValue, cssValuePool().createImplicit InitialValue());
2870 if ((properties[i] == CSSPropertyBackgroundOrigin || propert ies[i] == CSSPropertyWebkitMaskOrigin) && !parsedProperty[i]) {
2871 // If background-origin wasn't present, then reset backg round-clip also.
2872 addFillValue(clipValue, cssValuePool().createImplicitIni tialValue());
2873 }
2874 }
2875 parsedProperty[i] = false;
2876 }
2877 if (!m_valueList->current())
2878 break;
2879 }
2880
2881 bool sizeCSSPropertyExpected = false;
2882 if (isForwardSlashOperator(val) && foundPositionCSSProperty) {
2883 sizeCSSPropertyExpected = true;
2884 m_valueList->next();
2885 }
2886
2887 foundPositionCSSProperty = false;
2888 bool found = false;
2889 for (i = 0; !found && i < numProperties; ++i) {
2890
2891 if (sizeCSSPropertyExpected && (properties[i] != CSSPropertyBackgrou ndSize && properties[i] != CSSPropertyWebkitMaskSize))
2892 continue;
2893 if (!sizeCSSPropertyExpected && (properties[i] == CSSPropertyBackgro undSize || properties[i] == CSSPropertyWebkitMaskSize))
2894 continue;
2895
2896 if (!parsedProperty[i]) {
2897 RefPtrWillBeRawPtr<CSSValue> val1;
2898 RefPtrWillBeRawPtr<CSSValue> val2;
2899 CSSPropertyID propId1, propId2;
2900 CSSParserValue* parserValue = m_valueList->current();
2901 // parseFillProperty() may modify m_implicitShorthand, so we MUS T reset it
2902 // before EACH return below.
2903 if (parseFillProperty(properties[i], propId1, propId2, val1, val 2)) {
2904 parsedProperty[i] = found = true;
2905 addFillValue(values[i], val1.release());
2906 if (properties[i] == CSSPropertyBackgroundPosition || proper ties[i] == CSSPropertyWebkitMaskPosition)
2907 addFillValue(positionYValue, val2.release());
2908 if (properties[i] == CSSPropertyBackgroundRepeat || properti es[i] == CSSPropertyWebkitMaskRepeat)
2909 addFillValue(repeatYValue, val2.release());
2910 if (properties[i] == CSSPropertyBackgroundOrigin || properti es[i] == CSSPropertyWebkitMaskOrigin) {
2911 // Reparse the value as a clip, and see if we succeed.
2912 if (parseBackgroundClip(parserValue, val1))
2913 addFillValue(clipValue, val1.release()); // The prop erty parsed successfully.
2914 else
2915 addFillValue(clipValue, cssValuePool().createImplici tInitialValue()); // Some value was used for origin that is not supported by cli p. Just reset clip instead.
2916 }
2917 if (properties[i] == CSSPropertyBackgroundClip || properties [i] == CSSPropertyWebkitMaskClip) {
2918 // Update clipValue
2919 addFillValue(clipValue, val1.release());
2920 foundClip = true;
2921 }
2922 if (properties[i] == CSSPropertyBackgroundPosition || proper ties[i] == CSSPropertyWebkitMaskPosition)
2923 foundPositionCSSProperty = true;
2924 }
2925 }
2926 }
2927
2928 // if we didn't find at least one match, this is an
2929 // invalid shorthand and we have to ignore it
2930 if (!found) {
2931 m_implicitShorthand = false;
2932 return false;
2933 }
2934 }
2935
2936 // Now add all of the properties we found.
2937 for (i = 0; i < numProperties; i++) {
2938 // Fill in any remaining properties with the initial value.
2939 if (!parsedProperty[i]) {
2940 addFillValue(values[i], cssValuePool().createImplicitInitialValue()) ;
2941 if (properties[i] == CSSPropertyBackgroundPosition || properties[i] == CSSPropertyWebkitMaskPosition)
2942 addFillValue(positionYValue, cssValuePool().createImplicitInitia lValue());
2943 if (properties[i] == CSSPropertyBackgroundRepeat || properties[i] == CSSPropertyWebkitMaskRepeat)
2944 addFillValue(repeatYValue, cssValuePool().createImplicitInitialV alue());
2945 if (properties[i] == CSSPropertyBackgroundOrigin || properties[i] == CSSPropertyWebkitMaskOrigin) {
2946 // If background-origin wasn't present, then reset background-cl ip also.
2947 addFillValue(clipValue, cssValuePool().createImplicitInitialValu e());
2948 }
2949 }
2950 if (properties[i] == CSSPropertyBackgroundPosition) {
2951 addProperty(CSSPropertyBackgroundPositionX, values[i].release(), imp ortant);
2952 // it's OK to call positionYValue.release() since we only see CSSPro pertyBackgroundPosition once
2953 addProperty(CSSPropertyBackgroundPositionY, positionYValue.release() , important);
2954 } else if (properties[i] == CSSPropertyWebkitMaskPosition) {
2955 addProperty(CSSPropertyWebkitMaskPositionX, values[i].release(), imp ortant);
2956 // it's OK to call positionYValue.release() since we only see CSSPro pertyWebkitMaskPosition once
2957 addProperty(CSSPropertyWebkitMaskPositionY, positionYValue.release() , important);
2958 } else if (properties[i] == CSSPropertyBackgroundRepeat) {
2959 addProperty(CSSPropertyBackgroundRepeatX, values[i].release(), impor tant);
2960 // it's OK to call repeatYValue.release() since we only see CSSPrope rtyBackgroundPosition once
2961 addProperty(CSSPropertyBackgroundRepeatY, repeatYValue.release(), im portant);
2962 } else if (properties[i] == CSSPropertyWebkitMaskRepeat) {
2963 addProperty(CSSPropertyWebkitMaskRepeatX, values[i].release(), impor tant);
2964 // it's OK to call repeatYValue.release() since we only see CSSPrope rtyBackgroundPosition once
2965 addProperty(CSSPropertyWebkitMaskRepeatY, repeatYValue.release(), im portant);
2966 } else if ((properties[i] == CSSPropertyBackgroundClip || properties[i] == CSSPropertyWebkitMaskClip) && !foundClip)
2967 // Value is already set while updating origin
2968 continue;
2969 else if (properties[i] == CSSPropertyBackgroundSize && !parsedProperty[i ] && m_context.useLegacyBackgroundSizeShorthandBehavior())
2970 continue;
2971 else
2972 addProperty(properties[i], values[i].release(), important);
2973
2974 // Add in clip values when we hit the corresponding origin property.
2975 if (properties[i] == CSSPropertyBackgroundOrigin && !foundClip)
2976 addProperty(CSSPropertyBackgroundClip, clipValue.release(), importan t);
2977 else if (properties[i] == CSSPropertyWebkitMaskOrigin && !foundClip)
2978 addProperty(CSSPropertyWebkitMaskClip, clipValue.release(), importan t);
2979 }
2980
2981 m_implicitShorthand = false;
2982 return true;
2983 }
2984
2985 void CSSPropertyParser::addAnimationValue(RefPtrWillBeRawPtr<CSSValue>& lval, Pa ssRefPtrWillBeRawPtr<CSSValue> rval)
2986 {
2987 if (lval) {
2988 if (lval->isValueList())
2989 toCSSValueList(lval.get())->append(rval);
2990 else {
2991 PassRefPtrWillBeRawPtr<CSSValue> oldVal(lval.release());
2992 PassRefPtrWillBeRawPtr<CSSValueList> list = CSSValueList::createComm aSeparated();
2993 list->append(oldVal);
2994 list->append(rval);
2995 lval = list;
2996 }
2997 }
2998 else
2999 lval = rval;
3000 }
3001
3002 bool CSSPropertyParser::parseAnimationShorthand(CSSPropertyID propId, bool impor tant)
3003 {
3004 const StylePropertyShorthand& animationProperties = parsingShorthandForPrope rty(propId);
3005 const unsigned numProperties = 8;
3006
3007 // The list of properties in the shorthand should be the same
3008 // length as the list with animation name in last position, even though they are
3009 // in a different order.
3010 ASSERT(numProperties == animationProperties.length());
3011 ASSERT(numProperties == shorthandForProperty(propId).length());
3012
3013 ShorthandScope scope(this, propId);
3014
3015 bool parsedProperty[numProperties] = { false };
3016 AnimationParseContext context;
3017 RefPtrWillBeRawPtr<CSSValue> values[numProperties];
3018
3019 unsigned i;
3020 while (m_valueList->current()) {
3021 CSSParserValue* val = m_valueList->current();
3022 if (val->unit == CSSParserValue::Operator && val->iValue == ',') {
3023 // We hit the end. Fill in all remaining values with the initial va lue.
3024 m_valueList->next();
3025 for (i = 0; i < numProperties; ++i) {
3026 if (!parsedProperty[i])
3027 addAnimationValue(values[i], cssValuePool().createImplicitIn itialValue());
3028 parsedProperty[i] = false;
3029 }
3030 if (!m_valueList->current())
3031 break;
3032 context.commitFirstAnimation();
3033 }
3034
3035 bool found = false;
3036 for (i = 0; i < numProperties; ++i) {
3037 if (!parsedProperty[i]) {
3038 RefPtrWillBeRawPtr<CSSValue> val;
3039 if (parseAnimationProperty(animationProperties.properties()[i], val, context)) {
3040 parsedProperty[i] = found = true;
3041 addAnimationValue(values[i], val.release());
3042 break;
3043 }
3044 }
3045 }
3046
3047 // if we didn't find at least one match, this is an
3048 // invalid shorthand and we have to ignore it
3049 if (!found)
3050 return false;
3051 }
3052
3053 for (i = 0; i < numProperties; ++i) {
3054 // If we didn't find the property, set an intial value.
3055 if (!parsedProperty[i])
3056 addAnimationValue(values[i], cssValuePool().createImplicitInitialVal ue());
3057
3058 if (RuntimeEnabledFeatures::cssAnimationUnprefixedEnabled())
3059 addPropertyWithPrefixingVariant(animationProperties.properties()[i], values[i].release(), important);
3060 else
3061 addProperty(animationProperties.properties()[i], values[i].release() , important);
3062 }
3063
3064 return true;
3065 }
3066
3067 bool CSSPropertyParser::parseTransitionShorthand(CSSPropertyID propId, bool impo rtant)
3068 {
3069 const unsigned numProperties = 4;
3070 const StylePropertyShorthand& shorthand = shorthandForProperty(propId);
3071 ASSERT(numProperties == shorthand.length());
3072
3073 ShorthandScope scope(this, propId);
3074
3075 bool parsedProperty[numProperties] = { false };
3076 AnimationParseContext context;
3077 RefPtrWillBeRawPtr<CSSValue> values[numProperties];
3078
3079 unsigned i;
3080 while (m_valueList->current()) {
3081 CSSParserValue* val = m_valueList->current();
3082 if (val->unit == CSSParserValue::Operator && val->iValue == ',') {
3083 // We hit the end. Fill in all remaining values with the initial val ue.
3084 m_valueList->next();
3085 for (i = 0; i < numProperties; ++i) {
3086 if (!parsedProperty[i])
3087 addAnimationValue(values[i], cssValuePool().createImplicitIn itialValue());
3088 parsedProperty[i] = false;
3089 }
3090 if (!m_valueList->current())
3091 break;
3092 context.commitFirstAnimation();
3093 }
3094
3095 bool found = false;
3096 for (i = 0; !found && i < numProperties; ++i) {
3097 if (!parsedProperty[i]) {
3098 RefPtrWillBeRawPtr<CSSValue> val;
3099 if (parseAnimationProperty(shorthand.properties()[i], val, conte xt)) {
3100 parsedProperty[i] = found = true;
3101 addAnimationValue(values[i], val.release());
3102 }
3103
3104 // There are more values to process but 'none' or 'all' were alr eady defined as the animation property, the declaration becomes invalid.
3105 if (!context.animationPropertyKeywordAllowed() && context.hasCom mittedFirstAnimation())
3106 return false;
3107 }
3108 }
3109
3110 // if we didn't find at least one match, this is an
3111 // invalid shorthand and we have to ignore it
3112 if (!found)
3113 return false;
3114 }
3115
3116 // Fill in any remaining properties with the initial value.
3117 for (i = 0; i < numProperties; ++i) {
3118 if (!parsedProperty[i])
3119 addAnimationValue(values[i], cssValuePool().createImplicitInitialVal ue());
3120 }
3121
3122 // Now add all of the properties we found.
3123 for (i = 0; i < numProperties; i++)
3124 addPropertyWithPrefixingVariant(shorthand.properties()[i], values[i].rel ease(), important);
3125
3126 return true;
3127 }
3128
3129 PassRefPtrWillBeRawPtr<CSSValue> CSSPropertyParser::parseColumnWidth()
3130 {
3131 CSSParserValue* value = m_valueList->current();
3132 // Always parse lengths in strict mode here, since it would be ambiguous oth erwise when used in
3133 // the 'columns' shorthand property.
3134 if (value->id == CSSValueAuto
3135 || (validUnit(value, FLength | FNonNeg, HTMLStandardMode) && value->fVal ue)) {
3136 RefPtrWillBeRawPtr<CSSValue> parsedValue = parseValidPrimitive(value->id , value);
3137 m_valueList->next();
3138 return parsedValue;
3139 }
3140 return nullptr;
3141 }
3142
3143 PassRefPtrWillBeRawPtr<CSSValue> CSSPropertyParser::parseColumnCount()
3144 {
3145 CSSParserValue* value = m_valueList->current();
3146 if (value->id == CSSValueAuto
3147 || (!value->id && validUnit(value, FPositiveInteger, HTMLQuirksMode))) {
3148 RefPtrWillBeRawPtr<CSSValue> parsedValue = parseValidPrimitive(value->id , value);
3149 m_valueList->next();
3150 return parsedValue;
3151 }
3152 return nullptr;
3153 }
3154
3155 bool CSSPropertyParser::parseColumnsShorthand(bool important)
3156 {
3157 RefPtrWillBeRawPtr<CSSValue> columnWidth;
3158 RefPtrWillBeRawPtr<CSSValue> columnCount;
3159 bool hasPendingExplicitAuto = false;
3160
3161 for (unsigned propertiesParsed = 0; CSSParserValue* value = m_valueList->cur rent(); propertiesParsed++) {
3162 if (propertiesParsed >= 2)
3163 return false; // Too many values for this shorthand. Invalid declara tion.
3164 if (!propertiesParsed && value->id == CSSValueAuto) {
3165 // 'auto' is a valid value for any of the two longhands, and at this point we
3166 // don't know which one(s) it is meant for. We need to see if there are other
3167 // values first.
3168 m_valueList->next();
3169 hasPendingExplicitAuto = true;
3170 } else {
3171 if (!columnWidth) {
3172 if ((columnWidth = parseColumnWidth()))
3173 continue;
3174 }
3175 if (!columnCount) {
3176 if ((columnCount = parseColumnCount()))
3177 continue;
3178 }
3179 // If we didn't find at least one match, this is an
3180 // invalid shorthand and we have to ignore it.
3181 return false;
3182 }
3183 }
3184 if (hasPendingExplicitAuto) {
3185 // Time to assign the previously skipped 'auto' value to a property. If both properties are
3186 // unassigned at this point (i.e. 'columns:auto'), it doesn't matter tha t much which one we
3187 // set (although it does make a slight difference to web-inspector). The one we don't set
3188 // here will get an implicit 'auto' value further down.
3189 if (!columnWidth) {
3190 columnWidth = cssValuePool().createIdentifierValue(CSSValueAuto);
3191 } else {
3192 ASSERT(!columnCount);
3193 columnCount = cssValuePool().createIdentifierValue(CSSValueAuto);
3194 }
3195 }
3196 ASSERT(columnCount || columnWidth);
3197
3198 // Any unassigned property at this point will become implicit 'auto'.
3199 if (columnWidth)
3200 addProperty(CSSPropertyWebkitColumnWidth, columnWidth, important);
3201 else
3202 addProperty(CSSPropertyWebkitColumnWidth, cssValuePool().createIdentifie rValue(CSSValueAuto), important, true /* implicit */);
3203 if (columnCount)
3204 addProperty(CSSPropertyWebkitColumnCount, columnCount, important);
3205 else
3206 addProperty(CSSPropertyWebkitColumnCount, cssValuePool().createIdentifie rValue(CSSValueAuto), important, true /* implicit */);
3207 return true;
3208 }
3209
3210 bool CSSPropertyParser::parseShorthand(CSSPropertyID propId, const StyleProperty Shorthand& shorthand, bool important)
3211 {
3212 // We try to match as many properties as possible
3213 // We set up an array of booleans to mark which property has been found,
3214 // and we try to search for properties until it makes no longer any sense.
3215 ShorthandScope scope(this, propId);
3216
3217 bool found = false;
3218 unsigned propertiesParsed = 0;
3219 bool propertyFound[6] = { false, false, false, false, false, false }; // 6 i s enough size.
3220
3221 while (m_valueList->current()) {
3222 found = false;
3223 for (unsigned propIndex = 0; !found && propIndex < shorthand.length(); + +propIndex) {
3224 if (!propertyFound[propIndex] && parseValue(shorthand.properties()[p ropIndex], important)) {
3225 propertyFound[propIndex] = found = true;
3226 propertiesParsed++;
3227 }
3228 }
3229
3230 // if we didn't find at least one match, this is an
3231 // invalid shorthand and we have to ignore it
3232 if (!found)
3233 return false;
3234 }
3235
3236 if (propertiesParsed == shorthand.length())
3237 return true;
3238
3239 // Fill in any remaining properties with the initial value.
3240 ImplicitScope implicitScope(this, PropertyImplicit);
3241 const StylePropertyShorthand* const* const propertiesForInitialization = sho rthand.propertiesForInitialization();
3242 for (unsigned i = 0; i < shorthand.length(); ++i) {
3243 if (propertyFound[i])
3244 continue;
3245
3246 if (propertiesForInitialization) {
3247 const StylePropertyShorthand& initProperties = *(propertiesForInitia lization[i]);
3248 for (unsigned propIndex = 0; propIndex < initProperties.length(); ++ propIndex)
3249 addProperty(initProperties.properties()[propIndex], cssValuePool ().createImplicitInitialValue(), important);
3250 } else
3251 addProperty(shorthand.properties()[i], cssValuePool().createImplicit InitialValue(), important);
3252 }
3253
3254 return true;
3255 }
3256
3257 bool CSSPropertyParser::parse4Values(CSSPropertyID propId, const CSSPropertyID * properties, bool important)
3258 {
3259 /* From the CSS 2 specs, 8.3
3260 * If there is only one value, it applies to all sides. If there are two val ues, the top and
3261 * bottom margins are set to the first value and the right and left margins are set to the second.
3262 * If there are three values, the top is set to the first value, the left an d right are set to the
3263 * second, and the bottom is set to the third. If there are four values, the y apply to the top,
3264 * right, bottom, and left, respectively.
3265 */
3266
3267 int num = inShorthand() ? 1 : m_valueList->size();
3268
3269 ShorthandScope scope(this, propId);
3270
3271 // the order is top, right, bottom, left
3272 switch (num) {
3273 case 1: {
3274 if (!parseValue(properties[0], important))
3275 return false;
3276 CSSValue* value = m_parsedProperties.last().value();
3277 ImplicitScope implicitScope(this, PropertyImplicit);
3278 addProperty(properties[1], value, important);
3279 addProperty(properties[2], value, important);
3280 addProperty(properties[3], value, important);
3281 break;
3282 }
3283 case 2: {
3284 if (!parseValue(properties[0], important) || !parseValue(properties[ 1], important))
3285 return false;
3286 CSSValue* value = m_parsedProperties[m_parsedProperties.size() - 2]. value();
3287 ImplicitScope implicitScope(this, PropertyImplicit);
3288 addProperty(properties[2], value, important);
3289 value = m_parsedProperties[m_parsedProperties.size() - 2].value();
3290 addProperty(properties[3], value, important);
3291 break;
3292 }
3293 case 3: {
3294 if (!parseValue(properties[0], important) || !parseValue(properties[ 1], important) || !parseValue(properties[2], important))
3295 return false;
3296 CSSValue* value = m_parsedProperties[m_parsedProperties.size() - 2]. value();
3297 ImplicitScope implicitScope(this, PropertyImplicit);
3298 addProperty(properties[3], value, important);
3299 break;
3300 }
3301 case 4: {
3302 if (!parseValue(properties[0], important) || !parseValue(properties[ 1], important) ||
3303 !parseValue(properties[2], important) || !parseValue(properties[ 3], important))
3304 return false;
3305 break;
3306 }
3307 default: {
3308 return false;
3309 }
3310 }
3311
3312 return true;
3313 }
3314
3315 // auto | <identifier>
3316 bool CSSPropertyParser::parsePage(CSSPropertyID propId, bool important)
3317 {
3318 ASSERT(propId == CSSPropertyPage);
3319
3320 if (m_valueList->size() != 1)
3321 return false;
3322
3323 CSSParserValue* value = m_valueList->current();
3324 if (!value)
3325 return false;
3326
3327 if (value->id == CSSValueAuto) {
3328 addProperty(propId, cssValuePool().createIdentifierValue(value->id), imp ortant);
3329 return true;
3330 } else if (value->id == 0 && value->unit == CSSPrimitiveValue::CSS_IDENT) {
3331 addProperty(propId, createPrimitiveStringValue(value), important);
3332 return true;
3333 }
3334 return false;
3335 }
3336
3337 // <length>{1,2} | auto | [ <page-size> || [ portrait | landscape] ]
3338 bool CSSPropertyParser::parseSize(CSSPropertyID propId, bool important)
3339 {
3340 ASSERT(propId == CSSPropertySize);
3341
3342 if (m_valueList->size() > 2)
3343 return false;
3344
3345 CSSParserValue* value = m_valueList->current();
3346 if (!value)
3347 return false;
3348
3349 RefPtrWillBeRawPtr<CSSValueList> parsedValues = CSSValueList::createSpaceSep arated();
3350
3351 // First parameter.
3352 SizeParameterType paramType = parseSizeParameter(parsedValues.get(), value, None);
3353 if (paramType == None)
3354 return false;
3355
3356 // Second parameter, if any.
3357 value = m_valueList->next();
3358 if (value) {
3359 paramType = parseSizeParameter(parsedValues.get(), value, paramType);
3360 if (paramType == None)
3361 return false;
3362 }
3363
3364 addProperty(propId, parsedValues.release(), important);
3365 return true;
3366 }
3367
3368 CSSPropertyParser::SizeParameterType CSSPropertyParser::parseSizeParameter(CSSVa lueList* parsedValues, CSSParserValue* value, SizeParameterType prevParamType)
3369 {
3370 switch (value->id) {
3371 case CSSValueAuto:
3372 if (prevParamType == None) {
3373 parsedValues->append(cssValuePool().createIdentifierValue(value->id) );
3374 return Auto;
3375 }
3376 return None;
3377 case CSSValueLandscape:
3378 case CSSValuePortrait:
3379 if (prevParamType == None || prevParamType == PageSize) {
3380 parsedValues->append(cssValuePool().createIdentifierValue(value->id) );
3381 return Orientation;
3382 }
3383 return None;
3384 case CSSValueA3:
3385 case CSSValueA4:
3386 case CSSValueA5:
3387 case CSSValueB4:
3388 case CSSValueB5:
3389 case CSSValueLedger:
3390 case CSSValueLegal:
3391 case CSSValueLetter:
3392 if (prevParamType == None || prevParamType == Orientation) {
3393 // Normalize to Page Size then Orientation order by prepending.
3394 // This is not specified by the CSS3 Paged Media specification, but for simpler processing later (StyleResolver::applyPageSizeProperty).
3395 parsedValues->prepend(cssValuePool().createIdentifierValue(value->id ));
3396 return PageSize;
3397 }
3398 return None;
3399 case 0:
3400 if (validUnit(value, FLength | FNonNeg) && (prevParamType == None || pre vParamType == Length)) {
3401 parsedValues->append(createPrimitiveNumericValue(value));
3402 return Length;
3403 }
3404 return None;
3405 default:
3406 return None;
3407 }
3408 }
3409
3410 // [ <string> <string> ]+ | inherit | none
3411 // inherit and none are handled in parseValue.
3412 bool CSSPropertyParser::parseQuotes(CSSPropertyID propId, bool important)
3413 {
3414 RefPtrWillBeRawPtr<CSSValueList> values = CSSValueList::createCommaSeparated ();
3415 while (CSSParserValue* val = m_valueList->current()) {
3416 RefPtrWillBeRawPtr<CSSValue> parsedValue;
3417 if (val->unit == CSSPrimitiveValue::CSS_STRING)
3418 parsedValue = CSSPrimitiveValue::create(val->string, CSSPrimitiveVal ue::CSS_STRING);
3419 else
3420 break;
3421 values->append(parsedValue.release());
3422 m_valueList->next();
3423 }
3424 if (values->length()) {
3425 addProperty(propId, values.release(), important);
3426 m_valueList->next();
3427 return true;
3428 }
3429 return false;
3430 }
3431
3432 // [ <string> | <uri> | <counter> | attr(X) | open-quote | close-quote | no-open -quote | no-close-quote ]+ | inherit
3433 // in CSS 2.1 this got somewhat reduced:
3434 // [ <string> | attr(X) | open-quote | close-quote | no-open-quote | no-close-qu ote ]+ | inherit
3435 bool CSSPropertyParser::parseContent(CSSPropertyID propId, bool important)
3436 {
3437 RefPtrWillBeRawPtr<CSSValueList> values = CSSValueList::createCommaSeparated ();
3438
3439 while (CSSParserValue* val = m_valueList->current()) {
3440 RefPtrWillBeRawPtr<CSSValue> parsedValue;
3441 if (val->unit == CSSPrimitiveValue::CSS_URI) {
3442 // url
3443 parsedValue = CSSImageValue::create(val->string, completeURL(val->st ring));
3444 } else if (val->unit == CSSParserValue::Function) {
3445 // attr(X) | counter(X [,Y]) | counters(X, Y, [,Z]) | -webkit-gradie nt(...)
3446 CSSParserValueList* args = val->function->args.get();
3447 if (!args)
3448 return false;
3449 if (equalIgnoringCase(val->function->name, "attr(")) {
3450 parsedValue = parseAttr(args);
3451 if (!parsedValue)
3452 return false;
3453 } else if (equalIgnoringCase(val->function->name, "counter(")) {
3454 parsedValue = parseCounterContent(args, false);
3455 if (!parsedValue)
3456 return false;
3457 } else if (equalIgnoringCase(val->function->name, "counters(")) {
3458 parsedValue = parseCounterContent(args, true);
3459 if (!parsedValue)
3460 return false;
3461 } else if (equalIgnoringCase(val->function->name, "-webkit-image-set (")) {
3462 parsedValue = parseImageSet(m_valueList.get());
3463 if (!parsedValue)
3464 return false;
3465 } else if (isGeneratedImageValue(val)) {
3466 if (!parseGeneratedImage(m_valueList.get(), parsedValue))
3467 return false;
3468 } else
3469 return false;
3470 } else if (val->unit == CSSPrimitiveValue::CSS_IDENT) {
3471 // open-quote
3472 // close-quote
3473 // no-open-quote
3474 // no-close-quote
3475 // inherit
3476 // FIXME: These are not yet implemented (http://bugs.webkit.org/show _bug.cgi?id=6503).
3477 // none
3478 // normal
3479 switch (val->id) {
3480 case CSSValueOpenQuote:
3481 case CSSValueCloseQuote:
3482 case CSSValueNoOpenQuote:
3483 case CSSValueNoCloseQuote:
3484 case CSSValueNone:
3485 case CSSValueNormal:
3486 parsedValue = cssValuePool().createIdentifierValue(val->id);
3487 default:
3488 break;
3489 }
3490 } else if (val->unit == CSSPrimitiveValue::CSS_STRING) {
3491 parsedValue = createPrimitiveStringValue(val);
3492 }
3493 if (!parsedValue)
3494 break;
3495 values->append(parsedValue.release());
3496 m_valueList->next();
3497 }
3498
3499 if (values->length()) {
3500 addProperty(propId, values.release(), important);
3501 m_valueList->next();
3502 return true;
3503 }
3504
3505 return false;
3506 }
3507
3508 PassRefPtrWillBeRawPtr<CSSValue> CSSPropertyParser::parseAttr(CSSParserValueList * args)
3509 {
3510 if (args->size() != 1)
3511 return nullptr;
3512
3513 CSSParserValue* a = args->current();
3514
3515 if (a->unit != CSSPrimitiveValue::CSS_IDENT)
3516 return nullptr;
3517
3518 String attrName = a->string;
3519 // CSS allows identifiers with "-" at the start, like "-webkit-mask-image".
3520 // But HTML attribute names can't have those characters, and we should not
3521 // even parse them inside attr().
3522 if (attrName[0] == '-')
3523 return nullptr;
3524
3525 if (m_context.isHTMLDocument())
3526 attrName = attrName.lower();
3527
3528 return cssValuePool().createValue(attrName, CSSPrimitiveValue::CSS_ATTR);
3529 }
3530
3531 PassRefPtrWillBeRawPtr<CSSValue> CSSPropertyParser::parseBackgroundColor()
3532 {
3533 CSSValueID id = m_valueList->current()->id;
3534 if (id == CSSValueWebkitText || (id >= CSSValueAqua && id <= CSSValueWindowt ext) || id == CSSValueMenu || id == CSSValueCurrentcolor ||
3535 (id >= CSSValueGrey && id < CSSValueWebkitText && inQuirksMode()))
3536 return cssValuePool().createIdentifierValue(id);
3537 return parseColor();
3538 }
3539
3540 bool CSSPropertyParser::parseFillImage(CSSParserValueList* valueList, RefPtrWill BeRawPtr<CSSValue>& value)
3541 {
3542 if (valueList->current()->id == CSSValueNone) {
3543 value = cssValuePool().createIdentifierValue(CSSValueNone);
3544 return true;
3545 }
3546 if (valueList->current()->unit == CSSPrimitiveValue::CSS_URI) {
3547 value = CSSImageValue::create(valueList->current()->string, completeURL( valueList->current()->string));
3548 return true;
3549 }
3550
3551 if (isGeneratedImageValue(valueList->current()))
3552 return parseGeneratedImage(valueList, value);
3553
3554 if (valueList->current()->unit == CSSParserValue::Function && equalIgnoringC ase(valueList->current()->function->name, "-webkit-image-set(")) {
3555 value = parseImageSet(m_valueList.get());
3556 if (value)
3557 return true;
3558 }
3559
3560 return false;
3561 }
3562
3563 PassRefPtrWillBeRawPtr<CSSValue> CSSPropertyParser::parseFillPositionX(CSSParser ValueList* valueList)
3564 {
3565 int id = valueList->current()->id;
3566 if (id == CSSValueLeft || id == CSSValueRight || id == CSSValueCenter) {
3567 int percent = 0;
3568 if (id == CSSValueRight)
3569 percent = 100;
3570 else if (id == CSSValueCenter)
3571 percent = 50;
3572 return cssValuePool().createValue(percent, CSSPrimitiveValue::CSS_PERCEN TAGE);
3573 }
3574 if (validUnit(valueList->current(), FPercent | FLength))
3575 return createPrimitiveNumericValue(valueList->current());
3576 return nullptr;
3577 }
3578
3579 PassRefPtrWillBeRawPtr<CSSValue> CSSPropertyParser::parseFillPositionY(CSSParser ValueList* valueList)
3580 {
3581 int id = valueList->current()->id;
3582 if (id == CSSValueTop || id == CSSValueBottom || id == CSSValueCenter) {
3583 int percent = 0;
3584 if (id == CSSValueBottom)
3585 percent = 100;
3586 else if (id == CSSValueCenter)
3587 percent = 50;
3588 return cssValuePool().createValue(percent, CSSPrimitiveValue::CSS_PERCEN TAGE);
3589 }
3590 if (validUnit(valueList->current(), FPercent | FLength))
3591 return createPrimitiveNumericValue(valueList->current());
3592 return nullptr;
3593 }
3594
3595 PassRefPtrWillBeRawPtr<CSSPrimitiveValue> CSSPropertyParser::parseFillPositionCo mponent(CSSParserValueList* valueList, unsigned& cumulativeFlags, FillPositionFl ag& individualFlag, FillPositionParsingMode parsingMode)
3596 {
3597 CSSValueID id = valueList->current()->id;
3598 if (id == CSSValueLeft || id == CSSValueTop || id == CSSValueRight || id == CSSValueBottom || id == CSSValueCenter) {
3599 int percent = 0;
3600 if (id == CSSValueLeft || id == CSSValueRight) {
3601 if (cumulativeFlags & XFillPosition)
3602 return nullptr;
3603 cumulativeFlags |= XFillPosition;
3604 individualFlag = XFillPosition;
3605 if (id == CSSValueRight)
3606 percent = 100;
3607 }
3608 else if (id == CSSValueTop || id == CSSValueBottom) {
3609 if (cumulativeFlags & YFillPosition)
3610 return nullptr;
3611 cumulativeFlags |= YFillPosition;
3612 individualFlag = YFillPosition;
3613 if (id == CSSValueBottom)
3614 percent = 100;
3615 } else if (id == CSSValueCenter) {
3616 // Center is ambiguous, so we're not sure which position we've found yet, an x or a y.
3617 percent = 50;
3618 cumulativeFlags |= AmbiguousFillPosition;
3619 individualFlag = AmbiguousFillPosition;
3620 }
3621
3622 if (parsingMode == ResolveValuesAsKeyword)
3623 return cssValuePool().createIdentifierValue(id);
3624
3625 return cssValuePool().createValue(percent, CSSPrimitiveValue::CSS_PERCEN TAGE);
3626 }
3627 if (validUnit(valueList->current(), FPercent | FLength)) {
3628 if (!cumulativeFlags) {
3629 cumulativeFlags |= XFillPosition;
3630 individualFlag = XFillPosition;
3631 } else if (cumulativeFlags & (XFillPosition | AmbiguousFillPosition)) {
3632 cumulativeFlags |= YFillPosition;
3633 individualFlag = YFillPosition;
3634 } else {
3635 if (m_parsedCalculation)
3636 m_parsedCalculation.release();
3637 return nullptr;
3638 }
3639 return createPrimitiveNumericValue(valueList->current());
3640 }
3641 return nullptr;
3642 }
3643
3644 static bool isValueConflictingWithCurrentEdge(int value1, int value2)
3645 {
3646 if ((value1 == CSSValueLeft || value1 == CSSValueRight) && (value2 == CSSVal ueLeft || value2 == CSSValueRight))
3647 return true;
3648
3649 if ((value1 == CSSValueTop || value1 == CSSValueBottom) && (value2 == CSSVal ueTop || value2 == CSSValueBottom))
3650 return true;
3651
3652 return false;
3653 }
3654
3655 static bool isFillPositionKeyword(CSSValueID value)
3656 {
3657 return value == CSSValueLeft || value == CSSValueTop || value == CSSValueBot tom || value == CSSValueRight || value == CSSValueCenter;
3658 }
3659
3660 void CSSPropertyParser::parse4ValuesFillPosition(CSSParserValueList* valueList, RefPtrWillBeRawPtr<CSSValue>& value1, RefPtrWillBeRawPtr<CSSValue>& value2, Pass RefPtrWillBeRawPtr<CSSPrimitiveValue> parsedValue1, PassRefPtrWillBeRawPtr<CSSPr imitiveValue> parsedValue2)
3661 {
3662 // [ left | right ] [ <percentage] | <length> ] && [ top | bottom ] [ <perce ntage> | <length> ]
3663 // In the case of 4 values <position> requires the second value to be a leng th or a percentage.
3664 if (isFillPositionKeyword(parsedValue2->getValueID()))
3665 return;
3666
3667 unsigned cumulativeFlags = 0;
3668 FillPositionFlag value3Flag = InvalidFillPosition;
3669 RefPtrWillBeRawPtr<CSSPrimitiveValue> value3 = parseFillPositionComponent(va lueList, cumulativeFlags, value3Flag, ResolveValuesAsKeyword);
3670 if (!value3)
3671 return;
3672
3673 CSSValueID ident1 = parsedValue1->getValueID();
3674 CSSValueID ident3 = value3->getValueID();
3675
3676 if (ident1 == CSSValueCenter)
3677 return;
3678
3679 if (!isFillPositionKeyword(ident3) || ident3 == CSSValueCenter)
3680 return;
3681
3682 // We need to check if the values are not conflicting, e.g. they are not on the same edge. It is
3683 // needed as the second call to parseFillPositionComponent was on purpose no t checking it. In the
3684 // case of two values top 20px is invalid but in the case of 4 values it bec omes valid.
3685 if (isValueConflictingWithCurrentEdge(ident1, ident3))
3686 return;
3687
3688 valueList->next();
3689
3690 cumulativeFlags = 0;
3691 FillPositionFlag value4Flag = InvalidFillPosition;
3692 RefPtrWillBeRawPtr<CSSPrimitiveValue> value4 = parseFillPositionComponent(va lueList, cumulativeFlags, value4Flag, ResolveValuesAsKeyword);
3693 if (!value4)
3694 return;
3695
3696 // 4th value must be a length or a percentage.
3697 if (isFillPositionKeyword(value4->getValueID()))
3698 return;
3699
3700 value1 = createPrimitiveValuePair(parsedValue1, parsedValue2);
3701 value2 = createPrimitiveValuePair(value3, value4);
3702
3703 if (ident1 == CSSValueTop || ident1 == CSSValueBottom)
3704 value1.swap(value2);
3705
3706 valueList->next();
3707 }
3708 void CSSPropertyParser::parse3ValuesFillPosition(CSSParserValueList* valueList, RefPtrWillBeRawPtr<CSSValue>& value1, RefPtrWillBeRawPtr<CSSValue>& value2, Pass RefPtrWillBeRawPtr<CSSPrimitiveValue> parsedValue1, PassRefPtrWillBeRawPtr<CSSPr imitiveValue> parsedValue2)
3709 {
3710 unsigned cumulativeFlags = 0;
3711 FillPositionFlag value3Flag = InvalidFillPosition;
3712 RefPtrWillBeRawPtr<CSSPrimitiveValue> value3 = parseFillPositionComponent(va lueList, cumulativeFlags, value3Flag, ResolveValuesAsKeyword);
3713
3714 // value3 is not an expected value, we return.
3715 if (!value3)
3716 return;
3717
3718 valueList->next();
3719
3720 bool swapNeeded = false;
3721 CSSValueID ident1 = parsedValue1->getValueID();
3722 CSSValueID ident2 = parsedValue2->getValueID();
3723 CSSValueID ident3 = value3->getValueID();
3724
3725 CSSValueID firstPositionKeyword;
3726 CSSValueID secondPositionKeyword;
3727
3728 if (ident1 == CSSValueCenter) {
3729 // <position> requires the first 'center' to be followed by a keyword.
3730 if (!isFillPositionKeyword(ident2))
3731 return;
3732
3733 // If 'center' is the first keyword then the last one needs to be a leng th.
3734 if (isFillPositionKeyword(ident3))
3735 return;
3736
3737 firstPositionKeyword = CSSValueLeft;
3738 if (ident2 == CSSValueLeft || ident2 == CSSValueRight) {
3739 firstPositionKeyword = CSSValueTop;
3740 swapNeeded = true;
3741 }
3742 value1 = createPrimitiveValuePair(cssValuePool().createIdentifierValue(f irstPositionKeyword), cssValuePool().createValue(50, CSSPrimitiveValue::CSS_PERC ENTAGE));
3743 value2 = createPrimitiveValuePair(parsedValue2, value3);
3744 } else if (ident3 == CSSValueCenter) {
3745 if (isFillPositionKeyword(ident2))
3746 return;
3747
3748 secondPositionKeyword = CSSValueTop;
3749 if (ident1 == CSSValueTop || ident1 == CSSValueBottom) {
3750 secondPositionKeyword = CSSValueLeft;
3751 swapNeeded = true;
3752 }
3753 value1 = createPrimitiveValuePair(parsedValue1, parsedValue2);
3754 value2 = createPrimitiveValuePair(cssValuePool().createIdentifierValue(s econdPositionKeyword), cssValuePool().createValue(50, CSSPrimitiveValue::CSS_PER CENTAGE));
3755 } else {
3756 RefPtrWillBeRawPtr<CSSPrimitiveValue> firstPositionValue;
3757 RefPtrWillBeRawPtr<CSSPrimitiveValue> secondPositionValue;
3758
3759 if (isFillPositionKeyword(ident2)) {
3760 // To match CSS grammar, we should only accept: [ center | left | ri ght | bottom | top ] [ left | right | top | bottom ] [ <percentage> | <length> ] .
3761 ASSERT(ident2 != CSSValueCenter);
3762
3763 if (isFillPositionKeyword(ident3))
3764 return;
3765
3766 secondPositionValue = value3;
3767 secondPositionKeyword = ident2;
3768 firstPositionValue = cssValuePool().createValue(0, CSSPrimitiveValue ::CSS_PERCENTAGE);
3769 } else {
3770 // Per CSS, we should only accept: [ right | left | top | bottom ] [ <percentage> | <length> ] [ center | left | right | bottom | top ].
3771 if (!isFillPositionKeyword(ident3))
3772 return;
3773
3774 firstPositionValue = parsedValue2;
3775 secondPositionKeyword = ident3;
3776 secondPositionValue = cssValuePool().createValue(0, CSSPrimitiveValu e::CSS_PERCENTAGE);
3777 }
3778
3779 if (isValueConflictingWithCurrentEdge(ident1, secondPositionKeyword))
3780 return;
3781
3782 value1 = createPrimitiveValuePair(parsedValue1, firstPositionValue);
3783 value2 = createPrimitiveValuePair(cssValuePool().createIdentifierValue(s econdPositionKeyword), secondPositionValue);
3784 }
3785
3786 if (ident1 == CSSValueTop || ident1 == CSSValueBottom || swapNeeded)
3787 value1.swap(value2);
3788
3789 #ifndef NDEBUG
3790 CSSPrimitiveValue* first = toCSSPrimitiveValue(value1.get());
3791 CSSPrimitiveValue* second = toCSSPrimitiveValue(value2.get());
3792 ident1 = first->getPairValue()->first()->getValueID();
3793 ident2 = second->getPairValue()->first()->getValueID();
3794 ASSERT(ident1 == CSSValueLeft || ident1 == CSSValueRight);
3795 ASSERT(ident2 == CSSValueBottom || ident2 == CSSValueTop);
3796 #endif
3797 }
3798
3799 inline bool CSSPropertyParser::isPotentialPositionValue(CSSParserValue* value)
3800 {
3801 return isFillPositionKeyword(value->id) || validUnit(value, FPercent | FLeng th, ReleaseParsedCalcValue);
3802 }
3803
3804 void CSSPropertyParser::parseFillPosition(CSSParserValueList* valueList, RefPtrW illBeRawPtr<CSSValue>& value1, RefPtrWillBeRawPtr<CSSValue>& value2)
3805 {
3806 unsigned numberOfValues = 0;
3807 for (unsigned i = valueList->currentIndex(); i < valueList->size(); ++i, ++n umberOfValues) {
3808 CSSParserValue* current = valueList->valueAt(i);
3809 if (isComma(current) || !current || isForwardSlashOperator(current) || ! isPotentialPositionValue(current))
3810 break;
3811 }
3812
3813 if (numberOfValues > 4)
3814 return;
3815
3816 // If we are parsing two values, we can safely call the CSS 2.1 parsing func tion and return.
3817 if (numberOfValues <= 2) {
3818 parse2ValuesFillPosition(valueList, value1, value2);
3819 return;
3820 }
3821
3822 ASSERT(numberOfValues > 2 && numberOfValues <= 4);
3823
3824 CSSParserValue* value = valueList->current();
3825
3826 // <position> requires the first value to be a background keyword.
3827 if (!isFillPositionKeyword(value->id))
3828 return;
3829
3830 // Parse the first value. We're just making sure that it is one of the valid keywords or a percentage/length.
3831 unsigned cumulativeFlags = 0;
3832 FillPositionFlag value1Flag = InvalidFillPosition;
3833 FillPositionFlag value2Flag = InvalidFillPosition;
3834 value1 = parseFillPositionComponent(valueList, cumulativeFlags, value1Flag, ResolveValuesAsKeyword);
3835 if (!value1)
3836 return;
3837
3838 valueList->next();
3839
3840 // In case we are parsing more than two values, relax the check inside of pa rseFillPositionComponent. top 20px is
3841 // a valid start for <position>.
3842 cumulativeFlags = AmbiguousFillPosition;
3843 value2 = parseFillPositionComponent(valueList, cumulativeFlags, value2Flag, ResolveValuesAsKeyword);
3844 if (value2)
3845 valueList->next();
3846 else {
3847 value1.clear();
3848 return;
3849 }
3850
3851 RefPtrWillBeRawPtr<CSSPrimitiveValue> parsedValue1 = toCSSPrimitiveValue(val ue1.get());
3852 RefPtrWillBeRawPtr<CSSPrimitiveValue> parsedValue2 = toCSSPrimitiveValue(val ue2.get());
3853
3854 value1.clear();
3855 value2.clear();
3856
3857 // Per CSS3 syntax, <position> can't have 'center' as its second keyword as we have more arguments to follow.
3858 if (parsedValue2->getValueID() == CSSValueCenter)
3859 return;
3860
3861 if (numberOfValues == 3)
3862 parse3ValuesFillPosition(valueList, value1, value2, parsedValue1.release (), parsedValue2.release());
3863 else
3864 parse4ValuesFillPosition(valueList, value1, value2, parsedValue1.release (), parsedValue2.release());
3865 }
3866
3867 void CSSPropertyParser::parse2ValuesFillPosition(CSSParserValueList* valueList, RefPtrWillBeRawPtr<CSSValue>& value1, RefPtrWillBeRawPtr<CSSValue>& value2)
3868 {
3869 CSSParserValue* value = valueList->current();
3870
3871 // Parse the first value. We're just making sure that it is one of the vali d keywords or a percentage/length.
3872 unsigned cumulativeFlags = 0;
3873 FillPositionFlag value1Flag = InvalidFillPosition;
3874 FillPositionFlag value2Flag = InvalidFillPosition;
3875 value1 = parseFillPositionComponent(valueList, cumulativeFlags, value1Flag);
3876 if (!value1)
3877 return;
3878
3879 // It only takes one value for background-position to be correctly parsed if it was specified in a shorthand (since we
3880 // can assume that any other values belong to the rest of the shorthand). I f we're not parsing a shorthand, though, the
3881 // value was explicitly specified for our property.
3882 value = valueList->next();
3883
3884 // First check for the comma. If so, we are finished parsing this value or value pair.
3885 if (isComma(value))
3886 value = 0;
3887
3888 if (value) {
3889 value2 = parseFillPositionComponent(valueList, cumulativeFlags, value2Fl ag);
3890 if (value2)
3891 valueList->next();
3892 else {
3893 if (!inShorthand()) {
3894 value1.clear();
3895 return;
3896 }
3897 }
3898 }
3899
3900 if (!value2)
3901 // Only one value was specified. If that value was not a keyword, then i t sets the x position, and the y position
3902 // is simply 50%. This is our default.
3903 // For keywords, the keyword was either an x-keyword (left/right), a y-k eyword (top/bottom), or an ambiguous keyword (center).
3904 // For left/right/center, the default of 50% in the y is still correct.
3905 value2 = cssValuePool().createValue(50, CSSPrimitiveValue::CSS_PERCENTAG E);
3906
3907 if (value1Flag == YFillPosition || value2Flag == XFillPosition)
3908 value1.swap(value2);
3909 }
3910
3911 void CSSPropertyParser::parseFillRepeat(RefPtrWillBeRawPtr<CSSValue>& value1, Re fPtrWillBeRawPtr<CSSValue>& value2)
3912 {
3913 CSSValueID id = m_valueList->current()->id;
3914 if (id == CSSValueRepeatX) {
3915 m_implicitShorthand = true;
3916 value1 = cssValuePool().createIdentifierValue(CSSValueRepeat);
3917 value2 = cssValuePool().createIdentifierValue(CSSValueNoRepeat);
3918 m_valueList->next();
3919 return;
3920 }
3921 if (id == CSSValueRepeatY) {
3922 m_implicitShorthand = true;
3923 value1 = cssValuePool().createIdentifierValue(CSSValueNoRepeat);
3924 value2 = cssValuePool().createIdentifierValue(CSSValueRepeat);
3925 m_valueList->next();
3926 return;
3927 }
3928 if (id == CSSValueRepeat || id == CSSValueNoRepeat || id == CSSValueRound || id == CSSValueSpace)
3929 value1 = cssValuePool().createIdentifierValue(id);
3930 else {
3931 value1 = nullptr;
3932 return;
3933 }
3934
3935 CSSParserValue* value = m_valueList->next();
3936
3937 // Parse the second value if one is available
3938 if (value && !isComma(value)) {
3939 id = value->id;
3940 if (id == CSSValueRepeat || id == CSSValueNoRepeat || id == CSSValueRoun d || id == CSSValueSpace) {
3941 value2 = cssValuePool().createIdentifierValue(id);
3942 m_valueList->next();
3943 return;
3944 }
3945 }
3946
3947 // If only one value was specified, value2 is the same as value1.
3948 m_implicitShorthand = true;
3949 value2 = cssValuePool().createIdentifierValue(toCSSPrimitiveValue(value1.get ())->getValueID());
3950 }
3951
3952 PassRefPtrWillBeRawPtr<CSSValue> CSSPropertyParser::parseFillSize(CSSPropertyID propId, bool& allowComma)
3953 {
3954 allowComma = true;
3955 CSSParserValue* value = m_valueList->current();
3956
3957 if (value->id == CSSValueContain || value->id == CSSValueCover)
3958 return cssValuePool().createIdentifierValue(value->id);
3959
3960 RefPtrWillBeRawPtr<CSSPrimitiveValue> parsedValue1;
3961
3962 if (value->id == CSSValueAuto)
3963 parsedValue1 = cssValuePool().createIdentifierValue(CSSValueAuto);
3964 else {
3965 if (!validUnit(value, FLength | FPercent))
3966 return nullptr;
3967 parsedValue1 = createPrimitiveNumericValue(value);
3968 }
3969
3970 RefPtrWillBeRawPtr<CSSPrimitiveValue> parsedValue2;
3971 if ((value = m_valueList->next())) {
3972 if (value->unit == CSSParserValue::Operator && value->iValue == ',')
3973 allowComma = false;
3974 else if (value->id != CSSValueAuto) {
3975 if (!validUnit(value, FLength | FPercent)) {
3976 if (!inShorthand())
3977 return nullptr;
3978 // We need to rewind the value list, so that when it is advanced we'll end up back at this value.
3979 m_valueList->previous();
3980 } else
3981 parsedValue2 = createPrimitiveNumericValue(value);
3982 }
3983 } else if (!parsedValue2 && propId == CSSPropertyWebkitBackgroundSize) {
3984 // For backwards compatibility we set the second value to the first if i t is omitted.
3985 // We only need to do this for -webkit-background-size. It should be saf e to let masks match
3986 // the real property.
3987 parsedValue2 = parsedValue1;
3988 }
3989
3990 if (!parsedValue2)
3991 return parsedValue1;
3992 return createPrimitiveValuePair(parsedValue1.release(), parsedValue2.release ());
3993 }
3994
3995 bool CSSPropertyParser::parseFillProperty(CSSPropertyID propId, CSSPropertyID& p ropId1, CSSPropertyID& propId2,
3996 RefPtrWillBeRawPtr<CSSValue>& retValue1, RefPtrWillBeRawPtr<CSSValue>& retVa lue2)
3997 {
3998 RefPtrWillBeRawPtr<CSSValueList> values;
3999 RefPtrWillBeRawPtr<CSSValueList> values2;
4000 CSSParserValue* val;
4001 RefPtrWillBeRawPtr<CSSValue> value;
4002 RefPtrWillBeRawPtr<CSSValue> value2;
4003
4004 bool allowComma = false;
4005
4006 retValue1 = retValue2 = nullptr;
4007 propId1 = propId;
4008 propId2 = propId;
4009 if (propId == CSSPropertyBackgroundPosition) {
4010 propId1 = CSSPropertyBackgroundPositionX;
4011 propId2 = CSSPropertyBackgroundPositionY;
4012 } else if (propId == CSSPropertyWebkitMaskPosition) {
4013 propId1 = CSSPropertyWebkitMaskPositionX;
4014 propId2 = CSSPropertyWebkitMaskPositionY;
4015 } else if (propId == CSSPropertyBackgroundRepeat) {
4016 propId1 = CSSPropertyBackgroundRepeatX;
4017 propId2 = CSSPropertyBackgroundRepeatY;
4018 } else if (propId == CSSPropertyWebkitMaskRepeat) {
4019 propId1 = CSSPropertyWebkitMaskRepeatX;
4020 propId2 = CSSPropertyWebkitMaskRepeatY;
4021 }
4022
4023 while ((val = m_valueList->current())) {
4024 RefPtrWillBeRawPtr<CSSValue> currValue;
4025 RefPtrWillBeRawPtr<CSSValue> currValue2;
4026
4027 if (allowComma) {
4028 if (!isComma(val))
4029 return false;
4030 m_valueList->next();
4031 allowComma = false;
4032 } else {
4033 allowComma = true;
4034 switch (propId) {
4035 case CSSPropertyBackgroundColor:
4036 currValue = parseBackgroundColor();
4037 if (currValue)
4038 m_valueList->next();
4039 break;
4040 case CSSPropertyBackgroundAttachment:
4041 if (val->id == CSSValueScroll || val->id == CSSValueFixed || val->id == CSSValueLocal) {
4042 currValue = cssValuePool().createIdentifierValue(val->id );
4043 m_valueList->next();
4044 }
4045 break;
4046 case CSSPropertyBackgroundImage:
4047 case CSSPropertyWebkitMaskImage:
4048 if (parseFillImage(m_valueList.get(), currValue))
4049 m_valueList->next();
4050 break;
4051 case CSSPropertyWebkitBackgroundClip:
4052 case CSSPropertyWebkitBackgroundOrigin:
4053 case CSSPropertyWebkitMaskClip:
4054 case CSSPropertyWebkitMaskOrigin:
4055 // The first three values here are deprecated and do not app ly to the version of the property that has
4056 // the -webkit- prefix removed.
4057 if (val->id == CSSValueBorder || val->id == CSSValuePadding || val->id == CSSValueContent ||
4058 val->id == CSSValueBorderBox || val->id == CSSValuePaddi ngBox || val->id == CSSValueContentBox ||
4059 ((propId == CSSPropertyWebkitBackgroundClip || propId == CSSPropertyWebkitMaskClip) &&
4060 (val->id == CSSValueText || val->id == CSSValueWebkitTe xt))) {
4061 currValue = cssValuePool().createIdentifierValue(val->id );
4062 m_valueList->next();
4063 }
4064 break;
4065 case CSSPropertyBackgroundClip:
4066 if (parseBackgroundClip(val, currValue))
4067 m_valueList->next();
4068 break;
4069 case CSSPropertyBackgroundOrigin:
4070 if (val->id == CSSValueBorderBox || val->id == CSSValuePaddi ngBox || val->id == CSSValueContentBox) {
4071 currValue = cssValuePool().createIdentifierValue(val->id );
4072 m_valueList->next();
4073 }
4074 break;
4075 case CSSPropertyBackgroundPosition:
4076 case CSSPropertyWebkitMaskPosition:
4077 parseFillPosition(m_valueList.get(), currValue, currValue2);
4078 // parseFillPosition advances the m_valueList pointer.
4079 break;
4080 case CSSPropertyBackgroundPositionX:
4081 case CSSPropertyWebkitMaskPositionX: {
4082 currValue = parseFillPositionX(m_valueList.get());
4083 if (currValue)
4084 m_valueList->next();
4085 break;
4086 }
4087 case CSSPropertyBackgroundPositionY:
4088 case CSSPropertyWebkitMaskPositionY: {
4089 currValue = parseFillPositionY(m_valueList.get());
4090 if (currValue)
4091 m_valueList->next();
4092 break;
4093 }
4094 case CSSPropertyWebkitBackgroundComposite:
4095 case CSSPropertyWebkitMaskComposite:
4096 if (val->id >= CSSValueClear && val->id <= CSSValuePlusLight er) {
4097 currValue = cssValuePool().createIdentifierValue(val->id );
4098 m_valueList->next();
4099 }
4100 break;
4101 case CSSPropertyBackgroundBlendMode:
4102 if (val->id == CSSValueNormal || val->id == CSSValueMultiply
4103 || val->id == CSSValueScreen || val->id == CSSValueOverl ay || val->id == CSSValueDarken
4104 || val->id == CSSValueLighten || val->id == CSSValueCol orDodge || val->id == CSSValueColorBurn
4105 || val->id == CSSValueHardLight || val->id == CSSValueSo ftLight || val->id == CSSValueDifference
4106 || val->id == CSSValueExclusion || val->id == CSSValueHu e || val->id == CSSValueSaturation
4107 || val->id == CSSValueColor || val->id == CSSValueLumino sity) {
4108 currValue = cssValuePool().createIdentifierValue(val->id );
4109 m_valueList->next();
4110 }
4111 break;
4112 case CSSPropertyBackgroundRepeat:
4113 case CSSPropertyWebkitMaskRepeat:
4114 parseFillRepeat(currValue, currValue2);
4115 // parseFillRepeat advances the m_valueList pointer
4116 break;
4117 case CSSPropertyBackgroundSize:
4118 case CSSPropertyWebkitBackgroundSize:
4119 case CSSPropertyWebkitMaskSize: {
4120 currValue = parseFillSize(propId, allowComma);
4121 if (currValue)
4122 m_valueList->next();
4123 break;
4124 }
4125 case CSSPropertyMaskSourceType: {
4126 if (RuntimeEnabledFeatures::cssMaskSourceTypeEnabled()) {
4127 if (val->id == CSSValueAuto || val->id == CSSValueAlpha || val->id == CSSValueLuminance) {
4128 currValue = cssValuePool().createIdentifierValue(val ->id);
4129 m_valueList->next();
4130 } else {
4131 currValue = nullptr;
4132 }
4133 }
4134 break;
4135 }
4136 default:
4137 break;
4138 }
4139 if (!currValue)
4140 return false;
4141
4142 if (value && !values) {
4143 values = CSSValueList::createCommaSeparated();
4144 values->append(value.release());
4145 }
4146
4147 if (value2 && !values2) {
4148 values2 = CSSValueList::createCommaSeparated();
4149 values2->append(value2.release());
4150 }
4151
4152 if (values)
4153 values->append(currValue.release());
4154 else
4155 value = currValue.release();
4156 if (currValue2) {
4157 if (values2)
4158 values2->append(currValue2.release());
4159 else
4160 value2 = currValue2.release();
4161 }
4162 }
4163
4164 // When parsing any fill shorthand property, we let it handle building u p the lists for all
4165 // properties.
4166 if (inShorthand())
4167 break;
4168 }
4169
4170 if (values && values->length()) {
4171 retValue1 = values.release();
4172 if (values2 && values2->length())
4173 retValue2 = values2.release();
4174 return true;
4175 }
4176 if (value) {
4177 retValue1 = value.release();
4178 retValue2 = value2.release();
4179 return true;
4180 }
4181 return false;
4182 }
4183
4184 PassRefPtrWillBeRawPtr<CSSValue> CSSPropertyParser::parseAnimationDelay()
4185 {
4186 CSSParserValue* value = m_valueList->current();
4187 if (validUnit(value, FTime))
4188 return createPrimitiveNumericValue(value);
4189 return nullptr;
4190 }
4191
4192 PassRefPtrWillBeRawPtr<CSSValue> CSSPropertyParser::parseAnimationDirection()
4193 {
4194 CSSParserValue* value = m_valueList->current();
4195 if (value->id == CSSValueNormal || value->id == CSSValueAlternate || value-> id == CSSValueReverse || value->id == CSSValueAlternateReverse)
4196 return cssValuePool().createIdentifierValue(value->id);
4197 return nullptr;
4198 }
4199
4200 PassRefPtrWillBeRawPtr<CSSValue> CSSPropertyParser::parseAnimationDuration()
4201 {
4202 CSSParserValue* value = m_valueList->current();
4203 if (validUnit(value, FTime | FNonNeg))
4204 return createPrimitiveNumericValue(value);
4205 return nullptr;
4206 }
4207
4208 PassRefPtrWillBeRawPtr<CSSValue> CSSPropertyParser::parseAnimationFillMode()
4209 {
4210 CSSParserValue* value = m_valueList->current();
4211 if (value->id == CSSValueNone || value->id == CSSValueForwards || value->id == CSSValueBackwards || value->id == CSSValueBoth)
4212 return cssValuePool().createIdentifierValue(value->id);
4213 return nullptr;
4214 }
4215
4216 PassRefPtrWillBeRawPtr<CSSValue> CSSPropertyParser::parseAnimationIterationCount ()
4217 {
4218 CSSParserValue* value = m_valueList->current();
4219 if (value->id == CSSValueInfinite)
4220 return cssValuePool().createIdentifierValue(value->id);
4221 if (validUnit(value, FNumber | FNonNeg))
4222 return createPrimitiveNumericValue(value);
4223 return nullptr;
4224 }
4225
4226 PassRefPtrWillBeRawPtr<CSSValue> CSSPropertyParser::parseAnimationName()
4227 {
4228 CSSParserValue* value = m_valueList->current();
4229 if (value->unit == CSSPrimitiveValue::CSS_STRING || value->unit == CSSPrimit iveValue::CSS_IDENT) {
4230 if (value->id == CSSValueNone || (value->unit == CSSPrimitiveValue::CSS_ STRING && equalIgnoringCase(value, "none"))) {
4231 return cssValuePool().createIdentifierValue(CSSValueNone);
4232 } else {
4233 return createPrimitiveStringValue(value);
4234 }
4235 }
4236 return nullptr;
4237 }
4238
4239 PassRefPtrWillBeRawPtr<CSSValue> CSSPropertyParser::parseAnimationPlayState()
4240 {
4241 CSSParserValue* value = m_valueList->current();
4242 if (value->id == CSSValueRunning || value->id == CSSValuePaused)
4243 return cssValuePool().createIdentifierValue(value->id);
4244 return nullptr;
4245 }
4246
4247 PassRefPtrWillBeRawPtr<CSSValue> CSSPropertyParser::parseAnimationProperty(Anima tionParseContext& context)
4248 {
4249 CSSParserValue* value = m_valueList->current();
4250 if (value->unit != CSSPrimitiveValue::CSS_IDENT)
4251 return nullptr;
4252 CSSPropertyID result = cssPropertyID(value->string);
4253 if (result)
4254 return cssValuePool().createIdentifierValue(result);
4255 if (equalIgnoringCase(value, "all")) {
4256 context.sawAnimationPropertyKeyword();
4257 return cssValuePool().createIdentifierValue(CSSValueAll);
4258 }
4259 if (equalIgnoringCase(value, "none")) {
4260 context.commitAnimationPropertyKeyword();
4261 context.sawAnimationPropertyKeyword();
4262 return cssValuePool().createIdentifierValue(CSSValueNone);
4263 }
4264 return nullptr;
4265 }
4266
4267 bool CSSPropertyParser::parseTransformOriginShorthand(RefPtrWillBeRawPtr<CSSValu e>& value1, RefPtrWillBeRawPtr<CSSValue>& value2, RefPtrWillBeRawPtr<CSSValue>& value3)
4268 {
4269 parse2ValuesFillPosition(m_valueList.get(), value1, value2);
4270
4271 // now get z
4272 if (m_valueList->current()) {
4273 if (validUnit(m_valueList->current(), FLength)) {
4274 value3 = createPrimitiveNumericValue(m_valueList->current());
4275 m_valueList->next();
4276 return true;
4277 }
4278 return false;
4279 }
4280 value3 = cssValuePool().createImplicitInitialValue();
4281 return true;
4282 }
4283
4284 bool CSSPropertyParser::parseCubicBezierTimingFunctionValue(CSSParserValueList*& args, double& result)
4285 {
4286 CSSParserValue* v = args->current();
4287 if (!validUnit(v, FNumber))
4288 return false;
4289 result = v->fValue;
4290 v = args->next();
4291 if (!v)
4292 // The last number in the function has no comma after it, so we're done.
4293 return true;
4294 if (!isComma(v))
4295 return false;
4296 args->next();
4297 return true;
4298 }
4299
4300 PassRefPtrWillBeRawPtr<CSSValue> CSSPropertyParser::parseAnimationTimingFunction ()
4301 {
4302 CSSParserValue* value = m_valueList->current();
4303 if (value->id == CSSValueEase || value->id == CSSValueLinear || value->id == CSSValueEaseIn || value->id == CSSValueEaseOut
4304 || value->id == CSSValueEaseInOut || value->id == CSSValueStepStart || v alue->id == CSSValueStepEnd)
4305 return cssValuePool().createIdentifierValue(value->id);
4306
4307 // We must be a function.
4308 if (value->unit != CSSParserValue::Function)
4309 return nullptr;
4310
4311 CSSParserValueList* args = value->function->args.get();
4312
4313 if (equalIgnoringCase(value->function->name, "steps(")) {
4314 // For steps, 1 or 2 params must be specified (comma-separated)
4315 if (!args || (args->size() != 1 && args->size() != 3))
4316 return nullptr;
4317
4318 // There are two values.
4319 int numSteps;
4320 bool stepAtStart = false;
4321
4322 CSSParserValue* v = args->current();
4323 if (!validUnit(v, FInteger))
4324 return nullptr;
4325 numSteps = clampToInteger(v->fValue);
4326 if (numSteps < 1)
4327 return nullptr;
4328 v = args->next();
4329
4330 if (v) {
4331 // There is a comma so we need to parse the second value
4332 if (!isComma(v))
4333 return nullptr;
4334 v = args->next();
4335 if (v->id != CSSValueStart && v->id != CSSValueEnd)
4336 return nullptr;
4337 stepAtStart = v->id == CSSValueStart;
4338 }
4339
4340 return CSSStepsTimingFunctionValue::create(numSteps, stepAtStart);
4341 }
4342
4343 if (equalIgnoringCase(value->function->name, "cubic-bezier(")) {
4344 // For cubic bezier, 4 values must be specified.
4345 if (!args || args->size() != 7)
4346 return nullptr;
4347
4348 // There are two points specified. The x values must be between 0 and 1 but the y values can exceed this range.
4349 double x1, y1, x2, y2;
4350
4351 if (!parseCubicBezierTimingFunctionValue(args, x1))
4352 return nullptr;
4353 if (x1 < 0 || x1 > 1)
4354 return nullptr;
4355 if (!parseCubicBezierTimingFunctionValue(args, y1))
4356 return nullptr;
4357 if (!parseCubicBezierTimingFunctionValue(args, x2))
4358 return nullptr;
4359 if (x2 < 0 || x2 > 1)
4360 return nullptr;
4361 if (!parseCubicBezierTimingFunctionValue(args, y2))
4362 return nullptr;
4363
4364 return CSSCubicBezierTimingFunctionValue::create(x1, y1, x2, y2);
4365 }
4366
4367 return nullptr;
4368 }
4369
4370 bool CSSPropertyParser::parseAnimationProperty(CSSPropertyID propId, RefPtrWillB eRawPtr<CSSValue>& result, AnimationParseContext& context)
4371 {
4372 RefPtrWillBeRawPtr<CSSValueList> values;
4373 CSSParserValue* val;
4374 RefPtrWillBeRawPtr<CSSValue> value;
4375 bool allowComma = false;
4376
4377 result = nullptr;
4378
4379 while ((val = m_valueList->current())) {
4380 RefPtrWillBeRawPtr<CSSValue> currValue;
4381 if (allowComma) {
4382 if (!isComma(val))
4383 return false;
4384 m_valueList->next();
4385 allowComma = false;
4386 }
4387 else {
4388 switch (propId) {
4389 case CSSPropertyAnimationDelay:
4390 case CSSPropertyWebkitAnimationDelay:
4391 case CSSPropertyTransitionDelay:
4392 case CSSPropertyWebkitTransitionDelay:
4393 currValue = parseAnimationDelay();
4394 if (currValue)
4395 m_valueList->next();
4396 break;
4397 case CSSPropertyAnimationDirection:
4398 case CSSPropertyWebkitAnimationDirection:
4399 currValue = parseAnimationDirection();
4400 if (currValue)
4401 m_valueList->next();
4402 break;
4403 case CSSPropertyAnimationDuration:
4404 case CSSPropertyWebkitAnimationDuration:
4405 case CSSPropertyTransitionDuration:
4406 case CSSPropertyWebkitTransitionDuration:
4407 currValue = parseAnimationDuration();
4408 if (currValue)
4409 m_valueList->next();
4410 break;
4411 case CSSPropertyAnimationFillMode:
4412 case CSSPropertyWebkitAnimationFillMode:
4413 currValue = parseAnimationFillMode();
4414 if (currValue)
4415 m_valueList->next();
4416 break;
4417 case CSSPropertyAnimationIterationCount:
4418 case CSSPropertyWebkitAnimationIterationCount:
4419 currValue = parseAnimationIterationCount();
4420 if (currValue)
4421 m_valueList->next();
4422 break;
4423 case CSSPropertyAnimationName:
4424 case CSSPropertyWebkitAnimationName:
4425 currValue = parseAnimationName();
4426 if (currValue)
4427 m_valueList->next();
4428 break;
4429 case CSSPropertyAnimationPlayState:
4430 case CSSPropertyWebkitAnimationPlayState:
4431 currValue = parseAnimationPlayState();
4432 if (currValue)
4433 m_valueList->next();
4434 break;
4435 case CSSPropertyTransitionProperty:
4436 case CSSPropertyWebkitTransitionProperty:
4437 currValue = parseAnimationProperty(context);
4438 if (value && !context.animationPropertyKeywordAllowed())
4439 return false;
4440 if (currValue)
4441 m_valueList->next();
4442 break;
4443 case CSSPropertyAnimationTimingFunction:
4444 case CSSPropertyWebkitAnimationTimingFunction:
4445 case CSSPropertyTransitionTimingFunction:
4446 case CSSPropertyWebkitTransitionTimingFunction:
4447 currValue = parseAnimationTimingFunction();
4448 if (currValue)
4449 m_valueList->next();
4450 break;
4451 default:
4452 ASSERT_NOT_REACHED();
4453 return false;
4454 }
4455
4456 if (!currValue)
4457 return false;
4458
4459 if (value && !values) {
4460 values = CSSValueList::createCommaSeparated();
4461 values->append(value.release());
4462 }
4463
4464 if (values)
4465 values->append(currValue.release());
4466 else
4467 value = currValue.release();
4468
4469 allowComma = true;
4470 }
4471
4472 // When parsing the 'transition' shorthand property, we let it handle bu ilding up the lists for all
4473 // properties.
4474 if (inShorthand())
4475 break;
4476 }
4477
4478 if (values && values->length()) {
4479 result = values.release();
4480 return true;
4481 }
4482 if (value) {
4483 result = value.release();
4484 return true;
4485 }
4486 return false;
4487 }
4488
4489 // The function parses [ <integer> || <string> ] in <grid-line> (which can be st and alone or with 'span').
4490 bool CSSPropertyParser::parseIntegerOrStringFromGridPosition(RefPtrWillBeRawPtr< CSSPrimitiveValue>& numericValue, RefPtrWillBeRawPtr<CSSPrimitiveValue>& gridLin eName)
4491 {
4492 CSSParserValue* value = m_valueList->current();
4493 if (validUnit(value, FInteger) && value->fValue) {
4494 numericValue = createPrimitiveNumericValue(value);
4495 value = m_valueList->next();
4496 if (value && value->unit == CSSPrimitiveValue::CSS_STRING) {
4497 gridLineName = createPrimitiveStringValue(m_valueList->current());
4498 m_valueList->next();
4499 }
4500 return true;
4501 }
4502
4503 if (value->unit == CSSPrimitiveValue::CSS_STRING) {
4504 gridLineName = createPrimitiveStringValue(m_valueList->current());
4505 value = m_valueList->next();
4506 if (value && validUnit(value, FInteger) && value->fValue) {
4507 numericValue = createPrimitiveNumericValue(value);
4508 m_valueList->next();
4509 }
4510 return true;
4511 }
4512
4513 return false;
4514 }
4515
4516 PassRefPtrWillBeRawPtr<CSSValue> CSSPropertyParser::parseGridPosition()
4517 {
4518 ASSERT(RuntimeEnabledFeatures::cssGridLayoutEnabled());
4519
4520 CSSParserValue* value = m_valueList->current();
4521 if (value->id == CSSValueAuto) {
4522 m_valueList->next();
4523 return cssValuePool().createIdentifierValue(CSSValueAuto);
4524 }
4525
4526 if (value->id != CSSValueSpan && value->unit == CSSPrimitiveValue::CSS_IDENT ) {
4527 m_valueList->next();
4528 return cssValuePool().createValue(value->string, CSSPrimitiveValue::CSS_ STRING);
4529 }
4530
4531 RefPtrWillBeRawPtr<CSSPrimitiveValue> numericValue;
4532 RefPtrWillBeRawPtr<CSSPrimitiveValue> gridLineName;
4533 bool hasSeenSpanKeyword = false;
4534
4535 if (parseIntegerOrStringFromGridPosition(numericValue, gridLineName)) {
4536 value = m_valueList->current();
4537 if (value && value->id == CSSValueSpan) {
4538 hasSeenSpanKeyword = true;
4539 m_valueList->next();
4540 }
4541 } else if (value->id == CSSValueSpan) {
4542 hasSeenSpanKeyword = true;
4543 if (m_valueList->next())
4544 parseIntegerOrStringFromGridPosition(numericValue, gridLineName);
4545 }
4546
4547 // Check that we have consumed all the value list. For shorthands, the parse r will pass
4548 // the whole value list (including the opposite position).
4549 if (m_valueList->current() && !isForwardSlashOperator(m_valueList->current() ))
4550 return nullptr;
4551
4552 // If we didn't parse anything, this is not a valid grid position.
4553 if (!hasSeenSpanKeyword && !gridLineName && !numericValue)
4554 return nullptr;
4555
4556 // Negative numbers are not allowed for span (but are for <integer>).
4557 if (hasSeenSpanKeyword && numericValue && numericValue->getIntValue() < 0)
4558 return nullptr;
4559
4560 RefPtrWillBeRawPtr<CSSValueList> values = CSSValueList::createSpaceSeparated ();
4561 if (hasSeenSpanKeyword)
4562 values->append(cssValuePool().createIdentifierValue(CSSValueSpan));
4563 if (numericValue)
4564 values->append(numericValue.release());
4565 if (gridLineName)
4566 values->append(gridLineName.release());
4567 ASSERT(values->length());
4568 return values.release();
4569 }
4570
4571 static PassRefPtrWillBeRawPtr<CSSValue> gridMissingGridPositionValue(CSSValue* v alue)
4572 {
4573 if (value->isPrimitiveValue() && toCSSPrimitiveValue(value)->isString())
4574 return value;
4575
4576 return cssValuePool().createIdentifierValue(CSSValueAuto);
4577 }
4578
4579 bool CSSPropertyParser::parseGridItemPositionShorthand(CSSPropertyID shorthandId , bool important)
4580 {
4581 ShorthandScope scope(this, shorthandId);
4582 const StylePropertyShorthand& shorthand = shorthandForProperty(shorthandId);
4583 ASSERT(shorthand.length() == 2);
4584
4585 RefPtrWillBeRawPtr<CSSValue> startValue = parseGridPosition();
4586 if (!startValue)
4587 return false;
4588
4589 RefPtrWillBeRawPtr<CSSValue> endValue;
4590 if (m_valueList->current()) {
4591 if (!isForwardSlashOperator(m_valueList->current()))
4592 return false;
4593
4594 if (!m_valueList->next())
4595 return false;
4596
4597 endValue = parseGridPosition();
4598 if (!endValue || m_valueList->current())
4599 return false;
4600 } else {
4601 endValue = gridMissingGridPositionValue(startValue.get());
4602 }
4603
4604 addProperty(shorthand.properties()[0], startValue, important);
4605 addProperty(shorthand.properties()[1], endValue, important);
4606 return true;
4607 }
4608
4609 bool CSSPropertyParser::parseGridAreaShorthand(bool important)
4610 {
4611 ASSERT(RuntimeEnabledFeatures::cssGridLayoutEnabled());
4612
4613 ShorthandScope scope(this, CSSPropertyGridArea);
4614 const StylePropertyShorthand& shorthand = gridAreaShorthand();
4615 ASSERT_UNUSED(shorthand, shorthand.length() == 4);
4616
4617 RefPtrWillBeRawPtr<CSSValue> rowStartValue = parseGridPosition();
4618 if (!rowStartValue)
4619 return false;
4620
4621 RefPtrWillBeRawPtr<CSSValue> columnStartValue;
4622 if (!parseSingleGridAreaLonghand(columnStartValue))
4623 return false;
4624
4625 RefPtrWillBeRawPtr<CSSValue> rowEndValue;
4626 if (!parseSingleGridAreaLonghand(rowEndValue))
4627 return false;
4628
4629 RefPtrWillBeRawPtr<CSSValue> columnEndValue;
4630 if (!parseSingleGridAreaLonghand(columnEndValue))
4631 return false;
4632
4633 if (!columnStartValue)
4634 columnStartValue = gridMissingGridPositionValue(rowStartValue.get());
4635
4636 if (!rowEndValue)
4637 rowEndValue = gridMissingGridPositionValue(rowStartValue.get());
4638
4639 if (!columnEndValue)
4640 columnEndValue = gridMissingGridPositionValue(columnStartValue.get());
4641
4642 addProperty(CSSPropertyGridRowStart, rowStartValue, important);
4643 addProperty(CSSPropertyGridColumnStart, columnStartValue, important);
4644 addProperty(CSSPropertyGridRowEnd, rowEndValue, important);
4645 addProperty(CSSPropertyGridColumnEnd, columnEndValue, important);
4646 return true;
4647 }
4648
4649 bool CSSPropertyParser::parseSingleGridAreaLonghand(RefPtrWillBeRawPtr<CSSValue> & property)
4650 {
4651 if (!m_valueList->current())
4652 return true;
4653
4654 if (!isForwardSlashOperator(m_valueList->current()))
4655 return false;
4656
4657 if (!m_valueList->next())
4658 return false;
4659
4660 property = parseGridPosition();
4661 return true;
4662 }
4663
4664 void CSSPropertyParser::parseGridLineNames(CSSParserValueList* parserValueList, CSSValueList& valueList)
4665 {
4666 ASSERT(parserValueList->current() && parserValueList->current()->unit == CSS ParserValue::ValueList);
4667
4668 CSSParserValueList* identList = parserValueList->current()->valueList;
4669 if (!identList->size()) {
4670 parserValueList->next();
4671 return;
4672 }
4673
4674 RefPtrWillBeRawPtr<CSSGridLineNamesValue> lineNames = CSSGridLineNamesValue: :create();
4675 while (CSSParserValue* identValue = identList->current()) {
4676 ASSERT(identValue->unit == CSSPrimitiveValue::CSS_IDENT);
4677 RefPtrWillBeRawPtr<CSSPrimitiveValue> lineName = createPrimitiveStringVa lue(identValue);
4678 lineNames->append(lineName.release());
4679 identList->next();
4680 }
4681 valueList.append(lineNames.release());
4682
4683 parserValueList->next();
4684 }
4685
4686 bool CSSPropertyParser::parseGridTrackList(CSSPropertyID propId, bool important)
4687 {
4688 ASSERT(RuntimeEnabledFeatures::cssGridLayoutEnabled());
4689
4690 CSSParserValue* value = m_valueList->current();
4691 if (value->id == CSSValueNone) {
4692 if (m_valueList->next())
4693 return false;
4694
4695 addProperty(propId, cssValuePool().createIdentifierValue(value->id), imp ortant);
4696 return true;
4697 }
4698
4699 RefPtrWillBeRawPtr<CSSValueList> values = CSSValueList::createSpaceSeparated ();
4700 // Handle leading <ident>*.
4701 value = m_valueList->current();
4702 if (value && value->unit == CSSParserValue::ValueList)
4703 parseGridLineNames(m_valueList.get(), *values);
4704
4705 bool seenTrackSizeOrRepeatFunction = false;
4706 while (CSSParserValue* currentValue = m_valueList->current()) {
4707 if (currentValue->unit == CSSParserValue::Function && equalIgnoringCase( currentValue->function->name, "repeat(")) {
4708 if (!parseGridTrackRepeatFunction(*values))
4709 return false;
4710 seenTrackSizeOrRepeatFunction = true;
4711 } else {
4712 RefPtrWillBeRawPtr<CSSValue> value = parseGridTrackSize(*m_valueList );
4713 if (!value)
4714 return false;
4715 values->append(value);
4716 seenTrackSizeOrRepeatFunction = true;
4717 }
4718 // This will handle the trailing <ident>* in the grammar.
4719 value = m_valueList->current();
4720 if (value && value->unit == CSSParserValue::ValueList)
4721 parseGridLineNames(m_valueList.get(), *values);
4722 }
4723
4724 // We should have found a <track-size> or else it is not a valid <track-list >
4725 if (!seenTrackSizeOrRepeatFunction)
4726 return false;
4727
4728 addProperty(propId, values.release(), important);
4729 return true;
4730 }
4731
4732 bool CSSPropertyParser::parseGridTrackRepeatFunction(CSSValueList& list)
4733 {
4734 CSSParserValueList* arguments = m_valueList->current()->function->args.get() ;
4735 if (!arguments || arguments->size() < 3 || !validUnit(arguments->valueAt(0), FPositiveInteger) || !isComma(arguments->valueAt(1)))
4736 return false;
4737
4738 ASSERT_WITH_SECURITY_IMPLICATION(arguments->valueAt(0)->fValue > 0);
4739 size_t repetitions = arguments->valueAt(0)->fValue;
4740 RefPtrWillBeRawPtr<CSSValueList> repeatedValues = CSSValueList::createSpaceS eparated();
4741 arguments->next(); // Skip the repetition count.
4742 arguments->next(); // Skip the comma.
4743
4744 // Handle leading <ident>*.
4745 CSSParserValue* currentValue = arguments->current();
4746 if (currentValue && currentValue->unit == CSSParserValue::ValueList)
4747 parseGridLineNames(arguments, *repeatedValues);
4748
4749 while (arguments->current()) {
4750 RefPtrWillBeRawPtr<CSSValue> trackSize = parseGridTrackSize(*arguments);
4751 if (!trackSize)
4752 return false;
4753
4754 repeatedValues->append(trackSize);
4755
4756 // This takes care of any trailing <ident>* in the grammar.
4757 currentValue = arguments->current();
4758 if (currentValue && currentValue->unit == CSSParserValue::ValueList)
4759 parseGridLineNames(arguments, *repeatedValues);
4760 }
4761
4762 for (size_t i = 0; i < repetitions; ++i) {
4763 for (size_t j = 0; j < repeatedValues->length(); ++j)
4764 list.append(repeatedValues->itemWithoutBoundsCheck(j));
4765 }
4766
4767 // parseGridTrackSize iterated over the repeat arguments, move to the next v alue.
4768 m_valueList->next();
4769 return true;
4770 }
4771
4772
4773 PassRefPtrWillBeRawPtr<CSSValue> CSSPropertyParser::parseGridTrackSize(CSSParser ValueList& inputList)
4774 {
4775 ASSERT(RuntimeEnabledFeatures::cssGridLayoutEnabled());
4776
4777 CSSParserValue* currentValue = inputList.current();
4778 inputList.next();
4779
4780 if (currentValue->id == CSSValueAuto)
4781 return cssValuePool().createIdentifierValue(CSSValueAuto);
4782
4783 if (currentValue->unit == CSSParserValue::Function && equalIgnoringCase(curr entValue->function->name, "minmax(")) {
4784 // The spec defines the following grammar: minmax( <track-breadth> , <tr ack-breadth> )
4785 CSSParserValueList* arguments = currentValue->function->args.get();
4786 if (!arguments || arguments->size() != 3 || !isComma(arguments->valueAt( 1)))
4787 return nullptr;
4788
4789 RefPtrWillBeRawPtr<CSSPrimitiveValue> minTrackBreadth = parseGridBreadth (arguments->valueAt(0));
4790 if (!minTrackBreadth)
4791 return nullptr;
4792
4793 RefPtrWillBeRawPtr<CSSPrimitiveValue> maxTrackBreadth = parseGridBreadth (arguments->valueAt(2));
4794 if (!maxTrackBreadth)
4795 return nullptr;
4796
4797 RefPtrWillBeRawPtr<CSSValueList> parsedArguments = CSSValueList::createC ommaSeparated();
4798 parsedArguments->append(minTrackBreadth);
4799 parsedArguments->append(maxTrackBreadth);
4800 return CSSFunctionValue::create("minmax(", parsedArguments);
4801 }
4802
4803 return parseGridBreadth(currentValue);
4804 }
4805
4806 PassRefPtrWillBeRawPtr<CSSPrimitiveValue> CSSPropertyParser::parseGridBreadth(CS SParserValue* currentValue)
4807 {
4808 if (currentValue->id == CSSValueMinContent || currentValue->id == CSSValueMa xContent)
4809 return cssValuePool().createIdentifierValue(currentValue->id);
4810
4811 if (currentValue->unit == CSSPrimitiveValue::CSS_FR) {
4812 double flexValue = currentValue->fValue;
4813
4814 // Fractional unit is a non-negative dimension.
4815 if (flexValue <= 0)
4816 return nullptr;
4817
4818 return cssValuePool().createValue(flexValue, CSSPrimitiveValue::CSS_FR);
4819 }
4820
4821 if (!validUnit(currentValue, FNonNeg | FLength | FPercent))
4822 return nullptr;
4823
4824 return createPrimitiveNumericValue(currentValue);
4825 }
4826
4827 PassRefPtrWillBeRawPtr<CSSValue> CSSPropertyParser::parseGridTemplateAreas()
4828 {
4829 NamedGridAreaMap gridAreaMap;
4830 size_t rowCount = 0;
4831 size_t columnCount = 0;
4832
4833 while (CSSParserValue* currentValue = m_valueList->current()) {
4834 if (currentValue->unit != CSSPrimitiveValue::CSS_STRING)
4835 return nullptr;
4836
4837 String gridRowNames = currentValue->string;
4838 if (!gridRowNames.length())
4839 return nullptr;
4840
4841 Vector<String> columnNames;
4842 gridRowNames.split(' ', columnNames);
4843
4844 if (!columnCount) {
4845 columnCount = columnNames.size();
4846 ASSERT(columnCount);
4847 } else if (columnCount != columnNames.size()) {
4848 // The declaration is invalid is all the rows don't have the number of columns.
4849 return nullptr;
4850 }
4851
4852 for (size_t currentCol = 0; currentCol < columnCount; ++currentCol) {
4853 const String& gridAreaName = columnNames[currentCol];
4854
4855 // Unamed areas are always valid (we consider them to be 1x1).
4856 if (gridAreaName == ".")
4857 continue;
4858
4859 // We handle several grid areas with the same name at once to simpli fy the validation code.
4860 size_t lookAheadCol;
4861 for (lookAheadCol = currentCol; lookAheadCol < (columnCount - 1); ++ lookAheadCol) {
4862 if (columnNames[lookAheadCol + 1] != gridAreaName)
4863 break;
4864 }
4865
4866 NamedGridAreaMap::iterator gridAreaIt = gridAreaMap.find(gridAreaNam e);
4867 if (gridAreaIt == gridAreaMap.end()) {
4868 gridAreaMap.add(gridAreaName, GridCoordinate(GridSpan(rowCount, rowCount), GridSpan(currentCol, lookAheadCol)));
4869 } else {
4870 GridCoordinate& gridCoordinate = gridAreaIt->value;
4871
4872 // The following checks test that the grid area is a single fill ed-in rectangle.
4873 // 1. The new row is adjacent to the previously parsed row.
4874 if (rowCount != gridCoordinate.rows.initialPositionIndex + 1)
4875 return nullptr;
4876
4877 // 2. The new area starts at the same position as the previously parsed area.
4878 if (currentCol != gridCoordinate.columns.initialPositionIndex)
4879 return nullptr;
4880
4881 // 3. The new area ends at the same position as the previously p arsed area.
4882 if (lookAheadCol != gridCoordinate.columns.finalPositionIndex)
4883 return nullptr;
4884
4885 ++gridCoordinate.rows.finalPositionIndex;
4886 }
4887 currentCol = lookAheadCol;
4888 }
4889
4890 ++rowCount;
4891 m_valueList->next();
4892 }
4893
4894 if (!rowCount || !columnCount)
4895 return nullptr;
4896
4897 return CSSGridTemplateAreasValue::create(gridAreaMap, rowCount, columnCount) ;
4898 }
4899
4900 PassRefPtrWillBeRawPtr<CSSValue> CSSPropertyParser::parseCounterContent(CSSParse rValueList* args, bool counters)
4901 {
4902 unsigned numArgs = args->size();
4903 if (counters && numArgs != 3 && numArgs != 5)
4904 return nullptr;
4905 if (!counters && numArgs != 1 && numArgs != 3)
4906 return nullptr;
4907
4908 CSSParserValue* i = args->current();
4909 if (i->unit != CSSPrimitiveValue::CSS_IDENT)
4910 return nullptr;
4911 RefPtrWillBeRawPtr<CSSPrimitiveValue> identifier = createPrimitiveStringValu e(i);
4912
4913 RefPtrWillBeRawPtr<CSSPrimitiveValue> separator;
4914 if (!counters)
4915 separator = cssValuePool().createValue(String(), CSSPrimitiveValue::CSS_ STRING);
4916 else {
4917 i = args->next();
4918 if (i->unit != CSSParserValue::Operator || i->iValue != ',')
4919 return nullptr;
4920
4921 i = args->next();
4922 if (i->unit != CSSPrimitiveValue::CSS_STRING)
4923 return nullptr;
4924
4925 separator = createPrimitiveStringValue(i);
4926 }
4927
4928 RefPtrWillBeRawPtr<CSSPrimitiveValue> listStyle;
4929 i = args->next();
4930 if (!i) // Make the list style default decimal
4931 listStyle = cssValuePool().createIdentifierValue(CSSValueDecimal);
4932 else {
4933 if (i->unit != CSSParserValue::Operator || i->iValue != ',')
4934 return nullptr;
4935
4936 i = args->next();
4937 if (i->unit != CSSPrimitiveValue::CSS_IDENT)
4938 return nullptr;
4939
4940 CSSValueID listStyleID = CSSValueInvalid;
4941 if (i->id == CSSValueNone || (i->id >= CSSValueDisc && i->id <= CSSValue KatakanaIroha))
4942 listStyleID = i->id;
4943 else
4944 return nullptr;
4945
4946 listStyle = cssValuePool().createIdentifierValue(listStyleID);
4947 }
4948
4949 return cssValuePool().createValue(Counter::create(identifier.release(), list Style.release(), separator.release()));
4950 }
4951
4952 bool CSSPropertyParser::parseClipShape(CSSPropertyID propId, bool important)
4953 {
4954 CSSParserValue* value = m_valueList->current();
4955 CSSParserValueList* args = value->function->args.get();
4956
4957 if (!equalIgnoringCase(value->function->name, "rect(") || !args)
4958 return false;
4959
4960 // rect(t, r, b, l) || rect(t r b l)
4961 if (args->size() != 4 && args->size() != 7)
4962 return false;
4963 RefPtrWillBeRawPtr<Rect> rect = Rect::create();
4964 bool valid = true;
4965 int i = 0;
4966 CSSParserValue* a = args->current();
4967 while (a) {
4968 valid = a->id == CSSValueAuto || validUnit(a, FLength);
4969 if (!valid)
4970 break;
4971 RefPtrWillBeRawPtr<CSSPrimitiveValue> length = a->id == CSSValueAuto ?
4972 cssValuePool().createIdentifierValue(CSSValueAuto) :
4973 createPrimitiveNumericValue(a);
4974 if (i == 0)
4975 rect->setTop(length);
4976 else if (i == 1)
4977 rect->setRight(length);
4978 else if (i == 2)
4979 rect->setBottom(length);
4980 else
4981 rect->setLeft(length);
4982 a = args->next();
4983 if (a && args->size() == 7) {
4984 if (a->unit == CSSParserValue::Operator && a->iValue == ',') {
4985 a = args->next();
4986 } else {
4987 valid = false;
4988 break;
4989 }
4990 }
4991 i++;
4992 }
4993 if (valid) {
4994 addProperty(propId, cssValuePool().createValue(rect.release()), importan t);
4995 m_valueList->next();
4996 return true;
4997 }
4998 return false;
4999 }
5000
5001 static void completeBorderRadii(RefPtrWillBeRawPtr<CSSPrimitiveValue> radii[4])
5002 {
5003 if (radii[3])
5004 return;
5005 if (!radii[2]) {
5006 if (!radii[1])
5007 radii[1] = radii[0];
5008 radii[2] = radii[0];
5009 }
5010 radii[3] = radii[1];
5011 }
5012
5013 // FIXME: This should be refactored with CSSParser::parseBorderRadius.
5014 // CSSParser::parseBorderRadius contains support for some legacy radius construc tion.
5015 PassRefPtrWillBeRawPtr<CSSBasicShape> CSSPropertyParser::parseInsetRoundedCorner s(PassRefPtrWillBeRawPtr<CSSBasicShapeInset> shape, CSSParserValueList* args)
5016 {
5017 CSSParserValue* argument = args->next();
5018
5019 if (!argument)
5020 return nullptr;
5021
5022 CSSParserValueList radiusArguments;
5023 while (argument) {
5024 radiusArguments.addValue(*argument);
5025 argument = args->next();
5026 }
5027
5028 unsigned num = radiusArguments.size();
5029 if (!num || num > 9)
5030 return nullptr;
5031
5032 // FIXME: Refactor completeBorderRadii and the array
5033 RefPtrWillBeRawPtr<CSSPrimitiveValue> radii[2][4];
5034
5035 unsigned indexAfterSlash = 0;
5036 for (unsigned i = 0; i < num; ++i) {
5037 CSSParserValue* value = radiusArguments.valueAt(i);
5038 if (value->unit == CSSParserValue::Operator) {
5039 if (value->iValue != '/')
5040 return nullptr;
5041
5042 if (!i || indexAfterSlash || i + 1 == num)
5043 return nullptr;
5044
5045 indexAfterSlash = i + 1;
5046 completeBorderRadii(radii[0]);
5047 continue;
5048 }
5049
5050 if (i - indexAfterSlash >= 4)
5051 return nullptr;
5052
5053 if (!validUnit(value, FLength | FPercent | FNonNeg))
5054 return nullptr;
5055
5056 RefPtrWillBeRawPtr<CSSPrimitiveValue> radius = createPrimitiveNumericVal ue(value);
5057
5058 if (!indexAfterSlash)
5059 radii[0][i] = radius;
5060 else
5061 radii[1][i - indexAfterSlash] = radius.release();
5062 }
5063
5064 if (!indexAfterSlash) {
5065 completeBorderRadii(radii[0]);
5066 for (unsigned i = 0; i < 4; ++i)
5067 radii[1][i] = radii[0][i];
5068 } else {
5069 completeBorderRadii(radii[1]);
5070 }
5071 shape->setTopLeftRadius(createPrimitiveValuePair(radii[0][0].release(), radi i[1][0].release()));
5072 shape->setTopRightRadius(createPrimitiveValuePair(radii[0][1].release(), rad ii[1][1].release()));
5073 shape->setBottomRightRadius(createPrimitiveValuePair(radii[0][2].release(), radii[1][2].release()));
5074 shape->setBottomLeftRadius(createPrimitiveValuePair(radii[0][3].release(), r adii[1][3].release()));
5075
5076 return shape;
5077 }
5078
5079 PassRefPtrWillBeRawPtr<CSSBasicShape> CSSPropertyParser::parseBasicShapeInset(CS SParserValueList* args)
5080 {
5081 ASSERT(args);
5082
5083 RefPtrWillBeRawPtr<CSSBasicShapeInset> shape = CSSBasicShapeInset::create();
5084
5085 CSSParserValue* argument = args->current();
5086 WillBeHeapVector<RefPtrWillBeMember<CSSPrimitiveValue> > widthArguments;
5087 bool hasRoundedInset = false;
5088
5089 while (argument) {
5090 if (argument->unit == CSSPrimitiveValue::CSS_IDENT && equalIgnoringCase( argument->string, "round")) {
5091 hasRoundedInset = true;
5092 break;
5093 }
5094
5095 Units unitFlags = FLength | FPercent;
5096 if (!validUnit(argument, unitFlags) || widthArguments.size() > 4)
5097 return nullptr;
5098
5099 widthArguments.append(createPrimitiveNumericValue(argument));
5100 argument = args->next();
5101 }
5102
5103 switch (widthArguments.size()) {
5104 case 1: {
5105 shape->updateShapeSize1Value(widthArguments[0].get());
5106 break;
5107 }
5108 case 2: {
5109 shape->updateShapeSize2Values(widthArguments[0].get(), widthArguments[1] .get());
5110 break;
5111 }
5112 case 3: {
5113 shape->updateShapeSize3Values(widthArguments[0].get(), widthArguments[1] .get(), widthArguments[2].get());
5114 break;
5115 }
5116 case 4: {
5117 shape->updateShapeSize4Values(widthArguments[0].get(), widthArguments[1] .get(), widthArguments[2].get(), widthArguments[3].get());
5118 break;
5119 }
5120 default:
5121 return nullptr;
5122 }
5123
5124 if (hasRoundedInset)
5125 return parseInsetRoundedCorners(shape, args);
5126 return shape;
5127 }
5128
5129 static bool isItemPositionKeyword(CSSValueID id)
5130 {
5131 return id == CSSValueStart || id == CSSValueEnd || id == CSSValueCenter
5132 || id == CSSValueSelfStart || id == CSSValueSelfEnd || id == CSSValueFle xStart
5133 || id == CSSValueFlexEnd || id == CSSValueLeft || id == CSSValueRight;
5134 }
5135
5136 bool CSSPropertyParser::parseItemPositionOverflowPosition(CSSPropertyID propId, bool important)
5137 {
5138 // auto | baseline | stretch | [<item-position> && <overflow-position>? ]
5139 // <item-position> = center | start | end | self-start | self-end | flex-sta rt | flex-end | left | right;
5140 // <overflow-position> = true | safe
5141
5142 CSSParserValue* value = m_valueList->current();
5143
5144 if (value->id == CSSValueAuto || value->id == CSSValueBaseline || value->id == CSSValueStretch) {
5145 if (m_valueList->next())
5146 return false;
5147
5148 addProperty(propId, cssValuePool().createIdentifierValue(value->id), imp ortant);
5149 return true;
5150 }
5151
5152 RefPtrWillBeRawPtr<CSSPrimitiveValue> position = nullptr;
5153 RefPtrWillBeRawPtr<CSSPrimitiveValue> overflowAlignmentKeyword = nullptr;
5154 if (isItemPositionKeyword(value->id)) {
5155 position = cssValuePool().createIdentifierValue(value->id);
5156 value = m_valueList->next();
5157 if (value) {
5158 if (value->id == CSSValueTrue || value->id == CSSValueSafe)
5159 overflowAlignmentKeyword = cssValuePool().createIdentifierValue( value->id);
5160 else
5161 return false;
5162 }
5163 } else if (value->id == CSSValueTrue || value->id == CSSValueSafe) {
5164 overflowAlignmentKeyword = cssValuePool().createIdentifierValue(value->i d);
5165 value = m_valueList->next();
5166 if (value) {
5167 if (isItemPositionKeyword(value->id))
5168 position = cssValuePool().createIdentifierValue(value->id);
5169 else
5170 return false;
5171 }
5172 } else {
5173 return false;
5174 }
5175
5176 if (m_valueList->next())
5177 return false;
5178
5179 ASSERT(position);
5180 if (overflowAlignmentKeyword)
5181 addProperty(propId, createPrimitiveValuePair(position, overflowAlignment Keyword), important);
5182 else
5183 addProperty(propId, position.release(), important);
5184
5185 return true;
5186 }
5187
5188 PassRefPtrWillBeRawPtr<CSSBasicShape> CSSPropertyParser::parseBasicShapeRectangl e(CSSParserValueList* args)
5189 {
5190 ASSERT(args);
5191
5192 // rect(x, y, width, height, [[rx], ry])
5193 if (args->size() != 7 && args->size() != 9 && args->size() != 11)
5194 return nullptr;
5195
5196 RefPtrWillBeRawPtr<CSSBasicShapeRectangle> shape = CSSBasicShapeRectangle::c reate();
5197
5198 unsigned argumentNumber = 0;
5199 CSSParserValue* argument = args->current();
5200 while (argument) {
5201 Units unitFlags = FLength | FPercent;
5202 if (argumentNumber > 1) {
5203 // Arguments width, height, rx, and ry cannot be negative.
5204 unitFlags = unitFlags | FNonNeg;
5205 }
5206 if (!validUnit(argument, unitFlags))
5207 return nullptr;
5208
5209 RefPtrWillBeRawPtr<CSSPrimitiveValue> length = createPrimitiveNumericVal ue(argument);
5210 ASSERT(argumentNumber < 6);
5211 switch (argumentNumber) {
5212 case 0:
5213 shape->setX(length);
5214 break;
5215 case 1:
5216 shape->setY(length);
5217 break;
5218 case 2:
5219 shape->setWidth(length);
5220 break;
5221 case 3:
5222 shape->setHeight(length);
5223 break;
5224 case 4:
5225 shape->setRadiusX(length);
5226 break;
5227 case 5:
5228 shape->setRadiusY(length);
5229 break;
5230 }
5231 argument = args->next();
5232 if (argument) {
5233 if (!isComma(argument))
5234 return nullptr;
5235
5236 argument = args->next();
5237 }
5238 argumentNumber++;
5239 }
5240
5241 if (argumentNumber < 4)
5242 return nullptr;
5243 return shape;
5244 }
5245
5246 PassRefPtrWillBeRawPtr<CSSBasicShape> CSSPropertyParser::parseBasicShapeInsetRec tangle(CSSParserValueList* args)
5247 {
5248 ASSERT(args);
5249
5250 // inset-rectangle(top, right, bottom, left, [[rx], ry])
5251 if (args->size() != 7 && args->size() != 9 && args->size() != 11)
5252 return nullptr;
5253
5254 RefPtrWillBeRawPtr<CSSBasicShapeInsetRectangle> shape = CSSBasicShapeInsetRe ctangle::create();
5255
5256 unsigned argumentNumber = 0;
5257 CSSParserValue* argument = args->current();
5258 while (argument) {
5259 Units unitFlags = FLength | FPercent | FNonNeg;
5260 if (!validUnit(argument, unitFlags))
5261 return nullptr;
5262
5263 RefPtrWillBeRawPtr<CSSPrimitiveValue> length = createPrimitiveNumericVal ue(argument);
5264 ASSERT(argumentNumber < 6);
5265 switch (argumentNumber) {
5266 case 0:
5267 shape->setTop(length);
5268 break;
5269 case 1:
5270 shape->setRight(length);
5271 break;
5272 case 2:
5273 shape->setBottom(length);
5274 break;
5275 case 3:
5276 shape->setLeft(length);
5277 break;
5278 case 4:
5279 shape->setRadiusX(length);
5280 break;
5281 case 5:
5282 shape->setRadiusY(length);
5283 break;
5284 }
5285 argument = args->next();
5286 if (argument) {
5287 if (!isComma(argument))
5288 return nullptr;
5289
5290 argument = args->next();
5291 }
5292 argumentNumber++;
5293 }
5294
5295 if (argumentNumber < 4)
5296 return nullptr;
5297 return shape;
5298 }
5299
5300 PassRefPtrWillBeRawPtr<CSSPrimitiveValue> CSSPropertyParser::parseShapeRadius(CS SParserValue* value)
5301 {
5302 if (value->id == CSSValueClosestSide || value->id == CSSValueFarthestSide)
5303 return cssValuePool().createIdentifierValue(value->id);
5304
5305 if (!validUnit(value, FLength | FPercent | FNonNeg))
5306 return nullptr;
5307
5308 return createPrimitiveNumericValue(value);
5309 }
5310
5311 PassRefPtrWillBeRawPtr<CSSBasicShape> CSSPropertyParser::parseBasicShapeCircle(C SSParserValueList* args)
5312 {
5313 ASSERT(args);
5314
5315 // circle(radius)
5316 // circle(radius at <position>
5317 // circle(at <position>)
5318 // where position defines centerX and centerY using a CSS <position> data ty pe.
5319 RefPtrWillBeRawPtr<CSSBasicShapeCircle> shape = CSSBasicShapeCircle::create( );
5320
5321 for (CSSParserValue* argument = args->current(); argument; argument = args-> next()) {
5322 // The call to parseFillPosition below should consume all of the
5323 // arguments except the first two. Thus, and index greater than one
5324 // indicates an invalid production.
5325 if (args->currentIndex() > 1)
5326 return nullptr;
5327
5328 if (!args->currentIndex() && argument->id != CSSValueAt) {
5329 if (RefPtrWillBeRawPtr<CSSPrimitiveValue> radius = parseShapeRadius( argument)) {
5330 shape->setRadius(radius);
5331 continue;
5332 }
5333
5334 return nullptr;
5335 }
5336
5337 if (argument->id == CSSValueAt) {
5338 RefPtrWillBeRawPtr<CSSValue> centerX;
5339 RefPtrWillBeRawPtr<CSSValue> centerY;
5340 args->next(); // set list to start of position center
5341 parseFillPosition(args, centerX, centerY);
5342 if (centerX && centerY) {
5343 ASSERT(centerX->isPrimitiveValue());
5344 ASSERT(centerY->isPrimitiveValue());
5345 shape->setCenterX(toCSSPrimitiveValue(centerX.get()));
5346 shape->setCenterY(toCSSPrimitiveValue(centerY.get()));
5347 } else {
5348 return nullptr;
5349 }
5350 } else {
5351 return nullptr;
5352 }
5353 }
5354
5355 return shape;
5356 }
5357
5358 PassRefPtrWillBeRawPtr<CSSBasicShape> CSSPropertyParser::parseDeprecatedBasicSha peCircle(CSSParserValueList* args)
5359 {
5360 ASSERT(args);
5361
5362 // circle(centerX, centerY, radius)
5363 if (args->size() != 5)
5364 return nullptr;
5365
5366 RefPtrWillBeRawPtr<CSSDeprecatedBasicShapeCircle> shape = CSSDeprecatedBasic ShapeCircle::create();
5367
5368 unsigned argumentNumber = 0;
5369 CSSParserValue* argument = args->current();
5370 while (argument) {
5371 Units unitFlags = FLength | FPercent;
5372 if (argumentNumber == 2) {
5373 // Argument radius cannot be negative.
5374 unitFlags = unitFlags | FNonNeg;
5375 }
5376
5377 if (!validUnit(argument, unitFlags))
5378 return nullptr;
5379
5380 RefPtrWillBeRawPtr<CSSPrimitiveValue> length = createPrimitiveNumericVal ue(argument);
5381 ASSERT(argumentNumber < 3);
5382 switch (argumentNumber) {
5383 case 0:
5384 shape->setCenterX(length);
5385 break;
5386 case 1:
5387 shape->setCenterY(length);
5388 break;
5389 case 2:
5390 shape->setRadius(length);
5391 break;
5392 }
5393
5394 argument = args->next();
5395 if (argument) {
5396 if (!isComma(argument))
5397 return nullptr;
5398 argument = args->next();
5399 }
5400 argumentNumber++;
5401 }
5402
5403 if (argumentNumber < 3)
5404 return nullptr;
5405 return shape;
5406 }
5407
5408 PassRefPtrWillBeRawPtr<CSSBasicShape> CSSPropertyParser::parseBasicShapeEllipse( CSSParserValueList* args)
5409 {
5410 ASSERT(args);
5411
5412 // ellipse(radiusX)
5413 // ellipse(radiusX at <position>
5414 // ellipse(radiusX radiusY)
5415 // ellipse(radiusX radiusY at <position>
5416 // ellipse(at <position>)
5417 // where position defines centerX and centerY using a CSS <position> data ty pe.
5418 RefPtrWillBeRawPtr<CSSBasicShapeEllipse> shape = CSSBasicShapeEllipse::creat e();
5419
5420 for (CSSParserValue* argument = args->current(); argument; argument = args-> next()) {
5421 // The call to parseFillPosition below should consume all of the
5422 // arguments except the first three. Thus, an index greater than two
5423 // indicates an invalid production.
5424 if (args->currentIndex() > 2)
5425 return nullptr;
5426
5427 if (args->currentIndex() < 2 && argument->id != CSSValueAt) {
5428 if (RefPtrWillBeRawPtr<CSSPrimitiveValue> radius = parseShapeRadius( argument)) {
5429 if (!shape->radiusX())
5430 shape->setRadiusX(radius);
5431 else
5432 shape->setRadiusY(radius);
5433 continue;
5434 }
5435
5436 return nullptr;
5437 }
5438
5439 if (argument->id != CSSValueAt)
5440 return nullptr;
5441 RefPtrWillBeRawPtr<CSSValue> centerX;
5442 RefPtrWillBeRawPtr<CSSValue> centerY;
5443 args->next(); // set list to start of position center
5444 parseFillPosition(args, centerX, centerY);
5445 if (!centerX || !centerY)
5446 return nullptr;
5447
5448 ASSERT(centerX->isPrimitiveValue());
5449 ASSERT(centerY->isPrimitiveValue());
5450 shape->setCenterX(toCSSPrimitiveValue(centerX.get()));
5451 shape->setCenterY(toCSSPrimitiveValue(centerY.get()));
5452 }
5453
5454 return shape;
5455 }
5456
5457 PassRefPtrWillBeRawPtr<CSSBasicShape> CSSPropertyParser::parseDeprecatedBasicSha peEllipse(CSSParserValueList* args)
5458 {
5459 ASSERT(args);
5460
5461 // ellipse(centerX, centerY, radiusX, radiusY)
5462 if (args->size() != 7)
5463 return nullptr;
5464
5465 RefPtrWillBeRawPtr<CSSDeprecatedBasicShapeEllipse> shape = CSSDeprecatedBasi cShapeEllipse::create();
5466 unsigned argumentNumber = 0;
5467 CSSParserValue* argument = args->current();
5468 while (argument) {
5469 Units unitFlags = FLength | FPercent;
5470 if (argumentNumber > 1) {
5471 // Arguments radiusX and radiusY cannot be negative.
5472 unitFlags = unitFlags | FNonNeg;
5473 }
5474 if (!validUnit(argument, unitFlags))
5475 return nullptr;
5476
5477 RefPtrWillBeRawPtr<CSSPrimitiveValue> length = createPrimitiveNumericVal ue(argument);
5478 ASSERT(argumentNumber < 4);
5479 switch (argumentNumber) {
5480 case 0:
5481 shape->setCenterX(length);
5482 break;
5483 case 1:
5484 shape->setCenterY(length);
5485 break;
5486 case 2:
5487 shape->setRadiusX(length);
5488 break;
5489 case 3:
5490 shape->setRadiusY(length);
5491 break;
5492 }
5493
5494 argument = args->next();
5495 if (argument) {
5496 if (!isComma(argument))
5497 return nullptr;
5498 argument = args->next();
5499 }
5500 argumentNumber++;
5501 }
5502
5503 if (argumentNumber < 4)
5504 return nullptr;
5505 return shape;
5506 }
5507
5508 PassRefPtrWillBeRawPtr<CSSBasicShape> CSSPropertyParser::parseBasicShapePolygon( CSSParserValueList* args)
5509 {
5510 ASSERT(args);
5511
5512 unsigned size = args->size();
5513 if (!size)
5514 return nullptr;
5515
5516 RefPtrWillBeRawPtr<CSSBasicShapePolygon> shape = CSSBasicShapePolygon::creat e();
5517
5518 CSSParserValue* argument = args->current();
5519 if (argument->id == CSSValueEvenodd || argument->id == CSSValueNonzero) {
5520 shape->setWindRule(argument->id == CSSValueEvenodd ? RULE_EVENODD : RULE _NONZERO);
5521
5522 if (!isComma(args->next()))
5523 return nullptr;
5524
5525 argument = args->next();
5526 size -= 2;
5527 }
5528
5529 // <length> <length>, ... <length> <length> -> each pair has 3 elements exce pt the last one
5530 if (!size || (size % 3) - 2)
5531 return nullptr;
5532
5533 CSSParserValue* argumentX = argument;
5534 while (argumentX) {
5535 if (!validUnit(argumentX, FLength | FPercent))
5536 return nullptr;
5537
5538 CSSParserValue* argumentY = args->next();
5539 if (!argumentY || !validUnit(argumentY, FLength | FPercent))
5540 return nullptr;
5541
5542 RefPtrWillBeRawPtr<CSSPrimitiveValue> xLength = createPrimitiveNumericVa lue(argumentX);
5543 RefPtrWillBeRawPtr<CSSPrimitiveValue> yLength = createPrimitiveNumericVa lue(argumentY);
5544
5545 shape->appendPoint(xLength.release(), yLength.release());
5546
5547 CSSParserValue* commaOrNull = args->next();
5548 if (!commaOrNull)
5549 argumentX = 0;
5550 else if (!isComma(commaOrNull))
5551 return nullptr;
5552 else
5553 argumentX = args->next();
5554 }
5555
5556 return shape;
5557 }
5558
5559 static bool isBoxValue(CSSValueID valueId)
5560 {
5561 switch (valueId) {
5562 case CSSValueContentBox:
5563 case CSSValuePaddingBox:
5564 case CSSValueBorderBox:
5565 case CSSValueMarginBox:
5566 return true;
5567 default:
5568 break;
5569 }
5570
5571 return false;
5572 }
5573
5574 // FIXME This function is temporary to allow for an orderly transition between
5575 // the new CSS Shapes circle and ellipse syntax. It will be removed when the
5576 // old syntax is removed.
5577 static bool isDeprecatedBasicShape(CSSParserValueList* args)
5578 {
5579 for (unsigned i = args->currentIndex(); i < args->size(); ++i) {
5580 CSSParserValue* value = args->valueAt(i);
5581 if (isComma(value))
5582 return true;
5583 }
5584
5585 return false;
5586 }
5587
5588 PassRefPtrWillBeRawPtr<CSSValue> CSSPropertyParser::parseShapeProperty(CSSProper tyID propId)
5589 {
5590 if (!RuntimeEnabledFeatures::cssShapesEnabled())
5591 return nullptr;
5592
5593 CSSParserValue* value = m_valueList->current();
5594 CSSValueID valueId = value->id;
5595 RefPtrWillBeRawPtr<CSSPrimitiveValue> boxValue;
5596 RefPtrWillBeRawPtr<CSSPrimitiveValue> shapeValue;
5597
5598 if (valueId == CSSValueNone
5599 || (valueId == CSSValueOutsideShape && propId == CSSPropertyShapeInside) ) {
5600 RefPtrWillBeRawPtr<CSSPrimitiveValue> keywordValue = parseValidPrimitive (valueId, value);
5601 m_valueList->next();
5602 return keywordValue.release();
5603 }
5604
5605 RefPtrWillBeRawPtr<CSSValue> imageValue;
5606 if (valueId != CSSValueNone && parseFillImage(m_valueList.get(), imageValue) ) {
5607 m_valueList->next();
5608 return imageValue.release();
5609 }
5610
5611 if (value->unit == CSSParserValue::Function) {
5612 shapeValue = parseBasicShape();
5613 if (!shapeValue)
5614 return nullptr;
5615 } else if (isBoxValue(valueId)) {
5616 boxValue = parseValidPrimitive(valueId, value);
5617 m_valueList->next();
5618 } else {
5619 return nullptr;
5620 }
5621
5622 ASSERT(shapeValue || boxValue);
5623 value = m_valueList->current();
5624
5625 if (value) {
5626 valueId = value->id;
5627 if (boxValue && value->unit == CSSParserValue::Function) {
5628 shapeValue = parseBasicShape();
5629 if (!shapeValue)
5630 return nullptr;
5631 } else if (shapeValue && isBoxValue(valueId)) {
5632 boxValue = parseValidPrimitive(valueId, value);
5633 m_valueList->next();
5634 } else {
5635 return nullptr;
5636 }
5637
5638 ASSERT(shapeValue && boxValue);
5639 shapeValue->getShapeValue()->setLayoutBox(boxValue.release());
5640 }
5641
5642 if (shapeValue)
5643 return shapeValue.release();
5644 return boxValue.release();
5645 }
5646
5647 PassRefPtrWillBeRawPtr<CSSPrimitiveValue> CSSPropertyParser::parseBasicShape()
5648 {
5649 CSSParserValue* value = m_valueList->current();
5650 ASSERT(value->unit == CSSParserValue::Function);
5651 CSSParserValueList* args = value->function->args.get();
5652
5653 if (!args)
5654 return nullptr;
5655
5656 RefPtrWillBeRawPtr<CSSBasicShape> shape;
5657 if (equalIgnoringCase(value->function->name, "rectangle("))
5658 shape = parseBasicShapeRectangle(args);
5659 else if (equalIgnoringCase(value->function->name, "circle("))
5660 if (isDeprecatedBasicShape(args))
5661 shape = parseDeprecatedBasicShapeCircle(args);
5662 else
5663 shape = parseBasicShapeCircle(args);
5664 else if (equalIgnoringCase(value->function->name, "ellipse("))
5665 if (isDeprecatedBasicShape(args))
5666 shape = parseDeprecatedBasicShapeEllipse(args);
5667 else
5668 shape = parseBasicShapeEllipse(args);
5669 else if (equalIgnoringCase(value->function->name, "polygon("))
5670 shape = parseBasicShapePolygon(args);
5671 else if (equalIgnoringCase(value->function->name, "inset-rectangle("))
5672 shape = parseBasicShapeInsetRectangle(args);
5673 else if (equalIgnoringCase(value->function->name, "inset("))
5674 shape = parseBasicShapeInset(args);
5675
5676 if (!shape)
5677 return nullptr;
5678
5679 m_valueList->next();
5680 return cssValuePool().createValue(shape.release());
5681 }
5682
5683 // [ 'font-style' || 'font-variant' || 'font-weight' ]? 'font-size' [ / 'line-he ight' ]? 'font-family'
5684 bool CSSPropertyParser::parseFont(bool important)
5685 {
5686 // Let's check if there is an inherit or initial somewhere in the shorthand.
5687 for (unsigned i = 0; i < m_valueList->size(); ++i) {
5688 if (m_valueList->valueAt(i)->id == CSSValueInherit || m_valueList->value At(i)->id == CSSValueInitial)
5689 return false;
5690 }
5691
5692 ShorthandScope scope(this, CSSPropertyFont);
5693 // Optional font-style, font-variant and font-weight.
5694 bool fontStyleParsed = false;
5695 bool fontVariantParsed = false;
5696 bool fontWeightParsed = false;
5697 CSSParserValue* value;
5698 while ((value = m_valueList->current())) {
5699 if (!fontStyleParsed && isValidKeywordPropertyAndValue(CSSPropertyFontSt yle, value->id, m_context)) {
5700 addProperty(CSSPropertyFontStyle, cssValuePool().createIdentifierVal ue(value->id), important);
5701 fontStyleParsed = true;
5702 } else if (!fontVariantParsed && (value->id == CSSValueNormal || value-> id == CSSValueSmallCaps)) {
5703 // Font variant in the shorthand is particular, it only accepts norm al or small-caps.
5704 addProperty(CSSPropertyFontVariant, cssValuePool().createIdentifierV alue(value->id), important);
5705 fontVariantParsed = true;
5706 } else if (!fontWeightParsed && parseFontWeight(important))
5707 fontWeightParsed = true;
5708 else
5709 break;
5710 m_valueList->next();
5711 }
5712
5713 if (!value)
5714 return false;
5715
5716 if (!fontStyleParsed)
5717 addProperty(CSSPropertyFontStyle, cssValuePool().createIdentifierValue(C SSValueNormal), important, true);
5718 if (!fontVariantParsed)
5719 addProperty(CSSPropertyFontVariant, cssValuePool().createIdentifierValue (CSSValueNormal), important, true);
5720 if (!fontWeightParsed)
5721 addProperty(CSSPropertyFontWeight, cssValuePool().createIdentifierValue( CSSValueNormal), important, true);
5722
5723 // Now a font size _must_ come.
5724 // <absolute-size> | <relative-size> | <length> | <percentage> | inherit
5725 if (!parseFontSize(important))
5726 return false;
5727
5728 value = m_valueList->current();
5729 if (!value)
5730 return false;
5731
5732 if (isForwardSlashOperator(value)) {
5733 // The line-height property.
5734 value = m_valueList->next();
5735 if (!value)
5736 return false;
5737 if (!parseLineHeight(important))
5738 return false;
5739 } else
5740 addProperty(CSSPropertyLineHeight, cssValuePool().createIdentifierValue( CSSValueNormal), important, true);
5741
5742 // Font family must come now.
5743 RefPtrWillBeRawPtr<CSSValue> parsedFamilyValue = parseFontFamily();
5744 if (!parsedFamilyValue)
5745 return false;
5746
5747 addProperty(CSSPropertyFontFamily, parsedFamilyValue.release(), important);
5748
5749 // FIXME: http://www.w3.org/TR/2011/WD-css3-fonts-20110324/#font-prop requir es that
5750 // "font-stretch", "font-size-adjust", and "font-kerning" be reset to their initial values
5751 // but we don't seem to support them at the moment. They should also be adde d here once implemented.
5752 if (m_valueList->current())
5753 return false;
5754
5755 return true;
5756 }
5757
5758 class FontFamilyValueBuilder {
5759 DISALLOW_ALLOCATION();
5760 public:
5761 FontFamilyValueBuilder(CSSValueList* list)
5762 : m_list(list)
5763 {
5764 }
5765
5766 void add(const CSSParserString& string)
5767 {
5768 if (!m_builder.isEmpty())
5769 m_builder.append(' ');
5770
5771 if (string.is8Bit()) {
5772 m_builder.append(string.characters8(), string.length());
5773 return;
5774 }
5775
5776 m_builder.append(string.characters16(), string.length());
5777 }
5778
5779 void commit()
5780 {
5781 if (m_builder.isEmpty())
5782 return;
5783 m_list->append(cssValuePool().createFontFamilyValue(m_builder.toString() ));
5784 m_builder.clear();
5785 }
5786
5787 private:
5788 StringBuilder m_builder;
5789 CSSValueList* m_list;
5790 };
5791
5792 PassRefPtrWillBeRawPtr<CSSValueList> CSSPropertyParser::parseFontFamily()
5793 {
5794 RefPtrWillBeRawPtr<CSSValueList> list = CSSValueList::createCommaSeparated() ;
5795 CSSParserValue* value = m_valueList->current();
5796
5797 FontFamilyValueBuilder familyBuilder(list.get());
5798 bool inFamily = false;
5799
5800 while (value) {
5801 CSSParserValue* nextValue = m_valueList->next();
5802 bool nextValBreaksFont = !nextValue ||
5803 (nextValue->unit == CSSParserValue::Operator && nextValue->iValue == ',');
5804 bool nextValIsFontName = nextValue &&
5805 ((nextValue->id >= CSSValueSerif && nextValue->id <= CSSValueWebkitB ody) ||
5806 (nextValue->unit == CSSPrimitiveValue::CSS_STRING || nextValue->unit == CSSPrimitiveValue::CSS_IDENT));
5807
5808 bool valueIsKeyword = value->id == CSSValueInitial || value->id == CSSVa lueInherit || value->id == CSSValueDefault;
5809 if (valueIsKeyword && !inFamily) {
5810 if (nextValBreaksFont)
5811 value = m_valueList->next();
5812 else if (nextValIsFontName)
5813 value = nextValue;
5814 continue;
5815 }
5816
5817 if (value->id >= CSSValueSerif && value->id <= CSSValueWebkitBody) {
5818 if (inFamily)
5819 familyBuilder.add(value->string);
5820 else if (nextValBreaksFont || !nextValIsFontName)
5821 list->append(cssValuePool().createIdentifierValue(value->id));
5822 else {
5823 familyBuilder.commit();
5824 familyBuilder.add(value->string);
5825 inFamily = true;
5826 }
5827 } else if (value->unit == CSSPrimitiveValue::CSS_STRING) {
5828 // Strings never share in a family name.
5829 inFamily = false;
5830 familyBuilder.commit();
5831 list->append(cssValuePool().createFontFamilyValue(value->string));
5832 } else if (value->unit == CSSPrimitiveValue::CSS_IDENT) {
5833 if (inFamily)
5834 familyBuilder.add(value->string);
5835 else if (nextValBreaksFont || !nextValIsFontName)
5836 list->append(cssValuePool().createFontFamilyValue(value->string) );
5837 else {
5838 familyBuilder.commit();
5839 familyBuilder.add(value->string);
5840 inFamily = true;
5841 }
5842 } else {
5843 break;
5844 }
5845
5846 if (!nextValue)
5847 break;
5848
5849 if (nextValBreaksFont) {
5850 value = m_valueList->next();
5851 familyBuilder.commit();
5852 inFamily = false;
5853 }
5854 else if (nextValIsFontName)
5855 value = nextValue;
5856 else
5857 break;
5858 }
5859 familyBuilder.commit();
5860
5861 if (!list->length())
5862 list = nullptr;
5863 return list.release();
5864 }
5865
5866 bool CSSPropertyParser::parseLineHeight(bool important)
5867 {
5868 CSSParserValue* value = m_valueList->current();
5869 CSSValueID id = value->id;
5870 bool validPrimitive = false;
5871 // normal | <number> | <length> | <percentage> | inherit
5872 if (id == CSSValueNormal)
5873 validPrimitive = true;
5874 else
5875 validPrimitive = (!id && validUnit(value, FNumber | FLength | FPercent | FNonNeg));
5876 if (validPrimitive && (!m_valueList->next() || inShorthand()))
5877 addProperty(CSSPropertyLineHeight, parseValidPrimitive(id, value), impor tant);
5878 return validPrimitive;
5879 }
5880
5881 bool CSSPropertyParser::parseFontSize(bool important)
5882 {
5883 CSSParserValue* value = m_valueList->current();
5884 CSSValueID id = value->id;
5885 bool validPrimitive = false;
5886 // <absolute-size> | <relative-size> | <length> | <percentage> | inherit
5887 if (id >= CSSValueXxSmall && id <= CSSValueLarger)
5888 validPrimitive = true;
5889 else
5890 validPrimitive = validUnit(value, FLength | FPercent | FNonNeg);
5891 if (validPrimitive && (!m_valueList->next() || inShorthand()))
5892 addProperty(CSSPropertyFontSize, parseValidPrimitive(id, value), importa nt);
5893 return validPrimitive;
5894 }
5895
5896 bool CSSPropertyParser::parseFontVariant(bool important)
5897 {
5898 RefPtrWillBeRawPtr<CSSValueList> values;
5899 if (m_valueList->size() > 1)
5900 values = CSSValueList::createCommaSeparated();
5901 CSSParserValue* val;
5902 bool expectComma = false;
5903 while ((val = m_valueList->current())) {
5904 RefPtrWillBeRawPtr<CSSPrimitiveValue> parsedValue;
5905 if (!expectComma) {
5906 expectComma = true;
5907 if (val->id == CSSValueNormal || val->id == CSSValueSmallCaps)
5908 parsedValue = cssValuePool().createIdentifierValue(val->id);
5909 else if (val->id == CSSValueAll && !values) {
5910 // 'all' is only allowed in @font-face and with no other values. Make a value list to
5911 // indicate that we are in the @font-face case.
5912 values = CSSValueList::createCommaSeparated();
5913 parsedValue = cssValuePool().createIdentifierValue(val->id);
5914 }
5915 } else if (val->unit == CSSParserValue::Operator && val->iValue == ',') {
5916 expectComma = false;
5917 m_valueList->next();
5918 continue;
5919 }
5920
5921 if (!parsedValue)
5922 return false;
5923
5924 m_valueList->next();
5925
5926 if (values)
5927 values->append(parsedValue.release());
5928 else {
5929 addProperty(CSSPropertyFontVariant, parsedValue.release(), important );
5930 return true;
5931 }
5932 }
5933
5934 if (values && values->length()) {
5935 m_hasFontFaceOnlyValues = true;
5936 addProperty(CSSPropertyFontVariant, values.release(), important);
5937 return true;
5938 }
5939
5940 return false;
5941 }
5942
5943 bool CSSPropertyParser::parseFontWeight(bool important)
5944 {
5945 CSSParserValue* value = m_valueList->current();
5946 if ((value->id >= CSSValueNormal) && (value->id <= CSSValue900)) {
5947 addProperty(CSSPropertyFontWeight, cssValuePool().createIdentifierValue( value->id), important);
5948 return true;
5949 }
5950 if (validUnit(value, FInteger | FNonNeg, HTMLQuirksMode)) {
5951 int weight = static_cast<int>(value->fValue);
5952 if (!(weight % 100) && weight >= 100 && weight <= 900) {
5953 addProperty(CSSPropertyFontWeight, cssValuePool().createIdentifierVa lue(static_cast<CSSValueID>(CSSValue100 + weight / 100 - 1)), important);
5954 return true;
5955 }
5956 }
5957 return false;
5958 }
5959
5960 bool CSSPropertyParser::parseFontFaceSrcURI(CSSValueList* valueList)
5961 {
5962 RefPtrWillBeRawPtr<CSSFontFaceSrcValue> uriValue(CSSFontFaceSrcValue::create (completeURL(m_valueList->current()->string)));
5963
5964 CSSParserValue* value = m_valueList->next();
5965 if (!value) {
5966 valueList->append(uriValue.release());
5967 return true;
5968 }
5969 if (value->unit == CSSParserValue::Operator && value->iValue == ',') {
5970 m_valueList->next();
5971 valueList->append(uriValue.release());
5972 return true;
5973 }
5974
5975 if (value->unit != CSSParserValue::Function || !equalIgnoringCase(value->fun ction->name, "format("))
5976 return false;
5977
5978 // FIXME: http://www.w3.org/TR/2011/WD-css3-fonts-20111004/ says that format () contains a comma-separated list of strings,
5979 // but CSSFontFaceSrcValue stores only one format. Allowing one format for n ow.
5980 CSSParserValueList* args = value->function->args.get();
5981 if (!args || args->size() != 1 || (args->current()->unit != CSSPrimitiveValu e::CSS_STRING && args->current()->unit != CSSPrimitiveValue::CSS_IDENT))
5982 return false;
5983 uriValue->setFormat(args->current()->string);
5984 valueList->append(uriValue.release());
5985 value = m_valueList->next();
5986 if (value && value->unit == CSSParserValue::Operator && value->iValue == ',' )
5987 m_valueList->next();
5988 return true;
5989 }
5990
5991 bool CSSPropertyParser::parseFontFaceSrcLocal(CSSValueList* valueList)
5992 {
5993 CSSParserValueList* args = m_valueList->current()->function->args.get();
5994 if (!args || !args->size())
5995 return false;
5996
5997 if (args->size() == 1 && args->current()->unit == CSSPrimitiveValue::CSS_STR ING)
5998 valueList->append(CSSFontFaceSrcValue::createLocal(args->current()->stri ng));
5999 else if (args->current()->unit == CSSPrimitiveValue::CSS_IDENT) {
6000 StringBuilder builder;
6001 for (CSSParserValue* localValue = args->current(); localValue; localValu e = args->next()) {
6002 if (localValue->unit != CSSPrimitiveValue::CSS_IDENT)
6003 return false;
6004 if (!builder.isEmpty())
6005 builder.append(' ');
6006 builder.append(localValue->string);
6007 }
6008 valueList->append(CSSFontFaceSrcValue::createLocal(builder.toString()));
6009 } else
6010 return false;
6011
6012 if (CSSParserValue* value = m_valueList->next()) {
6013 if (value->unit == CSSParserValue::Operator && value->iValue == ',')
6014 m_valueList->next();
6015 }
6016 return true;
6017 }
6018
6019 bool CSSPropertyParser::parseFontFaceSrc()
6020 {
6021 RefPtrWillBeRawPtr<CSSValueList> values(CSSValueList::createCommaSeparated() );
6022
6023 while (CSSParserValue* value = m_valueList->current()) {
6024 if (value->unit == CSSPrimitiveValue::CSS_URI) {
6025 if (!parseFontFaceSrcURI(values.get()))
6026 return false;
6027 } else if (value->unit == CSSParserValue::Function && equalIgnoringCase( value->function->name, "local(")) {
6028 if (!parseFontFaceSrcLocal(values.get()))
6029 return false;
6030 } else
6031 return false;
6032 }
6033 if (!values->length())
6034 return false;
6035
6036 addProperty(CSSPropertySrc, values.release(), m_important);
6037 m_valueList->next();
6038 return true;
6039 }
6040
6041 bool CSSPropertyParser::parseFontFaceUnicodeRange()
6042 {
6043 RefPtrWillBeRawPtr<CSSValueList> values = CSSValueList::createCommaSeparated ();
6044 bool failed = false;
6045 bool operatorExpected = false;
6046 for (; m_valueList->current(); m_valueList->next(), operatorExpected = !oper atorExpected) {
6047 if (operatorExpected) {
6048 if (m_valueList->current()->unit == CSSParserValue::Operator && m_va lueList->current()->iValue == ',')
6049 continue;
6050 failed = true;
6051 break;
6052 }
6053 if (m_valueList->current()->unit != CSSPrimitiveValue::CSS_UNICODE_RANGE ) {
6054 failed = true;
6055 break;
6056 }
6057
6058 String rangeString = m_valueList->current()->string;
6059 UChar32 from = 0;
6060 UChar32 to = 0;
6061 unsigned length = rangeString.length();
6062
6063 if (length < 3) {
6064 failed = true;
6065 break;
6066 }
6067
6068 unsigned i = 2;
6069 while (i < length) {
6070 UChar c = rangeString[i];
6071 if (c == '-' || c == '?')
6072 break;
6073 from *= 16;
6074 if (c >= '0' && c <= '9')
6075 from += c - '0';
6076 else if (c >= 'A' && c <= 'F')
6077 from += 10 + c - 'A';
6078 else if (c >= 'a' && c <= 'f')
6079 from += 10 + c - 'a';
6080 else {
6081 failed = true;
6082 break;
6083 }
6084 i++;
6085 }
6086 if (failed)
6087 break;
6088
6089 if (i == length)
6090 to = from;
6091 else if (rangeString[i] == '?') {
6092 unsigned span = 1;
6093 while (i < length && rangeString[i] == '?') {
6094 span *= 16;
6095 from *= 16;
6096 i++;
6097 }
6098 if (i < length)
6099 failed = true;
6100 to = from + span - 1;
6101 } else {
6102 if (length < i + 2) {
6103 failed = true;
6104 break;
6105 }
6106 i++;
6107 while (i < length) {
6108 UChar c = rangeString[i];
6109 to *= 16;
6110 if (c >= '0' && c <= '9')
6111 to += c - '0';
6112 else if (c >= 'A' && c <= 'F')
6113 to += 10 + c - 'A';
6114 else if (c >= 'a' && c <= 'f')
6115 to += 10 + c - 'a';
6116 else {
6117 failed = true;
6118 break;
6119 }
6120 i++;
6121 }
6122 if (failed)
6123 break;
6124 }
6125 if (from <= to)
6126 values->append(CSSUnicodeRangeValue::create(from, to));
6127 }
6128 if (failed || !values->length())
6129 return false;
6130 addProperty(CSSPropertyUnicodeRange, values.release(), m_important);
6131 return true;
6132 }
6133
6134 // Returns the number of characters which form a valid double
6135 // and are terminated by the given terminator character
6136 template <typename CharacterType>
6137 static int checkForValidDouble(const CharacterType* string, const CharacterType* end, const char terminator)
6138 {
6139 int length = end - string;
6140 if (length < 1)
6141 return 0;
6142
6143 bool decimalMarkSeen = false;
6144 int processedLength = 0;
6145
6146 for (int i = 0; i < length; ++i) {
6147 if (string[i] == terminator) {
6148 processedLength = i;
6149 break;
6150 }
6151 if (!isASCIIDigit(string[i])) {
6152 if (!decimalMarkSeen && string[i] == '.')
6153 decimalMarkSeen = true;
6154 else
6155 return 0;
6156 }
6157 }
6158
6159 if (decimalMarkSeen && processedLength == 1)
6160 return 0;
6161
6162 return processedLength;
6163 }
6164
6165 // Returns the number of characters consumed for parsing a valid double
6166 // terminated by the given terminator character
6167 template <typename CharacterType>
6168 static int parseDouble(const CharacterType* string, const CharacterType* end, co nst char terminator, double& value)
6169 {
6170 int length = checkForValidDouble(string, end, terminator);
6171 if (!length)
6172 return 0;
6173
6174 int position = 0;
6175 double localValue = 0;
6176
6177 // The consumed characters here are guaranteed to be
6178 // ASCII digits with or without a decimal mark
6179 for (; position < length; ++position) {
6180 if (string[position] == '.')
6181 break;
6182 localValue = localValue * 10 + string[position] - '0';
6183 }
6184
6185 if (++position == length) {
6186 value = localValue;
6187 return length;
6188 }
6189
6190 double fraction = 0;
6191 double scale = 1;
6192
6193 while (position < length && scale < MAX_SCALE) {
6194 fraction = fraction * 10 + string[position++] - '0';
6195 scale *= 10;
6196 }
6197
6198 value = localValue + fraction / scale;
6199 return length;
6200 }
6201
6202 template <typename CharacterType>
6203 static bool parseColorIntOrPercentage(const CharacterType*& string, const Charac terType* end, const char terminator, CSSPrimitiveValue::UnitTypes& expect, int& value)
6204 {
6205 const CharacterType* current = string;
6206 double localValue = 0;
6207 bool negative = false;
6208 while (current != end && isHTMLSpace<CharacterType>(*current))
6209 current++;
6210 if (current != end && *current == '-') {
6211 negative = true;
6212 current++;
6213 }
6214 if (current == end || !isASCIIDigit(*current))
6215 return false;
6216 while (current != end && isASCIIDigit(*current)) {
6217 double newValue = localValue * 10 + *current++ - '0';
6218 if (newValue >= 255) {
6219 // Clamp values at 255.
6220 localValue = 255;
6221 while (current != end && isASCIIDigit(*current))
6222 ++current;
6223 break;
6224 }
6225 localValue = newValue;
6226 }
6227
6228 if (current == end)
6229 return false;
6230
6231 if (expect == CSSPrimitiveValue::CSS_NUMBER && (*current == '.' || *current == '%'))
6232 return false;
6233
6234 if (*current == '.') {
6235 // We already parsed the integral part, try to parse
6236 // the fraction part of the percentage value.
6237 double percentage = 0;
6238 int numCharactersParsed = parseDouble(current, end, '%', percentage);
6239 if (!numCharactersParsed)
6240 return false;
6241 current += numCharactersParsed;
6242 if (*current != '%')
6243 return false;
6244 localValue += percentage;
6245 }
6246
6247 if (expect == CSSPrimitiveValue::CSS_PERCENTAGE && *current != '%')
6248 return false;
6249
6250 if (*current == '%') {
6251 expect = CSSPrimitiveValue::CSS_PERCENTAGE;
6252 localValue = localValue / 100.0 * 256.0;
6253 // Clamp values at 255 for percentages over 100%
6254 if (localValue > 255)
6255 localValue = 255;
6256 current++;
6257 } else
6258 expect = CSSPrimitiveValue::CSS_NUMBER;
6259
6260 while (current != end && isHTMLSpace<CharacterType>(*current))
6261 current++;
6262 if (current == end || *current++ != terminator)
6263 return false;
6264 // Clamp negative values at zero.
6265 value = negative ? 0 : static_cast<int>(localValue);
6266 string = current;
6267 return true;
6268 }
6269
6270 template <typename CharacterType>
6271 static inline bool isTenthAlpha(const CharacterType* string, const int length)
6272 {
6273 // "0.X"
6274 if (length == 3 && string[0] == '0' && string[1] == '.' && isASCIIDigit(stri ng[2]))
6275 return true;
6276
6277 // ".X"
6278 if (length == 2 && string[0] == '.' && isASCIIDigit(string[1]))
6279 return true;
6280
6281 return false;
6282 }
6283
6284 template <typename CharacterType>
6285 static inline bool parseAlphaValue(const CharacterType*& string, const Character Type* end, const char terminator, int& value)
6286 {
6287 while (string != end && isHTMLSpace<CharacterType>(*string))
6288 string++;
6289
6290 bool negative = false;
6291
6292 if (string != end && *string == '-') {
6293 negative = true;
6294 string++;
6295 }
6296
6297 value = 0;
6298
6299 int length = end - string;
6300 if (length < 2)
6301 return false;
6302
6303 if (string[length - 1] != terminator || !isASCIIDigit(string[length - 2]))
6304 return false;
6305
6306 if (string[0] != '0' && string[0] != '1' && string[0] != '.') {
6307 if (checkForValidDouble(string, end, terminator)) {
6308 value = negative ? 0 : 255;
6309 string = end;
6310 return true;
6311 }
6312 return false;
6313 }
6314
6315 if (length == 2 && string[0] != '.') {
6316 value = !negative && string[0] == '1' ? 255 : 0;
6317 string = end;
6318 return true;
6319 }
6320
6321 if (isTenthAlpha(string, length - 1)) {
6322 static const int tenthAlphaValues[] = { 0, 25, 51, 76, 102, 127, 153, 17 9, 204, 230 };
6323 value = negative ? 0 : tenthAlphaValues[string[length - 2] - '0'];
6324 string = end;
6325 return true;
6326 }
6327
6328 double alpha = 0;
6329 if (!parseDouble(string, end, terminator, alpha))
6330 return false;
6331 value = negative ? 0 : static_cast<int>(alpha * nextafter(256.0, 0.0));
6332 string = end;
6333 return true;
6334 }
6335
6336 template <typename CharacterType>
6337 static inline bool mightBeRGBA(const CharacterType* characters, unsigned length)
6338 {
6339 if (length < 5)
6340 return false;
6341 return characters[4] == '('
6342 && isASCIIAlphaCaselessEqual(characters[0], 'r')
6343 && isASCIIAlphaCaselessEqual(characters[1], 'g')
6344 && isASCIIAlphaCaselessEqual(characters[2], 'b')
6345 && isASCIIAlphaCaselessEqual(characters[3], 'a');
6346 }
6347
6348 template <typename CharacterType>
6349 static inline bool mightBeRGB(const CharacterType* characters, unsigned length)
6350 {
6351 if (length < 4)
6352 return false;
6353 return characters[3] == '('
6354 && isASCIIAlphaCaselessEqual(characters[0], 'r')
6355 && isASCIIAlphaCaselessEqual(characters[1], 'g')
6356 && isASCIIAlphaCaselessEqual(characters[2], 'b');
6357 }
6358
6359 template <typename CharacterType>
6360 static inline bool fastParseColorInternal(RGBA32& rgb, const CharacterType* char acters, unsigned length , bool strict)
6361 {
6362 CSSPrimitiveValue::UnitTypes expect = CSSPrimitiveValue::CSS_UNKNOWN;
6363
6364 if (!strict && length >= 3) {
6365 if (characters[0] == '#') {
6366 if (Color::parseHexColor(characters + 1, length - 1, rgb))
6367 return true;
6368 } else {
6369 if (Color::parseHexColor(characters, length, rgb))
6370 return true;
6371 }
6372 }
6373
6374 // Try rgba() syntax.
6375 if (mightBeRGBA(characters, length)) {
6376 const CharacterType* current = characters + 5;
6377 const CharacterType* end = characters + length;
6378 int red;
6379 int green;
6380 int blue;
6381 int alpha;
6382
6383 if (!parseColorIntOrPercentage(current, end, ',', expect, red))
6384 return false;
6385 if (!parseColorIntOrPercentage(current, end, ',', expect, green))
6386 return false;
6387 if (!parseColorIntOrPercentage(current, end, ',', expect, blue))
6388 return false;
6389 if (!parseAlphaValue(current, end, ')', alpha))
6390 return false;
6391 if (current != end)
6392 return false;
6393 rgb = makeRGBA(red, green, blue, alpha);
6394 return true;
6395 }
6396
6397 // Try rgb() syntax.
6398 if (mightBeRGB(characters, length)) {
6399 const CharacterType* current = characters + 4;
6400 const CharacterType* end = characters + length;
6401 int red;
6402 int green;
6403 int blue;
6404 if (!parseColorIntOrPercentage(current, end, ',', expect, red))
6405 return false;
6406 if (!parseColorIntOrPercentage(current, end, ',', expect, green))
6407 return false;
6408 if (!parseColorIntOrPercentage(current, end, ')', expect, blue))
6409 return false;
6410 if (current != end)
6411 return false;
6412 rgb = makeRGB(red, green, blue);
6413 return true;
6414 }
6415
6416 return false;
6417 }
6418
6419 template<typename StringType>
6420 bool CSSPropertyParser::fastParseColor(RGBA32& rgb, const StringType& name, bool strict)
6421 {
6422 unsigned length = name.length();
6423 bool parseResult;
6424
6425 if (!length)
6426 return false;
6427
6428 if (name.is8Bit())
6429 parseResult = fastParseColorInternal(rgb, name.characters8(), length, st rict);
6430 else
6431 parseResult = fastParseColorInternal(rgb, name.characters16(), length, s trict);
6432
6433 if (parseResult)
6434 return true;
6435
6436 // Try named colors.
6437 Color tc;
6438 if (!tc.setNamedColor(name))
6439 return false;
6440 rgb = tc.rgb();
6441 return true;
6442 }
6443
6444 inline double CSSPropertyParser::parsedDouble(CSSParserValue *v, ReleaseParsedCa lcValueCondition releaseCalc)
6445 {
6446 const double result = m_parsedCalculation ? m_parsedCalculation->doubleValue () : v->fValue;
6447 if (releaseCalc == ReleaseParsedCalcValue)
6448 m_parsedCalculation.release();
6449 return result;
6450 }
6451
6452 bool CSSPropertyParser::isCalculation(CSSParserValue* value)
6453 {
6454 return (value->unit == CSSParserValue::Function)
6455 && (equalIgnoringCase(value->function->name, "calc(")
6456 || equalIgnoringCase(value->function->name, "-webkit-calc(")
6457 || equalIgnoringCase(value->function->name, "-webkit-min(")
6458 || equalIgnoringCase(value->function->name, "-webkit-max("));
6459 }
6460
6461 inline int CSSPropertyParser::colorIntFromValue(CSSParserValue* v)
6462 {
6463 bool isPercent;
6464
6465 if (m_parsedCalculation)
6466 isPercent = m_parsedCalculation->category() == CalcPercent;
6467 else
6468 isPercent = v->unit == CSSPrimitiveValue::CSS_PERCENTAGE;
6469
6470 const double value = parsedDouble(v, ReleaseParsedCalcValue);
6471
6472 if (value <= 0.0)
6473 return 0;
6474
6475 if (isPercent) {
6476 if (value >= 100.0)
6477 return 255;
6478 return static_cast<int>(value * 256.0 / 100.0);
6479 }
6480
6481 if (value >= 255.0)
6482 return 255;
6483
6484 return static_cast<int>(value);
6485 }
6486
6487 bool CSSPropertyParser::parseColorParameters(CSSParserValue* value, int* colorAr ray, bool parseAlpha)
6488 {
6489 CSSParserValueList* args = value->function->args.get();
6490 CSSParserValue* v = args->current();
6491 Units unitType = FUnknown;
6492 // Get the first value and its type
6493 if (validUnit(v, FInteger, HTMLStandardMode))
6494 unitType = FInteger;
6495 else if (validUnit(v, FPercent, HTMLStandardMode))
6496 unitType = FPercent;
6497 else
6498 return false;
6499
6500 colorArray[0] = colorIntFromValue(v);
6501 for (int i = 1; i < 3; i++) {
6502 v = args->next();
6503 if (v->unit != CSSParserValue::Operator && v->iValue != ',')
6504 return false;
6505 v = args->next();
6506 if (!validUnit(v, unitType, HTMLStandardMode))
6507 return false;
6508 colorArray[i] = colorIntFromValue(v);
6509 }
6510 if (parseAlpha) {
6511 v = args->next();
6512 if (v->unit != CSSParserValue::Operator && v->iValue != ',')
6513 return false;
6514 v = args->next();
6515 if (!validUnit(v, FNumber, HTMLStandardMode))
6516 return false;
6517 const double value = parsedDouble(v, ReleaseParsedCalcValue);
6518 // Convert the floating pointer number of alpha to an integer in the ran ge [0, 256),
6519 // with an equal distribution across all 256 values.
6520 colorArray[3] = static_cast<int>(max(0.0, min(1.0, value)) * nextafter(2 56.0, 0.0));
6521 }
6522 return true;
6523 }
6524
6525 // The CSS3 specification defines the format of a HSL color as
6526 // hsl(<number>, <percent>, <percent>)
6527 // and with alpha, the format is
6528 // hsla(<number>, <percent>, <percent>, <number>)
6529 // The first value, HUE, is in an angle with a value between 0 and 360
6530 bool CSSPropertyParser::parseHSLParameters(CSSParserValue* value, double* colorA rray, bool parseAlpha)
6531 {
6532 CSSParserValueList* args = value->function->args.get();
6533 CSSParserValue* v = args->current();
6534 // Get the first value
6535 if (!validUnit(v, FNumber, HTMLStandardMode))
6536 return false;
6537 // normalize the Hue value and change it to be between 0 and 1.0
6538 colorArray[0] = (((static_cast<int>(parsedDouble(v, ReleaseParsedCalcValue)) % 360) + 360) % 360) / 360.0;
6539 for (int i = 1; i < 3; i++) {
6540 v = args->next();
6541 if (v->unit != CSSParserValue::Operator && v->iValue != ',')
6542 return false;
6543 v = args->next();
6544 if (!validUnit(v, FPercent, HTMLStandardMode))
6545 return false;
6546 colorArray[i] = max(0.0, min(100.0, parsedDouble(v, ReleaseParsedCalcVal ue))) / 100.0; // needs to be value between 0 and 1.0
6547 }
6548 if (parseAlpha) {
6549 v = args->next();
6550 if (v->unit != CSSParserValue::Operator && v->iValue != ',')
6551 return false;
6552 v = args->next();
6553 if (!validUnit(v, FNumber, HTMLStandardMode))
6554 return false;
6555 colorArray[3] = max(0.0, min(1.0, parsedDouble(v, ReleaseParsedCalcValue )));
6556 }
6557 return true;
6558 }
6559
6560 PassRefPtrWillBeRawPtr<CSSPrimitiveValue> CSSPropertyParser::parseColor(CSSParse rValue* value)
6561 {
6562 RGBA32 c = Color::transparent;
6563 if (!parseColorFromValue(value ? value : m_valueList->current(), c))
6564 return nullptr;
6565 return cssValuePool().createColorValue(c);
6566 }
6567
6568 bool CSSPropertyParser::parseColorFromValue(CSSParserValue* value, RGBA32& c)
6569 {
6570 if (inQuirksMode() && value->unit == CSSPrimitiveValue::CSS_NUMBER
6571 && value->fValue >= 0. && value->fValue < 1000000.) {
6572 String str = String::format("%06d", static_cast<int>((value->fValue+.5)) );
6573 // FIXME: This should be strict parsing for SVG as well.
6574 if (!fastParseColor(c, str, !inQuirksMode()))
6575 return false;
6576 } else if (value->unit == CSSPrimitiveValue::CSS_PARSER_HEXCOLOR ||
6577 value->unit == CSSPrimitiveValue::CSS_IDENT ||
6578 (inQuirksMode() && value->unit == CSSPrimitiveValue::CSS_DIMENSI ON)) {
6579 if (!fastParseColor(c, value->string, !inQuirksMode() && value->unit == CSSPrimitiveValue::CSS_IDENT))
6580 return false;
6581 } else if (value->unit == CSSParserValue::Function &&
6582 value->function->args != 0 &&
6583 value->function->args->size() == 5 /* rgb + two commas */ &&
6584 equalIgnoringCase(value->function->name, "rgb(")) {
6585 int colorValues[3];
6586 if (!parseColorParameters(value, colorValues, false))
6587 return false;
6588 c = makeRGB(colorValues[0], colorValues[1], colorValues[2]);
6589 } else {
6590 if (value->unit == CSSParserValue::Function &&
6591 value->function->args != 0 &&
6592 value->function->args->size() == 7 /* rgba + three commas */ &&
6593 equalIgnoringCase(value->function->name, "rgba(")) {
6594 int colorValues[4];
6595 if (!parseColorParameters(value, colorValues, true))
6596 return false;
6597 c = makeRGBA(colorValues[0], colorValues[1], colorValues[2], colorVa lues[3]);
6598 } else if (value->unit == CSSParserValue::Function &&
6599 value->function->args != 0 &&
6600 value->function->args->size() == 5 /* hsl + two commas */ &&
6601 equalIgnoringCase(value->function->name, "hsl(")) {
6602 double colorValues[3];
6603 if (!parseHSLParameters(value, colorValues, false))
6604 return false;
6605 c = makeRGBAFromHSLA(colorValues[0], colorValues[1], colorValues[2], 1.0);
6606 } else if (value->unit == CSSParserValue::Function &&
6607 value->function->args != 0 &&
6608 value->function->args->size() == 7 /* hsla + three commas */ &&
6609 equalIgnoringCase(value->function->name, "hsla(")) {
6610 double colorValues[4];
6611 if (!parseHSLParameters(value, colorValues, true))
6612 return false;
6613 c = makeRGBAFromHSLA(colorValues[0], colorValues[1], colorValues[2], colorValues[3]);
6614 } else
6615 return false;
6616 }
6617
6618 return true;
6619 }
6620
6621 // This class tracks parsing state for shadow values. If it goes out of scope ( e.g., due to an early return)
6622 // without the allowBreak bit being set, then it will clean up all of the object s and destroy them.
6623 class ShadowParseContext {
6624 DISALLOW_ALLOCATION();
6625 public:
6626 ShadowParseContext(CSSPropertyID prop, CSSPropertyParser* parser)
6627 : property(prop)
6628 , m_parser(parser)
6629 , allowX(true)
6630 , allowY(false)
6631 , allowBlur(false)
6632 , allowSpread(false)
6633 , allowColor(true)
6634 , allowStyle(prop == CSSPropertyWebkitBoxShadow || prop == CSSPropertyBo xShadow)
6635 , allowBreak(true)
6636 {
6637 }
6638
6639 bool allowLength() { return allowX || allowY || allowBlur || allowSpread; }
6640
6641 void commitValue()
6642 {
6643 // Handle the ,, case gracefully by doing nothing.
6644 if (x || y || blur || spread || color || style) {
6645 if (!values)
6646 values = CSSValueList::createCommaSeparated();
6647
6648 // Construct the current shadow value and add it to the list.
6649 values->append(CSSShadowValue::create(x.release(), y.release(), blur .release(), spread.release(), style.release(), color.release()));
6650 }
6651
6652 // Now reset for the next shadow value.
6653 x = nullptr;
6654 y = nullptr;
6655 blur = nullptr;
6656 spread = nullptr;
6657 style = nullptr;
6658 color = nullptr;
6659
6660 allowX = true;
6661 allowColor = true;
6662 allowBreak = true;
6663 allowY = false;
6664 allowBlur = false;
6665 allowSpread = false;
6666 allowStyle = property == CSSPropertyWebkitBoxShadow || property == CSSPr opertyBoxShadow;
6667 }
6668
6669 void commitLength(CSSParserValue* v)
6670 {
6671 RefPtrWillBeRawPtr<CSSPrimitiveValue> val = m_parser->createPrimitiveNum ericValue(v);
6672
6673 if (allowX) {
6674 x = val.release();
6675 allowX = false;
6676 allowY = true;
6677 allowColor = false;
6678 allowStyle = false;
6679 allowBreak = false;
6680 } else if (allowY) {
6681 y = val.release();
6682 allowY = false;
6683 allowBlur = true;
6684 allowColor = true;
6685 allowStyle = property == CSSPropertyWebkitBoxShadow || property == C SSPropertyBoxShadow;
6686 allowBreak = true;
6687 } else if (allowBlur) {
6688 blur = val.release();
6689 allowBlur = false;
6690 allowSpread = property == CSSPropertyWebkitBoxShadow || property == CSSPropertyBoxShadow;
6691 } else if (allowSpread) {
6692 spread = val.release();
6693 allowSpread = false;
6694 }
6695 }
6696
6697 void commitColor(PassRefPtrWillBeRawPtr<CSSPrimitiveValue> val)
6698 {
6699 color = val;
6700 allowColor = false;
6701 if (allowX) {
6702 allowStyle = false;
6703 allowBreak = false;
6704 } else {
6705 allowBlur = false;
6706 allowSpread = false;
6707 allowStyle = property == CSSPropertyWebkitBoxShadow || property == C SSPropertyBoxShadow;
6708 }
6709 }
6710
6711 void commitStyle(CSSParserValue* v)
6712 {
6713 style = cssValuePool().createIdentifierValue(v->id);
6714 allowStyle = false;
6715 if (allowX)
6716 allowBreak = false;
6717 else {
6718 allowBlur = false;
6719 allowSpread = false;
6720 allowColor = false;
6721 }
6722 }
6723
6724 CSSPropertyID property;
6725 CSSPropertyParser* m_parser;
6726
6727 RefPtrWillBeRawPtr<CSSValueList> values;
6728 RefPtrWillBeRawPtr<CSSPrimitiveValue> x;
6729 RefPtrWillBeRawPtr<CSSPrimitiveValue> y;
6730 RefPtrWillBeRawPtr<CSSPrimitiveValue> blur;
6731 RefPtrWillBeRawPtr<CSSPrimitiveValue> spread;
6732 RefPtrWillBeRawPtr<CSSPrimitiveValue> style;
6733 RefPtrWillBeRawPtr<CSSPrimitiveValue> color;
6734
6735 bool allowX;
6736 bool allowY;
6737 bool allowBlur;
6738 bool allowSpread;
6739 bool allowColor;
6740 bool allowStyle; // inset or not.
6741 bool allowBreak;
6742 };
6743
6744 PassRefPtrWillBeRawPtr<CSSValueList> CSSPropertyParser::parseShadow(CSSParserVal ueList* valueList, CSSPropertyID propId)
6745 {
6746 ShadowParseContext context(propId, this);
6747 CSSParserValue* val;
6748 while ((val = valueList->current())) {
6749 // Check for a comma break first.
6750 if (val->unit == CSSParserValue::Operator) {
6751 if (val->iValue != ',' || !context.allowBreak) {
6752 // Other operators aren't legal or we aren't done with the curre nt shadow
6753 // value. Treat as invalid.
6754 return nullptr;
6755 }
6756 // The value is good. Commit it.
6757 context.commitValue();
6758 } else if (validUnit(val, FLength, HTMLStandardMode)) {
6759 // We required a length and didn't get one. Invalid.
6760 if (!context.allowLength())
6761 return nullptr;
6762
6763 // Blur radius must be non-negative.
6764 if (context.allowBlur && !validUnit(val, FLength | FNonNeg, HTMLStan dardMode))
6765 return nullptr;
6766
6767 // A length is allowed here. Construct the value and add it.
6768 context.commitLength(val);
6769 } else if (val->id == CSSValueInset) {
6770 if (!context.allowStyle)
6771 return nullptr;
6772
6773 context.commitStyle(val);
6774 } else {
6775 // The only other type of value that's ok is a color value.
6776 RefPtrWillBeRawPtr<CSSPrimitiveValue> parsedColor;
6777 bool isColor = ((val->id >= CSSValueAqua && val->id <= CSSValueWindo wtext) || val->id == CSSValueMenu
6778 || (val->id >= CSSValueWebkitFocusRingColor && val-> id <= CSSValueWebkitText && inQuirksMode())
6779 || val->id == CSSValueCurrentcolor);
6780 if (isColor) {
6781 if (!context.allowColor)
6782 return nullptr;
6783 parsedColor = cssValuePool().createIdentifierValue(val->id);
6784 }
6785
6786 if (!parsedColor)
6787 // It's not built-in. Try to parse it as a color.
6788 parsedColor = parseColor(val);
6789
6790 if (!parsedColor || !context.allowColor)
6791 return nullptr; // This value is not a color or length and is in valid or
6792 // it is a color, but a color isn't allowed at this po int.
6793
6794 context.commitColor(parsedColor.release());
6795 }
6796
6797 valueList->next();
6798 }
6799
6800 if (context.allowBreak) {
6801 context.commitValue();
6802 if (context.values && context.values->length())
6803 return context.values.release();
6804 }
6805
6806 return nullptr;
6807 }
6808
6809 bool CSSPropertyParser::parseReflect(CSSPropertyID propId, bool important)
6810 {
6811 // box-reflect: <direction> <offset> <mask>
6812
6813 // Direction comes first.
6814 CSSParserValue* val = m_valueList->current();
6815 RefPtrWillBeRawPtr<CSSPrimitiveValue> direction;
6816 switch (val->id) {
6817 case CSSValueAbove:
6818 case CSSValueBelow:
6819 case CSSValueLeft:
6820 case CSSValueRight:
6821 direction = cssValuePool().createIdentifierValue(val->id);
6822 break;
6823 default:
6824 return false;
6825 }
6826
6827 // The offset comes next.
6828 val = m_valueList->next();
6829 RefPtrWillBeRawPtr<CSSPrimitiveValue> offset;
6830 if (!val)
6831 offset = cssValuePool().createValue(0, CSSPrimitiveValue::CSS_PX);
6832 else {
6833 if (!validUnit(val, FLength | FPercent))
6834 return false;
6835 offset = createPrimitiveNumericValue(val);
6836 }
6837
6838 // Now for the mask.
6839 RefPtrWillBeRawPtr<CSSValue> mask;
6840 val = m_valueList->next();
6841 if (val) {
6842 mask = parseBorderImage(propId);
6843 if (!mask)
6844 return false;
6845 }
6846
6847 RefPtrWillBeRawPtr<CSSReflectValue> reflectValue = CSSReflectValue::create(d irection.release(), offset.release(), mask.release());
6848 addProperty(propId, reflectValue.release(), important);
6849 m_valueList->next();
6850 return true;
6851 }
6852
6853 bool CSSPropertyParser::parseFlex(CSSParserValueList* args, bool important)
6854 {
6855 if (!args || !args->size() || args->size() > 3)
6856 return false;
6857 static const double unsetValue = -1;
6858 double flexGrow = unsetValue;
6859 double flexShrink = unsetValue;
6860 RefPtrWillBeRawPtr<CSSPrimitiveValue> flexBasis;
6861
6862 while (CSSParserValue* arg = args->current()) {
6863 if (validUnit(arg, FNumber | FNonNeg)) {
6864 if (flexGrow == unsetValue)
6865 flexGrow = arg->fValue;
6866 else if (flexShrink == unsetValue)
6867 flexShrink = arg->fValue;
6868 else if (!arg->fValue) {
6869 // flex only allows a basis of 0 (sans units) if flex-grow and f lex-shrink values have already been set.
6870 flexBasis = cssValuePool().createValue(0, CSSPrimitiveValue::CSS _PX);
6871 } else {
6872 // We only allow 3 numbers without units if the last value is 0. E.g., flex:1 1 1 is invalid.
6873 return false;
6874 }
6875 } else if (!flexBasis && (arg->id == CSSValueAuto || validUnit(arg, FLen gth | FPercent | FNonNeg)))
6876 flexBasis = parseValidPrimitive(arg->id, arg);
6877 else {
6878 // Not a valid arg for flex.
6879 return false;
6880 }
6881 args->next();
6882 }
6883
6884 if (flexGrow == unsetValue)
6885 flexGrow = 1;
6886 if (flexShrink == unsetValue)
6887 flexShrink = 1;
6888 if (!flexBasis)
6889 flexBasis = cssValuePool().createValue(0, CSSPrimitiveValue::CSS_PX);
6890
6891 addProperty(CSSPropertyFlexGrow, cssValuePool().createValue(clampToFloat(fle xGrow), CSSPrimitiveValue::CSS_NUMBER), important);
6892 addProperty(CSSPropertyFlexShrink, cssValuePool().createValue(clampToFloat(f lexShrink), CSSPrimitiveValue::CSS_NUMBER), important);
6893 addProperty(CSSPropertyFlexBasis, flexBasis, important);
6894 return true;
6895 }
6896
6897 bool CSSPropertyParser::parseObjectPosition(bool important)
6898 {
6899 RefPtrWillBeRawPtr<CSSValue> xValue;
6900 RefPtrWillBeRawPtr<CSSValue> yValue;
6901 parseFillPosition(m_valueList.get(), xValue, yValue);
6902 if (!xValue || !yValue)
6903 return false;
6904 addProperty(
6905 CSSPropertyObjectPosition,
6906 createPrimitiveValuePair(toCSSPrimitiveValue(xValue.get()), toCSSPrimiti veValue(yValue.get()), Pair::KeepIdenticalValues),
6907 important);
6908 return true;
6909 }
6910
6911 class BorderImageParseContext {
6912 DISALLOW_ALLOCATION();
6913 public:
6914 BorderImageParseContext()
6915 : m_canAdvance(false)
6916 , m_allowCommit(true)
6917 , m_allowImage(true)
6918 , m_allowImageSlice(true)
6919 , m_allowRepeat(true)
6920 , m_allowForwardSlashOperator(false)
6921 , m_requireWidth(false)
6922 , m_requireOutset(false)
6923 {}
6924
6925 bool canAdvance() const { return m_canAdvance; }
6926 void setCanAdvance(bool canAdvance) { m_canAdvance = canAdvance; }
6927
6928 bool allowCommit() const { return m_allowCommit; }
6929 bool allowImage() const { return m_allowImage; }
6930 bool allowImageSlice() const { return m_allowImageSlice; }
6931 bool allowRepeat() const { return m_allowRepeat; }
6932 bool allowForwardSlashOperator() const { return m_allowForwardSlashOperator; }
6933
6934 bool requireWidth() const { return m_requireWidth; }
6935 bool requireOutset() const { return m_requireOutset; }
6936
6937 void commitImage(PassRefPtrWillBeRawPtr<CSSValue> image)
6938 {
6939 m_image = image;
6940 m_canAdvance = true;
6941 m_allowCommit = true;
6942 m_allowImage = m_allowForwardSlashOperator = m_requireWidth = m_requireO utset = false;
6943 m_allowImageSlice = !m_imageSlice;
6944 m_allowRepeat = !m_repeat;
6945 }
6946 void commitImageSlice(PassRefPtrWillBeRawPtr<CSSBorderImageSliceValue> slice )
6947 {
6948 m_imageSlice = slice;
6949 m_canAdvance = true;
6950 m_allowCommit = m_allowForwardSlashOperator = true;
6951 m_allowImageSlice = m_requireWidth = m_requireOutset = false;
6952 m_allowImage = !m_image;
6953 m_allowRepeat = !m_repeat;
6954 }
6955 void commitForwardSlashOperator()
6956 {
6957 m_canAdvance = true;
6958 m_allowCommit = m_allowImage = m_allowImageSlice = m_allowRepeat = m_all owForwardSlashOperator = false;
6959 if (!m_borderSlice) {
6960 m_requireWidth = true;
6961 m_requireOutset = false;
6962 } else {
6963 m_requireOutset = true;
6964 m_requireWidth = false;
6965 }
6966 }
6967 void commitBorderWidth(PassRefPtrWillBeRawPtr<CSSPrimitiveValue> slice)
6968 {
6969 m_borderSlice = slice;
6970 m_canAdvance = true;
6971 m_allowCommit = m_allowForwardSlashOperator = true;
6972 m_allowImageSlice = m_requireWidth = m_requireOutset = false;
6973 m_allowImage = !m_image;
6974 m_allowRepeat = !m_repeat;
6975 }
6976 void commitBorderOutset(PassRefPtrWillBeRawPtr<CSSPrimitiveValue> outset)
6977 {
6978 m_outset = outset;
6979 m_canAdvance = true;
6980 m_allowCommit = true;
6981 m_allowImageSlice = m_allowForwardSlashOperator = m_requireWidth = m_req uireOutset = false;
6982 m_allowImage = !m_image;
6983 m_allowRepeat = !m_repeat;
6984 }
6985 void commitRepeat(PassRefPtrWillBeRawPtr<CSSValue> repeat)
6986 {
6987 m_repeat = repeat;
6988 m_canAdvance = true;
6989 m_allowCommit = true;
6990 m_allowRepeat = m_allowForwardSlashOperator = m_requireWidth = m_require Outset = false;
6991 m_allowImageSlice = !m_imageSlice;
6992 m_allowImage = !m_image;
6993 }
6994
6995 PassRefPtrWillBeRawPtr<CSSValue> commitCSSValue()
6996 {
6997 return createBorderImageValue(m_image, m_imageSlice, m_borderSlice, m_ou tset, m_repeat);
6998 }
6999
7000 void commitMaskBoxImage(CSSPropertyParser* parser, bool important)
7001 {
7002 commitBorderImageProperty(CSSPropertyWebkitMaskBoxImageSource, parser, m _image, important);
7003 commitBorderImageProperty(CSSPropertyWebkitMaskBoxImageSlice, parser, m_ imageSlice, important);
7004 commitBorderImageProperty(CSSPropertyWebkitMaskBoxImageWidth, parser, m_ borderSlice, important);
7005 commitBorderImageProperty(CSSPropertyWebkitMaskBoxImageOutset, parser, m _outset, important);
7006 commitBorderImageProperty(CSSPropertyWebkitMaskBoxImageRepeat, parser, m _repeat, important);
7007 }
7008
7009 void commitBorderImage(CSSPropertyParser* parser, bool important)
7010 {
7011 commitBorderImageProperty(CSSPropertyBorderImageSource, parser, m_image, important);
7012 commitBorderImageProperty(CSSPropertyBorderImageSlice, parser, m_imageSl ice, important);
7013 commitBorderImageProperty(CSSPropertyBorderImageWidth, parser, m_borderS lice, important);
7014 commitBorderImageProperty(CSSPropertyBorderImageOutset, parser, m_outset , important);
7015 commitBorderImageProperty(CSSPropertyBorderImageRepeat, parser, m_repeat , important);
7016 }
7017
7018 void commitBorderImageProperty(CSSPropertyID propId, CSSPropertyParser* pars er, PassRefPtrWillBeRawPtr<CSSValue> value, bool important)
7019 {
7020 if (value)
7021 parser->addProperty(propId, value, important);
7022 else
7023 parser->addProperty(propId, cssValuePool().createImplicitInitialValu e(), important, true);
7024 }
7025
7026 static bool buildFromParser(CSSPropertyParser&, CSSPropertyID, BorderImagePa rseContext&);
7027
7028 bool m_canAdvance;
7029
7030 bool m_allowCommit;
7031 bool m_allowImage;
7032 bool m_allowImageSlice;
7033 bool m_allowRepeat;
7034 bool m_allowForwardSlashOperator;
7035
7036 bool m_requireWidth;
7037 bool m_requireOutset;
7038
7039 RefPtrWillBeRawPtr<CSSValue> m_image;
7040 RefPtrWillBeRawPtr<CSSBorderImageSliceValue> m_imageSlice;
7041 RefPtrWillBeRawPtr<CSSPrimitiveValue> m_borderSlice;
7042 RefPtrWillBeRawPtr<CSSPrimitiveValue> m_outset;
7043
7044 RefPtrWillBeRawPtr<CSSValue> m_repeat;
7045 };
7046
7047 bool BorderImageParseContext::buildFromParser(CSSPropertyParser& parser, CSSProp ertyID propId, BorderImageParseContext& context)
7048 {
7049 CSSPropertyParser::ShorthandScope scope(&parser, propId);
7050 while (CSSParserValue* val = parser.m_valueList->current()) {
7051 context.setCanAdvance(false);
7052
7053 if (!context.canAdvance() && context.allowForwardSlashOperator() && isFo rwardSlashOperator(val))
7054 context.commitForwardSlashOperator();
7055
7056 if (!context.canAdvance() && context.allowImage()) {
7057 if (val->unit == CSSPrimitiveValue::CSS_URI) {
7058 context.commitImage(CSSImageValue::create(val->string, parser.m_ context.completeURL(val->string)));
7059 } else if (isGeneratedImageValue(val)) {
7060 RefPtrWillBeRawPtr<CSSValue> value;
7061 if (parser.parseGeneratedImage(parser.m_valueList.get(), value))
7062 context.commitImage(value.release());
7063 else
7064 return false;
7065 } else if (val->unit == CSSParserValue::Function && equalIgnoringCas e(val->function->name, "-webkit-image-set(")) {
7066 RefPtrWillBeRawPtr<CSSValue> value = parser.parseImageSet(parser .m_valueList.get());
7067 if (value)
7068 context.commitImage(value.release());
7069 else
7070 return false;
7071 } else if (val->id == CSSValueNone)
7072 context.commitImage(cssValuePool().createIdentifierValue(CSSValu eNone));
7073 }
7074
7075 if (!context.canAdvance() && context.allowImageSlice()) {
7076 RefPtrWillBeRawPtr<CSSBorderImageSliceValue> imageSlice;
7077 if (parser.parseBorderImageSlice(propId, imageSlice))
7078 context.commitImageSlice(imageSlice.release());
7079 }
7080
7081 if (!context.canAdvance() && context.allowRepeat()) {
7082 RefPtrWillBeRawPtr<CSSValue> repeat;
7083 if (parser.parseBorderImageRepeat(repeat))
7084 context.commitRepeat(repeat.release());
7085 }
7086
7087 if (!context.canAdvance() && context.requireWidth()) {
7088 RefPtrWillBeRawPtr<CSSPrimitiveValue> borderSlice;
7089 if (parser.parseBorderImageWidth(borderSlice))
7090 context.commitBorderWidth(borderSlice.release());
7091 }
7092
7093 if (!context.canAdvance() && context.requireOutset()) {
7094 RefPtrWillBeRawPtr<CSSPrimitiveValue> borderOutset;
7095 if (parser.parseBorderImageOutset(borderOutset))
7096 context.commitBorderOutset(borderOutset.release());
7097 }
7098
7099 if (!context.canAdvance())
7100 return false;
7101
7102 parser.m_valueList->next();
7103 }
7104
7105 return context.allowCommit();
7106 }
7107
7108 bool CSSPropertyParser::parseBorderImageShorthand(CSSPropertyID propId, bool imp ortant)
7109 {
7110 BorderImageParseContext context;
7111 if (BorderImageParseContext::buildFromParser(*this, propId, context)) {
7112 switch (propId) {
7113 case CSSPropertyWebkitMaskBoxImage:
7114 context.commitMaskBoxImage(this, important);
7115 return true;
7116 case CSSPropertyBorderImage:
7117 context.commitBorderImage(this, important);
7118 return true;
7119 default:
7120 ASSERT_NOT_REACHED();
7121 return false;
7122 }
7123 }
7124 return false;
7125 }
7126
7127 PassRefPtrWillBeRawPtr<CSSValue> CSSPropertyParser::parseBorderImage(CSSProperty ID propId)
7128 {
7129 BorderImageParseContext context;
7130 if (BorderImageParseContext::buildFromParser(*this, propId, context)) {
7131 return context.commitCSSValue();
7132 }
7133 return nullptr;
7134 }
7135
7136 static bool isBorderImageRepeatKeyword(int id)
7137 {
7138 return id == CSSValueStretch || id == CSSValueRepeat || id == CSSValueSpace || id == CSSValueRound;
7139 }
7140
7141 bool CSSPropertyParser::parseBorderImageRepeat(RefPtrWillBeRawPtr<CSSValue>& res ult)
7142 {
7143 RefPtrWillBeRawPtr<CSSPrimitiveValue> firstValue;
7144 RefPtrWillBeRawPtr<CSSPrimitiveValue> secondValue;
7145 CSSParserValue* val = m_valueList->current();
7146 if (!val)
7147 return false;
7148 if (isBorderImageRepeatKeyword(val->id))
7149 firstValue = cssValuePool().createIdentifierValue(val->id);
7150 else
7151 return false;
7152
7153 val = m_valueList->next();
7154 if (val) {
7155 if (isBorderImageRepeatKeyword(val->id))
7156 secondValue = cssValuePool().createIdentifierValue(val->id);
7157 else if (!inShorthand()) {
7158 // If we're not parsing a shorthand then we are invalid.
7159 return false;
7160 } else {
7161 // We need to rewind the value list, so that when its advanced we'll
7162 // end up back at this value.
7163 m_valueList->previous();
7164 secondValue = firstValue;
7165 }
7166 } else
7167 secondValue = firstValue;
7168
7169 result = createPrimitiveValuePair(firstValue, secondValue);
7170 return true;
7171 }
7172
7173 class BorderImageSliceParseContext {
7174 DISALLOW_ALLOCATION();
7175 public:
7176 BorderImageSliceParseContext(CSSPropertyParser* parser)
7177 : m_parser(parser)
7178 , m_allowNumber(true)
7179 , m_allowFill(true)
7180 , m_allowFinalCommit(false)
7181 , m_fill(false)
7182 { }
7183
7184 bool allowNumber() const { return m_allowNumber; }
7185 bool allowFill() const { return m_allowFill; }
7186 bool allowFinalCommit() const { return m_allowFinalCommit; }
7187 CSSPrimitiveValue* top() const { return m_top.get(); }
7188
7189 void commitNumber(CSSParserValue* v)
7190 {
7191 RefPtrWillBeRawPtr<CSSPrimitiveValue> val = m_parser->createPrimitiveNum ericValue(v);
7192 if (!m_top)
7193 m_top = val;
7194 else if (!m_right)
7195 m_right = val;
7196 else if (!m_bottom)
7197 m_bottom = val;
7198 else {
7199 ASSERT(!m_left);
7200 m_left = val;
7201 }
7202
7203 m_allowNumber = !m_left;
7204 m_allowFinalCommit = true;
7205 }
7206
7207 void commitFill() { m_fill = true; m_allowFill = false; m_allowNumber = !m_t op; }
7208
7209 PassRefPtrWillBeRawPtr<CSSBorderImageSliceValue> commitBorderImageSlice()
7210 {
7211 // We need to clone and repeat values for any omissions.
7212 ASSERT(m_top);
7213 if (!m_right) {
7214 m_right = m_top;
7215 m_bottom = m_top;
7216 m_left = m_top;
7217 }
7218 if (!m_bottom) {
7219 m_bottom = m_top;
7220 m_left = m_right;
7221 }
7222 if (!m_left)
7223 m_left = m_right;
7224
7225 // Now build a rect value to hold all four of our primitive values.
7226 RefPtrWillBeRawPtr<Quad> quad = Quad::create();
7227 quad->setTop(m_top);
7228 quad->setRight(m_right);
7229 quad->setBottom(m_bottom);
7230 quad->setLeft(m_left);
7231
7232 // Make our new border image value now.
7233 return CSSBorderImageSliceValue::create(cssValuePool().createValue(quad. release()), m_fill);
7234 }
7235
7236 private:
7237 CSSPropertyParser* m_parser;
7238
7239 bool m_allowNumber;
7240 bool m_allowFill;
7241 bool m_allowFinalCommit;
7242
7243 RefPtrWillBeRawPtr<CSSPrimitiveValue> m_top;
7244 RefPtrWillBeRawPtr<CSSPrimitiveValue> m_right;
7245 RefPtrWillBeRawPtr<CSSPrimitiveValue> m_bottom;
7246 RefPtrWillBeRawPtr<CSSPrimitiveValue> m_left;
7247
7248 bool m_fill;
7249 };
7250
7251 bool CSSPropertyParser::parseBorderImageSlice(CSSPropertyID propId, RefPtrWillBe RawPtr<CSSBorderImageSliceValue>& result)
7252 {
7253 BorderImageSliceParseContext context(this);
7254 CSSParserValue* val;
7255 while ((val = m_valueList->current())) {
7256 // FIXME calc() http://webkit.org/b/16662 : calc is parsed but values ar e not created yet.
7257 if (context.allowNumber() && !isCalculation(val) && validUnit(val, FInte ger | FNonNeg | FPercent, HTMLStandardMode)) {
7258 context.commitNumber(val);
7259 } else if (context.allowFill() && val->id == CSSValueFill)
7260 context.commitFill();
7261 else if (!inShorthand()) {
7262 // If we're not parsing a shorthand then we are invalid.
7263 return false;
7264 } else {
7265 if (context.allowFinalCommit()) {
7266 // We're going to successfully parse, but we don't want to consu me this token.
7267 m_valueList->previous();
7268 }
7269 break;
7270 }
7271 m_valueList->next();
7272 }
7273
7274 if (context.allowFinalCommit()) {
7275 // FIXME: For backwards compatibility, -webkit-border-image, -webkit-mas k-box-image and -webkit-box-reflect have to do a fill by default.
7276 // FIXME: What do we do with -webkit-box-reflect and -webkit-mask-box-im age? Probably just have to leave them filling...
7277 if (propId == CSSPropertyWebkitBorderImage || propId == CSSPropertyWebki tMaskBoxImage || propId == CSSPropertyWebkitBoxReflect)
7278 context.commitFill();
7279
7280 // Need to fully commit as a single value.
7281 result = context.commitBorderImageSlice();
7282 return true;
7283 }
7284
7285 return false;
7286 }
7287
7288 class BorderImageQuadParseContext {
7289 public:
7290 BorderImageQuadParseContext(CSSPropertyParser* parser)
7291 : m_parser(parser)
7292 , m_allowNumber(true)
7293 , m_allowFinalCommit(false)
7294 { }
7295
7296 bool allowNumber() const { return m_allowNumber; }
7297 bool allowFinalCommit() const { return m_allowFinalCommit; }
7298 CSSPrimitiveValue* top() const { return m_top.get(); }
7299
7300 void commitNumber(CSSParserValue* v)
7301 {
7302 RefPtrWillBeRawPtr<CSSPrimitiveValue> val;
7303 if (v->id == CSSValueAuto)
7304 val = cssValuePool().createIdentifierValue(v->id);
7305 else
7306 val = m_parser->createPrimitiveNumericValue(v);
7307
7308 if (!m_top)
7309 m_top = val;
7310 else if (!m_right)
7311 m_right = val;
7312 else if (!m_bottom)
7313 m_bottom = val;
7314 else {
7315 ASSERT(!m_left);
7316 m_left = val;
7317 }
7318
7319 m_allowNumber = !m_left;
7320 m_allowFinalCommit = true;
7321 }
7322
7323 void setAllowFinalCommit() { m_allowFinalCommit = true; }
7324 void setTop(PassRefPtrWillBeRawPtr<CSSPrimitiveValue> val) { m_top = val; }
7325
7326 PassRefPtrWillBeRawPtr<CSSPrimitiveValue> commitBorderImageQuad()
7327 {
7328 // We need to clone and repeat values for any omissions.
7329 ASSERT(m_top);
7330 if (!m_right) {
7331 m_right = m_top;
7332 m_bottom = m_top;
7333 m_left = m_top;
7334 }
7335 if (!m_bottom) {
7336 m_bottom = m_top;
7337 m_left = m_right;
7338 }
7339 if (!m_left)
7340 m_left = m_right;
7341
7342 // Now build a quad value to hold all four of our primitive values.
7343 RefPtrWillBeRawPtr<Quad> quad = Quad::create();
7344 quad->setTop(m_top);
7345 quad->setRight(m_right);
7346 quad->setBottom(m_bottom);
7347 quad->setLeft(m_left);
7348
7349 // Make our new value now.
7350 return cssValuePool().createValue(quad.release());
7351 }
7352
7353 private:
7354 CSSPropertyParser* m_parser;
7355
7356 bool m_allowNumber;
7357 bool m_allowFinalCommit;
7358
7359 RefPtrWillBeRawPtr<CSSPrimitiveValue> m_top;
7360 RefPtrWillBeRawPtr<CSSPrimitiveValue> m_right;
7361 RefPtrWillBeRawPtr<CSSPrimitiveValue> m_bottom;
7362 RefPtrWillBeRawPtr<CSSPrimitiveValue> m_left;
7363 };
7364
7365 bool CSSPropertyParser::parseBorderImageQuad(Units validUnits, RefPtrWillBeRawPt r<CSSPrimitiveValue>& result)
7366 {
7367 BorderImageQuadParseContext context(this);
7368 CSSParserValue* val;
7369 while ((val = m_valueList->current())) {
7370 if (context.allowNumber() && (validUnit(val, validUnits, HTMLStandardMod e) || val->id == CSSValueAuto)) {
7371 context.commitNumber(val);
7372 } else if (!inShorthand()) {
7373 // If we're not parsing a shorthand then we are invalid.
7374 return false;
7375 } else {
7376 if (context.allowFinalCommit())
7377 m_valueList->previous(); // The shorthand loop will advance back to this point.
7378 break;
7379 }
7380 m_valueList->next();
7381 }
7382
7383 if (context.allowFinalCommit()) {
7384 // Need to fully commit as a single value.
7385 result = context.commitBorderImageQuad();
7386 return true;
7387 }
7388 return false;
7389 }
7390
7391 bool CSSPropertyParser::parseBorderImageWidth(RefPtrWillBeRawPtr<CSSPrimitiveVal ue>& result)
7392 {
7393 return parseBorderImageQuad(FLength | FNumber | FNonNeg | FPercent, result);
7394 }
7395
7396 bool CSSPropertyParser::parseBorderImageOutset(RefPtrWillBeRawPtr<CSSPrimitiveVa lue>& result)
7397 {
7398 return parseBorderImageQuad(FLength | FNumber | FNonNeg, result);
7399 }
7400
7401 bool CSSPropertyParser::parseBorderRadius(CSSPropertyID propId, bool important)
7402 {
7403 unsigned num = m_valueList->size();
7404 if (num > 9)
7405 return false;
7406
7407 ShorthandScope scope(this, propId);
7408 RefPtrWillBeRawPtr<CSSPrimitiveValue> radii[2][4];
7409
7410 unsigned indexAfterSlash = 0;
7411 for (unsigned i = 0; i < num; ++i) {
7412 CSSParserValue* value = m_valueList->valueAt(i);
7413 if (value->unit == CSSParserValue::Operator) {
7414 if (value->iValue != '/')
7415 return false;
7416
7417 if (!i || indexAfterSlash || i + 1 == num || num > i + 5)
7418 return false;
7419
7420 indexAfterSlash = i + 1;
7421 completeBorderRadii(radii[0]);
7422 continue;
7423 }
7424
7425 if (i - indexAfterSlash >= 4)
7426 return false;
7427
7428 if (!validUnit(value, FLength | FPercent | FNonNeg))
7429 return false;
7430
7431 RefPtrWillBeRawPtr<CSSPrimitiveValue> radius = createPrimitiveNumericVal ue(value);
7432
7433 if (!indexAfterSlash) {
7434 radii[0][i] = radius;
7435
7436 // Legacy syntax: -webkit-border-radius: l1 l2; is equivalent to bor der-radius: l1 / l2;
7437 if (num == 2 && propId == CSSPropertyWebkitBorderRadius) {
7438 indexAfterSlash = 1;
7439 completeBorderRadii(radii[0]);
7440 }
7441 } else
7442 radii[1][i - indexAfterSlash] = radius.release();
7443 }
7444
7445 if (!indexAfterSlash) {
7446 completeBorderRadii(radii[0]);
7447 for (unsigned i = 0; i < 4; ++i)
7448 radii[1][i] = radii[0][i];
7449 } else
7450 completeBorderRadii(radii[1]);
7451
7452 ImplicitScope implicitScope(this, PropertyImplicit);
7453 addProperty(CSSPropertyBorderTopLeftRadius, createPrimitiveValuePair(radii[0 ][0].release(), radii[1][0].release()), important);
7454 addProperty(CSSPropertyBorderTopRightRadius, createPrimitiveValuePair(radii[ 0][1].release(), radii[1][1].release()), important);
7455 addProperty(CSSPropertyBorderBottomRightRadius, createPrimitiveValuePair(rad ii[0][2].release(), radii[1][2].release()), important);
7456 addProperty(CSSPropertyBorderBottomLeftRadius, createPrimitiveValuePair(radi i[0][3].release(), radii[1][3].release()), important);
7457 return true;
7458 }
7459
7460 bool CSSPropertyParser::parseAspectRatio(bool important)
7461 {
7462 unsigned num = m_valueList->size();
7463 if (num == 1 && m_valueList->valueAt(0)->id == CSSValueNone) {
7464 addProperty(CSSPropertyWebkitAspectRatio, cssValuePool().createIdentifie rValue(CSSValueNone), important);
7465 return true;
7466 }
7467
7468 if (num != 3)
7469 return false;
7470
7471 CSSParserValue* lvalue = m_valueList->valueAt(0);
7472 CSSParserValue* op = m_valueList->valueAt(1);
7473 CSSParserValue* rvalue = m_valueList->valueAt(2);
7474
7475 if (!isForwardSlashOperator(op))
7476 return false;
7477
7478 if (!validUnit(lvalue, FNumber | FNonNeg) || !validUnit(rvalue, FNumber | FN onNeg))
7479 return false;
7480
7481 if (!lvalue->fValue || !rvalue->fValue)
7482 return false;
7483
7484 addProperty(CSSPropertyWebkitAspectRatio, CSSAspectRatioValue::create(narrow PrecisionToFloat(lvalue->fValue), narrowPrecisionToFloat(rvalue->fValue)), impor tant);
7485
7486 return true;
7487 }
7488
7489 bool CSSPropertyParser::parseCounter(CSSPropertyID propId, int defaultValue, boo l important)
7490 {
7491 enum { ID, VAL } state = ID;
7492
7493 RefPtrWillBeRawPtr<CSSValueList> list = CSSValueList::createCommaSeparated() ;
7494 RefPtrWillBeRawPtr<CSSPrimitiveValue> counterName;
7495
7496 while (true) {
7497 CSSParserValue* val = m_valueList->current();
7498 switch (state) {
7499 case ID:
7500 if (val && val->unit == CSSPrimitiveValue::CSS_IDENT) {
7501 counterName = createPrimitiveStringValue(val);
7502 state = VAL;
7503 m_valueList->next();
7504 continue;
7505 }
7506 break;
7507 case VAL: {
7508 int i = defaultValue;
7509 if (val && val->unit == CSSPrimitiveValue::CSS_NUMBER) {
7510 i = clampToInteger(val->fValue);
7511 m_valueList->next();
7512 }
7513
7514 list->append(createPrimitiveValuePair(counterName.release(),
7515 cssValuePool().createValue(i, CSSPrimitiveValue::CSS_NUMBER) ));
7516 state = ID;
7517 continue;
7518 }
7519 }
7520 break;
7521 }
7522
7523 if (list->length() > 0) {
7524 addProperty(propId, list.release(), important);
7525 return true;
7526 }
7527
7528 return false;
7529 }
7530
7531 // This should go away once we drop support for -webkit-gradient
7532 static PassRefPtrWillBeRawPtr<CSSPrimitiveValue> parseDeprecatedGradientPoint(CS SParserValue* a, bool horizontal)
7533 {
7534 RefPtrWillBeRawPtr<CSSPrimitiveValue> result;
7535 if (a->unit == CSSPrimitiveValue::CSS_IDENT) {
7536 if ((equalIgnoringCase(a, "left") && horizontal)
7537 || (equalIgnoringCase(a, "top") && !horizontal))
7538 result = cssValuePool().createValue(0., CSSPrimitiveValue::CSS_PERCE NTAGE);
7539 else if ((equalIgnoringCase(a, "right") && horizontal)
7540 || (equalIgnoringCase(a, "bottom") && !horizontal))
7541 result = cssValuePool().createValue(100., CSSPrimitiveValue::CSS_PER CENTAGE);
7542 else if (equalIgnoringCase(a, "center"))
7543 result = cssValuePool().createValue(50., CSSPrimitiveValue::CSS_PERC ENTAGE);
7544 } else if (a->unit == CSSPrimitiveValue::CSS_NUMBER || a->unit == CSSPrimiti veValue::CSS_PERCENTAGE)
7545 result = cssValuePool().createValue(a->fValue, static_cast<CSSPrimitiveV alue::UnitTypes>(a->unit));
7546 return result;
7547 }
7548
7549 bool parseDeprecatedGradientColorStop(CSSPropertyParser* p, CSSParserValue* a, C SSGradientColorStop& stop)
7550 {
7551 if (a->unit != CSSParserValue::Function)
7552 return false;
7553
7554 if (!equalIgnoringCase(a->function->name, "from(") &&
7555 !equalIgnoringCase(a->function->name, "to(") &&
7556 !equalIgnoringCase(a->function->name, "color-stop("))
7557 return false;
7558
7559 CSSParserValueList* args = a->function->args.get();
7560 if (!args)
7561 return false;
7562
7563 if (equalIgnoringCase(a->function->name, "from(")
7564 || equalIgnoringCase(a->function->name, "to(")) {
7565 // The "from" and "to" stops expect 1 argument.
7566 if (args->size() != 1)
7567 return false;
7568
7569 if (equalIgnoringCase(a->function->name, "from("))
7570 stop.m_position = cssValuePool().createValue(0, CSSPrimitiveValue::C SS_NUMBER);
7571 else
7572 stop.m_position = cssValuePool().createValue(1, CSSPrimitiveValue::C SS_NUMBER);
7573
7574 CSSValueID id = args->current()->id;
7575 if (id == CSSValueWebkitText || (id >= CSSValueAqua && id <= CSSValueWin dowtext) || id == CSSValueMenu)
7576 stop.m_color = cssValuePool().createIdentifierValue(id);
7577 else
7578 stop.m_color = p->parseColor(args->current());
7579 if (!stop.m_color)
7580 return false;
7581 }
7582
7583 // The "color-stop" function expects 3 arguments.
7584 if (equalIgnoringCase(a->function->name, "color-stop(")) {
7585 if (args->size() != 3)
7586 return false;
7587
7588 CSSParserValue* stopArg = args->current();
7589 if (stopArg->unit == CSSPrimitiveValue::CSS_PERCENTAGE)
7590 stop.m_position = cssValuePool().createValue(stopArg->fValue / 100, CSSPrimitiveValue::CSS_NUMBER);
7591 else if (stopArg->unit == CSSPrimitiveValue::CSS_NUMBER)
7592 stop.m_position = cssValuePool().createValue(stopArg->fValue, CSSPri mitiveValue::CSS_NUMBER);
7593 else
7594 return false;
7595
7596 stopArg = args->next();
7597 if (stopArg->unit != CSSParserValue::Operator || stopArg->iValue != ',')
7598 return false;
7599
7600 stopArg = args->next();
7601 CSSValueID id = stopArg->id;
7602 if (id == CSSValueWebkitText || (id >= CSSValueAqua && id <= CSSValueWin dowtext) || id == CSSValueMenu)
7603 stop.m_color = cssValuePool().createIdentifierValue(id);
7604 else
7605 stop.m_color = p->parseColor(stopArg);
7606 if (!stop.m_color)
7607 return false;
7608 }
7609
7610 return true;
7611 }
7612
7613 bool CSSPropertyParser::parseDeprecatedGradient(CSSParserValueList* valueList, R efPtrWillBeRawPtr<CSSValue>& gradient)
7614 {
7615 // Walk the arguments.
7616 CSSParserValueList* args = valueList->current()->function->args.get();
7617 if (!args || args->size() == 0)
7618 return false;
7619
7620 // The first argument is the gradient type. It is an identifier.
7621 CSSGradientType gradientType;
7622 CSSParserValue* a = args->current();
7623 if (!a || a->unit != CSSPrimitiveValue::CSS_IDENT)
7624 return false;
7625 if (equalIgnoringCase(a, "linear"))
7626 gradientType = CSSDeprecatedLinearGradient;
7627 else if (equalIgnoringCase(a, "radial"))
7628 gradientType = CSSDeprecatedRadialGradient;
7629 else
7630 return false;
7631
7632 RefPtrWillBeRawPtr<CSSGradientValue> result;
7633 switch (gradientType) {
7634 case CSSDeprecatedLinearGradient:
7635 result = CSSLinearGradientValue::create(NonRepeating, gradientType);
7636 break;
7637 case CSSDeprecatedRadialGradient:
7638 result = CSSRadialGradientValue::create(NonRepeating, gradientType);
7639 break;
7640 default:
7641 // The rest of the gradient types shouldn't appear here.
7642 ASSERT_NOT_REACHED();
7643 }
7644
7645 // Comma.
7646 a = args->next();
7647 if (!isComma(a))
7648 return false;
7649
7650 // Next comes the starting point for the gradient as an x y pair. There is no
7651 // comma between the x and the y values.
7652 // First X. It can be left, right, number or percent.
7653 a = args->next();
7654 if (!a)
7655 return false;
7656 RefPtrWillBeRawPtr<CSSPrimitiveValue> point = parseDeprecatedGradientPoint(a , true);
7657 if (!point)
7658 return false;
7659 result->setFirstX(point.release());
7660
7661 // First Y. It can be top, bottom, number or percent.
7662 a = args->next();
7663 if (!a)
7664 return false;
7665 point = parseDeprecatedGradientPoint(a, false);
7666 if (!point)
7667 return false;
7668 result->setFirstY(point.release());
7669
7670 // Comma after the first point.
7671 a = args->next();
7672 if (!isComma(a))
7673 return false;
7674
7675 // For radial gradients only, we now expect a numeric radius.
7676 if (gradientType == CSSDeprecatedRadialGradient) {
7677 a = args->next();
7678 if (!a || a->unit != CSSPrimitiveValue::CSS_NUMBER)
7679 return false;
7680 toCSSRadialGradientValue(result.get())->setFirstRadius(createPrimitiveNu mericValue(a));
7681
7682 // Comma after the first radius.
7683 a = args->next();
7684 if (!isComma(a))
7685 return false;
7686 }
7687
7688 // Next is the ending point for the gradient as an x, y pair.
7689 // Second X. It can be left, right, number or percent.
7690 a = args->next();
7691 if (!a)
7692 return false;
7693 point = parseDeprecatedGradientPoint(a, true);
7694 if (!point)
7695 return false;
7696 result->setSecondX(point.release());
7697
7698 // Second Y. It can be top, bottom, number or percent.
7699 a = args->next();
7700 if (!a)
7701 return false;
7702 point = parseDeprecatedGradientPoint(a, false);
7703 if (!point)
7704 return false;
7705 result->setSecondY(point.release());
7706
7707 // For radial gradients only, we now expect the second radius.
7708 if (gradientType == CSSDeprecatedRadialGradient) {
7709 // Comma after the second point.
7710 a = args->next();
7711 if (!isComma(a))
7712 return false;
7713
7714 a = args->next();
7715 if (!a || a->unit != CSSPrimitiveValue::CSS_NUMBER)
7716 return false;
7717 toCSSRadialGradientValue(result.get())->setSecondRadius(createPrimitiveN umericValue(a));
7718 }
7719
7720 // We now will accept any number of stops (0 or more).
7721 a = args->next();
7722 while (a) {
7723 // Look for the comma before the next stop.
7724 if (!isComma(a))
7725 return false;
7726
7727 // Now examine the stop itself.
7728 a = args->next();
7729 if (!a)
7730 return false;
7731
7732 // The function name needs to be one of "from", "to", or "color-stop."
7733 CSSGradientColorStop stop;
7734 if (!parseDeprecatedGradientColorStop(this, a, stop))
7735 return false;
7736 result->addStop(stop);
7737
7738 // Advance
7739 a = args->next();
7740 }
7741
7742 gradient = result.release();
7743 return true;
7744 }
7745
7746 static PassRefPtrWillBeRawPtr<CSSPrimitiveValue> valueFromSideKeyword(CSSParserV alue* a, bool& isHorizontal)
7747 {
7748 if (a->unit != CSSPrimitiveValue::CSS_IDENT)
7749 return nullptr;
7750
7751 switch (a->id) {
7752 case CSSValueLeft:
7753 case CSSValueRight:
7754 isHorizontal = true;
7755 break;
7756 case CSSValueTop:
7757 case CSSValueBottom:
7758 isHorizontal = false;
7759 break;
7760 default:
7761 return nullptr;
7762 }
7763 return cssValuePool().createIdentifierValue(a->id);
7764 }
7765
7766 PassRefPtrWillBeRawPtr<CSSPrimitiveValue> parseGradientColorOrKeyword(CSSPropert yParser* p, CSSParserValue* value)
7767 {
7768 CSSValueID id = value->id;
7769 if (id == CSSValueWebkitText || (id >= CSSValueAqua && id <= CSSValueWindowt ext) || id == CSSValueMenu || id == CSSValueCurrentcolor)
7770 return cssValuePool().createIdentifierValue(id);
7771
7772 return p->parseColor(value);
7773 }
7774
7775 bool CSSPropertyParser::parseDeprecatedLinearGradient(CSSParserValueList* valueL ist, RefPtrWillBeRawPtr<CSSValue>& gradient, CSSGradientRepeat repeating)
7776 {
7777 RefPtrWillBeRawPtr<CSSLinearGradientValue> result = CSSLinearGradientValue:: create(repeating, CSSPrefixedLinearGradient);
7778
7779 // Walk the arguments.
7780 CSSParserValueList* args = valueList->current()->function->args.get();
7781 if (!args || !args->size())
7782 return false;
7783
7784 CSSParserValue* a = args->current();
7785 if (!a)
7786 return false;
7787
7788 bool expectComma = false;
7789 // Look for angle.
7790 if (validUnit(a, FAngle, HTMLStandardMode)) {
7791 result->setAngle(createPrimitiveNumericValue(a));
7792
7793 args->next();
7794 expectComma = true;
7795 } else {
7796 // Look one or two optional keywords that indicate a side or corner.
7797 RefPtrWillBeRawPtr<CSSPrimitiveValue> startX, startY;
7798
7799 RefPtrWillBeRawPtr<CSSPrimitiveValue> location;
7800 bool isHorizontal = false;
7801 if ((location = valueFromSideKeyword(a, isHorizontal))) {
7802 if (isHorizontal)
7803 startX = location;
7804 else
7805 startY = location;
7806
7807 if ((a = args->next())) {
7808 if ((location = valueFromSideKeyword(a, isHorizontal))) {
7809 if (isHorizontal) {
7810 if (startX)
7811 return false;
7812 startX = location;
7813 } else {
7814 if (startY)
7815 return false;
7816 startY = location;
7817 }
7818
7819 args->next();
7820 }
7821 }
7822
7823 expectComma = true;
7824 }
7825
7826 if (!startX && !startY)
7827 startY = cssValuePool().createIdentifierValue(CSSValueTop);
7828
7829 result->setFirstX(startX.release());
7830 result->setFirstY(startY.release());
7831 }
7832
7833 if (!parseGradientColorStops(args, result.get(), expectComma))
7834 return false;
7835
7836 if (!result->stopCount())
7837 return false;
7838
7839 gradient = result.release();
7840 return true;
7841 }
7842
7843 bool CSSPropertyParser::parseDeprecatedRadialGradient(CSSParserValueList* valueL ist, RefPtrWillBeRawPtr<CSSValue>& gradient, CSSGradientRepeat repeating)
7844 {
7845 RefPtrWillBeRawPtr<CSSRadialGradientValue> result = CSSRadialGradientValue:: create(repeating, CSSPrefixedRadialGradient);
7846
7847 // Walk the arguments.
7848 CSSParserValueList* args = valueList->current()->function->args.get();
7849 if (!args || !args->size())
7850 return false;
7851
7852 CSSParserValue* a = args->current();
7853 if (!a)
7854 return false;
7855
7856 bool expectComma = false;
7857
7858 // Optional background-position
7859 RefPtrWillBeRawPtr<CSSValue> centerX;
7860 RefPtrWillBeRawPtr<CSSValue> centerY;
7861 // parse2ValuesFillPosition advances the args next pointer.
7862 parse2ValuesFillPosition(args, centerX, centerY);
7863 a = args->current();
7864 if (!a)
7865 return false;
7866
7867 if (centerX || centerY) {
7868 // Comma
7869 if (!isComma(a))
7870 return false;
7871
7872 a = args->next();
7873 if (!a)
7874 return false;
7875 }
7876
7877 result->setFirstX(toCSSPrimitiveValue(centerX.get()));
7878 result->setSecondX(toCSSPrimitiveValue(centerX.get()));
7879 // CSS3 radial gradients always share the same start and end point.
7880 result->setFirstY(toCSSPrimitiveValue(centerY.get()));
7881 result->setSecondY(toCSSPrimitiveValue(centerY.get()));
7882
7883 RefPtrWillBeRawPtr<CSSPrimitiveValue> shapeValue;
7884 RefPtrWillBeRawPtr<CSSPrimitiveValue> sizeValue;
7885
7886 // Optional shape and/or size in any order.
7887 for (int i = 0; i < 2; ++i) {
7888 if (a->unit != CSSPrimitiveValue::CSS_IDENT)
7889 break;
7890
7891 bool foundValue = false;
7892 switch (a->id) {
7893 case CSSValueCircle:
7894 case CSSValueEllipse:
7895 shapeValue = cssValuePool().createIdentifierValue(a->id);
7896 foundValue = true;
7897 break;
7898 case CSSValueClosestSide:
7899 case CSSValueClosestCorner:
7900 case CSSValueFarthestSide:
7901 case CSSValueFarthestCorner:
7902 case CSSValueContain:
7903 case CSSValueCover:
7904 sizeValue = cssValuePool().createIdentifierValue(a->id);
7905 foundValue = true;
7906 break;
7907 default:
7908 break;
7909 }
7910
7911 if (foundValue) {
7912 a = args->next();
7913 if (!a)
7914 return false;
7915
7916 expectComma = true;
7917 }
7918 }
7919
7920 result->setShape(shapeValue);
7921 result->setSizingBehavior(sizeValue);
7922
7923 // Or, two lengths or percentages
7924 RefPtrWillBeRawPtr<CSSPrimitiveValue> horizontalSize;
7925 RefPtrWillBeRawPtr<CSSPrimitiveValue> verticalSize;
7926
7927 if (!shapeValue && !sizeValue) {
7928 if (validUnit(a, FLength | FPercent)) {
7929 horizontalSize = createPrimitiveNumericValue(a);
7930 a = args->next();
7931 if (!a)
7932 return false;
7933
7934 expectComma = true;
7935 }
7936
7937 if (validUnit(a, FLength | FPercent)) {
7938 verticalSize = createPrimitiveNumericValue(a);
7939
7940 a = args->next();
7941 if (!a)
7942 return false;
7943 expectComma = true;
7944 }
7945 }
7946
7947 // Must have neither or both.
7948 if (!horizontalSize != !verticalSize)
7949 return false;
7950
7951 result->setEndHorizontalSize(horizontalSize);
7952 result->setEndVerticalSize(verticalSize);
7953
7954 if (!parseGradientColorStops(args, result.get(), expectComma))
7955 return false;
7956
7957 gradient = result.release();
7958 return true;
7959 }
7960
7961 bool CSSPropertyParser::parseLinearGradient(CSSParserValueList* valueList, RefPt rWillBeRawPtr<CSSValue>& gradient, CSSGradientRepeat repeating)
7962 {
7963 RefPtrWillBeRawPtr<CSSLinearGradientValue> result = CSSLinearGradientValue:: create(repeating, CSSLinearGradient);
7964
7965 CSSParserValueList* args = valueList->current()->function->args.get();
7966 if (!args || !args->size())
7967 return false;
7968
7969 CSSParserValue* a = args->current();
7970 if (!a)
7971 return false;
7972
7973 bool expectComma = false;
7974 // Look for angle.
7975 if (validUnit(a, FAngle, HTMLStandardMode)) {
7976 result->setAngle(createPrimitiveNumericValue(a));
7977
7978 args->next();
7979 expectComma = true;
7980 } else if (a->unit == CSSPrimitiveValue::CSS_IDENT && equalIgnoringCase(a, " to")) {
7981 // to [ [left | right] || [top | bottom] ]
7982 a = args->next();
7983 if (!a)
7984 return false;
7985
7986 RefPtrWillBeRawPtr<CSSPrimitiveValue> endX, endY;
7987 RefPtrWillBeRawPtr<CSSPrimitiveValue> location;
7988 bool isHorizontal = false;
7989
7990 location = valueFromSideKeyword(a, isHorizontal);
7991 if (!location)
7992 return false;
7993
7994 if (isHorizontal)
7995 endX = location;
7996 else
7997 endY = location;
7998
7999 a = args->next();
8000 if (!a)
8001 return false;
8002
8003 location = valueFromSideKeyword(a, isHorizontal);
8004 if (location) {
8005 if (isHorizontal) {
8006 if (endX)
8007 return false;
8008 endX = location;
8009 } else {
8010 if (endY)
8011 return false;
8012 endY = location;
8013 }
8014
8015 args->next();
8016 }
8017
8018 expectComma = true;
8019 result->setFirstX(endX.release());
8020 result->setFirstY(endY.release());
8021 }
8022
8023 if (!parseGradientColorStops(args, result.get(), expectComma))
8024 return false;
8025
8026 if (!result->stopCount())
8027 return false;
8028
8029 gradient = result.release();
8030 return true;
8031 }
8032
8033 bool CSSPropertyParser::parseRadialGradient(CSSParserValueList* valueList, RefPt rWillBeRawPtr<CSSValue>& gradient, CSSGradientRepeat repeating)
8034 {
8035 RefPtrWillBeRawPtr<CSSRadialGradientValue> result = CSSRadialGradientValue:: create(repeating, CSSRadialGradient);
8036
8037 CSSParserValueList* args = valueList->current()->function->args.get();
8038 if (!args || !args->size())
8039 return false;
8040
8041 CSSParserValue* a = args->current();
8042 if (!a)
8043 return false;
8044
8045 bool expectComma = false;
8046
8047 RefPtrWillBeRawPtr<CSSPrimitiveValue> shapeValue;
8048 RefPtrWillBeRawPtr<CSSPrimitiveValue> sizeValue;
8049 RefPtrWillBeRawPtr<CSSPrimitiveValue> horizontalSize;
8050 RefPtrWillBeRawPtr<CSSPrimitiveValue> verticalSize;
8051
8052 // First part of grammar, the size/shape clause:
8053 // [ circle || <length> ] |
8054 // [ ellipse || [ <length> | <percentage> ]{2} ] |
8055 // [ [ circle | ellipse] || <size-keyword> ]
8056 for (int i = 0; i < 3; ++i) {
8057 if (a->unit == CSSPrimitiveValue::CSS_IDENT) {
8058 bool badIdent = false;
8059 switch (a->id) {
8060 case CSSValueCircle:
8061 case CSSValueEllipse:
8062 if (shapeValue)
8063 return false;
8064 shapeValue = cssValuePool().createIdentifierValue(a->id);
8065 break;
8066 case CSSValueClosestSide:
8067 case CSSValueClosestCorner:
8068 case CSSValueFarthestSide:
8069 case CSSValueFarthestCorner:
8070 if (sizeValue || horizontalSize)
8071 return false;
8072 sizeValue = cssValuePool().createIdentifierValue(a->id);
8073 break;
8074 default:
8075 badIdent = true;
8076 }
8077
8078 if (badIdent)
8079 break;
8080
8081 a = args->next();
8082 if (!a)
8083 return false;
8084 } else if (validUnit(a, FLength | FPercent)) {
8085
8086 if (sizeValue || horizontalSize)
8087 return false;
8088 horizontalSize = createPrimitiveNumericValue(a);
8089
8090 a = args->next();
8091 if (!a)
8092 return false;
8093
8094 if (validUnit(a, FLength | FPercent)) {
8095 verticalSize = createPrimitiveNumericValue(a);
8096 ++i;
8097 a = args->next();
8098 if (!a)
8099 return false;
8100 }
8101 } else
8102 break;
8103 }
8104
8105 // You can specify size as a keyword or a length/percentage, not both.
8106 if (sizeValue && horizontalSize)
8107 return false;
8108 // Circles must have 0 or 1 lengths.
8109 if (shapeValue && shapeValue->getValueID() == CSSValueCircle && verticalSize )
8110 return false;
8111 // Ellipses must have 0 or 2 length/percentages.
8112 if (shapeValue && shapeValue->getValueID() == CSSValueEllipse && horizontalS ize && !verticalSize)
8113 return false;
8114 // If there's only one size, it must be a length.
8115 if (!verticalSize && horizontalSize && horizontalSize->isPercentage())
8116 return false;
8117
8118 result->setShape(shapeValue);
8119 result->setSizingBehavior(sizeValue);
8120 result->setEndHorizontalSize(horizontalSize);
8121 result->setEndVerticalSize(verticalSize);
8122
8123 // Second part of grammar, the center-position clause:
8124 // at <position>
8125 RefPtrWillBeRawPtr<CSSValue> centerX;
8126 RefPtrWillBeRawPtr<CSSValue> centerY;
8127 if (a->unit == CSSPrimitiveValue::CSS_IDENT && equalIgnoringCase(a, "at")) {
8128 a = args->next();
8129 if (!a)
8130 return false;
8131
8132 parseFillPosition(args, centerX, centerY);
8133 if (!(centerX && centerY))
8134 return false;
8135
8136 a = args->current();
8137 if (!a)
8138 return false;
8139 result->setFirstX(toCSSPrimitiveValue(centerX.get()));
8140 result->setFirstY(toCSSPrimitiveValue(centerY.get()));
8141 // Right now, CSS radial gradients have the same start and end centers.
8142 result->setSecondX(toCSSPrimitiveValue(centerX.get()));
8143 result->setSecondY(toCSSPrimitiveValue(centerY.get()));
8144 }
8145
8146 if (shapeValue || sizeValue || horizontalSize || centerX || centerY)
8147 expectComma = true;
8148
8149 if (!parseGradientColorStops(args, result.get(), expectComma))
8150 return false;
8151
8152 gradient = result.release();
8153 return true;
8154 }
8155
8156 bool CSSPropertyParser::parseGradientColorStops(CSSParserValueList* valueList, C SSGradientValue* gradient, bool expectComma)
8157 {
8158 CSSParserValue* a = valueList->current();
8159
8160 // Now look for color stops.
8161 while (a) {
8162 // Look for the comma before the next stop.
8163 if (expectComma) {
8164 if (!isComma(a))
8165 return false;
8166
8167 a = valueList->next();
8168 if (!a)
8169 return false;
8170 }
8171
8172 // <color-stop> = <color> [ <percentage> | <length> ]?
8173 CSSGradientColorStop stop;
8174 stop.m_color = parseGradientColorOrKeyword(this, a);
8175 if (!stop.m_color)
8176 return false;
8177
8178 a = valueList->next();
8179 if (a) {
8180 if (validUnit(a, FLength | FPercent)) {
8181 stop.m_position = createPrimitiveNumericValue(a);
8182 a = valueList->next();
8183 }
8184 }
8185
8186 gradient->addStop(stop);
8187 expectComma = true;
8188 }
8189
8190 // Must have 2 or more stops to be valid.
8191 return gradient->stopCount() >= 2;
8192 }
8193
8194 bool CSSPropertyParser::parseGeneratedImage(CSSParserValueList* valueList, RefPt rWillBeRawPtr<CSSValue>& value)
8195 {
8196 CSSParserValue* val = valueList->current();
8197
8198 if (val->unit != CSSParserValue::Function)
8199 return false;
8200
8201 if (equalIgnoringCase(val->function->name, "-webkit-gradient(")) {
8202 // FIXME: This should send a deprecation message.
8203 if (m_context.useCounter())
8204 m_context.useCounter()->count(UseCounter::DeprecatedWebKitGradient);
8205 return parseDeprecatedGradient(valueList, value);
8206 }
8207
8208 if (equalIgnoringCase(val->function->name, "-webkit-linear-gradient(")) {
8209 // FIXME: This should send a deprecation message.
8210 if (m_context.useCounter())
8211 m_context.useCounter()->count(UseCounter::DeprecatedWebKitLinearGrad ient);
8212 return parseDeprecatedLinearGradient(valueList, value, NonRepeating);
8213 }
8214
8215 if (equalIgnoringCase(val->function->name, "linear-gradient("))
8216 return parseLinearGradient(valueList, value, NonRepeating);
8217
8218 if (equalIgnoringCase(val->function->name, "-webkit-repeating-linear-gradien t(")) {
8219 // FIXME: This should send a deprecation message.
8220 if (m_context.useCounter())
8221 m_context.useCounter()->count(UseCounter::DeprecatedWebKitRepeatingL inearGradient);
8222 return parseDeprecatedLinearGradient(valueList, value, Repeating);
8223 }
8224
8225 if (equalIgnoringCase(val->function->name, "repeating-linear-gradient("))
8226 return parseLinearGradient(valueList, value, Repeating);
8227
8228 if (equalIgnoringCase(val->function->name, "-webkit-radial-gradient(")) {
8229 // FIXME: This should send a deprecation message.
8230 if (m_context.useCounter())
8231 m_context.useCounter()->count(UseCounter::DeprecatedWebKitRadialGrad ient);
8232 return parseDeprecatedRadialGradient(valueList, value, NonRepeating);
8233 }
8234
8235 if (equalIgnoringCase(val->function->name, "radial-gradient("))
8236 return parseRadialGradient(valueList, value, NonRepeating);
8237
8238 if (equalIgnoringCase(val->function->name, "-webkit-repeating-radial-gradien t(")) {
8239 if (m_context.useCounter())
8240 m_context.useCounter()->count(UseCounter::DeprecatedWebKitRepeatingR adialGradient);
8241 return parseDeprecatedRadialGradient(valueList, value, Repeating);
8242 }
8243
8244 if (equalIgnoringCase(val->function->name, "repeating-radial-gradient("))
8245 return parseRadialGradient(valueList, value, Repeating);
8246
8247 if (equalIgnoringCase(val->function->name, "-webkit-canvas("))
8248 return parseCanvas(valueList, value);
8249
8250 if (equalIgnoringCase(val->function->name, "-webkit-cross-fade("))
8251 return parseCrossfade(valueList, value);
8252
8253 return false;
8254 }
8255
8256 bool CSSPropertyParser::parseCrossfade(CSSParserValueList* valueList, RefPtrWill BeRawPtr<CSSValue>& crossfade)
8257 {
8258 // Walk the arguments.
8259 CSSParserValueList* args = valueList->current()->function->args.get();
8260 if (!args || args->size() != 5)
8261 return false;
8262 CSSParserValue* a = args->current();
8263 RefPtrWillBeRawPtr<CSSValue> fromImageValue;
8264 RefPtrWillBeRawPtr<CSSValue> toImageValue;
8265
8266 // The first argument is the "from" image. It is a fill image.
8267 if (!a || !parseFillImage(args, fromImageValue))
8268 return false;
8269 a = args->next();
8270
8271 // Skip a comma
8272 if (!isComma(a))
8273 return false;
8274 a = args->next();
8275
8276 // The second argument is the "to" image. It is a fill image.
8277 if (!a || !parseFillImage(args, toImageValue))
8278 return false;
8279 a = args->next();
8280
8281 // Skip a comma
8282 if (!isComma(a))
8283 return false;
8284 a = args->next();
8285
8286 // The third argument is the crossfade value. It is a percentage or a fracti onal number.
8287 RefPtrWillBeRawPtr<CSSPrimitiveValue> percentage;
8288 if (!a)
8289 return false;
8290
8291 if (a->unit == CSSPrimitiveValue::CSS_PERCENTAGE)
8292 percentage = cssValuePool().createValue(clampTo<double>(a->fValue / 100, 0, 1), CSSPrimitiveValue::CSS_NUMBER);
8293 else if (a->unit == CSSPrimitiveValue::CSS_NUMBER)
8294 percentage = cssValuePool().createValue(clampTo<double>(a->fValue, 0, 1) , CSSPrimitiveValue::CSS_NUMBER);
8295 else
8296 return false;
8297
8298 RefPtrWillBeRawPtr<CSSCrossfadeValue> result = CSSCrossfadeValue::create(fro mImageValue, toImageValue);
8299 result->setPercentage(percentage);
8300
8301 crossfade = result;
8302
8303 return true;
8304 }
8305
8306 bool CSSPropertyParser::parseCanvas(CSSParserValueList* valueList, RefPtrWillBeR awPtr<CSSValue>& canvas)
8307 {
8308 // Walk the arguments.
8309 CSSParserValueList* args = valueList->current()->function->args.get();
8310 if (!args || args->size() != 1)
8311 return false;
8312
8313 // The first argument is the canvas name. It is an identifier.
8314 CSSParserValue* value = args->current();
8315 if (!value || value->unit != CSSPrimitiveValue::CSS_IDENT)
8316 return false;
8317
8318 canvas = CSSCanvasValue::create(value->string);
8319 return true;
8320 }
8321
8322 PassRefPtrWillBeRawPtr<CSSValue> CSSPropertyParser::parseImageSet(CSSParserValue List* valueList)
8323 {
8324 CSSParserValue* function = valueList->current();
8325
8326 if (function->unit != CSSParserValue::Function)
8327 return nullptr;
8328
8329 CSSParserValueList* functionArgs = valueList->current()->function->args.get( );
8330 if (!functionArgs || !functionArgs->size() || !functionArgs->current())
8331 return nullptr;
8332
8333 RefPtrWillBeRawPtr<CSSImageSetValue> imageSet = CSSImageSetValue::create();
8334
8335 CSSParserValue* arg = functionArgs->current();
8336 while (arg) {
8337 if (arg->unit != CSSPrimitiveValue::CSS_URI)
8338 return nullptr;
8339
8340 RefPtrWillBeRawPtr<CSSImageValue> image = CSSImageValue::create(arg->str ing, completeURL(arg->string));
8341 imageSet->append(image);
8342
8343 arg = functionArgs->next();
8344 if (!arg || arg->unit != CSSPrimitiveValue::CSS_DIMENSION)
8345 return nullptr;
8346
8347 double imageScaleFactor = 0;
8348 const String& string = arg->string;
8349 unsigned length = string.length();
8350 if (!length)
8351 return nullptr;
8352 if (string.is8Bit()) {
8353 const LChar* start = string.characters8();
8354 parseDouble(start, start + length, 'x', imageScaleFactor);
8355 } else {
8356 const UChar* start = string.characters16();
8357 parseDouble(start, start + length, 'x', imageScaleFactor);
8358 }
8359 if (imageScaleFactor <= 0)
8360 return nullptr;
8361 imageSet->append(cssValuePool().createValue(imageScaleFactor, CSSPrimiti veValue::CSS_NUMBER));
8362
8363 // If there are no more arguments, we're done.
8364 arg = functionArgs->next();
8365 if (!arg)
8366 break;
8367
8368 // If there are more arguments, they should be after a comma.
8369 if (!isComma(arg))
8370 return nullptr;
8371
8372 // Skip the comma and move on to the next argument.
8373 arg = functionArgs->next();
8374 }
8375
8376 return imageSet.release();
8377 }
8378
8379 bool CSSPropertyParser::parseWillChange(bool important)
8380 {
8381 ASSERT(RuntimeEnabledFeatures::cssWillChangeEnabled());
8382
8383 RefPtrWillBeRawPtr<CSSValueList> values = CSSValueList::createCommaSeparated ();
8384 if (m_valueList->current()->id == CSSValueAuto) {
8385 if (m_valueList->next())
8386 return false;
8387 }
8388
8389 CSSParserValue* currentValue;
8390 bool expectComma = false;
8391
8392 // Every comma-separated list of CSS_IDENTs is a valid will-change value,
8393 // unless the list includes an explicitly disallowed CSS_IDENT.
8394 while ((currentValue = m_valueList->current())) {
8395 if (expectComma) {
8396 if (!isComma(currentValue))
8397 return false;
8398 expectComma = false;
8399 m_valueList->next();
8400 continue;
8401 }
8402
8403 if (currentValue->unit != CSSPrimitiveValue::CSS_IDENT)
8404 return false;
8405
8406 if (CSSPropertyID property = cssPropertyID(currentValue->string)) {
8407 if (property == CSSPropertyWillChange)
8408 return false;
8409 values->append(cssValuePool().createIdentifierValue(property));
8410 } else {
8411 switch (currentValue->id) {
8412 case CSSValueNone:
8413 case CSSValueAll:
8414 case CSSValueAuto:
8415 case CSSValueDefault:
8416 case CSSValueInitial:
8417 case CSSValueInherit:
8418 return false;
8419 case CSSValueContents:
8420 case CSSValueScrollPosition:
8421 values->append(cssValuePool().createIdentifierValue(currentValue ->id));
8422 break;
8423 default:
8424 break;
8425 }
8426 }
8427 expectComma = true;
8428 m_valueList->next();
8429 }
8430
8431 addProperty(CSSPropertyWillChange, values.release(), important);
8432 return true;
8433 }
8434 1284
8435 class TransformOperationInfo { 1285 class TransformOperationInfo {
8436 public: 1286 public:
8437 TransformOperationInfo(const CSSParserString& name) 1287 TransformOperationInfo(const CSSParserString& name)
8438 : m_type(CSSTransformValue::UnknownTransformOperation) 1288 : m_type(CSSTransformValue::UnknownTransformOperation)
8439 , m_argCount(1) 1289 , m_argCount(1)
8440 , m_allowSingleArgument(false) 1290 , m_allowSingleArgument(false)
8441 , m_unit(CSSPropertyParser::FUnknown) 1291 , m_unit(CSSPropertyParser::FUnknown)
8442 { 1292 {
8443 const UChar* characters; 1293 const UChar* characters;
(...skipping 199 matching lines...) Expand 10 before | Expand all | Expand 10 after
8643 if (a->unit != CSSParserValue::Operator || a->iValue != ',') 1493 if (a->unit != CSSParserValue::Operator || a->iValue != ',')
8644 return nullptr; 1494 return nullptr;
8645 a = args->next(); 1495 a = args->next();
8646 1496
8647 argNumber++; 1497 argNumber++;
8648 } 1498 }
8649 1499
8650 return transformValue.release(); 1500 return transformValue.release();
8651 } 1501 }
8652 1502
8653 bool CSSPropertyParser::isBlendMode(CSSValueID valueID)
8654 {
8655 return (valueID >= CSSValueMultiply && valueID <= CSSValueLuminosity)
8656 || valueID == CSSValueNormal
8657 || valueID == CSSValueOverlay;
8658 }
8659
8660 bool CSSPropertyParser::isCompositeOperator(CSSValueID valueID)
8661 {
8662 // FIXME: Add CSSValueDestination and CSSValueLighter when the Compositing s pec updates.
8663 return valueID >= CSSValueClear && valueID <= CSSValueXor;
8664 }
8665
8666 static void filterInfoForName(const CSSParserString& name, CSSFilterValue::Filte rOperationType& filterType, unsigned& maximumArgumentCount)
8667 {
8668 if (equalIgnoringCase(name, "grayscale("))
8669 filterType = CSSFilterValue::GrayscaleFilterOperation;
8670 else if (equalIgnoringCase(name, "sepia("))
8671 filterType = CSSFilterValue::SepiaFilterOperation;
8672 else if (equalIgnoringCase(name, "saturate("))
8673 filterType = CSSFilterValue::SaturateFilterOperation;
8674 else if (equalIgnoringCase(name, "hue-rotate("))
8675 filterType = CSSFilterValue::HueRotateFilterOperation;
8676 else if (equalIgnoringCase(name, "invert("))
8677 filterType = CSSFilterValue::InvertFilterOperation;
8678 else if (equalIgnoringCase(name, "opacity("))
8679 filterType = CSSFilterValue::OpacityFilterOperation;
8680 else if (equalIgnoringCase(name, "brightness("))
8681 filterType = CSSFilterValue::BrightnessFilterOperation;
8682 else if (equalIgnoringCase(name, "contrast("))
8683 filterType = CSSFilterValue::ContrastFilterOperation;
8684 else if (equalIgnoringCase(name, "blur("))
8685 filterType = CSSFilterValue::BlurFilterOperation;
8686 else if (equalIgnoringCase(name, "drop-shadow(")) {
8687 filterType = CSSFilterValue::DropShadowFilterOperation;
8688 maximumArgumentCount = 4; // x-offset, y-offset, blur-radius, color -- spread and inset style not allowed.
8689 }
8690 }
8691
8692 PassRefPtrWillBeRawPtr<CSSFilterValue> CSSPropertyParser::parseBuiltinFilterArgu ments(CSSParserValueList* args, CSSFilterValue::FilterOperationType filterType)
8693 {
8694 RefPtrWillBeRawPtr<CSSFilterValue> filterValue = CSSFilterValue::create(filt erType);
8695 ASSERT(args);
8696
8697 switch (filterType) {
8698 case CSSFilterValue::GrayscaleFilterOperation:
8699 case CSSFilterValue::SepiaFilterOperation:
8700 case CSSFilterValue::SaturateFilterOperation:
8701 case CSSFilterValue::InvertFilterOperation:
8702 case CSSFilterValue::OpacityFilterOperation:
8703 case CSSFilterValue::ContrastFilterOperation: {
8704 // One optional argument, 0-1 or 0%-100%, if missing use 100%.
8705 if (args->size() > 1)
8706 return nullptr;
8707
8708 if (args->size()) {
8709 CSSParserValue* value = args->current();
8710 if (!validUnit(value, FNumber | FPercent | FNonNeg, HTMLStandardMode ))
8711 return nullptr;
8712
8713 double amount = value->fValue;
8714
8715 // Saturate and Contrast allow values over 100%.
8716 if (filterType != CSSFilterValue::SaturateFilterOperation
8717 && filterType != CSSFilterValue::ContrastFilterOperation) {
8718 double maxAllowed = value->unit == CSSPrimitiveValue::CSS_PERCEN TAGE ? 100.0 : 1.0;
8719 if (amount > maxAllowed)
8720 return nullptr;
8721 }
8722
8723 filterValue->append(cssValuePool().createValue(amount, static_cast<C SSPrimitiveValue::UnitTypes>(value->unit)));
8724 }
8725 break;
8726 }
8727 case CSSFilterValue::BrightnessFilterOperation: {
8728 // One optional argument, if missing use 100%.
8729 if (args->size() > 1)
8730 return nullptr;
8731
8732 if (args->size()) {
8733 CSSParserValue* value = args->current();
8734 if (!validUnit(value, FNumber | FPercent, HTMLStandardMode))
8735 return nullptr;
8736
8737 filterValue->append(cssValuePool().createValue(value->fValue, static _cast<CSSPrimitiveValue::UnitTypes>(value->unit)));
8738 }
8739 break;
8740 }
8741 case CSSFilterValue::HueRotateFilterOperation: {
8742 // hue-rotate() takes one optional angle.
8743 if (args->size() > 1)
8744 return nullptr;
8745
8746 if (args->size()) {
8747 CSSParserValue* argument = args->current();
8748 if (!validUnit(argument, FAngle, HTMLStandardMode))
8749 return nullptr;
8750
8751 filterValue->append(createPrimitiveNumericValue(argument));
8752 }
8753 break;
8754 }
8755 case CSSFilterValue::BlurFilterOperation: {
8756 // Blur takes a single length. Zero parameters are allowed.
8757 if (args->size() > 1)
8758 return nullptr;
8759
8760 if (args->size()) {
8761 CSSParserValue* argument = args->current();
8762 if (!validUnit(argument, FLength | FNonNeg, HTMLStandardMode))
8763 return nullptr;
8764
8765 filterValue->append(createPrimitiveNumericValue(argument));
8766 }
8767 break;
8768 }
8769 case CSSFilterValue::DropShadowFilterOperation: {
8770 // drop-shadow() takes a single shadow.
8771 RefPtrWillBeRawPtr<CSSValueList> shadowValueList = parseShadow(args, CSS PropertyWebkitFilter);
8772 if (!shadowValueList || shadowValueList->length() != 1)
8773 return nullptr;
8774
8775 filterValue->append((shadowValueList.release())->itemWithoutBoundsCheck( 0));
8776 break;
8777 }
8778 default:
8779 ASSERT_NOT_REACHED();
8780 }
8781 return filterValue.release();
8782 }
8783
8784 PassRefPtrWillBeRawPtr<CSSValueList> CSSPropertyParser::parseFilter()
8785 {
8786 if (!m_valueList)
8787 return nullptr;
8788
8789 // The filter is a list of functional primitives that specify individual ope rations.
8790 RefPtrWillBeRawPtr<CSSValueList> list = CSSValueList::createSpaceSeparated() ;
8791 for (CSSParserValue* value = m_valueList->current(); value; value = m_valueL ist->next()) {
8792 if (value->unit != CSSPrimitiveValue::CSS_URI && (value->unit != CSSPars erValue::Function || !value->function))
8793 return nullptr;
8794
8795 CSSFilterValue::FilterOperationType filterType = CSSFilterValue::Unknown FilterOperation;
8796
8797 // See if the specified primitive is one we understand.
8798 if (value->unit == CSSPrimitiveValue::CSS_URI) {
8799 RefPtrWillBeRawPtr<CSSFilterValue> referenceFilterValue = CSSFilterV alue::create(CSSFilterValue::ReferenceFilterOperation);
8800 list->append(referenceFilterValue);
8801 referenceFilterValue->append(CSSSVGDocumentValue::create(value->stri ng));
8802 } else {
8803 const CSSParserString name = value->function->name;
8804 unsigned maximumArgumentCount = 1;
8805
8806 filterInfoForName(name, filterType, maximumArgumentCount);
8807
8808 if (filterType == CSSFilterValue::UnknownFilterOperation)
8809 return nullptr;
8810
8811 CSSParserValueList* args = value->function->args.get();
8812 if (!args)
8813 return nullptr;
8814
8815 RefPtrWillBeRawPtr<CSSFilterValue> filterValue = parseBuiltinFilterA rguments(args, filterType);
8816 if (!filterValue)
8817 return nullptr;
8818
8819 list->append(filterValue);
8820 }
8821 }
8822
8823 return list.release();
8824 }
8825
8826 bool CSSPropertyParser::parseTransformOrigin(CSSPropertyID propId, CSSPropertyID & propId1, CSSPropertyID& propId2, CSSPropertyID& propId3, RefPtrWillBeRawPtr<CS SValue>& value, RefPtrWillBeRawPtr<CSSValue>& value2, RefPtrWillBeRawPtr<CSSValu e>& value3)
8827 {
8828 propId1 = propId;
8829 propId2 = propId;
8830 propId3 = propId;
8831 if (propId == CSSPropertyWebkitTransformOrigin) {
8832 propId1 = CSSPropertyWebkitTransformOriginX;
8833 propId2 = CSSPropertyWebkitTransformOriginY;
8834 propId3 = CSSPropertyWebkitTransformOriginZ;
8835 }
8836
8837 switch (propId) {
8838 case CSSPropertyWebkitTransformOrigin:
8839 if (!parseTransformOriginShorthand(value, value2, value3))
8840 return false;
8841 // parseTransformOriginShorthand advances the m_valueList pointer
8842 break;
8843 case CSSPropertyWebkitTransformOriginX: {
8844 value = parseFillPositionX(m_valueList.get());
8845 if (value)
8846 m_valueList->next();
8847 break;
8848 }
8849 case CSSPropertyWebkitTransformOriginY: {
8850 value = parseFillPositionY(m_valueList.get());
8851 if (value)
8852 m_valueList->next();
8853 break;
8854 }
8855 case CSSPropertyWebkitTransformOriginZ: {
8856 if (validUnit(m_valueList->current(), FLength))
8857 value = createPrimitiveNumericValue(m_valueList->current());
8858 if (value)
8859 m_valueList->next();
8860 break;
8861 }
8862 default:
8863 ASSERT_NOT_REACHED();
8864 return false;
8865 }
8866
8867 return value;
8868 }
8869
8870 bool CSSPropertyParser::parsePerspectiveOrigin(CSSPropertyID propId, CSSProperty ID& propId1, CSSPropertyID& propId2, RefPtrWillBeRawPtr<CSSValue>& value, RefPtr WillBeRawPtr<CSSValue>& value2)
8871 {
8872 propId1 = propId;
8873 propId2 = propId;
8874 if (propId == CSSPropertyWebkitPerspectiveOrigin) {
8875 propId1 = CSSPropertyWebkitPerspectiveOriginX;
8876 propId2 = CSSPropertyWebkitPerspectiveOriginY;
8877 }
8878
8879 switch (propId) {
8880 case CSSPropertyWebkitPerspectiveOrigin:
8881 if (m_valueList->size() > 2)
8882 return false;
8883 parse2ValuesFillPosition(m_valueList.get(), value, value2);
8884 break;
8885 case CSSPropertyWebkitPerspectiveOriginX: {
8886 value = parseFillPositionX(m_valueList.get());
8887 if (value)
8888 m_valueList->next();
8889 break;
8890 }
8891 case CSSPropertyWebkitPerspectiveOriginY: {
8892 value = parseFillPositionY(m_valueList.get());
8893 if (value)
8894 m_valueList->next();
8895 break;
8896 }
8897 default:
8898 ASSERT_NOT_REACHED();
8899 return false;
8900 }
8901
8902 return value;
8903 }
8904
8905 bool CSSPropertyParser::parseTouchAction(bool important)
8906 {
8907 if (!RuntimeEnabledFeatures::cssTouchActionEnabled())
8908 return false;
8909
8910 CSSParserValue* value = m_valueList->current();
8911 RefPtrWillBeRawPtr<CSSValueList> list = CSSValueList::createSpaceSeparated() ;
8912 if (m_valueList->size() == 1 && value && (value->id == CSSValueAuto || value ->id == CSSValueNone)) {
8913 list->append(cssValuePool().createIdentifierValue(value->id));
8914 addProperty(CSSPropertyTouchAction, list.release(), important);
8915 m_valueList->next();
8916 return true;
8917 }
8918
8919 bool isValid = true;
8920 while (isValid && value) {
8921 switch (value->id) {
8922 case CSSValuePanX:
8923 case CSSValuePanY: {
8924 RefPtrWillBeRawPtr<CSSValue> panValue = cssValuePool().createIdentif ierValue(value->id);
8925 if (list->hasValue(panValue.get())) {
8926 isValid = false;
8927 break;
8928 }
8929 list->append(panValue.release());
8930 break;
8931 }
8932 default:
8933 isValid = false;
8934 break;
8935 }
8936 if (isValid)
8937 value = m_valueList->next();
8938 }
8939
8940 if (list->length() && isValid) {
8941 addProperty(CSSPropertyTouchAction, list.release(), important);
8942 return true;
8943 }
8944
8945 return false;
8946 }
8947
8948 void CSSPropertyParser::addTextDecorationProperty(CSSPropertyID propId, PassRefP trWillBeRawPtr<CSSValue> value, bool important)
8949 {
8950 // The text-decoration-line property takes priority over text-decoration, un less the latter has important priority set.
8951 if (propId == CSSPropertyTextDecoration && !important && !inShorthand()) {
8952 for (unsigned i = 0; i < m_parsedProperties.size(); ++i) {
8953 if (m_parsedProperties[i].id() == CSSPropertyTextDecorationLine)
8954 return;
8955 }
8956 }
8957 addProperty(propId, value, important);
8958 }
8959
8960 bool CSSPropertyParser::parseTextDecoration(CSSPropertyID propId, bool important )
8961 {
8962 if (propId == CSSPropertyTextDecorationLine
8963 && !RuntimeEnabledFeatures::css3TextDecorationsEnabled())
8964 return false;
8965
8966 CSSParserValue* value = m_valueList->current();
8967 if (value && value->id == CSSValueNone) {
8968 addTextDecorationProperty(propId, cssValuePool().createIdentifierValue(C SSValueNone), important);
8969 m_valueList->next();
8970 return true;
8971 }
8972
8973 RefPtrWillBeRawPtr<CSSValueList> list = CSSValueList::createSpaceSeparated() ;
8974 bool isValid = true;
8975 while (isValid && value) {
8976 switch (value->id) {
8977 case CSSValueUnderline:
8978 case CSSValueOverline:
8979 case CSSValueLineThrough:
8980 case CSSValueBlink:
8981 list->append(cssValuePool().createIdentifierValue(value->id));
8982 break;
8983 default:
8984 isValid = false;
8985 break;
8986 }
8987 if (isValid)
8988 value = m_valueList->next();
8989 }
8990
8991 // Values are either valid or in shorthand scope.
8992 if (list->length() && (isValid || inShorthand())) {
8993 addTextDecorationProperty(propId, list.release(), important);
8994 return true;
8995 }
8996
8997 return false;
8998 }
8999
9000 bool CSSPropertyParser::parseTextUnderlinePosition(bool important)
9001 {
9002 // The text-underline-position property has syntax "auto | [ under || [ left | right ] ]".
9003 // However, values 'left' and 'right' are not implemented yet, so we will pa rse syntax
9004 // "auto | under" for now.
9005 CSSParserValue* value = m_valueList->current();
9006 switch (value->id) {
9007 case CSSValueAuto:
9008 case CSSValueUnder:
9009 if (m_valueList->next())
9010 return false;
9011 addProperty(CSSPropertyTextUnderlinePosition, cssValuePool().createIdent ifierValue(value->id), important);
9012 return true;
9013 default:
9014 return false;
9015 }
9016 }
9017
9018 bool CSSPropertyParser::parseTextEmphasisStyle(bool important)
9019 {
9020 unsigned valueListSize = m_valueList->size();
9021
9022 RefPtrWillBeRawPtr<CSSPrimitiveValue> fill;
9023 RefPtrWillBeRawPtr<CSSPrimitiveValue> shape;
9024
9025 for (CSSParserValue* value = m_valueList->current(); value; value = m_valueL ist->next()) {
9026 if (value->unit == CSSPrimitiveValue::CSS_STRING) {
9027 if (fill || shape || (valueListSize != 1 && !inShorthand()))
9028 return false;
9029 addProperty(CSSPropertyWebkitTextEmphasisStyle, createPrimitiveStrin gValue(value), important);
9030 m_valueList->next();
9031 return true;
9032 }
9033
9034 if (value->id == CSSValueNone) {
9035 if (fill || shape || (valueListSize != 1 && !inShorthand()))
9036 return false;
9037 addProperty(CSSPropertyWebkitTextEmphasisStyle, cssValuePool().creat eIdentifierValue(CSSValueNone), important);
9038 m_valueList->next();
9039 return true;
9040 }
9041
9042 if (value->id == CSSValueOpen || value->id == CSSValueFilled) {
9043 if (fill)
9044 return false;
9045 fill = cssValuePool().createIdentifierValue(value->id);
9046 } else if (value->id == CSSValueDot || value->id == CSSValueCircle || va lue->id == CSSValueDoubleCircle || value->id == CSSValueTriangle || value->id == CSSValueSesame) {
9047 if (shape)
9048 return false;
9049 shape = cssValuePool().createIdentifierValue(value->id);
9050 } else if (!inShorthand())
9051 return false;
9052 else
9053 break;
9054 }
9055
9056 if (fill && shape) {
9057 RefPtrWillBeRawPtr<CSSValueList> parsedValues = CSSValueList::createSpac eSeparated();
9058 parsedValues->append(fill.release());
9059 parsedValues->append(shape.release());
9060 addProperty(CSSPropertyWebkitTextEmphasisStyle, parsedValues.release(), important);
9061 return true;
9062 }
9063 if (fill) {
9064 addProperty(CSSPropertyWebkitTextEmphasisStyle, fill.release(), importan t);
9065 return true;
9066 }
9067 if (shape) {
9068 addProperty(CSSPropertyWebkitTextEmphasisStyle, shape.release(), importa nt);
9069 return true;
9070 }
9071
9072 return false;
9073 }
9074
9075 PassRefPtrWillBeRawPtr<CSSValue> CSSPropertyParser::parseTextIndent()
9076 {
9077 RefPtrWillBeRawPtr<CSSValueList> list = CSSValueList::createSpaceSeparated() ;
9078
9079 // <length> | <percentage> | inherit
9080 if (m_valueList->size() == 1) {
9081 CSSParserValue* value = m_valueList->current();
9082 if (!value->id && validUnit(value, FLength | FPercent)) {
9083 list->append(createPrimitiveNumericValue(value));
9084 m_valueList->next();
9085 return list.release();
9086 }
9087 }
9088
9089 if (!RuntimeEnabledFeatures::css3TextEnabled())
9090 return nullptr;
9091
9092 // The case where text-indent has only <length>(or <percentage>) value
9093 // is handled above if statement even though css3TextEnabled() returns true.
9094
9095 // [ [ <length> | <percentage> ] && each-line ] | inherit
9096 if (m_valueList->size() != 2)
9097 return nullptr;
9098
9099 CSSParserValue* firstValue = m_valueList->current();
9100 CSSParserValue* secondValue = m_valueList->next();
9101 CSSParserValue* lengthOrPercentageValue = 0;
9102
9103 // [ <length> | <percentage> ] each-line
9104 if (validUnit(firstValue, FLength | FPercent) && secondValue->id == CSSValue EachLine)
9105 lengthOrPercentageValue = firstValue;
9106 // each-line [ <length> | <percentage> ]
9107 else if (firstValue->id == CSSValueEachLine && validUnit(secondValue, FLengt h | FPercent))
9108 lengthOrPercentageValue = secondValue;
9109
9110 if (lengthOrPercentageValue) {
9111 list->append(createPrimitiveNumericValue(lengthOrPercentageValue));
9112 list->append(cssValuePool().createIdentifierValue(CSSValueEachLine));
9113 m_valueList->next();
9114 return list.release();
9115 }
9116
9117 return nullptr;
9118 }
9119
9120 bool CSSPropertyParser::parseLineBoxContain(bool important)
9121 {
9122 LineBoxContain lineBoxContain = LineBoxContainNone;
9123
9124 for (CSSParserValue* value = m_valueList->current(); value; value = m_valueL ist->next()) {
9125 if (value->id == CSSValueBlock) {
9126 if (lineBoxContain & LineBoxContainBlock)
9127 return false;
9128 lineBoxContain |= LineBoxContainBlock;
9129 } else if (value->id == CSSValueInline) {
9130 if (lineBoxContain & LineBoxContainInline)
9131 return false;
9132 lineBoxContain |= LineBoxContainInline;
9133 } else if (value->id == CSSValueFont) {
9134 if (lineBoxContain & LineBoxContainFont)
9135 return false;
9136 lineBoxContain |= LineBoxContainFont;
9137 } else if (value->id == CSSValueGlyphs) {
9138 if (lineBoxContain & LineBoxContainGlyphs)
9139 return false;
9140 lineBoxContain |= LineBoxContainGlyphs;
9141 } else if (value->id == CSSValueReplaced) {
9142 if (lineBoxContain & LineBoxContainReplaced)
9143 return false;
9144 lineBoxContain |= LineBoxContainReplaced;
9145 } else if (value->id == CSSValueInlineBox) {
9146 if (lineBoxContain & LineBoxContainInlineBox)
9147 return false;
9148 lineBoxContain |= LineBoxContainInlineBox;
9149 } else
9150 return false;
9151 }
9152
9153 if (!lineBoxContain)
9154 return false;
9155
9156 addProperty(CSSPropertyWebkitLineBoxContain, CSSLineBoxContainValue::create( lineBoxContain), important);
9157 return true;
9158 }
9159
9160 bool CSSPropertyParser::parseFontFeatureTag(CSSValueList* settings)
9161 {
9162 // Feature tag name consists of 4-letter characters.
9163 static const unsigned tagNameLength = 4;
9164
9165 CSSParserValue* value = m_valueList->current();
9166 // Feature tag name comes first
9167 if (value->unit != CSSPrimitiveValue::CSS_STRING)
9168 return false;
9169 if (value->string.length() != tagNameLength)
9170 return false;
9171 for (unsigned i = 0; i < tagNameLength; ++i) {
9172 // Limits the range of characters to 0x20-0x7E, following the tag name r ules defiend in the OpenType specification.
9173 UChar character = value->string[i];
9174 if (character < 0x20 || character > 0x7E)
9175 return false;
9176 }
9177
9178 AtomicString tag = value->string;
9179 int tagValue = 1;
9180 // Feature tag values could follow: <integer> | on | off
9181 value = m_valueList->next();
9182 if (value) {
9183 if (value->unit == CSSPrimitiveValue::CSS_NUMBER && value->isInt && valu e->fValue >= 0) {
9184 tagValue = clampToInteger(value->fValue);
9185 if (tagValue < 0)
9186 return false;
9187 m_valueList->next();
9188 } else if (value->id == CSSValueOn || value->id == CSSValueOff) {
9189 tagValue = value->id == CSSValueOn;
9190 m_valueList->next();
9191 }
9192 }
9193 settings->append(CSSFontFeatureValue::create(tag, tagValue));
9194 return true;
9195 }
9196
9197 bool CSSPropertyParser::parseFontFeatureSettings(bool important)
9198 {
9199 if (m_valueList->size() == 1 && m_valueList->current()->id == CSSValueNormal ) {
9200 RefPtrWillBeRawPtr<CSSPrimitiveValue> normalValue = cssValuePool().creat eIdentifierValue(CSSValueNormal);
9201 m_valueList->next();
9202 addProperty(CSSPropertyWebkitFontFeatureSettings, normalValue.release(), important);
9203 return true;
9204 }
9205
9206 RefPtrWillBeRawPtr<CSSValueList> settings = CSSValueList::createCommaSeparat ed();
9207 for (CSSParserValue* value = m_valueList->current(); value; value = m_valueL ist->next()) {
9208 if (!parseFontFeatureTag(settings.get()))
9209 return false;
9210
9211 // If the list isn't parsed fully, the current value should be comma.
9212 value = m_valueList->current();
9213 if (value && !isComma(value))
9214 return false;
9215 }
9216 if (settings->length()) {
9217 addProperty(CSSPropertyWebkitFontFeatureSettings, settings.release(), im portant);
9218 return true;
9219 }
9220 return false;
9221 }
9222
9223 bool CSSPropertyParser::parseFontVariantLigatures(bool important)
9224 {
9225 RefPtrWillBeRawPtr<CSSValueList> ligatureValues = CSSValueList::createSpaceS eparated();
9226 bool sawCommonLigaturesValue = false;
9227 bool sawDiscretionaryLigaturesValue = false;
9228 bool sawHistoricalLigaturesValue = false;
9229
9230 for (CSSParserValue* value = m_valueList->current(); value; value = m_valueL ist->next()) {
9231 if (value->unit != CSSPrimitiveValue::CSS_IDENT)
9232 return false;
9233
9234 switch (value->id) {
9235 case CSSValueNoCommonLigatures:
9236 case CSSValueCommonLigatures:
9237 if (sawCommonLigaturesValue)
9238 return false;
9239 sawCommonLigaturesValue = true;
9240 ligatureValues->append(cssValuePool().createIdentifierValue(value->i d));
9241 break;
9242 case CSSValueNoDiscretionaryLigatures:
9243 case CSSValueDiscretionaryLigatures:
9244 if (sawDiscretionaryLigaturesValue)
9245 return false;
9246 sawDiscretionaryLigaturesValue = true;
9247 ligatureValues->append(cssValuePool().createIdentifierValue(value->i d));
9248 break;
9249 case CSSValueNoHistoricalLigatures:
9250 case CSSValueHistoricalLigatures:
9251 if (sawHistoricalLigaturesValue)
9252 return false;
9253 sawHistoricalLigaturesValue = true;
9254 ligatureValues->append(cssValuePool().createIdentifierValue(value->i d));
9255 break;
9256 default:
9257 return false;
9258 }
9259 }
9260
9261 if (!ligatureValues->length())
9262 return false;
9263
9264 addProperty(CSSPropertyFontVariantLigatures, ligatureValues.release(), impor tant);
9265 return true;
9266 }
9267
9268 bool CSSPropertyParser::parseCalculation(CSSParserValue* value, ValueRange range )
9269 {
9270 ASSERT(isCalculation(value));
9271
9272 CSSParserValueList* args = value->function->args.get();
9273 if (!args || !args->size())
9274 return false;
9275
9276 ASSERT(!m_parsedCalculation);
9277 m_parsedCalculation = CSSCalcValue::create(value->function->name, args, rang e);
9278
9279 if (!m_parsedCalculation)
9280 return false;
9281
9282 return true;
9283 }
9284
9285 void BisonCSSParser::ensureLineEndings() 1503 void BisonCSSParser::ensureLineEndings()
9286 { 1504 {
9287 if (!m_lineEndings) 1505 if (!m_lineEndings)
9288 m_lineEndings = lineEndings(*m_source); 1506 m_lineEndings = lineEndings(*m_source);
9289 } 1507 }
9290 1508
9291 CSSParserSelector* BisonCSSParser::createFloatingSelectorWithTagName(const Quali fiedName& tagQName) 1509 CSSParserSelector* BisonCSSParser::createFloatingSelectorWithTagName(const Quali fiedName& tagQName)
9292 { 1510 {
9293 CSSParserSelector* selector = new CSSParserSelector(tagQName); 1511 CSSParserSelector* selector = new CSSParserSelector(tagQName);
9294 m_floatingSelectors.append(selector); 1512 m_floatingSelectors.append(selector);
(...skipping 705 matching lines...) Expand 10 before | Expand all | Expand 10 after
10000 2218
10001 rule->setProperties(createStylePropertySet()); 2219 rule->setProperties(createStylePropertySet());
10002 clearProperties(); 2220 clearProperties();
10003 2221
10004 StyleRuleViewport* result = rule.get(); 2222 StyleRuleViewport* result = rule.get();
10005 m_parsedRules.append(rule.release()); 2223 m_parsedRules.append(rule.release());
10006 2224
10007 return result; 2225 return result;
10008 } 2226 }
10009 2227
10010 bool CSSPropertyParser::parseViewportProperty(CSSPropertyID propId, bool importa nt)
10011 {
10012 ASSERT(RuntimeEnabledFeatures::cssViewportEnabled() || isUASheetBehavior(m_c ontext.mode()));
10013
10014 CSSParserValue* value = m_valueList->current();
10015 if (!value)
10016 return false;
10017
10018 CSSValueID id = value->id;
10019 bool validPrimitive = false;
10020
10021 switch (propId) {
10022 case CSSPropertyMinWidth: // auto | extend-to-zoom | <length> | <percentage>
10023 case CSSPropertyMaxWidth:
10024 case CSSPropertyMinHeight:
10025 case CSSPropertyMaxHeight:
10026 if (id == CSSValueAuto || id == CSSValueInternalExtendToZoom)
10027 validPrimitive = true;
10028 else
10029 validPrimitive = (!id && validUnit(value, FLength | FPercent | FNonN eg));
10030 break;
10031 case CSSPropertyWidth: // shorthand
10032 return parseViewportShorthand(propId, CSSPropertyMinWidth, CSSPropertyMa xWidth, important);
10033 case CSSPropertyHeight:
10034 return parseViewportShorthand(propId, CSSPropertyMinHeight, CSSPropertyM axHeight, important);
10035 case CSSPropertyMinZoom: // auto | <number> | <percentage>
10036 case CSSPropertyMaxZoom:
10037 case CSSPropertyZoom:
10038 if (id == CSSValueAuto)
10039 validPrimitive = true;
10040 else
10041 validPrimitive = (!id && validUnit(value, FNumber | FPercent | FNonN eg));
10042 break;
10043 case CSSPropertyUserZoom: // zoom | fixed
10044 if (id == CSSValueZoom || id == CSSValueFixed)
10045 validPrimitive = true;
10046 break;
10047 case CSSPropertyOrientation: // auto | portrait | landscape
10048 if (id == CSSValueAuto || id == CSSValuePortrait || id == CSSValueLandsc ape)
10049 validPrimitive = true;
10050 default:
10051 break;
10052 }
10053
10054 RefPtrWillBeRawPtr<CSSValue> parsedValue;
10055 if (validPrimitive) {
10056 parsedValue = parseValidPrimitive(id, value);
10057 m_valueList->next();
10058 }
10059
10060 if (parsedValue) {
10061 if (!m_valueList->current() || inShorthand()) {
10062 addProperty(propId, parsedValue.release(), important);
10063 return true;
10064 }
10065 }
10066
10067 return false;
10068 } 2228 }
10069
10070 bool CSSPropertyParser::parseViewportShorthand(CSSPropertyID propId, CSSProperty ID first, CSSPropertyID second, bool important)
10071 {
10072 ASSERT(RuntimeEnabledFeatures::cssViewportEnabled() || isUASheetBehavior(m_c ontext.mode()));
10073 unsigned numValues = m_valueList->size();
10074
10075 if (numValues > 2)
10076 return false;
10077
10078 ShorthandScope scope(this, propId);
10079
10080 if (!parseViewportProperty(first, important))
10081 return false;
10082
10083 // If just one value is supplied, the second value
10084 // is implicitly initialized with the first value.
10085 if (numValues == 1)
10086 m_valueList->previous();
10087
10088 return parseViewportProperty(second, important);
10089 }
10090
10091 template <typename CharacterType>
10092 static CSSPropertyID cssPropertyID(const CharacterType* propertyName, unsigned l ength)
10093 {
10094 char buffer[maxCSSPropertyNameLength + 1]; // 1 for null character
10095
10096 for (unsigned i = 0; i != length; ++i) {
10097 CharacterType c = propertyName[i];
10098 if (c == 0 || c >= 0x7F)
10099 return CSSPropertyInvalid; // illegal character
10100 buffer[i] = toASCIILower(c);
10101 }
10102 buffer[length] = '\0';
10103
10104 const char* name = buffer;
10105 const Property* hashTableEntry = findProperty(name, length);
10106 return hashTableEntry ? static_cast<CSSPropertyID>(hashTableEntry->id) : CSS PropertyInvalid;
10107 }
10108
10109 CSSPropertyID cssPropertyID(const String& string)
10110 {
10111 unsigned length = string.length();
10112
10113 if (!length)
10114 return CSSPropertyInvalid;
10115 if (length > maxCSSPropertyNameLength)
10116 return CSSPropertyInvalid;
10117
10118 return string.is8Bit() ? cssPropertyID(string.characters8(), length) : cssPr opertyID(string.characters16(), length);
10119 }
10120
10121 CSSPropertyID cssPropertyID(const CSSParserString& string)
10122 {
10123 unsigned length = string.length();
10124
10125 if (!length)
10126 return CSSPropertyInvalid;
10127 if (length > maxCSSPropertyNameLength)
10128 return CSSPropertyInvalid;
10129
10130 return string.is8Bit() ? cssPropertyID(string.characters8(), length) : cssPr opertyID(string.characters16(), length);
10131 }
10132
10133 template <typename CharacterType>
10134 static CSSValueID cssValueKeywordID(const CharacterType* valueKeyword, unsigned length)
10135 {
10136 char buffer[maxCSSValueKeywordLength + 1]; // 1 for null character
10137
10138 for (unsigned i = 0; i != length; ++i) {
10139 CharacterType c = valueKeyword[i];
10140 if (c == 0 || c >= 0x7F)
10141 return CSSValueInvalid; // illegal character
10142 buffer[i] = WTF::toASCIILower(c);
10143 }
10144 buffer[length] = '\0';
10145
10146 const Value* hashTableEntry = findValue(buffer, length);
10147 return hashTableEntry ? static_cast<CSSValueID>(hashTableEntry->id) : CSSVal ueInvalid;
10148 }
10149
10150 CSSValueID cssValueKeywordID(const CSSParserString& string)
10151 {
10152 unsigned length = string.length();
10153 if (!length)
10154 return CSSValueInvalid;
10155 if (length > maxCSSValueKeywordLength)
10156 return CSSValueInvalid;
10157
10158 return string.is8Bit() ? cssValueKeywordID(string.characters8(), length) : c ssValueKeywordID(string.characters16(), length);
10159 }
10160
10161 bool isValidNthToken(const CSSParserString& token)
10162 {
10163 // The tokenizer checks for the construct of an+b.
10164 // However, since the {ident} rule precedes the {nth} rule, some of those
10165 // tokens are identified as string literal. Furthermore we need to accept
10166 // "odd" and "even" which does not match to an+b.
10167 return equalIgnoringCase(token, "odd") || equalIgnoringCase(token, "even")
10168 || equalIgnoringCase(token, "n") || equalIgnoringCase(token, "-n");
10169 }
10170
10171 }
OLDNEW
« no previous file with comments | « Source/core/css/parser/BisonCSSParser.h ('k') | Source/core/css/parser/CSSPropertyParser.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698