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

Side by Side Diff: Source/core/css/parser/CSSPropertyParser.cpp

Issue 1319343004: Add property parser code path based on CSSParserTokenRange (Closed) Base URL: https://chromium.googlesource.com/chromium/blink.git@master
Patch Set: Move driver code Created 5 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 /* 1 // Copyright 2015 The Chromium Authors. All rights reserved.
2 * Copyright (C) 2003 Lars Knoll (knoll@kde.org) 2 // Use of this source code is governed by a BSD-style license that can be
3 * Copyright (C) 2005 Allan Sandfeld Jensen (kde@carewolf.com) 3 // found in the LICENSE file.
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>
6 * Copyright (C) 2008 Eric Seidel <eric@webkit.org>
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.
9 * Copyright (C) 2012 Intel Corporation. All rights reserved.
10 *
11 * This library is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU Library General Public
13 * License as published by the Free Software Foundation; either
14 * version 2 of the License, or (at your option) any later version.
15 *
16 * This library is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 * Library General Public License for more details.
20 *
21 * You should have received a copy of the GNU Library General Public License
22 * along with this library; see the file COPYING.LIB. If not, write to
23 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
24 * Boston, MA 02110-1301, USA.
25 */
26 4
27 #include "config.h" 5 #include "config.h"
28 #include "core/css/parser/CSSPropertyParser.h" 6 #include "core/css/parser/CSSPropertyParser.h"
29 7
30 #include "core/StylePropertyShorthand.h" 8 #include "core/StylePropertyShorthand.h"
31 #include "core/css/CSSBasicShapes.h"
32 #include "core/css/CSSBorderImage.h"
33 #include "core/css/CSSCanvasValue.h"
34 #include "core/css/CSSContentDistributionValue.h"
35 #include "core/css/CSSCounterValue.h"
36 #include "core/css/CSSCrossfadeValue.h"
37 #include "core/css/CSSCursorImageValue.h"
38 #include "core/css/CSSFontFaceSrcValue.h"
39 #include "core/css/CSSFontFeatureValue.h"
40 #include "core/css/CSSFunctionValue.h"
41 #include "core/css/CSSGridLineNamesValue.h"
42 #include "core/css/CSSImageSetValue.h"
43 #include "core/css/CSSImageValue.h"
44 #include "core/css/CSSPathValue.h"
45 #include "core/css/CSSPrimitiveValueMappings.h"
46 #include "core/css/CSSProperty.h"
47 #include "core/css/CSSPropertyMetadata.h"
48 #include "core/css/CSSQuadValue.h"
49 #include "core/css/CSSReflectValue.h"
50 #include "core/css/CSSSVGDocumentValue.h"
51 #include "core/css/CSSShadowValue.h"
52 #include "core/css/CSSTimingFunctionValue.h"
53 #include "core/css/CSSUnicodeRangeValue.h"
54 #include "core/css/CSSValuePair.h"
55 #include "core/css/CSSValuePool.h" 9 #include "core/css/CSSValuePool.h"
56 #include "core/css/HashTools.h" 10 #include "core/css/CSSCalculationValue.h"
57 #include "core/css/parser/CSSParserFastPaths.h" 11 #include "core/css/parser/CSSParserFastPaths.h"
58 #include "core/css/parser/CSSParserValues.h" 12 #include "core/css/parser/CSSParserValues.h"
59 #include "core/frame/UseCounter.h" 13 #include "core/frame/UseCounter.h"
60 #include "core/layout/LayoutTheme.h"
61 #include "core/style/GridCoordinate.h"
62 #include "core/svg/SVGPathUtilities.h"
63 #include "platform/RuntimeEnabledFeatures.h"
64 14
65 namespace blink { 15 namespace blink {
66 16
67 template <unsigned N> 17 CSSPropertyParser::CSSPropertyParser(CSSParserValueList* valueList, const CSSPar serTokenRange& range,
68 static bool equalIgnoringCase(const CSSParserString& a, const char (&b)[N])
69 {
70 unsigned length = N - 1; // Ignore the trailing null character
71 if (a.length() != length)
72 return false;
73
74 return a.is8Bit() ? WTF::equalIgnoringCase(b, a.characters8(), length) : WTF ::equalIgnoringCase(b, a.characters16(), length);
75 }
76
77 CSSPropertyParser::CSSPropertyParser(CSSParserValueList* valueList,
78 const CSSParserContext& context, WillBeHeapVector<CSSProperty, 256>& parsedP roperties, 18 const CSSParserContext& context, WillBeHeapVector<CSSProperty, 256>& parsedP roperties,
79 StyleRule::Type ruleType) 19 StyleRule::Type ruleType)
80 : m_valueList(valueList) 20 : m_valueList(valueList)
21 , m_range(range)
81 , m_context(context) 22 , m_context(context)
82 , m_parsedProperties(parsedProperties) 23 , m_parsedProperties(parsedProperties)
83 , m_ruleType(ruleType) 24 , m_ruleType(ruleType)
84 , m_inParseShorthand(0) 25 , m_inParseShorthand(0)
85 , m_currentShorthand(CSSPropertyInvalid) 26 , m_currentShorthand(CSSPropertyInvalid)
86 , m_implicitShorthand(false) 27 , m_implicitShorthand(false)
87 { 28 {
88 } 29 }
89 30
90 bool CSSPropertyParser::parseValue(CSSPropertyID unresolvedProperty, bool import ant, 31 bool CSSPropertyParser::parseValue(CSSPropertyID unresolvedProperty, bool import ant,
91 CSSParserValueList* valueList, const CSSParserContext& context, 32 const CSSParserTokenRange& range, const CSSParserContext& context,
92 WillBeHeapVector<CSSProperty, 256>& parsedProperties, StyleRule::Type ruleTy pe) 33 WillBeHeapVector<CSSProperty, 256>& parsedProperties, StyleRule::Type ruleTy pe)
93 { 34 {
94 int parsedPropertiesSize = parsedProperties.size(); 35 int parsedPropertiesSize = parsedProperties.size();
95 36
96 CSSPropertyParser parser(valueList, context, parsedProperties, ruleType); 37 CSSParserValueList valueList(range);
38 if (!valueList.size())
39 return false; // Parser error
40 CSSPropertyParser parser(&valueList, range, context, parsedProperties, ruleT ype);
97 CSSPropertyID resolvedProperty = resolveCSSPropertyID(unresolvedProperty); 41 CSSPropertyID resolvedProperty = resolveCSSPropertyID(unresolvedProperty);
98 bool parseSuccess; 42 bool parseSuccess;
99 43
100 if (ruleType == StyleRule::Viewport) { 44 if (ruleType == StyleRule::Viewport) {
101 parseSuccess = (RuntimeEnabledFeatures::cssViewportEnabled() || isUAShee tBehavior(context.mode())) 45 parseSuccess = (RuntimeEnabledFeatures::cssViewportEnabled() || isUAShee tBehavior(context.mode()))
102 && parser.parseViewportProperty(resolvedProperty, important); 46 && parser.parseViewportProperty(resolvedProperty, important);
103 } else if (ruleType == StyleRule::FontFace) { 47 } else if (ruleType == StyleRule::FontFace) {
104 parseSuccess = parser.parseFontFaceDescriptor(resolvedProperty); 48 parseSuccess = parser.parseFontFaceDescriptor(resolvedProperty);
105 } else { 49 } else {
106 parseSuccess = parser.parseValue(unresolvedProperty, important); 50 parseSuccess = parser.parseValue(unresolvedProperty, important);
107 } 51 }
108 52
109 // This doesn't count UA style sheets 53 // This doesn't count UA style sheets
110 if (parseSuccess && context.useCounter()) 54 if (parseSuccess && context.useCounter())
111 context.useCounter()->count(context, unresolvedProperty); 55 context.useCounter()->count(context, unresolvedProperty);
112 56
113 if (!parseSuccess) 57 if (!parseSuccess)
114 parser.rollbackLastProperties(parsedProperties.size() - parsedProperties Size); 58 parser.rollbackLastProperties(parsedProperties.size() - parsedProperties Size);
115 59
116 return parseSuccess; 60 return parseSuccess;
117 } 61 }
118 62
119 void CSSPropertyParser::addProperty(CSSPropertyID propId, PassRefPtrWillBeRawPtr <CSSValue> value, bool important, bool implicit) 63 // Helper methods for consuming tokens starts here.
64 static bool consumeCommaIncludingWhitespace(CSSParserTokenRange& valueList)
120 { 65 {
121 ASSERT(!isPropertyAlias(propId)); 66 CSSParserToken value = valueList.peek();
67 if (value.type() != CommaToken)
68 return false;
69 valueList.consumeIncludingWhitespace();
70 return true;
71 }
122 72
123 int shorthandIndex = 0; 73 static PassRefPtrWillBeRawPtr<CSSPrimitiveValue> consumeIdent(CSSParserTokenRang e& range)
124 bool setFromShorthand = false; 74 {
75 ASSERT(range.peek().type() == IdentToken);
alancutter (OOO until 2018) 2015/09/11 07:53:49 Let's just return nullptr, that way we can avoid d
76 return cssValuePool().createIdentifierValue(range.consumeIncludingWhitespace ().id());
77 }
125 78
126 if (m_currentShorthand) { 79 static PassRefPtrWillBeRawPtr<CSSPrimitiveValue> consumeCustomIdent(CSSParserTok enRange& range)
127 Vector<StylePropertyShorthand, 4> shorthands; 80 {
128 getMatchingShorthandsForLonghand(propId, &shorthands); 81 ASSERT(range.peek().type() == IdentToken);
129 // Viewport descriptors have width and height as shorthands, but it does n't 82 return cssValuePool().createValue(range.consumeIncludingWhitespace().value() , CSSPrimitiveValue::UnitType::CustomIdentifier);
130 // make sense for CSSProperties.in to consider them as such. The shortha nd 83 }
131 // index is only used by the inspector and doesn't affect viewport
132 // descriptors.
133 if (shorthands.isEmpty())
134 ASSERT(m_currentShorthand == CSSPropertyWidth || m_currentShorthand == CSSPropertyHeight);
135 else
136 setFromShorthand = true;
137 84
138 if (shorthands.size() > 1) 85 static PassRefPtrWillBeRawPtr<CSSPrimitiveValue> consumeString(CSSParserTokenRan ge& range)
139 shorthandIndex = indexOfShorthandForLonghand(m_currentShorthand, sho rthands); 86 {
87 ASSERT(range.peek().type() == StringToken);
88 return cssValuePool().createValue(range.consumeIncludingWhitespace().value() , CSSPrimitiveValue::UnitType::String);
89 }
90
91 // Methods for consuming non-shorthand properties starts here.
92 static PassRefPtrWillBeRawPtr<CSSValue> consumeWillChange(CSSParserTokenRange& r ange)
93 {
94 RefPtrWillBeRawPtr<CSSValueList> values = CSSValueList::createCommaSeparated ();
95 if (range.peek().id() == CSSValueAuto) {
96 values->append(consumeIdent(range));
97 return values.release();
140 } 98 }
141 99
142 m_parsedProperties.append(CSSProperty(propId, value, important, setFromShort hand, shorthandIndex, m_implicitShorthand || implicit)); 100 // Every comma-separated list of identifiers is a valid will-change value,
101 // unless the list includes an explicitly disallowed identifier.
102 while (true) {
103 if (range.peek().type() != IdentToken)
104 return nullptr;
105 CSSPropertyID unresolvedProperty = unresolvedCSSPropertyID(range.peek(). value());
106 if (unresolvedProperty) {
107 ASSERT(CSSPropertyMetadata::isEnabledProperty(unresolvedProperty));
108 // Now "all" is used by both CSSValue and CSSPropertyValue.
109 // Need to return nullptr when currentValue is CSSPropertyAll.
110 if (unresolvedProperty == CSSPropertyWillChange || unresolvedPropert y == CSSPropertyAll)
111 return nullptr;
112 values->append(cssValuePool().createIdentifierValue(unresolvedProper ty));
113 range.consumeIncludingWhitespace();
114 } else {
115 switch (range.peek().id()) {
116 case CSSValueNone:
117 case CSSValueAll:
118 case CSSValueAuto:
119 case CSSValueDefault:
120 case CSSValueInitial:
121 case CSSValueInherit:
122 return nullptr;
123 case CSSValueContents:
124 case CSSValueScrollPosition:
125 values->append(consumeIdent(range));
126 break;
127 default:
128 range.consumeIncludingWhitespace();
129 break;
130 }
131 }
132
133 if (range.atEnd())
134 break;
135 if (!consumeCommaIncludingWhitespace(range))
136 return nullptr;
137 }
138
139 return values.release();
143 } 140 }
144 141
145 void CSSPropertyParser::rollbackLastProperties(int num) 142 static PassRefPtrWillBeRawPtr<CSSPrimitiveValue> consumePage(CSSParserTokenRange & range)
146 { 143 {
147 ASSERT(num >= 0); 144 const CSSParserToken& token = range.peek();
148 ASSERT(m_parsedProperties.size() >= static_cast<unsigned>(num)); 145 if (token.id() == CSSValueAuto)
149 m_parsedProperties.shrink(m_parsedProperties.size() - num); 146 return consumeIdent(range);
147 if (token.type() == IdentToken)
148 return consumeCustomIdent(range);
149 return nullptr;
150 } 150 }
151 151
152 KURL CSSPropertyParser::completeURL(const String& url) const 152 // [ <string> <string> ]+ | none
153 static PassRefPtrWillBeRawPtr<CSSValue> consumeQuotes(CSSParserTokenRange& range )
153 { 154 {
154 return m_context.completeURL(url); 155 if (range.peek().id() == CSSValueNone)
156 return consumeIdent(range);
157 RefPtrWillBeRawPtr<CSSValueList> values = CSSValueList::createSpaceSeparated ();
158 while (!range.atEnd()) {
159 if (range.peek().type() != StringToken)
160 return nullptr;
161 RefPtrWillBeRawPtr<CSSValue> parsedValue = consumeString(range);
162 values->append(parsedValue.release());
163 }
164 if (values->length() && values->length() % 2 == 0)
165 return values.release();
166 return nullptr;
155 } 167 }
156 168
157 bool CSSPropertyParser::validCalculationUnit(CSSParserValue* value, Units unitfl ags, ReleaseParsedCalcValueCondition releaseCalc) 169 static PassRefPtrWillBeRawPtr<CSSValue> consumeWebkitHighlight(CSSParserTokenRan ge& range)
158 { 170 {
159 bool mustBeNonNegative = unitflags & (FNonNeg | FPositiveInteger); 171 if (range.peek().id() == CSSValueNone)
160 172 return consumeIdent(range);
161 if (!parseCalculation(value, mustBeNonNegative ? ValueRangeNonNegative : Val ueRangeAll)) 173 if (range.peek().type() == StringToken)
162 return false; 174 return consumeString(range);
163 175 return nullptr;
164 bool b = false;
165 switch (m_parsedCalculation->category()) {
166 case CalcLength:
167 b = (unitflags & FLength);
168 break;
169 case CalcNumber:
170 b = (unitflags & FNumber);
171 if (!b && (unitflags & (FInteger | FPositiveInteger)) && m_parsedCalcula tion->isInt())
172 b = true;
173 if (b && mustBeNonNegative && m_parsedCalculation->isNegative())
174 b = false;
175 // Always resolve calc() to a UnitType::Number in the CSSParserValue if there are no non-numbers specified in the unitflags.
176 if (b && !(unitflags & ~(FInteger | FNumber | FPositiveInteger | FNonNeg ))) {
177 double number = m_parsedCalculation->doubleValue();
178 if ((unitflags & FPositiveInteger) && number <= 0) {
179 b = false;
180 } else {
181 delete value->calcFunction;
182 value->setUnit(CSSPrimitiveValue::UnitType::Number);
183 value->fValue = number;
184 value->isInt = m_parsedCalculation->isInt();
185 }
186 m_parsedCalculation.release();
187 return b;
188 }
189 break;
190 case CalcPercent:
191 b = (unitflags & FPercent);
192 if (b && mustBeNonNegative && m_parsedCalculation->isNegative())
193 b = false;
194 break;
195 case CalcPercentLength:
196 b = (unitflags & FPercent) && (unitflags & FLength);
197 break;
198 case CalcPercentNumber:
199 b = (unitflags & FPercent) && (unitflags & FNumber);
200 break;
201 case CalcAngle:
202 b = (unitflags & FAngle);
203 break;
204 case CalcTime:
205 b = (unitflags & FTime);
206 break;
207 case CalcFrequency:
208 b = (unitflags & FFrequency);
209 break;
210 case CalcOther:
211 break;
212 }
213 if (!b || releaseCalc == ReleaseParsedCalcValue)
214 m_parsedCalculation.release();
215 return b;
216 } 176 }
217 177
218 inline bool CSSPropertyParser::shouldAcceptUnitLessValues(CSSParserValue* value, Units unitflags, CSSParserMode cssParserMode) 178 PassRefPtrWillBeRawPtr<CSSValue> CSSPropertyParser::parseSingleValue(CSSProperty ID propId)
219 { 179 {
220 // Quirks mode for certain properties and presentation attributes accept uni t-less values for certain units. 180 m_range.consumeWhitespace();
221 return (unitflags & (FLength | FAngle)) 181 switch (propId) {
222 && (!value->fValue // 0 can always be unitless. 182 case CSSPropertyWillChange:
223 || isUnitLessLengthParsingEnabledForMode(cssParserMode) // HTML and SVG attribute values can always be unitless. 183 return consumeWillChange(m_range);
224 || (cssParserMode == HTMLQuirksMode && (unitflags & FUnitlessQuirk)) ); 184 case CSSPropertyPage:
225 } 185 return consumePage(m_range);
226 186 case CSSPropertyQuotes:
227 inline bool isCalculation(CSSParserValue* value) 187 return consumeQuotes(m_range);
228 { 188 case CSSPropertyWebkitHighlight:
229 return value->m_unit == CSSParserValue::CalcFunction; 189 return consumeWebkitHighlight(m_range);
230 }
231
232 bool CSSPropertyParser::validUnit(CSSParserValue* value, Units unitflags, CSSPar serMode cssParserMode, ReleaseParsedCalcValueCondition releaseCalc)
233 {
234 if (isCalculation(value))
235 return validCalculationUnit(value, unitflags, releaseCalc);
236
237 if (unitflags & FNonNeg && value->fValue < 0)
238 return false;
239 switch (value->unit()) {
240 case CSSPrimitiveValue::UnitType::Number:
241 if (unitflags & FNumber)
242 return true;
243 if (shouldAcceptUnitLessValues(value, unitflags, cssParserMode)) {
244 value->setUnit((unitflags & FLength) ? CSSPrimitiveValue::UnitType:: Pixels : CSSPrimitiveValue::UnitType::Degrees);
245 return true;
246 }
247 if ((unitflags & FInteger) && value->isInt)
248 return true;
249 if ((unitflags & FPositiveInteger) && value->isInt && value->fValue > 0)
250 return true;
251 return false;
252 case CSSPrimitiveValue::UnitType::Percentage:
253 return unitflags & FPercent;
254 case CSSPrimitiveValue::UnitType::QuirkyEms:
255 if (cssParserMode != UASheetMode)
256 return false;
257 /* fallthrough intentional */
258 case CSSPrimitiveValue::UnitType::Ems:
259 case CSSPrimitiveValue::UnitType::Rems:
260 case CSSPrimitiveValue::UnitType::Chs:
261 case CSSPrimitiveValue::UnitType::Exs:
262 case CSSPrimitiveValue::UnitType::Pixels:
263 case CSSPrimitiveValue::UnitType::Centimeters:
264 case CSSPrimitiveValue::UnitType::Millimeters:
265 case CSSPrimitiveValue::UnitType::Inches:
266 case CSSPrimitiveValue::UnitType::Points:
267 case CSSPrimitiveValue::UnitType::Picas:
268 case CSSPrimitiveValue::UnitType::ViewportWidth:
269 case CSSPrimitiveValue::UnitType::ViewportHeight:
270 case CSSPrimitiveValue::UnitType::ViewportMin:
271 case CSSPrimitiveValue::UnitType::ViewportMax:
272 return unitflags & FLength;
273 case CSSPrimitiveValue::UnitType::Milliseconds:
274 case CSSPrimitiveValue::UnitType::Seconds:
275 return unitflags & FTime;
276 case CSSPrimitiveValue::UnitType::Degrees:
277 case CSSPrimitiveValue::UnitType::Radians:
278 case CSSPrimitiveValue::UnitType::Gradians:
279 case CSSPrimitiveValue::UnitType::Turns:
280 return unitflags & FAngle;
281 case CSSPrimitiveValue::UnitType::DotsPerPixel:
282 case CSSPrimitiveValue::UnitType::DotsPerInch:
283 case CSSPrimitiveValue::UnitType::DotsPerCentimeter:
284 return unitflags & FResolution;
285 default: 190 default:
286 return false; 191 return nullptr;
287 } 192 }
288 } 193 }
289 194
290 PassRefPtrWillBeRawPtr<CSSPrimitiveValue> CSSPropertyParser::createPrimitiveNume ricValue(CSSParserValue* value) 195 bool CSSPropertyParser::parseShorthand(CSSPropertyID propId, bool important)
291 { 196 {
292 if (m_parsedCalculation) { 197 m_range.consumeWhitespace();
293 ASSERT(isCalculation(value)); 198 switch (propId) {
294 return CSSPrimitiveValue::create(m_parsedCalculation.release()); 199 case CSSPropertyWebkitMarginCollapse: {
295 } 200 CSSValueID id = m_range.consumeIncludingWhitespace().id();
296 201 if (!CSSParserFastPaths::isValidKeywordPropertyAndValue(CSSPropertyWebki tMarginBeforeCollapse, id))
297 ASSERT((value->unit() >= CSSPrimitiveValue::UnitType::Number && value->unit( ) <= CSSPrimitiveValue::UnitType::Kilohertz) 202 return false;
298 || (value->unit() >= CSSPrimitiveValue::UnitType::Turns && value->unit() <= CSSPrimitiveValue::UnitType::Chs) 203 RefPtrWillBeRawPtr<CSSValue> beforeCollapse = cssValuePool().createIdent ifierValue(id);
299 || (value->unit() >= CSSPrimitiveValue::UnitType::ViewportWidth && value ->unit() <= CSSPrimitiveValue::UnitType::ViewportMax) 204 addProperty(CSSPropertyWebkitMarginBeforeCollapse, beforeCollapse, impor tant);
300 || (value->unit() >= CSSPrimitiveValue::UnitType::DotsPerPixel && value- >unit() <= CSSPrimitiveValue::UnitType::DotsPerCentimeter)); 205 if (m_range.atEnd()) {
301 return cssValuePool().createValue(value->fValue, value->unit()); 206 addProperty(CSSPropertyWebkitMarginAfterCollapse, beforeCollapse, im portant);
302 } 207 return true;
303
304 inline PassRefPtrWillBeRawPtr<CSSPrimitiveValue> CSSPropertyParser::createPrimit iveStringValue(CSSParserValue* value)
305 {
306 ASSERT(value->unit() == CSSPrimitiveValue::UnitType::String || value->m_unit == CSSParserValue::Identifier);
307 return cssValuePool().createValue(value->string, CSSPrimitiveValue::UnitType ::String);
308 }
309
310 inline PassRefPtrWillBeRawPtr<CSSPrimitiveValue> CSSPropertyParser::createPrimit iveCustomIdentValue(CSSParserValue* value)
311 {
312 ASSERT(value->unit() == CSSPrimitiveValue::UnitType::String || value->m_unit == CSSParserValue::Identifier);
313 return cssValuePool().createValue(value->string, CSSPrimitiveValue::UnitType ::CustomIdentifier);
314 }
315
316 inline PassRefPtrWillBeRawPtr<CSSValue> CSSPropertyParser::createCSSImageValueWi thReferrer(const String& rawValue, const KURL& url)
317 {
318 RefPtrWillBeRawPtr<CSSValue> imageValue = CSSImageValue::create(rawValue, ur l);
319 toCSSImageValue(imageValue.get())->setReferrer(m_context.referrer());
320 return imageValue;
321 }
322
323 static inline bool isComma(CSSParserValue* value)
324 {
325 ASSERT(value);
326 return value->m_unit == CSSParserValue::Operator && value->iValue == ',';
327 }
328
329 static bool consumeComma(CSSParserValueList* valueList)
330 {
331 CSSParserValue* value = valueList->current();
332 if (!value || !isComma(value))
333 return false;
334 valueList->next();
335 return true;
336 }
337
338 static inline bool isForwardSlashOperator(CSSParserValue* value)
339 {
340 ASSERT(value);
341 return value->m_unit == CSSParserValue::Operator && value->iValue == '/';
342 }
343
344 static bool isGeneratedImageValue(CSSParserValue* val)
345 {
346 if (val->m_unit != CSSParserValue::Function)
347 return false;
348
349 CSSValueID id = val->function->id;
350 return id == CSSValueLinearGradient
351 || id == CSSValueRadialGradient
352 || id == CSSValueRepeatingLinearGradient
353 || id == CSSValueRepeatingRadialGradient
354 || id == CSSValueWebkitLinearGradient
355 || id == CSSValueWebkitRadialGradient
356 || id == CSSValueWebkitRepeatingLinearGradient
357 || id == CSSValueWebkitRepeatingRadialGradient
358 || id == CSSValueWebkitGradient
359 || id == CSSValueWebkitCanvas
360 || id == CSSValueWebkitCrossFade;
361 }
362
363 bool CSSPropertyParser::validWidthOrHeight(CSSParserValue* value, Units unitless )
364 {
365 int id = value->id;
366 if (id == CSSValueIntrinsic || id == CSSValueMinIntrinsic
367 || id == CSSValueWebkitMinContent || id == CSSValueWebkitMaxContent || i d == CSSValueWebkitFillAvailable || id == CSSValueWebkitFitContent
368 || id == CSSValueMinContent || id == CSSValueMaxContent || id == CSSValu eFitContent) {
369 if (m_context.useCounter()) {
370 switch (value->id) {
371 case CSSValueIntrinsic:
372 m_context.useCounter()->count(UseCounter::LegacyCSSValueIntrinsi c);
373 break;
374 case CSSValueMinIntrinsic:
375 m_context.useCounter()->count(UseCounter::LegacyCSSValueMinIntri nsic);
376 break;
377 case CSSValueWebkitMinContent:
378 m_context.useCounter()->count(UseCounter::CSSValuePrefixedMinCon tent);
379 break;
380 case CSSValueWebkitMaxContent:
381 m_context.useCounter()->count(UseCounter::CSSValuePrefixedMaxCon tent);
382 break;
383 case CSSValueWebkitFillAvailable:
384 m_context.useCounter()->count(UseCounter::CSSValuePrefixedFillAv ailable);
385 break;
386 case CSSValueWebkitFitContent:
387 m_context.useCounter()->count(UseCounter::CSSValuePrefixedFitCon tent);
388 break;
389 default:
390 break;
391 }
392 } 208 }
209 id = m_range.consumeIncludingWhitespace().id();
210 if (!CSSParserFastPaths::isValidKeywordPropertyAndValue(CSSPropertyWebki tMarginAfterCollapse, id))
211 return false;
212 addProperty(CSSPropertyWebkitMarginAfterCollapse, cssValuePool().createI dentifierValue(id), important);
393 return true; 213 return true;
394 } 214 }
395 return validUnit(value, FLength | FPercent | FNonNeg | unitless); 215 case CSSPropertyOverflow: {
396 } 216 CSSValueID id = m_range.consumeIncludingWhitespace().id();
397 217 if (!CSSParserFastPaths::isValidKeywordPropertyAndValue(CSSPropertyOverf lowY, id))
398 inline PassRefPtrWillBeRawPtr<CSSPrimitiveValue> CSSPropertyParser::parseValidPr imitive(CSSValueID identifier, CSSParserValue* value)
399 {
400 if (identifier)
401 return cssValuePool().createIdentifierValue(identifier);
402 if (value->unit() >= CSSPrimitiveValue::UnitType::Number && value->unit() <= CSSPrimitiveValue::UnitType::Kilohertz)
403 return createPrimitiveNumericValue(value);
404 if (value->unit() >= CSSPrimitiveValue::UnitType::Turns && value->unit() <= CSSPrimitiveValue::UnitType::Chs)
405 return createPrimitiveNumericValue(value);
406 if (value->unit() >= CSSPrimitiveValue::UnitType::ViewportWidth && value->un it() <= CSSPrimitiveValue::UnitType::ViewportMax)
407 return createPrimitiveNumericValue(value);
408 if (value->unit() >= CSSPrimitiveValue::UnitType::DotsPerPixel && value->uni t() <= CSSPrimitiveValue::UnitType::DotsPerCentimeter)
409 return createPrimitiveNumericValue(value);
410 if (value->unit() == CSSPrimitiveValue::UnitType::QuirkyEms)
411 return CSSPrimitiveValue::create(value->fValue, CSSPrimitiveValue::UnitT ype::QuirkyEms);
412 if (isCalculation(value))
413 return CSSPrimitiveValue::create(m_parsedCalculation.release());
414
415 return nullptr;
416 }
417
418 void CSSPropertyParser::addExpandedPropertyForValue(CSSPropertyID propId, PassRe fPtrWillBeRawPtr<CSSValue> prpValue, bool important)
419 {
420 const StylePropertyShorthand& shorthand = shorthandForProperty(propId);
421 unsigned shorthandLength = shorthand.length();
422 if (!shorthandLength) {
423 addProperty(propId, prpValue, important);
424 return;
425 }
426
427 RefPtrWillBeRawPtr<CSSValue> value = prpValue;
428 ShorthandScope scope(this, propId);
429 const CSSPropertyID* longhands = shorthand.properties();
430 for (unsigned i = 0; i < shorthandLength; ++i)
431 addProperty(longhands[i], value, important);
432 }
433
434 bool CSSPropertyParser::parseValue(CSSPropertyID unresolvedProperty, bool import ant)
435 {
436 CSSPropertyID propId = resolveCSSPropertyID(unresolvedProperty);
437
438 CSSParserValue* value = m_valueList->current();
439
440 // Note: m_parsedCalculation is used to pass the calc value to validUnit and then cleared at the end of this function.
441 // FIXME: This is to avoid having to pass parsedCalc to all validUnit caller s.
442 ASSERT(!m_parsedCalculation);
443
444 CSSValueID id = value->id;
445
446 if (id == CSSValueInherit) {
447 if (m_valueList->size() != 1)
448 return false; 218 return false;
449 addExpandedPropertyForValue(propId, cssValuePool().createInheritedValue( ), important); 219 if (!m_range.atEnd())
450 return true;
451 } else if (id == CSSValueInitial) {
452 if (m_valueList->size() != 1)
453 return false; 220 return false;
454 addExpandedPropertyForValue(propId, cssValuePool().createExplicitInitial Value(), important); 221 RefPtrWillBeRawPtr<CSSValue> overflowYValue = cssValuePool().createIdent ifierValue(id);
455 return true;
456 } else if (id == CSSValueUnset) {
457 if (m_valueList->size() != 1)
458 return false;
459 addExpandedPropertyForValue(propId, cssValuePool().createUnsetValue(), i mportant);
460 return true;
461 }
462
463 if (CSSParserFastPaths::isKeywordPropertyID(propId)) {
464 if (!CSSParserFastPaths::isValidKeywordPropertyAndValue(propId, id))
465 return false;
466 if (m_valueList->next() && !inShorthand())
467 return false;
468 addProperty(propId, cssValuePool().createIdentifierValue(id), important) ;
469 return true;
470 }
471
472 bool validPrimitive = false;
473 Units unitless = FUnknown;
474 RefPtrWillBeRawPtr<CSSValue> parsedValue = nullptr;
475
476 switch (propId) {
477 case CSSPropertySize: // <length>{1,2} | auto | [ <page-size> || [ portrait | landscape] ]
478 parsedValue = parseSize();
479 break;
480 case CSSPropertyQuotes: // [<string> <string>]+ | none
481 if (id == CSSValueNone)
482 validPrimitive = true;
483 else
484 parsedValue = parseQuotes();
485 break;
486
487 case CSSPropertyContent: // [ <string> | <uri> | <counter> | at tr(X) | open-quote |
488 // close-quote | no-open-quote | no-close-quote ]+ | inherit
489 parsedValue = parseContent();
490 break;
491 case CSSPropertyClip: // <shape> | auto | inherit
492 if (id == CSSValueAuto)
493 validPrimitive = true;
494 else if (value->m_unit == CSSParserValue::Function)
495 parsedValue = parseClipShape();
496 break;
497
498 /* Start of supported CSS properties with validation. This is needed for par seShorthand to work
499 * correctly and allows optimization in blink::applyRule(..)
500 */
501 case CSSPropertyOverflow: {
502 ShorthandScope scope(this, propId);
503 if (!parseValue(CSSPropertyOverflowY, important) || m_valueList->current ())
504 return false;
505 222
506 RefPtrWillBeRawPtr<CSSValue> overflowXValue = nullptr; 223 RefPtrWillBeRawPtr<CSSValue> overflowXValue = nullptr;
507 224
508 // FIXME: -webkit-paged-x or -webkit-paged-y only apply to overflow-y. I f this value has been 225 // FIXME: -webkit-paged-x or -webkit-paged-y only apply to overflow-y. I f this value has been
509 // set using the shorthand, then for now overflow-x will default to auto , but once we implement 226 // set using the shorthand, then for now overflow-x will default to auto , but once we implement
510 // pagination controls, it should default to hidden. If the overflow-y v alue is anything but 227 // pagination controls, it should default to hidden. If the overflow-y v alue is anything but
511 // paged-x or paged-y, then overflow-x and overflow-y should have the sa me value. 228 // paged-x or paged-y, then overflow-x and overflow-y should have the sa me value.
512 if (id == CSSValueWebkitPagedX || id == CSSValueWebkitPagedY) 229 if (id == CSSValueWebkitPagedX || id == CSSValueWebkitPagedY)
513 overflowXValue = cssValuePool().createIdentifierValue(CSSValueAuto); 230 overflowXValue = cssValuePool().createIdentifierValue(CSSValueAuto);
514 else 231 else
515 overflowXValue = m_parsedProperties.last().value(); 232 overflowXValue = overflowYValue;
516 addProperty(CSSPropertyOverflowX, overflowXValue.release(), important); 233 addProperty(CSSPropertyOverflowX, overflowXValue.release(), important);
234 addProperty(CSSPropertyOverflowY, overflowYValue.release(), important);
517 return true; 235 return true;
518 } 236 }
519 237 default:
520 case CSSPropertyTextAlign:
521 // left | right | center | justify | -webkit-left | -webkit-right | -web kit-center | -webkit-match-parent
522 // | start | end | <string> | inherit | -webkit-auto (converted to start )
523 // FIXME: <string> not supported right now
524 if ((id >= CSSValueWebkitAuto && id <= CSSValueWebkitMatchParent) || id == CSSValueStart || id == CSSValueEnd) {
525 validPrimitive = true;
526 }
527 break;
528
529 case CSSPropertyFontWeight: // normal | bold | bolder | lighter | 100 | 200 | 300 | 400 | 500 | 600 | 700 | 800 | 900 | inherit
530 return parseFontWeight(important) && !m_valueList->next();
531
532 case CSSPropertyBorderSpacing: {
533 ShorthandScope scope(this, CSSPropertyBorderSpacing);
534 if (!parseValue(CSSPropertyWebkitBorderHorizontalSpacing, important))
535 return false;
536 if (!m_valueList->current()) {
537 CSSValue* value = m_parsedProperties.last().value();
538 addProperty(CSSPropertyWebkitBorderVerticalSpacing, value, important );
539 return true;
540 }
541 if (!parseValue(CSSPropertyWebkitBorderVerticalSpacing, important))
542 return false;
543 return !m_valueList->current();
544 }
545 case CSSPropertyWebkitBorderHorizontalSpacing:
546 case CSSPropertyWebkitBorderVerticalSpacing:
547 unitless = FLength | FNonNeg;
548 if (inShorthand() && m_currentShorthand == CSSPropertyBorderSpacing)
549 unitless = unitless | FUnitlessQuirk;
550 validPrimitive = validUnit(value, unitless);
551 break;
552 case CSSPropertyOutlineColor: // <color> | invert | inherit
553 // Outline color has "invert" as additional keyword.
554 // Also, we want to allow the special focus color even in HTML Standard parsing mode.
555 if (id == CSSValueInvert || id == CSSValueWebkitFocusRingColor) {
556 validPrimitive = true;
557 break;
558 }
559 /* nobreak */
560 case CSSPropertyBackgroundColor: // <color> | inherit
561 case CSSPropertyBorderTopColor: // <color> | inherit
562 case CSSPropertyBorderRightColor:
563 case CSSPropertyBorderBottomColor:
564 case CSSPropertyBorderLeftColor:
565 case CSSPropertyWebkitBorderStartColor:
566 case CSSPropertyWebkitBorderEndColor:
567 case CSSPropertyWebkitBorderBeforeColor:
568 case CSSPropertyWebkitBorderAfterColor:
569 case CSSPropertyColor: // <color> | inherit
570 case CSSPropertyTextDecorationColor: // CSS3 text decoration colors
571 case CSSPropertyWebkitColumnRuleColor:
572 case CSSPropertyWebkitTextEmphasisColor:
573 case CSSPropertyWebkitTextFillColor:
574 case CSSPropertyWebkitTextStrokeColor:
575 ASSERT(propId != CSSPropertyTextDecorationColor || RuntimeEnabledFeature s::css3TextDecorationsEnabled());
576 parsedValue = parseColor(m_valueList->current(), acceptQuirkyColors(prop Id));
577 if (parsedValue)
578 m_valueList->next();
579 break;
580
581 case CSSPropertyCursor: {
582 // Grammar defined by CSS3 UI and modified by CSS4 images:
583 // [ [<image> [<x> <y>]?,]*
584 // [ auto | crosshair | default | pointer | progress | move | e-resize | ne-resize |
585 // nw-resize | n-resize | se-resize | sw-resize | s-resize | w-resize | ew-resize |
586 // ns-resize | nesw-resize | nwse-resize | col-resize | row-resize | tex t | wait | help |
587 // vertical-text | cell | context-menu | alias | copy | no-drop | not-al lowed | all-scroll |
588 // zoom-in | zoom-out | -webkit-grab | -webkit-grabbing | -webkit-zoom-i n | -webkit-zoom-out ] ] | inherit
589 RefPtrWillBeRawPtr<CSSValueList> list = nullptr;
590 while (value) {
591 RefPtrWillBeRawPtr<CSSValue> image = nullptr;
592 if (value->unit() == CSSPrimitiveValue::UnitType::URI) {
593 String uri = value->string;
594 if (!uri.isNull())
595 image = createCSSImageValueWithReferrer(uri, completeURL(uri ));
596 } else if (value->m_unit == CSSParserValue::Function && value->funct ion->id == CSSValueWebkitImageSet) {
597 image = parseImageSet(m_valueList);
598 if (!image)
599 break;
600 } else
601 break;
602
603 Vector<int> coords;
604 value = m_valueList->next();
605 while (value && validUnit(value, FNumber)) {
606 coords.append(int(value->fValue));
607 value = m_valueList->next();
608 }
609 bool hotSpotSpecified = false;
610 IntPoint hotSpot(-1, -1);
611 int nrcoords = coords.size();
612 if (nrcoords > 0 && nrcoords != 2)
613 return false;
614 if (nrcoords == 2) {
615 hotSpotSpecified = true;
616 hotSpot = IntPoint(coords[0], coords[1]);
617 }
618
619 if (!list)
620 list = CSSValueList::createCommaSeparated();
621
622 if (image)
623 list->append(CSSCursorImageValue::create(image, hotSpotSpecified , hotSpot));
624
625 if (!consumeComma(m_valueList))
626 return false;
627 value = m_valueList->current();
628 }
629 if (value && m_context.useCounter()) {
630 if (value->id == CSSValueWebkitZoomIn)
631 m_context.useCounter()->count(UseCounter::PrefixedCursorZoomIn);
632 else if (value->id == CSSValueWebkitZoomOut)
633 m_context.useCounter()->count(UseCounter::PrefixedCursorZoomOut) ;
634 }
635 if (list) {
636 if (!value)
637 return false;
638 if (inQuirksMode() && value->id == CSSValueHand) // MSIE 5 compatibi lity :/
639 list->append(cssValuePool().createIdentifierValue(CSSValuePointe r));
640 else if ((value->id >= CSSValueAuto && value->id <= CSSValueWebkitZo omOut) || value->id == CSSValueCopy || value->id == CSSValueNone)
641 list->append(cssValuePool().createIdentifierValue(value->id));
642 m_valueList->next();
643 parsedValue = list.release();
644 break;
645 } else if (value) {
646 id = value->id;
647 if (inQuirksMode() && value->id == CSSValueHand) { // MSIE 5 compati bility :/
648 id = CSSValuePointer;
649 validPrimitive = true;
650 } else if ((value->id >= CSSValueAuto && value->id <= CSSValueWebkit ZoomOut) || value->id == CSSValueCopy || value->id == CSSValueNone)
651 validPrimitive = true;
652 } else {
653 ASSERT_NOT_REACHED();
654 return false;
655 }
656 break;
657 }
658 case CSSPropertyImageOrientation:
659 if (RuntimeEnabledFeatures::imageOrientationEnabled())
660 validPrimitive = value->id == CSSValueFromImage || (value->unit() != CSSPrimitiveValue::UnitType::Number && validUnit(value, FAngle) && value->fValu e == 0);
661 break;
662
663 case CSSPropertyBackgroundBlendMode:
664 case CSSPropertyBackgroundAttachment:
665 case CSSPropertyBackgroundClip:
666 case CSSPropertyWebkitBackgroundClip:
667 case CSSPropertyWebkitBackgroundComposite:
668 case CSSPropertyBackgroundImage:
669 case CSSPropertyBackgroundOrigin:
670 case CSSPropertyMaskSourceType:
671 case CSSPropertyWebkitBackgroundOrigin:
672 case CSSPropertyBackgroundPosition:
673 case CSSPropertyBackgroundPositionX:
674 case CSSPropertyBackgroundPositionY:
675 case CSSPropertyBackgroundSize:
676 case CSSPropertyBackgroundRepeat:
677 case CSSPropertyWebkitMaskClip:
678 case CSSPropertyWebkitMaskComposite:
679 case CSSPropertyWebkitMaskImage:
680 case CSSPropertyWebkitMaskOrigin:
681 case CSSPropertyWebkitMaskPosition:
682 case CSSPropertyWebkitMaskPositionX:
683 case CSSPropertyWebkitMaskPositionY:
684 case CSSPropertyWebkitMaskSize:
685 case CSSPropertyWebkitMaskRepeat:
686 case CSSPropertyWebkitMaskRepeatX:
687 case CSSPropertyWebkitMaskRepeatY:
688 {
689 RefPtrWillBeRawPtr<CSSValue> val1 = nullptr;
690 RefPtrWillBeRawPtr<CSSValue> val2 = nullptr;
691 CSSPropertyID propId1, propId2;
692 bool result = false;
693 if (parseFillProperty(unresolvedProperty, propId1, propId2, val1, val2)) {
694 if (propId == CSSPropertyBackgroundPosition ||
695 propId == CSSPropertyBackgroundRepeat ||
696 propId == CSSPropertyWebkitMaskPosition ||
697 propId == CSSPropertyWebkitMaskRepeat) {
698 ShorthandScope scope(this, propId);
699 addProperty(propId1, val1.release(), important);
700 if (val2)
701 addProperty(propId2, val2.release(), important);
702 } else {
703 addProperty(propId1, val1.release(), important);
704 if (val2)
705 addProperty(propId2, val2.release(), important);
706 }
707 result = true;
708 }
709 m_implicitShorthand = false;
710 return result;
711 }
712 case CSSPropertyObjectPosition:
713 parsedValue = parsePosition(m_valueList);
714 break;
715 case CSSPropertyListStyleImage: // <uri> | none | inherit
716 case CSSPropertyBorderImageSource:
717 case CSSPropertyWebkitMaskBoxImageSource:
718 if (id == CSSValueNone) {
719 parsedValue = cssValuePool().createIdentifierValue(CSSValueNone);
720 m_valueList->next();
721 } else if (value->unit() == CSSPrimitiveValue::UnitType::URI) {
722 parsedValue = createCSSImageValueWithReferrer(value->string, complet eURL(value->string));
723 m_valueList->next();
724 } else if (isGeneratedImageValue(value)) {
725 if (parseGeneratedImage(m_valueList, parsedValue))
726 m_valueList->next();
727 else
728 return false;
729 } else if (value->m_unit == CSSParserValue::Function && value->function- >id == CSSValueWebkitImageSet) {
730 parsedValue = parseImageSet(m_valueList);
731 if (!parsedValue)
732 return false;
733 m_valueList->next();
734 }
735 break;
736
737 case CSSPropertyBorderTopWidth: //// <border-width> | inherit
738 case CSSPropertyBorderRightWidth: // Which is defined as
739 case CSSPropertyBorderBottomWidth: // thin | medium | thick | <length>
740 case CSSPropertyBorderLeftWidth:
741 if (!inShorthand() || m_currentShorthand == CSSPropertyBorderWidth)
742 unitless = FUnitlessQuirk;
743 // fall through
744 case CSSPropertyWebkitTextStrokeWidth:
745 case CSSPropertyOutlineWidth: // <border-width> | inherit
746 case CSSPropertyWebkitBorderStartWidth:
747 case CSSPropertyWebkitBorderEndWidth:
748 case CSSPropertyWebkitBorderBeforeWidth:
749 case CSSPropertyWebkitBorderAfterWidth:
750 case CSSPropertyWebkitColumnRuleWidth:
751 if (id == CSSValueThin || id == CSSValueMedium || id == CSSValueThick)
752 validPrimitive = true;
753 else
754 validPrimitive = validUnit(value, FLength | FNonNeg | unitless);
755 break;
756
757 case CSSPropertyLetterSpacing: // normal | <length> | inherit
758 case CSSPropertyWordSpacing: // normal | <length> | inherit
759 if (id == CSSValueNormal)
760 validPrimitive = true;
761 else
762 validPrimitive = validUnit(value, FLength | FUnitlessQuirk);
763 break;
764
765 case CSSPropertyTextIndent:
766 parsedValue = parseTextIndent();
767 break;
768
769 case CSSPropertyPaddingTop: //// <padding-width> | inherit
770 case CSSPropertyPaddingRight: // Which is defined as
771 case CSSPropertyPaddingBottom: // <length> | <percentage>
772 case CSSPropertyPaddingLeft: ////
773 unitless = FUnitlessQuirk;
774 // fall through
775 case CSSPropertyWebkitPaddingStart:
776 case CSSPropertyWebkitPaddingEnd:
777 case CSSPropertyWebkitPaddingBefore:
778 case CSSPropertyWebkitPaddingAfter:
779 validPrimitive = validUnit(value, FLength | FPercent | FNonNeg | unitles s);
780 break;
781
782 case CSSPropertyMaxWidth:
783 case CSSPropertyMaxHeight:
784 unitless = FUnitlessQuirk;
785 // fall through
786 case CSSPropertyWebkitMaxLogicalWidth:
787 case CSSPropertyWebkitMaxLogicalHeight:
788 validPrimitive = (id == CSSValueNone || validWidthOrHeight(value, unitle ss));
789 break;
790
791 case CSSPropertyMinWidth:
792 case CSSPropertyMinHeight:
793 case CSSPropertyWidth:
794 case CSSPropertyHeight:
795 unitless = FUnitlessQuirk;
796 // fall through
797 case CSSPropertyWebkitMinLogicalWidth:
798 case CSSPropertyWebkitMinLogicalHeight:
799 case CSSPropertyWebkitLogicalWidth:
800 case CSSPropertyWebkitLogicalHeight:
801 validPrimitive = (id == CSSValueAuto || validWidthOrHeight(value, unitle ss));
802 break;
803
804 case CSSPropertyFontSize:
805 return parseFontSize(important);
806
807 case CSSPropertyFontVariant: // normal | small-caps | inherit
808 return parseFontVariant(important);
809
810 case CSSPropertyVerticalAlign:
811 // baseline | sub | super | top | text-top | middle | bottom | text-bott om |
812 // <percentage> | <length> | inherit
813
814 if (id >= CSSValueBaseline && id <= CSSValueWebkitBaselineMiddle)
815 validPrimitive = true;
816 else
817 validPrimitive = validUnit(value, FLength | FPercent | FUnitlessQuir k);
818 break;
819
820 case CSSPropertyBottom: // <length> | <percentage> | auto | in herit
821 case CSSPropertyLeft: // <length> | <percentage> | auto | in herit
822 case CSSPropertyRight: // <length> | <percentage> | auto | in herit
823 case CSSPropertyTop: // <length> | <percentage> | auto | in herit
824 case CSSPropertyMarginTop: //// <margin-width> | inherit
825 case CSSPropertyMarginRight: // Which is defined as
826 case CSSPropertyMarginBottom: // <length> | <percentage> | auto | i nherit
827 case CSSPropertyMarginLeft: ////
828 unitless = FUnitlessQuirk;
829 // fall through
830 case CSSPropertyWebkitMarginStart:
831 case CSSPropertyWebkitMarginEnd:
832 case CSSPropertyWebkitMarginBefore:
833 case CSSPropertyWebkitMarginAfter:
834 if (id == CSSValueAuto)
835 validPrimitive = true;
836 else
837 validPrimitive = validUnit(value, FLength | FPercent | unitless);
838 break;
839
840 case CSSPropertyOrphans: // <integer> | inherit | auto (We've added support for auto for backwards compatibility)
841 case CSSPropertyWidows: // <integer> | inherit | auto (Ditto)
842 if (id == CSSValueAuto)
843 validPrimitive = true;
844 else
845 validPrimitive = validUnit(value, FPositiveInteger);
846 break;
847
848 case CSSPropertyZIndex: // auto | <integer> | inherit
849 if (id == CSSValueAuto) {
850 validPrimitive = true;
851 } else if (validUnit(value, FInteger)) {
852 addProperty(propId, cssValuePool().createValue(value->fValue, CSSPri mitiveValue::UnitType::Integer), important);
853 return true;
854 }
855 break;
856
857 case CSSPropertyLineHeight:
858 parsedValue = parseLineHeight();
859 break;
860 case CSSPropertyCounterIncrement:
861 if (id == CSSValueNone)
862 validPrimitive = true;
863 else
864 parsedValue = parseCounter(1);
865 break;
866 case CSSPropertyCounterReset:
867 if (id == CSSValueNone)
868 validPrimitive = true;
869 else
870 parsedValue = parseCounter(0);
871 break;
872 case CSSPropertyFontFamily:
873 // [[ <family-name> | <generic-family> ],]* [<family-name> | <generic-fa mily>] | inherit
874 {
875 parsedValue = parseFontFamily();
876 break;
877 }
878
879 case CSSPropertyTextDecoration:
880 // Fall through 'text-decoration-line' parsing if CSS 3 Text Decoration
881 // is disabled to match CSS 2.1 rules for parsing 'text-decoration'.
882 if (RuntimeEnabledFeatures::css3TextDecorationsEnabled()) {
883 // [ <text-decoration-line> || <text-decoration-style> || <text-deco ration-color> ] | inherit
884 return parseShorthand(CSSPropertyTextDecoration, textDecorationShort hand(), important);
885 }
886 case CSSPropertyWebkitTextDecorationsInEffect:
887 case CSSPropertyTextDecorationLine:
888 // none | [ underline || overline || line-through || blink ] | inherit
889 parsedValue = parseTextDecoration();
890 break;
891
892 case CSSPropertyTextUnderlinePosition:
893 // auto | [ under || [ left | right ] ], but we only support auto | unde r for now
894 ASSERT(RuntimeEnabledFeatures::css3TextDecorationsEnabled());
895 validPrimitive = (id == CSSValueAuto || id == CSSValueUnder);
896 break;
897
898 case CSSPropertyZoom: // normal | reset | document | <number> | <pe rcentage> | inherit
899 if (id == CSSValueNormal || id == CSSValueReset || id == CSSValueDocumen t)
900 validPrimitive = true;
901 else
902 validPrimitive = validUnit(value, FNumber | FPercent | FNonNeg);
903 if (validPrimitive && m_context.useCounter()
904 && !(id == CSSValueNormal
905 || (value->unit() == CSSPrimitiveValue::UnitType::Number && valu e->fValue == 1)
906 || (value->unit() == CSSPrimitiveValue::UnitType::Percentage && value->fValue == 100)))
907 m_context.useCounter()->count(UseCounter::CSSZoomNotEqualToOne);
908 break;
909
910 case CSSPropertySrc:
911 case CSSPropertyUnicodeRange:
912 /* @font-face only descriptors */
913 break;
914
915 /* CSS3 properties */
916
917 case CSSPropertyBorderImage:
918 case CSSPropertyWebkitMaskBoxImage:
919 return parseBorderImageShorthand(propId, important);
920 case CSSPropertyWebkitBorderImage: {
921 if (RefPtrWillBeRawPtr<CSSValue> result = parseBorderImage(propId)) {
922 addProperty(propId, result, important);
923 return true;
924 }
925 return false; 238 return false;
926 } 239 }
927
928 case CSSPropertyBorderImageOutset:
929 case CSSPropertyWebkitMaskBoxImageOutset: {
930 RefPtrWillBeRawPtr<CSSQuadValue> result = nullptr;
931 if (parseBorderImageOutset(result)) {
932 addProperty(propId, result, important);
933 return true;
934 }
935 break;
936 }
937 case CSSPropertyBorderImageRepeat:
938 case CSSPropertyWebkitMaskBoxImageRepeat: {
939 RefPtrWillBeRawPtr<CSSValue> result = nullptr;
940 if (parseBorderImageRepeat(result)) {
941 addProperty(propId, result, important);
942 return true;
943 }
944 break;
945 }
946 case CSSPropertyBorderImageSlice:
947 case CSSPropertyWebkitMaskBoxImageSlice: {
948 RefPtrWillBeRawPtr<CSSBorderImageSliceValue> result = nullptr;
949 if (parseBorderImageSlice(propId, result)) {
950 addProperty(propId, result, important);
951 return true;
952 }
953 break;
954 }
955 case CSSPropertyBorderImageWidth:
956 case CSSPropertyWebkitMaskBoxImageWidth: {
957 RefPtrWillBeRawPtr<CSSQuadValue> result = nullptr;
958 if (parseBorderImageWidth(result)) {
959 addProperty(propId, result, important);
960 return true;
961 }
962 break;
963 }
964 case CSSPropertyBorderTopRightRadius:
965 case CSSPropertyBorderTopLeftRadius:
966 case CSSPropertyBorderBottomLeftRadius:
967 case CSSPropertyBorderBottomRightRadius: {
968 validPrimitive = validUnit(value, FLength | FPercent | FNonNeg);
969 if (!validPrimitive)
970 return false;
971 RefPtrWillBeRawPtr<CSSPrimitiveValue> parsedValue1 = createPrimitiveNume ricValue(value);
972 RefPtrWillBeRawPtr<CSSPrimitiveValue> parsedValue2 = nullptr;
973 value = m_valueList->next();
974 if (value) {
975 validPrimitive = validUnit(value, FLength | FPercent | FNonNeg);
976 if (!validPrimitive)
977 return false;
978 parsedValue2 = createPrimitiveNumericValue(value);
979 } else
980 parsedValue2 = parsedValue1;
981
982 if (m_valueList->next())
983 return false;
984 addProperty(propId, CSSValuePair::create(parsedValue1.release(), parsedV alue2.release(), CSSValuePair::DropIdenticalValues), important);
985 return true;
986 }
987 case CSSPropertyTabSize:
988 // May be specified as a unit-less non-negative integer or length indica ting number of space characters.
989 validPrimitive = validUnit(value, FInteger | FLength | FNonNeg);
990 break;
991 case CSSPropertyBorderRadius:
992 case CSSPropertyAliasWebkitBorderRadius:
993 return parseBorderRadius(unresolvedProperty, important);
994 case CSSPropertyOutlineOffset:
995 validPrimitive = validUnit(value, FLength);
996 break;
997 case CSSPropertyTextShadow: // CSS2 property, dropped in CSS2.1, back in CSS 3, so treat as CSS3
998 case CSSPropertyBoxShadow:
999 if (id == CSSValueNone)
1000 validPrimitive = true;
1001 else
1002 parsedValue = parseShadow(m_valueList, propId);
1003 break;
1004 case CSSPropertyWebkitBoxReflect:
1005 if (id == CSSValueNone)
1006 validPrimitive = true;
1007 else
1008 parsedValue = parseReflect();
1009 break;
1010 case CSSPropertyFontSizeAdjust: // none | <number>
1011 ASSERT(RuntimeEnabledFeatures::cssFontSizeAdjustEnabled());
1012 validPrimitive = (id == CSSValueNone) ? true : validUnit(value, FNumber | FNonNeg);
1013 break;
1014 case CSSPropertyOpacity:
1015 case CSSPropertyWebkitBoxFlex:
1016 validPrimitive = validUnit(value, FNumber);
1017 break;
1018 case CSSPropertyWebkitBoxFlexGroup:
1019 validPrimitive = validUnit(value, FInteger | FNonNeg);
1020 break;
1021 case CSSPropertyWebkitBoxOrdinalGroup:
1022 validPrimitive = validUnit(value, FInteger | FNonNeg) && value->fValue;
1023 break;
1024 case CSSPropertyWebkitFilter:
1025 case CSSPropertyBackdropFilter:
1026 if (id == CSSValueNone)
1027 validPrimitive = true;
1028 else {
1029 RefPtrWillBeRawPtr<CSSValue> val = parseFilter();
1030 if (val) {
1031 addProperty(propId, val, important);
1032 return true;
1033 }
1034 return false;
1035 }
1036 break;
1037 case CSSPropertyFlex: {
1038 ShorthandScope scope(this, propId);
1039 if (id == CSSValueNone) {
1040 addProperty(CSSPropertyFlexGrow, cssValuePool().createValue(0, CSSPr imitiveValue::UnitType::Number), important);
1041 addProperty(CSSPropertyFlexShrink, cssValuePool().createValue(0, CSS PrimitiveValue::UnitType::Number), important);
1042 addProperty(CSSPropertyFlexBasis, cssValuePool().createIdentifierVal ue(CSSValueAuto), important);
1043 return true;
1044 }
1045 return parseFlex(m_valueList, important);
1046 }
1047 case CSSPropertyFlexBasis:
1048 // FIXME: Support intrinsic dimensions too.
1049 if (id == CSSValueAuto)
1050 validPrimitive = true;
1051 else
1052 validPrimitive = validUnit(value, FLength | FPercent | FNonNeg);
1053 break;
1054 case CSSPropertyFlexGrow:
1055 case CSSPropertyFlexShrink:
1056 validPrimitive = validUnit(value, FNumber | FNonNeg);
1057 break;
1058 case CSSPropertyOrder:
1059 validPrimitive = validUnit(value, FInteger);
1060 break;
1061 case CSSPropertyTransform:
1062 if (id == CSSValueNone)
1063 validPrimitive = true;
1064 else
1065 parsedValue = parseTransform(unresolvedProperty == CSSPropertyAliasW ebkitTransform);
1066 break;
1067 case CSSPropertyTransformOrigin: {
1068 RefPtrWillBeRawPtr<CSSValueList> list = parseTransformOrigin();
1069 if (!list)
1070 return false;
1071 // These values are added to match gecko serialization.
1072 if (list->length() == 1)
1073 list->append(cssValuePool().createValue(50, CSSPrimitiveValue::UnitT ype::Percentage));
1074 if (list->length() == 2)
1075 list->append(cssValuePool().createValue(0, CSSPrimitiveValue::UnitTy pe::Pixels));
1076 addProperty(propId, list.release(), important);
1077 return true;
1078 }
1079
1080 case CSSPropertyTranslate: {
1081 // translate : [ <length> | <percentage> ] [[ <length> | <percentage> ] <length>? ]?
1082 // defaults to 0 on all axis, note that the last value CANNOT be a perce ntage
1083 ASSERT(RuntimeEnabledFeatures::cssIndependentTransformPropertiesEnabled( ));
1084 RefPtrWillBeRawPtr<CSSValueList> list = CSSValueList::createSpaceSeparat ed();
1085 if (!validUnit(value, FLength | FPercent))
1086 return false;
1087
1088 list->append(createPrimitiveNumericValue(value));
1089 value = m_valueList->next();
1090
1091 if (value) {
1092 if (!validUnit(value, FLength | FPercent))
1093 return false;
1094
1095 list->append(createPrimitiveNumericValue(value));
1096 value = m_valueList->next();
1097
1098 if (value) {
1099 if (!validUnit(value, FLength))
1100 return false;
1101
1102 list->append(createPrimitiveNumericValue(value));
1103 value = m_valueList->next();
1104 }
1105 }
1106
1107 parsedValue = list.release();
1108 break;
1109 }
1110
1111 case CSSPropertyRotate: { // rotate : <angle> <number>{3}? defaults to a 0 0 1
1112 ASSERT(RuntimeEnabledFeatures::cssIndependentTransformPropertiesEnabled( ));
1113 RefPtrWillBeRawPtr<CSSValueList> list = CSSValueList::createSpaceSeparat ed();
1114
1115 if (!validUnit(value, FAngle))
1116 return false;
1117 list->append(createPrimitiveNumericValue(value));
1118 value = m_valueList->next();
1119
1120 if (!value) {
1121 parsedValue = list.release();
1122 break;
1123 }
1124
1125 for (unsigned i = 0; i < 3; i++) { // 3 dimensions of rotation
1126 if (!value || !validUnit(value, FNumber))
1127 return false;
1128 list->append(createPrimitiveNumericValue(value));
1129 value = m_valueList->next();
1130 }
1131
1132 parsedValue = list.release();
1133 break;
1134 }
1135
1136 case CSSPropertyScale: { // scale: <number>{1,3}, default scale for all axis is 1
1137 ASSERT(RuntimeEnabledFeatures::cssIndependentTransformPropertiesEnabled( ));
1138 RefPtrWillBeRawPtr<CSSValueList> scaleList = CSSValueList::createSpaceSe parated();
1139
1140 for (unsigned i = 0; value && i < 3; i++) { // up to 3 dimensions of sca le
1141 if (!validUnit(value, FNumber))
1142 return false;
1143 scaleList->append(createPrimitiveNumericValue(value));
1144 value = m_valueList->next();
1145 }
1146
1147 parsedValue = scaleList.release();
1148 break;
1149 }
1150
1151 case CSSPropertyWebkitPerspectiveOriginX:
1152 case CSSPropertyWebkitTransformOriginX:
1153 parsedValue = parseFillPositionX(m_valueList);
1154 if (parsedValue)
1155 m_valueList->next();
1156 break;
1157 case CSSPropertyWebkitPerspectiveOriginY:
1158 case CSSPropertyWebkitTransformOriginY:
1159 parsedValue = parseFillPositionY(m_valueList);
1160 if (parsedValue)
1161 m_valueList->next();
1162 break;
1163 case CSSPropertyWebkitTransformOriginZ:
1164 validPrimitive = validUnit(value, FLength);
1165 break;
1166 case CSSPropertyPerspective:
1167 if (id == CSSValueNone) {
1168 validPrimitive = true;
1169 } else if (validUnit(value, FLength) && (m_parsedCalculation || value->f Value > 0)) {
1170 validPrimitive = true;
1171 } else if (unresolvedProperty == CSSPropertyAliasWebkitPerspective && va lidUnit(value, FNumber) && value->fValue > 0) {
1172 value->setUnit(CSSPrimitiveValue::UnitType::Pixels);
1173 validPrimitive = true;
1174 } else {
1175 return false;
1176 }
1177 break;
1178 case CSSPropertyPerspectiveOrigin: {
1179 RefPtrWillBeRawPtr<CSSValueList> list = parseTransformOrigin();
1180 if (!list || list->length() == 3)
1181 return false;
1182 // This values are added to match gecko serialization.
1183 if (list->length() == 1)
1184 list->append(cssValuePool().createValue(50, CSSPrimitiveValue::UnitT ype::Percentage));
1185 addProperty(propId, list.release(), important);
1186 return true;
1187 }
1188
1189 case CSSPropertyMotion:
1190 // <motion-path> && <motion-offset> && <motion-rotation>
1191 ASSERT(RuntimeEnabledFeatures::cssMotionPathEnabled());
1192 return parseShorthand(propId, motionShorthand(), important);
1193 case CSSPropertyMotionPath:
1194 ASSERT(RuntimeEnabledFeatures::cssMotionPathEnabled());
1195 if (id == CSSValueNone)
1196 validPrimitive = true;
1197 else
1198 parsedValue = parseMotionPath();
1199 break;
1200 case CSSPropertyMotionOffset:
1201 ASSERT(RuntimeEnabledFeatures::cssMotionPathEnabled());
1202 validPrimitive = validUnit(value, FLength | FPercent);
1203 break;
1204 case CSSPropertyMotionRotation:
1205 ASSERT(RuntimeEnabledFeatures::cssMotionPathEnabled());
1206 parsedValue = parseMotionRotation();
1207 break;
1208
1209 case CSSPropertyAnimationDelay:
1210 case CSSPropertyAnimationDirection:
1211 case CSSPropertyAnimationDuration:
1212 case CSSPropertyAnimationFillMode:
1213 case CSSPropertyAnimationName:
1214 case CSSPropertyAnimationPlayState:
1215 case CSSPropertyAnimationIterationCount:
1216 case CSSPropertyAnimationTimingFunction:
1217 case CSSPropertyTransitionDelay:
1218 case CSSPropertyTransitionDuration:
1219 case CSSPropertyTransitionTimingFunction:
1220 case CSSPropertyTransitionProperty:
1221 parsedValue = parseAnimationPropertyList(propId, unresolvedProperty == C SSPropertyAliasWebkitAnimationName);
1222 break;
1223
1224 case CSSPropertyJustifyContent:
1225 parsedValue = parseContentDistributionOverflowPosition();
1226 break;
1227 case CSSPropertyJustifySelf:
1228 ASSERT(RuntimeEnabledFeatures::cssGridLayoutEnabled());
1229 return parseItemPositionOverflowPosition(propId, important);
1230 case CSSPropertyJustifyItems:
1231 ASSERT(RuntimeEnabledFeatures::cssGridLayoutEnabled());
1232
1233 if (parseLegacyPosition(propId, important))
1234 return true;
1235
1236 m_valueList->setCurrentIndex(0);
1237 return parseItemPositionOverflowPosition(propId, important);
1238 case CSSPropertyGridAutoFlow:
1239 ASSERT(RuntimeEnabledFeatures::cssGridLayoutEnabled());
1240 parsedValue = parseGridAutoFlow(*m_valueList);
1241 break;
1242 case CSSPropertyGridAutoColumns:
1243 case CSSPropertyGridAutoRows:
1244 ASSERT(RuntimeEnabledFeatures::cssGridLayoutEnabled());
1245 parsedValue = parseGridTrackSize(*m_valueList);
1246 break;
1247
1248 case CSSPropertyGridTemplateColumns:
1249 case CSSPropertyGridTemplateRows:
1250 ASSERT(RuntimeEnabledFeatures::cssGridLayoutEnabled());
1251 parsedValue = parseGridTrackList();
1252 break;
1253
1254 case CSSPropertyGridColumnEnd:
1255 case CSSPropertyGridColumnStart:
1256 case CSSPropertyGridRowEnd:
1257 case CSSPropertyGridRowStart:
1258 ASSERT(RuntimeEnabledFeatures::cssGridLayoutEnabled());
1259 parsedValue = parseGridPosition();
1260 break;
1261
1262 case CSSPropertyGridColumn:
1263 case CSSPropertyGridRow:
1264 ASSERT(RuntimeEnabledFeatures::cssGridLayoutEnabled());
1265 return parseGridItemPositionShorthand(propId, important);
1266
1267 case CSSPropertyGridArea:
1268 ASSERT(RuntimeEnabledFeatures::cssGridLayoutEnabled());
1269 return parseGridAreaShorthand(important);
1270
1271 case CSSPropertyGridTemplateAreas:
1272 ASSERT(RuntimeEnabledFeatures::cssGridLayoutEnabled());
1273 parsedValue = parseGridTemplateAreas();
1274 break;
1275
1276 case CSSPropertyGridTemplate:
1277 ASSERT(RuntimeEnabledFeatures::cssGridLayoutEnabled());
1278 return parseGridTemplateShorthand(important);
1279
1280 case CSSPropertyGrid:
1281 ASSERT(RuntimeEnabledFeatures::cssGridLayoutEnabled());
1282 return parseGridShorthand(important);
1283
1284 case CSSPropertyWebkitMarginCollapse: {
1285 ShorthandScope scope(this, CSSPropertyWebkitMarginCollapse);
1286 if (!parseValue(webkitMarginCollapseShorthand().properties()[0], importa nt))
1287 return false;
1288 if (!m_valueList->current()) {
1289 CSSValue* value = m_parsedProperties.last().value();
1290 addProperty(webkitMarginCollapseShorthand().properties()[1], value, important);
1291 return true;
1292 }
1293 if (!parseValue(webkitMarginCollapseShorthand().properties()[1], importa nt))
1294 return false;
1295 return !m_valueList->current();
1296 }
1297 case CSSPropertyWebkitColumnCount:
1298 parsedValue = parseColumnCount();
1299 break;
1300 case CSSPropertyWebkitColumnGap: // normal | <length>
1301 if (id == CSSValueNormal)
1302 validPrimitive = true;
1303 else
1304 validPrimitive = validUnit(value, FLength | FNonNeg);
1305 break;
1306 case CSSPropertyWebkitColumnSpan: // none | all | 1 (will be dropped in the unprefixed property)
1307 validPrimitive = id == CSSValueAll || id == CSSValueNone || (value->unit () == CSSPrimitiveValue::UnitType::Number && value->fValue == 1);
1308 break;
1309 case CSSPropertyWebkitColumnWidth: // auto | <length>
1310 parsedValue = parseColumnWidth();
1311 break;
1312 case CSSPropertyWillChange:
1313 parsedValue = parseWillChange();
1314 break;
1315 // End of CSS3 properties
1316
1317 // Apple specific properties. These will never be standardized and are pure ly to
1318 // support custom WebKit-based Apple applications.
1319 case CSSPropertyWebkitLineClamp:
1320 // When specifying number of lines, don't allow 0 as a valid value
1321 // When specifying either type of unit, require non-negative integers
1322 validPrimitive = (!id && !isCalculation(value) && validUnit(value, FInte ger | FPercent | FNonNeg) && (value->unit() == CSSPrimitiveValue::UnitType::Perc entage || value->fValue));
1323 break;
1324
1325 case CSSPropertyWebkitFontSizeDelta: // <length>
1326 validPrimitive = validUnit(value, FLength | FUnitlessQuirk);
1327 break;
1328
1329 case CSSPropertyWebkitHighlight:
1330 if (id == CSSValueNone) {
1331 validPrimitive = true;
1332 } else if (value->unit() == CSSPrimitiveValue::UnitType::String) {
1333 parsedValue = createPrimitiveStringValue(value);
1334 m_valueList->next();
1335 }
1336 break;
1337
1338 case CSSPropertyWebkitHyphenateCharacter:
1339 case CSSPropertyWebkitLocale:
1340 if (id == CSSValueAuto) {
1341 validPrimitive = true;
1342 } else if (value->unit() == CSSPrimitiveValue::UnitType::String) {
1343 parsedValue = createPrimitiveStringValue(value);
1344 m_valueList->next();
1345 }
1346 break;
1347
1348 // End Apple-specific properties
1349
1350 case CSSPropertyWebkitAppRegion:
1351 if (id >= CSSValueDrag && id <= CSSValueNoDrag)
1352 validPrimitive = true;
1353 break;
1354
1355 case CSSPropertyWebkitTapHighlightColor:
1356 parsedValue = parseColor(m_valueList->current());
1357 if (parsedValue)
1358 m_valueList->next();
1359 break;
1360
1361 /* shorthand properties */
1362 case CSSPropertyBackground: {
1363 // Position must come before color in this array because a plain old "0" is a legal color
1364 // in quirks mode but it's usually the X coordinate of a position.
1365 const CSSPropertyID properties[] = { CSSPropertyBackgroundImage, CSSProp ertyBackgroundRepeat,
1366 CSSPropertyBackgroundAttachment, CSSPropertyB ackgroundPosition, CSSPropertyBackgroundOrigin,
1367 CSSPropertyBackgroundClip, CSSPropertyBackgro undColor, CSSPropertyBackgroundSize };
1368 return parseFillShorthand(propId, properties, WTF_ARRAY_LENGTH(propertie s), important);
1369 }
1370 case CSSPropertyWebkitMask: {
1371 const CSSPropertyID properties[] = { CSSPropertyWebkitMaskImage, CSSProp ertyWebkitMaskRepeat,
1372 CSSPropertyWebkitMaskPosition, CSSPropertyWebkitMaskOrigin, CSSPrope rtyWebkitMaskClip, CSSPropertyWebkitMaskSize };
1373 return parseFillShorthand(propId, properties, WTF_ARRAY_LENGTH(propertie s), important);
1374 }
1375 case CSSPropertyBorder:
1376 // [ 'border-width' || 'border-style' || <color> ] | inherit
1377 {
1378 if (parseShorthand(propId, borderShorthandForParsing(), important)) {
1379 // The CSS3 Borders and Backgrounds specification says that border a lso resets border-image. It's as
1380 // though a value of none was specified for the image.
1381 addExpandedPropertyForValue(CSSPropertyBorderImage, cssValuePool().c reateImplicitInitialValue(), important);
1382 return true;
1383 }
1384 return false;
1385 }
1386 case CSSPropertyBorderTop:
1387 // [ 'border-top-width' || 'border-style' || <color> ] | inherit
1388 return parseShorthand(propId, borderTopShorthand(), important);
1389 case CSSPropertyBorderRight:
1390 // [ 'border-right-width' || 'border-style' || <color> ] | inherit
1391 return parseShorthand(propId, borderRightShorthand(), important);
1392 case CSSPropertyBorderBottom:
1393 // [ 'border-bottom-width' || 'border-style' || <color> ] | inherit
1394 return parseShorthand(propId, borderBottomShorthand(), important);
1395 case CSSPropertyBorderLeft:
1396 // [ 'border-left-width' || 'border-style' || <color> ] | inherit
1397 return parseShorthand(propId, borderLeftShorthand(), important);
1398 case CSSPropertyWebkitBorderStart:
1399 return parseShorthand(propId, webkitBorderStartShorthand(), important);
1400 case CSSPropertyWebkitBorderEnd:
1401 return parseShorthand(propId, webkitBorderEndShorthand(), important);
1402 case CSSPropertyWebkitBorderBefore:
1403 return parseShorthand(propId, webkitBorderBeforeShorthand(), important);
1404 case CSSPropertyWebkitBorderAfter:
1405 return parseShorthand(propId, webkitBorderAfterShorthand(), important);
1406 case CSSPropertyOutline:
1407 // [ 'outline-color' || 'outline-style' || 'outline-width' ] | inherit
1408 return parseShorthand(propId, outlineShorthand(), important);
1409 case CSSPropertyBorderColor:
1410 // <color>{1,4} | inherit
1411 return parse4Values(propId, borderColorShorthand().properties(), importa nt);
1412 case CSSPropertyBorderWidth:
1413 // <border-width>{1,4} | inherit
1414 return parse4Values(propId, borderWidthShorthand().properties(), importa nt);
1415 case CSSPropertyBorderStyle:
1416 // <border-style>{1,4} | inherit
1417 return parse4Values(propId, borderStyleShorthand().properties(), importa nt);
1418 case CSSPropertyMargin:
1419 // <margin-width>{1,4} | inherit
1420 return parse4Values(propId, marginShorthand().properties(), important);
1421 case CSSPropertyPadding:
1422 // <padding-width>{1,4} | inherit
1423 return parse4Values(propId, paddingShorthand().properties(), important);
1424 case CSSPropertyFlexFlow:
1425 return parseShorthand(propId, flexFlowShorthand(), important);
1426 case CSSPropertyFont:
1427 // [ [ 'font-style' || 'font-variant' || 'font-weight' ]? 'font-size' [ / 'line-height' ]?
1428 // 'font-family' ] | caption | icon | menu | message-box | small-caption | status-bar | inherit
1429 if (id >= CSSValueCaption && id <= CSSValueStatusBar)
1430 return parseSystemFont(important);
1431 return parseFont(important);
1432 case CSSPropertyListStyle:
1433 return parseShorthand(propId, listStyleShorthand(), important);
1434 case CSSPropertyWebkitColumns:
1435 return parseColumnsShorthand(important);
1436 case CSSPropertyWebkitColumnRule:
1437 return parseShorthand(propId, webkitColumnRuleShorthand(), important);
1438 case CSSPropertyWebkitTextStroke:
1439 return parseShorthand(propId, webkitTextStrokeShorthand(), important);
1440 case CSSPropertyAnimation:
1441 return parseAnimationShorthand(unresolvedProperty == CSSPropertyAliasWeb kitAnimation, important);
1442 case CSSPropertyTransition:
1443 return parseTransitionShorthand(important);
1444 case CSSPropertyInvalid:
1445 return false;
1446 case CSSPropertyPage:
1447 parsedValue = parsePage();
1448 break;
1449 // CSS Text Layout Module Level 3: Vertical writing support
1450 case CSSPropertyWebkitTextEmphasis:
1451 return parseShorthand(propId, webkitTextEmphasisShorthand(), important);
1452
1453 case CSSPropertyWebkitTextEmphasisStyle:
1454 parsedValue = parseTextEmphasisStyle();
1455 break;
1456
1457 case CSSPropertyWebkitTextOrientation:
1458 // FIXME: For now just support sideways, sideways-right, upright and ver tical-right.
1459 if (id == CSSValueSideways || id == CSSValueSidewaysRight || id == CSSVa lueVerticalRight || id == CSSValueUpright)
1460 validPrimitive = true;
1461 break;
1462
1463 case CSSPropertyWebkitFontFeatureSettings:
1464 if (id == CSSValueNormal)
1465 validPrimitive = true;
1466 else
1467 parsedValue = parseFontFeatureSettings();
1468 break;
1469
1470 case CSSPropertyFontVariantLigatures:
1471 if (id == CSSValueNormal)
1472 validPrimitive = true;
1473 else
1474 return parseFontVariantLigatures(important);
1475 break;
1476 case CSSPropertyWebkitClipPath:
1477 if (id == CSSValueNone) {
1478 validPrimitive = true;
1479 } else if (value->m_unit == CSSParserValue::Function) {
1480 parsedValue = parseBasicShape();
1481 } else if (value->unit() == CSSPrimitiveValue::UnitType::URI) {
1482 parsedValue = CSSPrimitiveValue::create(value->string, CSSPrimitiveV alue::UnitType::URI);
1483 addProperty(propId, parsedValue.release(), important);
1484 return true;
1485 }
1486 break;
1487 case CSSPropertyShapeOutside:
1488 if (id == CSSValueNone)
1489 validPrimitive = true;
1490 else
1491 parsedValue = parseShapeProperty(propId);
1492 break;
1493 case CSSPropertyShapeMargin:
1494 validPrimitive = validUnit(value, FLength | FPercent | FNonNeg);
1495 break;
1496 case CSSPropertyShapeImageThreshold:
1497 validPrimitive = validUnit(value, FNumber);
1498 break;
1499
1500 case CSSPropertyTouchAction:
1501 parsedValue = parseTouchAction();
1502 break;
1503
1504 case CSSPropertyAlignContent:
1505 parsedValue = parseContentDistributionOverflowPosition();
1506 break;
1507
1508 case CSSPropertyAlignSelf:
1509 ASSERT(RuntimeEnabledFeatures::cssGridLayoutEnabled());
1510 return parseItemPositionOverflowPosition(propId, important);
1511
1512 case CSSPropertyAlignItems:
1513 ASSERT(RuntimeEnabledFeatures::cssGridLayoutEnabled());
1514 return parseItemPositionOverflowPosition(propId, important);
1515
1516 // Properties below are validated inside parseViewportProperty, because we
1517 // check for parser state. We need to invalidate if someone adds them outsid e
1518 // a @viewport rule.
1519 case CSSPropertyMaxZoom:
1520 case CSSPropertyMinZoom:
1521 case CSSPropertyOrientation:
1522 case CSSPropertyUserZoom:
1523 validPrimitive = false;
1524 break;
1525
1526 case CSSPropertyScrollSnapPointsX:
1527 case CSSPropertyScrollSnapPointsY:
1528 parsedValue = parseScrollSnapPoints();
1529 break;
1530 case CSSPropertyScrollSnapCoordinate:
1531 parsedValue = parseScrollSnapCoordinate();
1532 break;
1533 case CSSPropertyScrollSnapDestination:
1534 parsedValue = parsePosition(m_valueList);
1535 break;
1536
1537 default:
1538 return parseSVGValue(propId, important);
1539 }
1540
1541 if (validPrimitive) {
1542 parsedValue = parseValidPrimitive(id, value);
1543 m_valueList->next();
1544 }
1545 ASSERT(!m_parsedCalculation);
1546 if (parsedValue) {
1547 if (!m_valueList->current() || inShorthand()) {
1548 addProperty(propId, parsedValue.release(), important);
1549 return true;
1550 }
1551 }
1552 return false;
1553 }
1554
1555 void CSSPropertyParser::addFillValue(RefPtrWillBeRawPtr<CSSValue>& lval, PassRef PtrWillBeRawPtr<CSSValue> rval)
1556 {
1557 if (lval) {
1558 if (lval->isBaseValueList())
1559 toCSSValueList(lval.get())->append(rval);
1560 else {
1561 PassRefPtrWillBeRawPtr<CSSValue> oldlVal(lval.release());
1562 PassRefPtrWillBeRawPtr<CSSValueList> list = CSSValueList::createComm aSeparated();
1563 list->append(oldlVal);
1564 list->append(rval);
1565 lval = list;
1566 }
1567 }
1568 else
1569 lval = rval;
1570 }
1571
1572 static bool parseBackgroundClip(CSSParserValue* parserValue, RefPtrWillBeRawPtr< CSSValue>& cssValue)
1573 {
1574 if (parserValue->id == CSSValueBorderBox || parserValue->id == CSSValuePaddi ngBox
1575 || parserValue->id == CSSValueContentBox || parserValue->id == CSSValueW ebkitText) {
1576 cssValue = cssValuePool().createIdentifierValue(parserValue->id);
1577 return true;
1578 }
1579 return false;
1580 }
1581
1582 const int cMaxFillProperties = 9;
1583
1584 bool CSSPropertyParser::parseFillShorthand(CSSPropertyID propId, const CSSProper tyID* properties, int numProperties, bool important)
1585 {
1586 ASSERT(numProperties <= cMaxFillProperties);
1587 if (numProperties > cMaxFillProperties)
1588 return false;
1589
1590 ShorthandScope scope(this, propId);
1591
1592 bool parsedProperty[cMaxFillProperties] = { false };
1593 RefPtrWillBeRawPtr<CSSValue> values[cMaxFillProperties];
1594 #if ENABLE(OILPAN)
1595 // Zero initialize the array of raw pointers.
1596 memset(&values, 0, sizeof(values));
1597 #endif
1598 RefPtrWillBeRawPtr<CSSValue> clipValue = nullptr;
1599 RefPtrWillBeRawPtr<CSSValue> positionYValue = nullptr;
1600 RefPtrWillBeRawPtr<CSSValue> repeatYValue = nullptr;
1601 bool foundClip = false;
1602 int i;
1603 bool foundPositionCSSProperty = false;
1604
1605 while (m_valueList->current()) {
1606 CSSParserValue* val = m_valueList->current();
1607 if (isComma(val)) {
1608 // We hit the end. Fill in all remaining values with the initial va lue.
1609 m_valueList->next();
1610 for (i = 0; i < numProperties; ++i) {
1611 if (properties[i] == CSSPropertyBackgroundColor && parsedPropert y[i])
1612 // Color is not allowed except as the last item in a list fo r backgrounds.
1613 // Reject the entire property.
1614 return false;
1615
1616 if (!parsedProperty[i] && properties[i] != CSSPropertyBackground Color) {
1617 addFillValue(values[i], cssValuePool().createImplicitInitial Value());
1618 if (properties[i] == CSSPropertyBackgroundPosition || proper ties[i] == CSSPropertyWebkitMaskPosition)
1619 addFillValue(positionYValue, cssValuePool().createImplic itInitialValue());
1620 if (properties[i] == CSSPropertyBackgroundRepeat || properti es[i] == CSSPropertyWebkitMaskRepeat)
1621 addFillValue(repeatYValue, cssValuePool().createImplicit InitialValue());
1622 if ((properties[i] == CSSPropertyBackgroundOrigin || propert ies[i] == CSSPropertyWebkitMaskOrigin) && !parsedProperty[i]) {
1623 // If background-origin wasn't present, then reset backg round-clip also.
1624 addFillValue(clipValue, cssValuePool().createImplicitIni tialValue());
1625 }
1626 }
1627 parsedProperty[i] = false;
1628 }
1629 if (!m_valueList->current())
1630 break;
1631 }
1632
1633 bool sizeCSSPropertyExpected = false;
1634 if (isForwardSlashOperator(val) && foundPositionCSSProperty) {
1635 sizeCSSPropertyExpected = true;
1636 m_valueList->next();
1637 }
1638
1639 foundPositionCSSProperty = false;
1640 bool found = false;
1641 for (i = 0; !found && i < numProperties; ++i) {
1642
1643 if (sizeCSSPropertyExpected && (properties[i] != CSSPropertyBackgrou ndSize && properties[i] != CSSPropertyWebkitMaskSize))
1644 continue;
1645 if (!sizeCSSPropertyExpected && (properties[i] == CSSPropertyBackgro undSize || properties[i] == CSSPropertyWebkitMaskSize))
1646 continue;
1647
1648 if (!parsedProperty[i]) {
1649 RefPtrWillBeRawPtr<CSSValue> val1 = nullptr;
1650 RefPtrWillBeRawPtr<CSSValue> val2 = nullptr;
1651 CSSPropertyID propId1, propId2;
1652 CSSParserValue* parserValue = m_valueList->current();
1653 // parseFillProperty() may modify m_implicitShorthand, so we MUS T reset it
1654 // before EACH return below.
1655 if (parserValue && parseFillProperty(properties[i], propId1, pro pId2, val1, val2)) {
1656 parsedProperty[i] = found = true;
1657 addFillValue(values[i], val1.release());
1658 if (properties[i] == CSSPropertyBackgroundPosition || proper ties[i] == CSSPropertyWebkitMaskPosition)
1659 addFillValue(positionYValue, val2.release());
1660 if (properties[i] == CSSPropertyBackgroundRepeat || properti es[i] == CSSPropertyWebkitMaskRepeat)
1661 addFillValue(repeatYValue, val2.release());
1662 if (properties[i] == CSSPropertyBackgroundOrigin || properti es[i] == CSSPropertyWebkitMaskOrigin) {
1663 // Reparse the value as a clip, and see if we succeed.
1664 if (parseBackgroundClip(parserValue, val1))
1665 addFillValue(clipValue, val1.release()); // The prop erty parsed successfully.
1666 else
1667 addFillValue(clipValue, cssValuePool().createImplici tInitialValue()); // Some value was used for origin that is not supported by cli p. Just reset clip instead.
1668 }
1669 if (properties[i] == CSSPropertyBackgroundClip || properties [i] == CSSPropertyWebkitMaskClip) {
1670 // Update clipValue
1671 addFillValue(clipValue, val1.release());
1672 foundClip = true;
1673 }
1674 if (properties[i] == CSSPropertyBackgroundPosition || proper ties[i] == CSSPropertyWebkitMaskPosition)
1675 foundPositionCSSProperty = true;
1676 }
1677 }
1678 }
1679
1680 // if we didn't find at least one match, this is an
1681 // invalid shorthand and we have to ignore it
1682 if (!found) {
1683 m_implicitShorthand = false;
1684 return false;
1685 }
1686 }
1687
1688 // Now add all of the properties we found.
1689 for (i = 0; i < numProperties; i++) {
1690 // Fill in any remaining properties with the initial value.
1691 if (!parsedProperty[i]) {
1692 addFillValue(values[i], cssValuePool().createImplicitInitialValue()) ;
1693 if (properties[i] == CSSPropertyBackgroundPosition || properties[i] == CSSPropertyWebkitMaskPosition)
1694 addFillValue(positionYValue, cssValuePool().createImplicitInitia lValue());
1695 if (properties[i] == CSSPropertyBackgroundRepeat || properties[i] == CSSPropertyWebkitMaskRepeat)
1696 addFillValue(repeatYValue, cssValuePool().createImplicitInitialV alue());
1697 if (properties[i] == CSSPropertyBackgroundOrigin || properties[i] == CSSPropertyWebkitMaskOrigin) {
1698 // If background-origin wasn't present, then reset background-cl ip also.
1699 addFillValue(clipValue, cssValuePool().createImplicitInitialValu e());
1700 }
1701 }
1702 if (properties[i] == CSSPropertyBackgroundPosition) {
1703 addProperty(CSSPropertyBackgroundPositionX, values[i].release(), imp ortant);
1704 // it's OK to call positionYValue.release() since we only see CSSPro pertyBackgroundPosition once
1705 addProperty(CSSPropertyBackgroundPositionY, positionYValue.release() , important);
1706 } else if (properties[i] == CSSPropertyWebkitMaskPosition) {
1707 addProperty(CSSPropertyWebkitMaskPositionX, values[i].release(), imp ortant);
1708 // it's OK to call positionYValue.release() since we only see CSSPro pertyWebkitMaskPosition once
1709 addProperty(CSSPropertyWebkitMaskPositionY, positionYValue.release() , important);
1710 } else if (properties[i] == CSSPropertyBackgroundRepeat) {
1711 addProperty(CSSPropertyBackgroundRepeatX, values[i].release(), impor tant);
1712 // it's OK to call repeatYValue.release() since we only see CSSPrope rtyBackgroundPosition once
1713 addProperty(CSSPropertyBackgroundRepeatY, repeatYValue.release(), im portant);
1714 } else if (properties[i] == CSSPropertyWebkitMaskRepeat) {
1715 addProperty(CSSPropertyWebkitMaskRepeatX, values[i].release(), impor tant);
1716 // it's OK to call repeatYValue.release() since we only see CSSPrope rtyBackgroundPosition once
1717 addProperty(CSSPropertyWebkitMaskRepeatY, repeatYValue.release(), im portant);
1718 } else if ((properties[i] == CSSPropertyBackgroundClip || properties[i] == CSSPropertyWebkitMaskClip) && !foundClip)
1719 // Value is already set while updating origin
1720 continue;
1721 else if (properties[i] == CSSPropertyBackgroundSize && !parsedProperty[i ] && m_context.useLegacyBackgroundSizeShorthandBehavior())
1722 continue;
1723 else
1724 addProperty(properties[i], values[i].release(), important);
1725
1726 // Add in clip values when we hit the corresponding origin property.
1727 if (properties[i] == CSSPropertyBackgroundOrigin && !foundClip)
1728 addProperty(CSSPropertyBackgroundClip, clipValue.release(), importan t);
1729 else if (properties[i] == CSSPropertyWebkitMaskOrigin && !foundClip)
1730 addProperty(CSSPropertyWebkitMaskClip, clipValue.release(), importan t);
1731 }
1732
1733 m_implicitShorthand = false;
1734 return true;
1735 }
1736
1737 static bool isValidTransitionPropertyList(CSSValueList* value)
1738 {
1739 if (value->length() < 2)
1740 return true;
1741 for (auto& property : *value) {
1742 // FIXME: Shorthand parsing shouldn't add initial to the list since it w on't round-trip
1743 if (property->isInitialValue())
1744 continue;
1745 CSSPrimitiveValue* primitiveValue = toCSSPrimitiveValue(property.get());
1746 if (primitiveValue->isValueID() && primitiveValue->getValueID() == CSSVa lueNone)
1747 return false;
1748 }
1749 return true;
1750 }
1751
1752 bool CSSPropertyParser::parseAnimationShorthand(bool useLegacyparsing, bool impo rtant)
1753 {
1754 const StylePropertyShorthand& animationProperties = animationShorthandForPar sing();
1755 const unsigned numProperties = 8;
1756
1757 // The list of properties in the shorthand should be the same
1758 // length as the list with animation name in last position, even though they are
1759 // in a different order.
1760 ASSERT(numProperties == animationProperties.length());
1761 ASSERT(numProperties == animationShorthand().length());
1762
1763 ShorthandScope scope(this, CSSPropertyAnimation);
1764
1765 bool parsedProperty[numProperties] = { false };
1766 RefPtrWillBeRawPtr<CSSValueList> values[numProperties];
1767 for (size_t i = 0; i < numProperties; ++i)
1768 values[i] = CSSValueList::createCommaSeparated();
1769
1770 while (m_valueList->current()) {
1771 if (consumeComma(m_valueList)) {
1772 // We hit the end. Fill in all remaining values with the initial val ue.
1773 for (size_t i = 0; i < numProperties; ++i) {
1774 if (!parsedProperty[i])
1775 values[i]->append(cssValuePool().createImplicitInitialValue( ));
1776 parsedProperty[i] = false;
1777 }
1778 if (!m_valueList->current())
1779 break;
1780 }
1781
1782 bool found = false;
1783 for (size_t i = 0; i < numProperties; ++i) {
1784 if (parsedProperty[i])
1785 continue;
1786 if (RefPtrWillBeRawPtr<CSSValue> val = parseAnimationProperty(animat ionProperties.properties()[i], useLegacyparsing)) {
1787 parsedProperty[i] = found = true;
1788 values[i]->append(val.release());
1789 break;
1790 }
1791 }
1792
1793 // if we didn't find at least one match, this is an
1794 // invalid shorthand and we have to ignore it
1795 if (!found)
1796 return false;
1797 }
1798
1799 for (size_t i = 0; i < numProperties; ++i) {
1800 // If we didn't find the property, set an intial value.
1801 if (!parsedProperty[i])
1802 values[i]->append(cssValuePool().createImplicitInitialValue());
1803
1804 addProperty(animationProperties.properties()[i], values[i].release(), im portant);
1805 }
1806
1807 return true;
1808 }
1809
1810 bool CSSPropertyParser::parseTransitionShorthand(bool important)
1811 {
1812 const unsigned numProperties = 4;
1813 const StylePropertyShorthand& shorthand = transitionShorthandForParsing();
1814 ASSERT(numProperties == shorthand.length());
1815
1816 ShorthandScope scope(this, CSSPropertyTransition);
1817
1818 bool parsedProperty[numProperties] = { false };
1819 RefPtrWillBeRawPtr<CSSValueList> values[numProperties];
1820 for (size_t i = 0; i < numProperties; ++i)
1821 values[i] = CSSValueList::createCommaSeparated();
1822
1823 while (m_valueList->current()) {
1824 if (consumeComma(m_valueList)) {
1825 // We hit the end. Fill in all remaining values with the initial val ue.
1826 for (size_t i = 0; i < numProperties; ++i) {
1827 if (!parsedProperty[i])
1828 values[i]->append(cssValuePool().createImplicitInitialValue( ));
1829 parsedProperty[i] = false;
1830 }
1831 if (!m_valueList->current())
1832 break;
1833 }
1834
1835 bool found = false;
1836 for (size_t i = 0; i < numProperties; ++i) {
1837 if (parsedProperty[i])
1838 continue;
1839 if (RefPtrWillBeRawPtr<CSSValue> val = parseAnimationProperty(shorth and.properties()[i], false)) {
1840 parsedProperty[i] = found = true;
1841 values[i]->append(val.release());
1842 break;
1843 }
1844 }
1845
1846 // if we didn't find at least one match, this is an
1847 // invalid shorthand and we have to ignore it
1848 if (!found)
1849 return false;
1850 }
1851
1852 ASSERT(shorthand.properties()[3] == CSSPropertyTransitionProperty);
1853 if (!isValidTransitionPropertyList(values[3].get()))
1854 return false;
1855
1856 // Fill in any remaining properties with the initial value and add
1857 for (size_t i = 0; i < numProperties; ++i) {
1858 if (!parsedProperty[i])
1859 values[i]->append(cssValuePool().createImplicitInitialValue());
1860 addProperty(shorthand.properties()[i], values[i].release(), important);
1861 }
1862
1863 return true;
1864 }
1865
1866 PassRefPtrWillBeRawPtr<CSSValue> CSSPropertyParser::parseColumnWidth()
1867 {
1868 CSSParserValue* value = m_valueList->current();
1869 // Always parse lengths in strict mode here, since it would be ambiguous oth erwise when used in
1870 // the 'columns' shorthand property.
1871 if (value->id == CSSValueAuto || (validUnit(value, FLength | FNonNeg, HTMLSt andardMode) && (m_parsedCalculation || value->fValue != 0))) {
1872 RefPtrWillBeRawPtr<CSSValue> parsedValue = parseValidPrimitive(value->id , value);
1873 m_valueList->next();
1874 return parsedValue;
1875 }
1876 return nullptr;
1877 }
1878
1879 PassRefPtrWillBeRawPtr<CSSValue> CSSPropertyParser::parseColumnCount()
1880 {
1881 CSSParserValue* value = m_valueList->current();
1882 if (value->id == CSSValueAuto || validUnit(value, FPositiveInteger)) {
1883 RefPtrWillBeRawPtr<CSSValue> parsedValue = parseValidPrimitive(value->id , value);
1884 m_valueList->next();
1885 return parsedValue;
1886 }
1887 return nullptr;
1888 }
1889
1890 bool CSSPropertyParser::parseColumnsShorthand(bool important)
1891 {
1892 RefPtrWillBeRawPtr<CSSValue> columnWidth = nullptr;
1893 RefPtrWillBeRawPtr<CSSValue> columnCount = nullptr;
1894
1895 for (unsigned propertiesParsed = 0; CSSParserValue* value = m_valueList->cur rent(); propertiesParsed++) {
1896 if (propertiesParsed >= 2)
1897 return false; // Too many values for this shorthand. Invalid declara tion.
1898 if (value->id == CSSValueAuto) {
1899 // Skip 'auto' as we will use it for initial value if no width/count was parsed.
1900 m_valueList->next();
1901 } else {
1902 if (!columnWidth) {
1903 if ((columnWidth = parseColumnWidth()))
1904 continue;
1905 }
1906 if (!columnCount) {
1907 if ((columnCount = parseColumnCount()))
1908 continue;
1909 }
1910 // If we didn't find at least one match, this is an
1911 // invalid shorthand and we have to ignore it.
1912 return false;
1913 }
1914 }
1915
1916 if (!columnWidth)
1917 columnWidth = cssValuePool().createIdentifierValue(CSSValueAuto);
1918 addProperty(CSSPropertyWebkitColumnWidth, columnWidth, important);
1919 if (!columnCount)
1920 columnCount = cssValuePool().createIdentifierValue(CSSValueAuto);
1921 addProperty(CSSPropertyWebkitColumnCount, columnCount, important);
1922 return true;
1923 }
1924
1925 bool CSSPropertyParser::parseShorthand(CSSPropertyID propId, const StyleProperty Shorthand& shorthand, bool important)
1926 {
1927 // We try to match as many properties as possible
1928 // We set up an array of booleans to mark which property has been found,
1929 // and we try to search for properties until it makes no longer any sense.
1930 ShorthandScope scope(this, propId);
1931
1932 bool found = false;
1933 unsigned propertiesParsed = 0;
1934 bool propertyFound[6] = { false, false, false, false, false, false }; // 6 i s enough size.
1935
1936 while (m_valueList->current()) {
1937 found = false;
1938 for (unsigned propIndex = 0; !found && propIndex < shorthand.length(); + +propIndex) {
1939 if (!propertyFound[propIndex] && parseValue(shorthand.properties()[p ropIndex], important)) {
1940 propertyFound[propIndex] = found = true;
1941 propertiesParsed++;
1942 }
1943 }
1944
1945 // if we didn't find at least one match, this is an
1946 // invalid shorthand and we have to ignore it
1947 if (!found)
1948 return false;
1949 }
1950
1951 if (propertiesParsed == shorthand.length())
1952 return true;
1953
1954 // Fill in any remaining properties with the initial value.
1955 ImplicitScope implicitScope(this);
1956 const StylePropertyShorthand* const* const propertiesForInitialization = sho rthand.propertiesForInitialization();
1957 for (unsigned i = 0; i < shorthand.length(); ++i) {
1958 if (propertyFound[i])
1959 continue;
1960
1961 if (propertiesForInitialization) {
1962 const StylePropertyShorthand& initProperties = *(propertiesForInitia lization[i]);
1963 for (unsigned propIndex = 0; propIndex < initProperties.length(); ++ propIndex)
1964 addProperty(initProperties.properties()[propIndex], cssValuePool ().createImplicitInitialValue(), important);
1965 } else
1966 addProperty(shorthand.properties()[i], cssValuePool().createImplicit InitialValue(), important);
1967 }
1968
1969 return true;
1970 }
1971
1972 bool CSSPropertyParser::parse4Values(CSSPropertyID propId, const CSSPropertyID * properties, bool important)
1973 {
1974 /* From the CSS 2 specs, 8.3
1975 * If there is only one value, it applies to all sides. If there are two val ues, the top and
1976 * bottom margins are set to the first value and the right and left margins are set to the second.
1977 * If there are three values, the top is set to the first value, the left an d right are set to the
1978 * second, and the bottom is set to the third. If there are four values, the y apply to the top,
1979 * right, bottom, and left, respectively.
1980 */
1981
1982 int num = inShorthand() ? 1 : m_valueList->size();
1983
1984 ShorthandScope scope(this, propId);
1985
1986 // the order is top, right, bottom, left
1987 switch (num) {
1988 case 1: {
1989 if (!parseValue(properties[0], important))
1990 return false;
1991 CSSValue* value = m_parsedProperties.last().value();
1992 ImplicitScope implicitScope(this);
1993 addProperty(properties[1], value, important);
1994 addProperty(properties[2], value, important);
1995 addProperty(properties[3], value, important);
1996 break;
1997 }
1998 case 2: {
1999 if (!parseValue(properties[0], important) || !parseValue(properties[ 1], important))
2000 return false;
2001 CSSValue* value = m_parsedProperties[m_parsedProperties.size() - 2]. value();
2002 ImplicitScope implicitScope(this);
2003 addProperty(properties[2], value, important);
2004 value = m_parsedProperties[m_parsedProperties.size() - 2].value();
2005 addProperty(properties[3], value, important);
2006 break;
2007 }
2008 case 3: {
2009 if (!parseValue(properties[0], important) || !parseValue(properties[ 1], important) || !parseValue(properties[2], important))
2010 return false;
2011 CSSValue* value = m_parsedProperties[m_parsedProperties.size() - 2]. value();
2012 ImplicitScope implicitScope(this);
2013 addProperty(properties[3], value, important);
2014 break;
2015 }
2016 case 4: {
2017 if (!parseValue(properties[0], important) || !parseValue(properties[ 1], important) ||
2018 !parseValue(properties[2], important) || !parseValue(properties[ 3], important))
2019 return false;
2020 break;
2021 }
2022 default: {
2023 return false;
2024 }
2025 }
2026
2027 return true;
2028 }
2029
2030 PassRefPtrWillBeRawPtr<CSSValue> CSSPropertyParser::parseScrollSnapPoints()
2031 {
2032 CSSParserValue* value = m_valueList->current();
2033
2034 if (value->id == CSSValueNone) {
2035 m_valueList->next();
2036 return cssValuePool().createIdentifierValue(CSSValueNone);
2037 }
2038
2039 if (value->m_unit == CSSParserValue::Function && value->function->id == CSSV alueRepeat) {
2040 // The spec defines the following grammar: repeat( <length>)
2041 CSSParserValueList* arguments = value->function->args.get();
2042 if (!arguments || arguments->size() != 1)
2043 return nullptr;
2044
2045 CSSParserValue* repeatValue = arguments->valueAt(0);
2046 if (validUnit(repeatValue, FNonNeg | FLength | FPercent) && (m_parsedCal culation || repeatValue->fValue > 0)) {
2047 RefPtrWillBeRawPtr<CSSFunctionValue> result = CSSFunctionValue::crea te(CSSValueRepeat);
2048 result->append(parseValidPrimitive(repeatValue->id, repeatValue));
2049 m_valueList->next();
2050 return result.release();
2051 }
2052 }
2053
2054 return nullptr;
2055 }
2056
2057 PassRefPtrWillBeRawPtr<CSSValue> CSSPropertyParser::parseScrollSnapCoordinate()
2058 {
2059 if (m_valueList->current()->id == CSSValueNone) {
2060 m_valueList->next();
2061 return cssValuePool().createIdentifierValue(CSSValueNone);
2062 }
2063
2064 return parsePositionList(m_valueList);
2065 }
2066
2067 PassRefPtrWillBeRawPtr<CSSPrimitiveValue> CSSPropertyParser::parsePage()
2068 {
2069 CSSParserValue* value = m_valueList->current();
2070 m_valueList->next();
2071 ASSERT(value);
2072
2073 if (value->id == CSSValueAuto)
2074 return cssValuePool().createIdentifierValue(value->id);
2075 if (value->m_unit == CSSParserValue::Identifier)
2076 return createPrimitiveCustomIdentValue(value);
2077 return nullptr;
2078 }
2079
2080 // <length>{1,2} | auto | [ <page-size> || [ portrait | landscape] ]
2081 PassRefPtrWillBeRawPtr<CSSValueList> CSSPropertyParser::parseSize()
2082 {
2083 CSSParserValue* value = m_valueList->current();
2084 ASSERT(value);
2085
2086 RefPtrWillBeRawPtr<CSSValueList> parsedValues = CSSValueList::createSpaceSep arated();
2087
2088 // First parameter.
2089 SizeParameterType paramType = parseSizeParameter(parsedValues.get(), value, None);
2090 if (paramType == None)
2091 return nullptr;
2092 value = m_valueList->next();
2093
2094 // Second parameter, if any.
2095 if (value) {
2096 paramType = parseSizeParameter(parsedValues.get(), value, paramType);
2097 if (paramType == None)
2098 return nullptr;
2099 m_valueList->next();
2100 }
2101
2102 return parsedValues.release();
2103 }
2104
2105 CSSPropertyParser::SizeParameterType CSSPropertyParser::parseSizeParameter(CSSVa lueList* parsedValues, CSSParserValue* value, SizeParameterType prevParamType)
2106 {
2107 switch (value->id) {
2108 case CSSValueAuto:
2109 if (prevParamType == None) {
2110 parsedValues->append(cssValuePool().createIdentifierValue(value->id) );
2111 return Auto;
2112 }
2113 return None;
2114 case CSSValueLandscape:
2115 case CSSValuePortrait:
2116 if (prevParamType == None || prevParamType == PageSize) {
2117 parsedValues->append(cssValuePool().createIdentifierValue(value->id) );
2118 return Orientation;
2119 }
2120 return None;
2121 case CSSValueA3:
2122 case CSSValueA4:
2123 case CSSValueA5:
2124 case CSSValueB4:
2125 case CSSValueB5:
2126 case CSSValueLedger:
2127 case CSSValueLegal:
2128 case CSSValueLetter:
2129 if (prevParamType == None || prevParamType == Orientation) {
2130 // Normalize to Page Size then Orientation order by prepending for s impler StyleBuilder handling
2131 parsedValues->prepend(cssValuePool().createIdentifierValue(value->id ));
2132 return PageSize;
2133 }
2134 return None;
2135 case 0:
2136 if (validUnit(value, FLength | FNonNeg) && (prevParamType == None || pre vParamType == Length)) {
2137 parsedValues->append(createPrimitiveNumericValue(value));
2138 return Length;
2139 }
2140 return None;
2141 default:
2142 return None;
2143 }
2144 } 240 }
2145 241
2146 // [ <string> <string> ]+ | none, but none is handled in parseValue
2147 PassRefPtrWillBeRawPtr<CSSValue> CSSPropertyParser::parseQuotes()
2148 {
2149 RefPtrWillBeRawPtr<CSSValueList> values = CSSValueList::createSpaceSeparated ();
2150 while (CSSParserValue* val = m_valueList->current()) {
2151 RefPtrWillBeRawPtr<CSSValue> parsedValue = nullptr;
2152 if (val->unit() != CSSPrimitiveValue::UnitType::String)
2153 return nullptr;
2154 parsedValue = createPrimitiveStringValue(val);
2155 values->append(parsedValue.release());
2156 m_valueList->next();
2157 }
2158 if (values->length() && values->length() % 2 == 0)
2159 return values.release();
2160 return nullptr;
2161 }
2162
2163 // [ <string> | <uri> | <counter> | attr(X) | open-quote | close-quote | no-open -quote | no-close-quote ]+ | inherit
2164 // in CSS 2.1 this got somewhat reduced:
2165 // [ <string> | attr(X) | open-quote | close-quote | no-open-quote | no-close-qu ote ]+ | inherit
2166 PassRefPtrWillBeRawPtr<CSSValueList> CSSPropertyParser::parseContent()
2167 {
2168 RefPtrWillBeRawPtr<CSSValueList> values = CSSValueList::createSpaceSeparated ();
2169
2170 while (CSSParserValue* val = m_valueList->current()) {
2171 RefPtrWillBeRawPtr<CSSValue> parsedValue = nullptr;
2172 if (val->unit() == CSSPrimitiveValue::UnitType::URI) {
2173 // url
2174 parsedValue = createCSSImageValueWithReferrer(val->string, completeU RL(val->string));
2175 } else if (val->m_unit == CSSParserValue::Function) {
2176 // attr(X) | counter(X [,Y]) | counters(X, Y, [,Z]) | -webkit-gradie nt(...)
2177 CSSParserValueList* args = val->function->args.get();
2178 if (!args)
2179 return nullptr;
2180 if (val->function->id == CSSValueAttr) {
2181 parsedValue = parseAttr(args);
2182 } else if (val->function->id == CSSValueCounter) {
2183 parsedValue = parseCounterContent(args, false);
2184 } else if (val->function->id == CSSValueCounters) {
2185 parsedValue = parseCounterContent(args, true);
2186 } else if (val->function->id == CSSValueWebkitImageSet) {
2187 parsedValue = parseImageSet(m_valueList);
2188 } else if (isGeneratedImageValue(val)) {
2189 if (!parseGeneratedImage(m_valueList, parsedValue))
2190 return nullptr;
2191 }
2192 } else if (val->m_unit == CSSParserValue::Identifier) {
2193 switch (val->id) {
2194 case CSSValueOpenQuote:
2195 case CSSValueCloseQuote:
2196 case CSSValueNoOpenQuote:
2197 case CSSValueNoCloseQuote:
2198 case CSSValueNone:
2199 case CSSValueNormal:
2200 parsedValue = cssValuePool().createIdentifierValue(val->id);
2201 default:
2202 break;
2203 }
2204 } else if (val->unit() == CSSPrimitiveValue::UnitType::String) {
2205 parsedValue = createPrimitiveStringValue(val);
2206 }
2207 if (!parsedValue)
2208 return nullptr;
2209 values->append(parsedValue.release());
2210 m_valueList->next();
2211 }
2212
2213 return values.release();
2214 }
2215
2216 PassRefPtrWillBeRawPtr<CSSValue> CSSPropertyParser::parseAttr(CSSParserValueList * args)
2217 {
2218 if (args->size() != 1)
2219 return nullptr;
2220
2221 CSSParserValue* a = args->current();
2222
2223 if (a->m_unit != CSSParserValue::Identifier)
2224 return nullptr;
2225
2226 String attrName = a->string;
2227 // CSS allows identifiers with "-" at the start, like "-webkit-mask-image".
2228 // But HTML attribute names can't have those characters, and we should not
2229 // even parse them inside attr().
2230 if (attrName[0] == '-')
2231 return nullptr;
2232
2233 if (m_context.isHTMLDocument())
2234 attrName = attrName.lower();
2235
2236 RefPtrWillBeRawPtr<CSSFunctionValue> attrValue = CSSFunctionValue::create(CS SValueAttr);
2237 attrValue->append(CSSPrimitiveValue::create(attrName, CSSPrimitiveValue::Uni tType::CustomIdentifier));
2238 return attrValue.release();
2239 }
2240
2241 bool CSSPropertyParser::acceptQuirkyColors(CSSPropertyID propertyId) const
2242 {
2243 if (!inQuirksMode())
2244 return false;
2245 switch (propertyId) {
2246 case CSSPropertyBackgroundColor:
2247 case CSSPropertyBorderBottomColor:
2248 case CSSPropertyBorderLeftColor:
2249 case CSSPropertyBorderRightColor:
2250 case CSSPropertyBorderTopColor:
2251 return !inShorthand() || m_currentShorthand == CSSPropertyBorderColor;
2252 case CSSPropertyColor:
2253 return true;
2254 default:
2255 break;
2256 }
2257 return false;
2258 }
2259
2260 bool CSSPropertyParser::isColorKeyword(CSSValueID id)
2261 {
2262 // Named colors and color keywords:
2263 //
2264 // <named-color>
2265 // 'aqua', 'black', 'blue', ..., 'yellow' (CSS3: "basic color keywords")
2266 // 'aliceblue', ..., 'yellowgreen' (CSS3: "extended color keywords" )
2267 // 'transparent'
2268 //
2269 // 'currentcolor'
2270 //
2271 // <deprecated-system-color>
2272 // 'ActiveBorder', ..., 'WindowText'
2273 //
2274 // WebKit proprietary/internal:
2275 // '-webkit-link'
2276 // '-webkit-activelink'
2277 // '-internal-active-list-box-selection'
2278 // '-internal-active-list-box-selection-text'
2279 // '-internal-inactive-list-box-selection'
2280 // '-internal-inactive-list-box-selection-text'
2281 // '-webkit-focus-ring-color'
2282 // '-webkit-text'
2283 //
2284 return (id >= CSSValueAqua && id <= CSSValueWebkitText)
2285 || (id >= CSSValueAliceblue && id <= CSSValueYellowgreen)
2286 || id == CSSValueMenu;
2287 }
2288
2289 PassRefPtrWillBeRawPtr<CSSPrimitiveValue> CSSPropertyParser::parseColor(const CS SParserValue* value, bool acceptQuirkyColors)
2290 {
2291 CSSValueID id = value->id;
2292 if (isColorKeyword(id)) {
2293 if (!isValueAllowedInMode(id, m_context.mode()))
2294 return nullptr;
2295 if (id == CSSValueWebkitText && m_context.useCounter())
2296 m_context.useCounter()->count(UseCounter::WebkitTextInColorProperty) ;
2297 return cssValuePool().createIdentifierValue(id);
2298 }
2299 RGBA32 c = Color::transparent;
2300 if (!parseColorFromValue(value, c, acceptQuirkyColors))
2301 return nullptr;
2302 return cssValuePool().createColorValue(c);
2303 }
2304
2305 bool CSSPropertyParser::parseFillImage(CSSParserValueList* valueList, RefPtrWill BeRawPtr<CSSValue>& value)
2306 {
2307 if (valueList->current()->id == CSSValueNone) {
2308 value = cssValuePool().createIdentifierValue(CSSValueNone);
2309 return true;
2310 }
2311 if (valueList->current()->unit() == CSSPrimitiveValue::UnitType::URI) {
2312 value = createCSSImageValueWithReferrer(valueList->current()->string, co mpleteURL(valueList->current()->string));
2313 return true;
2314 }
2315
2316 if (isGeneratedImageValue(valueList->current()))
2317 return parseGeneratedImage(valueList, value);
2318
2319 if (valueList->current()->m_unit == CSSParserValue::Function && valueList->c urrent()->function->id == CSSValueWebkitImageSet) {
2320 value = parseImageSet(m_valueList);
2321 if (value)
2322 return true;
2323 }
2324
2325 return false;
2326 }
2327
2328 PassRefPtrWillBeRawPtr<CSSValue> CSSPropertyParser::parseFillPositionX(CSSParser ValueList* valueList)
2329 {
2330 int id = valueList->current()->id;
2331 if (id == CSSValueLeft || id == CSSValueRight || id == CSSValueCenter) {
2332 int percent = 0;
2333 if (id == CSSValueRight)
2334 percent = 100;
2335 else if (id == CSSValueCenter)
2336 percent = 50;
2337 return cssValuePool().createValue(percent, CSSPrimitiveValue::UnitType:: Percentage);
2338 }
2339 if (validUnit(valueList->current(), FPercent | FLength))
2340 return createPrimitiveNumericValue(valueList->current());
2341 return nullptr;
2342 }
2343
2344 PassRefPtrWillBeRawPtr<CSSValue> CSSPropertyParser::parseFillPositionY(CSSParser ValueList* valueList)
2345 {
2346 int id = valueList->current()->id;
2347 if (id == CSSValueTop || id == CSSValueBottom || id == CSSValueCenter) {
2348 int percent = 0;
2349 if (id == CSSValueBottom)
2350 percent = 100;
2351 else if (id == CSSValueCenter)
2352 percent = 50;
2353 return cssValuePool().createValue(percent, CSSPrimitiveValue::UnitType:: Percentage);
2354 }
2355 if (validUnit(valueList->current(), FPercent | FLength))
2356 return createPrimitiveNumericValue(valueList->current());
2357 return nullptr;
2358 }
2359
2360 PassRefPtrWillBeRawPtr<CSSPrimitiveValue> CSSPropertyParser::parseFillPositionCo mponent(CSSParserValueList* valueList, unsigned& cumulativeFlags, FillPositionFl ag& individualFlag, FillPositionParsingMode parsingMode, Units unitless)
2361 {
2362 CSSValueID id = valueList->current()->id;
2363 if (id == CSSValueLeft || id == CSSValueTop || id == CSSValueRight || id == CSSValueBottom || id == CSSValueCenter) {
2364 int percent = 0;
2365 if (id == CSSValueLeft || id == CSSValueRight) {
2366 if (cumulativeFlags & XFillPosition)
2367 return nullptr;
2368 cumulativeFlags |= XFillPosition;
2369 individualFlag = XFillPosition;
2370 if (id == CSSValueRight)
2371 percent = 100;
2372 }
2373 else if (id == CSSValueTop || id == CSSValueBottom) {
2374 if (cumulativeFlags & YFillPosition)
2375 return nullptr;
2376 cumulativeFlags |= YFillPosition;
2377 individualFlag = YFillPosition;
2378 if (id == CSSValueBottom)
2379 percent = 100;
2380 } else if (id == CSSValueCenter) {
2381 // Center is ambiguous, so we're not sure which position we've found yet, an x or a y.
2382 percent = 50;
2383 cumulativeFlags |= AmbiguousFillPosition;
2384 individualFlag = AmbiguousFillPosition;
2385 }
2386
2387 if (parsingMode == ResolveValuesAsKeyword)
2388 return cssValuePool().createIdentifierValue(id);
2389
2390 return cssValuePool().createValue(percent, CSSPrimitiveValue::UnitType:: Percentage);
2391 }
2392 if (validUnit(valueList->current(), FPercent | FLength | unitless)) {
2393 if (!cumulativeFlags) {
2394 cumulativeFlags |= XFillPosition;
2395 individualFlag = XFillPosition;
2396 } else if (cumulativeFlags & (XFillPosition | AmbiguousFillPosition)) {
2397 cumulativeFlags |= YFillPosition;
2398 individualFlag = YFillPosition;
2399 } else {
2400 if (m_parsedCalculation)
2401 m_parsedCalculation.release();
2402 return nullptr;
2403 }
2404 return createPrimitiveNumericValue(valueList->current());
2405 }
2406 return nullptr;
2407 }
2408
2409 static bool isValueConflictingWithCurrentEdge(int value1, int value2)
2410 {
2411 if ((value1 == CSSValueLeft || value1 == CSSValueRight) && (value2 == CSSVal ueLeft || value2 == CSSValueRight))
2412 return true;
2413
2414 if ((value1 == CSSValueTop || value1 == CSSValueBottom) && (value2 == CSSVal ueTop || value2 == CSSValueBottom))
2415 return true;
2416
2417 return false;
2418 }
2419
2420 static bool isFillPositionKeyword(CSSValueID value)
2421 {
2422 return value == CSSValueLeft || value == CSSValueTop || value == CSSValueBot tom || value == CSSValueRight || value == CSSValueCenter;
2423 }
2424
2425 void CSSPropertyParser::parse4ValuesFillPosition(CSSParserValueList* valueList, RefPtrWillBeRawPtr<CSSValue>& value1, RefPtrWillBeRawPtr<CSSValue>& value2, Pass RefPtrWillBeRawPtr<CSSPrimitiveValue> parsedValue1, PassRefPtrWillBeRawPtr<CSSPr imitiveValue> parsedValue2)
2426 {
2427 // [ left | right ] [ <percentage] | <length> ] && [ top | bottom ] [ <perce ntage> | <length> ]
2428 // In the case of 4 values <position> requires the second value to be a leng th or a percentage.
2429 if (isFillPositionKeyword(parsedValue2->getValueID()))
2430 return;
2431
2432 unsigned cumulativeFlags = 0;
2433 FillPositionFlag value3Flag = InvalidFillPosition;
2434 RefPtrWillBeRawPtr<CSSPrimitiveValue> value3 = parseFillPositionComponent(va lueList, cumulativeFlags, value3Flag, ResolveValuesAsKeyword);
2435 if (!value3)
2436 return;
2437
2438 CSSValueID ident1 = parsedValue1->getValueID();
2439 CSSValueID ident3 = value3->getValueID();
2440
2441 if (ident1 == CSSValueCenter)
2442 return;
2443
2444 if (!isFillPositionKeyword(ident3) || ident3 == CSSValueCenter)
2445 return;
2446
2447 // We need to check if the values are not conflicting, e.g. they are not on the same edge. It is
2448 // needed as the second call to parseFillPositionComponent was on purpose no t checking it. In the
2449 // case of two values top 20px is invalid but in the case of 4 values it bec omes valid.
2450 if (isValueConflictingWithCurrentEdge(ident1, ident3))
2451 return;
2452
2453 valueList->next();
2454
2455 cumulativeFlags = 0;
2456 FillPositionFlag value4Flag = InvalidFillPosition;
2457 RefPtrWillBeRawPtr<CSSPrimitiveValue> value4 = parseFillPositionComponent(va lueList, cumulativeFlags, value4Flag, ResolveValuesAsKeyword);
2458 if (!value4)
2459 return;
2460
2461 // 4th value must be a length or a percentage.
2462 if (isFillPositionKeyword(value4->getValueID()))
2463 return;
2464
2465 value1 = CSSValuePair::create(parsedValue1, parsedValue2, CSSValuePair::Drop IdenticalValues);
2466 value2 = CSSValuePair::create(value3, value4, CSSValuePair::DropIdenticalVal ues);
2467
2468 if (ident1 == CSSValueTop || ident1 == CSSValueBottom)
2469 value1.swap(value2);
2470
2471 valueList->next();
2472 }
2473 void CSSPropertyParser::parse3ValuesFillPosition(CSSParserValueList* valueList, RefPtrWillBeRawPtr<CSSValue>& value1, RefPtrWillBeRawPtr<CSSValue>& value2, Pass RefPtrWillBeRawPtr<CSSPrimitiveValue> parsedValue1, PassRefPtrWillBeRawPtr<CSSPr imitiveValue> parsedValue2)
2474 {
2475 unsigned cumulativeFlags = 0;
2476 FillPositionFlag value3Flag = InvalidFillPosition;
2477 RefPtrWillBeRawPtr<CSSPrimitiveValue> value3 = parseFillPositionComponent(va lueList, cumulativeFlags, value3Flag, ResolveValuesAsKeyword);
2478
2479 // value3 is not an expected value, we return.
2480 if (!value3)
2481 return;
2482
2483 valueList->next();
2484
2485 bool swapNeeded = false;
2486 CSSValueID ident1 = parsedValue1->getValueID();
2487 CSSValueID ident2 = parsedValue2->getValueID();
2488 CSSValueID ident3 = value3->getValueID();
2489
2490 CSSValueID firstPositionKeyword;
2491 CSSValueID secondPositionKeyword;
2492
2493 if (ident1 == CSSValueCenter) {
2494 // <position> requires the first 'center' to be followed by a keyword.
2495 if (!isFillPositionKeyword(ident2))
2496 return;
2497
2498 // If 'center' is the first keyword then the last one needs to be a leng th.
2499 if (isFillPositionKeyword(ident3))
2500 return;
2501
2502 firstPositionKeyword = CSSValueLeft;
2503 if (ident2 == CSSValueLeft || ident2 == CSSValueRight) {
2504 firstPositionKeyword = CSSValueTop;
2505 swapNeeded = true;
2506 }
2507 value1 = CSSValuePair::create(cssValuePool().createIdentifierValue(first PositionKeyword), cssValuePool().createValue(50, CSSPrimitiveValue::UnitType::Pe rcentage), CSSValuePair::DropIdenticalValues);
2508 value2 = CSSValuePair::create(parsedValue2, value3, CSSValuePair::DropId enticalValues);
2509 } else if (ident3 == CSSValueCenter) {
2510 if (isFillPositionKeyword(ident2))
2511 return;
2512
2513 secondPositionKeyword = CSSValueTop;
2514 if (ident1 == CSSValueTop || ident1 == CSSValueBottom) {
2515 secondPositionKeyword = CSSValueLeft;
2516 swapNeeded = true;
2517 }
2518 value1 = CSSValuePair::create(parsedValue1, parsedValue2, CSSValuePair:: DropIdenticalValues);
2519 value2 = CSSValuePair::create(cssValuePool().createIdentifierValue(secon dPositionKeyword), cssValuePool().createValue(50, CSSPrimitiveValue::UnitType::P ercentage), CSSValuePair::DropIdenticalValues);
2520 } else {
2521 RefPtrWillBeRawPtr<CSSPrimitiveValue> firstPositionValue = nullptr;
2522 RefPtrWillBeRawPtr<CSSPrimitiveValue> secondPositionValue = nullptr;
2523
2524 if (isFillPositionKeyword(ident2)) {
2525 // To match CSS grammar, we should only accept: [ center | left | ri ght | bottom | top ] [ left | right | top | bottom ] [ <percentage> | <length> ] .
2526 ASSERT(ident2 != CSSValueCenter);
2527
2528 if (isFillPositionKeyword(ident3))
2529 return;
2530
2531 secondPositionValue = value3;
2532 secondPositionKeyword = ident2;
2533 firstPositionValue = cssValuePool().createValue(0, CSSPrimitiveValue ::UnitType::Percentage);
2534 } else {
2535 // Per CSS, we should only accept: [ right | left | top | bottom ] [ <percentage> | <length> ] [ center | left | right | bottom | top ].
2536 if (!isFillPositionKeyword(ident3))
2537 return;
2538
2539 firstPositionValue = parsedValue2;
2540 secondPositionKeyword = ident3;
2541 secondPositionValue = cssValuePool().createValue(0, CSSPrimitiveValu e::UnitType::Percentage);
2542 }
2543
2544 if (isValueConflictingWithCurrentEdge(ident1, secondPositionKeyword))
2545 return;
2546
2547 value1 = CSSValuePair::create(parsedValue1, firstPositionValue, CSSValue Pair::DropIdenticalValues);
2548 value2 = CSSValuePair::create(cssValuePool().createIdentifierValue(secon dPositionKeyword), secondPositionValue, CSSValuePair::DropIdenticalValues);
2549 }
2550
2551 if (ident1 == CSSValueTop || ident1 == CSSValueBottom || swapNeeded)
2552 value1.swap(value2);
2553
2554 #if ENABLE(ASSERT)
2555 const CSSValuePair& first = toCSSValuePair(*value1);
2556 const CSSValuePair& second = toCSSValuePair(*value2);
2557 ident1 = toCSSPrimitiveValue(first.first()).getValueID();
2558 ident2 = toCSSPrimitiveValue(second.first()).getValueID();
2559 ASSERT(ident1 == CSSValueLeft || ident1 == CSSValueRight);
2560 ASSERT(ident2 == CSSValueBottom || ident2 == CSSValueTop);
2561 #endif
2562 }
2563
2564 inline bool CSSPropertyParser::isPotentialPositionValue(CSSParserValue* value)
2565 {
2566 return isFillPositionKeyword(value->id) || validUnit(value, FPercent | FLeng th, ReleaseParsedCalcValue);
2567 }
2568
2569 void CSSPropertyParser::parseFillPosition(CSSParserValueList* valueList, RefPtrW illBeRawPtr<CSSValue>& value1, RefPtrWillBeRawPtr<CSSValue>& value2, Units unitl ess)
2570 {
2571 unsigned numberOfValues = 0;
2572 for (unsigned i = valueList->currentIndex(); i < valueList->size(); ++i, ++n umberOfValues) {
2573 CSSParserValue* current = valueList->valueAt(i);
2574 if (!current || isComma(current) || isForwardSlashOperator(current) || ! isPotentialPositionValue(current))
2575 break;
2576 }
2577
2578 if (numberOfValues > 4)
2579 return;
2580
2581 // If we are parsing two values, we can safely call the CSS 2.1 parsing func tion and return.
2582 if (numberOfValues <= 2) {
2583 parse2ValuesFillPosition(valueList, value1, value2, unitless);
2584 return;
2585 }
2586
2587 ASSERT(numberOfValues > 2 && numberOfValues <= 4);
2588
2589 CSSParserValue* value = valueList->current();
2590
2591 // <position> requires the first value to be a background keyword.
2592 if (!isFillPositionKeyword(value->id))
2593 return;
2594
2595 // Parse the first value. We're just making sure that it is one of the valid keywords or a percentage/length.
2596 unsigned cumulativeFlags = 0;
2597 FillPositionFlag value1Flag = InvalidFillPosition;
2598 FillPositionFlag value2Flag = InvalidFillPosition;
2599 value1 = parseFillPositionComponent(valueList, cumulativeFlags, value1Flag, ResolveValuesAsKeyword);
2600 if (!value1)
2601 return;
2602
2603 valueList->next();
2604
2605 // In case we are parsing more than two values, relax the check inside of pa rseFillPositionComponent. top 20px is
2606 // a valid start for <position>.
2607 cumulativeFlags = AmbiguousFillPosition;
2608 value2 = parseFillPositionComponent(valueList, cumulativeFlags, value2Flag, ResolveValuesAsKeyword);
2609 if (value2)
2610 valueList->next();
2611 else {
2612 value1.clear();
2613 return;
2614 }
2615
2616 RefPtrWillBeRawPtr<CSSPrimitiveValue> parsedValue1 = toCSSPrimitiveValue(val ue1.get());
2617 RefPtrWillBeRawPtr<CSSPrimitiveValue> parsedValue2 = toCSSPrimitiveValue(val ue2.get());
2618
2619 value1.clear();
2620 value2.clear();
2621
2622 // Per CSS3 syntax, <position> can't have 'center' as its second keyword as we have more arguments to follow.
2623 if (parsedValue2->getValueID() == CSSValueCenter)
2624 return;
2625
2626 if (numberOfValues == 3)
2627 parse3ValuesFillPosition(valueList, value1, value2, parsedValue1.release (), parsedValue2.release());
2628 else
2629 parse4ValuesFillPosition(valueList, value1, value2, parsedValue1.release (), parsedValue2.release());
2630 }
2631
2632 void CSSPropertyParser::parse2ValuesFillPosition(CSSParserValueList* valueList, RefPtrWillBeRawPtr<CSSValue>& value1, RefPtrWillBeRawPtr<CSSValue>& value2, Unit s unitless)
2633 {
2634 // Parse the first value. We're just making sure that it is one of the vali d keywords or a percentage/length.
2635 unsigned cumulativeFlags = 0;
2636 FillPositionFlag value1Flag = InvalidFillPosition;
2637 FillPositionFlag value2Flag = InvalidFillPosition;
2638 value1 = parseFillPositionComponent(valueList, cumulativeFlags, value1Flag, ResolveValuesAsPercent, unitless);
2639 if (!value1)
2640 return;
2641
2642 // It only takes one value for background-position to be correctly parsed if it was specified in a shorthand (since we
2643 // can assume that any other values belong to the rest of the shorthand). I f we're not parsing a shorthand, though, the
2644 // value was explicitly specified for our property.
2645 CSSParserValue* value = valueList->next();
2646
2647 // First check for the comma. If so, we are finished parsing this value or value pair.
2648 if (value && isComma(value))
2649 value = 0;
2650
2651 if (value) {
2652 value2 = parseFillPositionComponent(valueList, cumulativeFlags, value2Fl ag, ResolveValuesAsPercent, unitless);
2653 if (value2)
2654 valueList->next();
2655 else {
2656 if (!inShorthand()) {
2657 value1.clear();
2658 return;
2659 }
2660 }
2661 }
2662
2663 if (!value2) {
2664 // Only one value was specified. If that value was not a keyword, then i t sets the x position, and the y position
2665 // is simply 50%. This is our default.
2666 // For keywords, the keyword was either an x-keyword (left/right), a y-k eyword (top/bottom), or an ambiguous keyword (center).
2667 // For left/right/center, the default of 50% in the y is still correct.
2668 value2 = cssValuePool().createValue(50, CSSPrimitiveValue::UnitType::Per centage);
2669 }
2670
2671 if (value1Flag == YFillPosition || value2Flag == XFillPosition)
2672 value1.swap(value2);
2673 }
2674
2675 void CSSPropertyParser::parseFillRepeat(RefPtrWillBeRawPtr<CSSValue>& value1, Re fPtrWillBeRawPtr<CSSValue>& value2)
2676 {
2677 CSSValueID id = m_valueList->current()->id;
2678 if (id == CSSValueRepeatX) {
2679 m_implicitShorthand = true;
2680 value1 = cssValuePool().createIdentifierValue(CSSValueRepeat);
2681 value2 = cssValuePool().createIdentifierValue(CSSValueNoRepeat);
2682 m_valueList->next();
2683 return;
2684 }
2685 if (id == CSSValueRepeatY) {
2686 m_implicitShorthand = true;
2687 value1 = cssValuePool().createIdentifierValue(CSSValueNoRepeat);
2688 value2 = cssValuePool().createIdentifierValue(CSSValueRepeat);
2689 m_valueList->next();
2690 return;
2691 }
2692 if (id == CSSValueRepeat || id == CSSValueNoRepeat || id == CSSValueRound || id == CSSValueSpace)
2693 value1 = cssValuePool().createIdentifierValue(id);
2694 else {
2695 value1 = nullptr;
2696 return;
2697 }
2698
2699 CSSParserValue* value = m_valueList->next();
2700
2701 // Parse the second value if one is available
2702 if (value && !isComma(value)) {
2703 id = value->id;
2704 if (id == CSSValueRepeat || id == CSSValueNoRepeat || id == CSSValueRoun d || id == CSSValueSpace) {
2705 value2 = cssValuePool().createIdentifierValue(id);
2706 m_valueList->next();
2707 return;
2708 }
2709 }
2710
2711 // If only one value was specified, value2 is the same as value1.
2712 m_implicitShorthand = true;
2713 value2 = cssValuePool().createIdentifierValue(toCSSPrimitiveValue(value1.get ())->getValueID());
2714 }
2715
2716 PassRefPtrWillBeRawPtr<CSSValue> CSSPropertyParser::parseFillSize(CSSPropertyID unresolvedProperty)
2717 {
2718 CSSParserValue* value = m_valueList->current();
2719 m_valueList->next();
2720
2721 if (value->id == CSSValueContain || value->id == CSSValueCover)
2722 return cssValuePool().createIdentifierValue(value->id);
2723
2724 RefPtrWillBeRawPtr<CSSPrimitiveValue> parsedValue1 = nullptr;
2725
2726 if (value->id == CSSValueAuto)
2727 parsedValue1 = cssValuePool().createIdentifierValue(CSSValueAuto);
2728 else {
2729 if (!validUnit(value, FLength | FPercent))
2730 return nullptr;
2731 parsedValue1 = createPrimitiveNumericValue(value);
2732 }
2733
2734 RefPtrWillBeRawPtr<CSSPrimitiveValue> parsedValue2 = nullptr;
2735 value = m_valueList->current();
2736 if (value) {
2737 if (value->id == CSSValueAuto) {
2738 // `auto' is the default
2739 m_valueList->next();
2740 } else if (validUnit(value, FLength | FPercent)) {
2741 parsedValue2 = createPrimitiveNumericValue(value);
2742 m_valueList->next();
2743 }
2744 } else if (unresolvedProperty == CSSPropertyAliasWebkitBackgroundSize) {
2745 // For backwards compatibility we set the second value to the first if i t is omitted.
2746 // We only need to do this for -webkit-background-size. It should be saf e to let masks match
2747 // the real property.
2748 parsedValue2 = parsedValue1;
2749 }
2750
2751 if (!parsedValue2)
2752 return parsedValue1;
2753
2754 return CSSValuePair::create(parsedValue1.release(), parsedValue2.release(), CSSValuePair::KeepIdenticalValues);
2755 }
2756
2757 bool CSSPropertyParser::parseFillProperty(CSSPropertyID propId, CSSPropertyID& p ropId1, CSSPropertyID& propId2,
2758 RefPtrWillBeRawPtr<CSSValue>& retValue1, RefPtrWillBeRawPtr<CSSValue>& retVa lue2)
2759 {
2760 // We initially store the first value in value/value2, and only create
2761 // CSSValueLists if we have more values.
2762 RefPtrWillBeRawPtr<CSSValueList> values = nullptr;
2763 RefPtrWillBeRawPtr<CSSValueList> values2 = nullptr;
2764 RefPtrWillBeRawPtr<CSSValue> value = nullptr;
2765 RefPtrWillBeRawPtr<CSSValue> value2 = nullptr;
2766
2767 retValue1 = retValue2 = nullptr;
2768 propId1 = resolveCSSPropertyID(propId);
2769 propId2 = propId1;
2770 if (propId == CSSPropertyBackgroundPosition) {
2771 propId1 = CSSPropertyBackgroundPositionX;
2772 propId2 = CSSPropertyBackgroundPositionY;
2773 } else if (propId == CSSPropertyWebkitMaskPosition) {
2774 propId1 = CSSPropertyWebkitMaskPositionX;
2775 propId2 = CSSPropertyWebkitMaskPositionY;
2776 } else if (propId == CSSPropertyBackgroundRepeat) {
2777 propId1 = CSSPropertyBackgroundRepeatX;
2778 propId2 = CSSPropertyBackgroundRepeatY;
2779 } else if (propId == CSSPropertyWebkitMaskRepeat) {
2780 propId1 = CSSPropertyWebkitMaskRepeatX;
2781 propId2 = CSSPropertyWebkitMaskRepeatY;
2782 }
2783
2784 while (true) {
2785 RefPtrWillBeRawPtr<CSSValue> currValue = nullptr;
2786 RefPtrWillBeRawPtr<CSSValue> currValue2 = nullptr;
2787
2788 Units unitless = FUnknown;
2789 CSSParserValue* val = m_valueList->current();
2790 ASSERT(val);
2791
2792 switch (propId) {
2793 case CSSPropertyBackgroundColor:
2794 currValue = parseColor(val);
2795 if (currValue)
2796 m_valueList->next();
2797 break;
2798 case CSSPropertyBackgroundAttachment:
2799 if (val->id == CSSValueScroll || val->id == CSSValueFixed || val->id == CSSValueLocal) {
2800 currValue = cssValuePool().createIdentifierValue(val->id);
2801 m_valueList->next();
2802 }
2803 break;
2804 case CSSPropertyBackgroundImage:
2805 case CSSPropertyWebkitMaskImage:
2806 if (parseFillImage(m_valueList, currValue))
2807 m_valueList->next();
2808 break;
2809 case CSSPropertyWebkitBackgroundClip:
2810 case CSSPropertyWebkitBackgroundOrigin:
2811 case CSSPropertyWebkitMaskClip:
2812 case CSSPropertyWebkitMaskOrigin:
2813 // The first three values here are deprecated and do not apply to th e version of the property that has
2814 // the -webkit- prefix removed.
2815 if (val->id == CSSValueBorder || val->id == CSSValuePadding || val-> id == CSSValueContent
2816 || val->id == CSSValueBorderBox || val->id == CSSValuePaddingBox || val->id == CSSValueContentBox
2817 || ((propId == CSSPropertyWebkitBackgroundClip || propId == CSSP ropertyWebkitMaskClip)
2818 && (val->id == CSSValueText || val->id == CSSValueWebkitText ))) {
2819 if (val->id == CSSValueWebkitText && m_context.useCounter())
2820 m_context.useCounter()->count(UseCounter::WebkitTextInClipPr operty);
2821 currValue = cssValuePool().createIdentifierValue(val->id);
2822 m_valueList->next();
2823 }
2824 break;
2825 case CSSPropertyBackgroundClip:
2826 if (parseBackgroundClip(val, currValue)) {
2827 if (val->id == CSSValueWebkitText && m_context.useCounter())
2828 m_context.useCounter()->count(UseCounter::WebkitTextInClipPr operty);
2829 m_valueList->next();
2830 }
2831 break;
2832 case CSSPropertyBackgroundOrigin:
2833 if (val->id == CSSValueBorderBox || val->id == CSSValuePaddingBox || val->id == CSSValueContentBox) {
2834 currValue = cssValuePool().createIdentifierValue(val->id);
2835 m_valueList->next();
2836 }
2837 break;
2838 case CSSPropertyBackgroundPosition:
2839 if (!inShorthand())
2840 unitless = FUnitlessQuirk;
2841 // fall-through
2842 case CSSPropertyWebkitMaskPosition:
2843 parseFillPosition(m_valueList, currValue, currValue2, unitless);
2844 // parseFillPosition advances the m_valueList pointer.
2845 break;
2846 case CSSPropertyBackgroundPositionX:
2847 case CSSPropertyWebkitMaskPositionX: {
2848 currValue = parseFillPositionX(m_valueList);
2849 if (currValue)
2850 m_valueList->next();
2851 break;
2852 }
2853 case CSSPropertyBackgroundPositionY:
2854 case CSSPropertyWebkitMaskPositionY: {
2855 currValue = parseFillPositionY(m_valueList);
2856 if (currValue)
2857 m_valueList->next();
2858 break;
2859 }
2860 case CSSPropertyWebkitBackgroundComposite:
2861 case CSSPropertyWebkitMaskComposite:
2862 if (val->id >= CSSValueClear && val->id <= CSSValuePlusLighter) {
2863 currValue = cssValuePool().createIdentifierValue(val->id);
2864 m_valueList->next();
2865 }
2866 break;
2867 case CSSPropertyBackgroundBlendMode:
2868 if (val->id == CSSValueNormal || val->id == CSSValueMultiply
2869 || val->id == CSSValueScreen || val->id == CSSValueOverlay || va l->id == CSSValueDarken
2870 || val->id == CSSValueLighten || val->id == CSSValueColorDodge || val->id == CSSValueColorBurn
2871 || val->id == CSSValueHardLight || val->id == CSSValueSoftLight || val->id == CSSValueDifference
2872 || val->id == CSSValueExclusion || val->id == CSSValueHue || val ->id == CSSValueSaturation
2873 || val->id == CSSValueColor || val->id == CSSValueLuminosity) {
2874 currValue = cssValuePool().createIdentifierValue(val->id);
2875 m_valueList->next();
2876 }
2877 break;
2878 case CSSPropertyBackgroundRepeat:
2879 case CSSPropertyWebkitMaskRepeat:
2880 parseFillRepeat(currValue, currValue2);
2881 // parseFillRepeat advances the m_valueList pointer
2882 break;
2883 case CSSPropertyBackgroundSize:
2884 case CSSPropertyAliasWebkitBackgroundSize:
2885 case CSSPropertyWebkitMaskSize: {
2886 currValue = parseFillSize(propId);
2887 break;
2888 }
2889 case CSSPropertyMaskSourceType: {
2890 ASSERT(RuntimeEnabledFeatures::cssMaskSourceTypeEnabled());
2891 if (val->id == CSSValueAuto || val->id == CSSValueAlpha || val->id = = CSSValueLuminance) {
2892 currValue = cssValuePool().createIdentifierValue(val->id);
2893 m_valueList->next();
2894 } else {
2895 currValue = nullptr;
2896 }
2897 break;
2898 }
2899 default:
2900 break;
2901 }
2902 if (!currValue)
2903 return false;
2904
2905 if (value && !values) {
2906 values = CSSValueList::createCommaSeparated();
2907 values->append(value.release());
2908 }
2909
2910 if (value2 && !values2) {
2911 values2 = CSSValueList::createCommaSeparated();
2912 values2->append(value2.release());
2913 }
2914
2915 if (values)
2916 values->append(currValue.release());
2917 else
2918 value = currValue.release();
2919 if (currValue2) {
2920 if (values2)
2921 values2->append(currValue2.release());
2922 else
2923 value2 = currValue2.release();
2924 }
2925
2926 // When parsing any fill shorthand property, we let it handle building u p the lists for all
2927 // properties.
2928 if (inShorthand())
2929 break;
2930
2931 if (!m_valueList->current())
2932 break;
2933 if (!consumeComma(m_valueList) || !m_valueList->current())
2934 return false;
2935 }
2936
2937 if (values) {
2938 ASSERT(values->length());
2939 retValue1 = values.release();
2940 if (values2) {
2941 ASSERT(values2->length());
2942 retValue2 = values2.release();
2943 }
2944 } else {
2945 ASSERT(value);
2946 retValue1 = value.release();
2947 retValue2 = value2.release();
2948 }
2949
2950 return true;
2951 }
2952
2953 PassRefPtrWillBeRawPtr<CSSValue> CSSPropertyParser::parseAnimationDelay()
2954 {
2955 CSSParserValue* value = m_valueList->current();
2956 if (validUnit(value, FTime))
2957 return createPrimitiveNumericValue(value);
2958 return nullptr;
2959 }
2960
2961 PassRefPtrWillBeRawPtr<CSSValue> CSSPropertyParser::parseAnimationDirection()
2962 {
2963 CSSParserValue* value = m_valueList->current();
2964 if (value->id == CSSValueNormal || value->id == CSSValueAlternate || value-> id == CSSValueReverse || value->id == CSSValueAlternateReverse)
2965 return cssValuePool().createIdentifierValue(value->id);
2966 return nullptr;
2967 }
2968
2969 PassRefPtrWillBeRawPtr<CSSValue> CSSPropertyParser::parseAnimationDuration()
2970 {
2971 CSSParserValue* value = m_valueList->current();
2972 if (validUnit(value, FTime | FNonNeg))
2973 return createPrimitiveNumericValue(value);
2974 return nullptr;
2975 }
2976
2977 PassRefPtrWillBeRawPtr<CSSValue> CSSPropertyParser::parseAnimationFillMode()
2978 {
2979 CSSParserValue* value = m_valueList->current();
2980 if (value->id == CSSValueNone || value->id == CSSValueForwards || value->id == CSSValueBackwards || value->id == CSSValueBoth)
2981 return cssValuePool().createIdentifierValue(value->id);
2982 return nullptr;
2983 }
2984
2985 PassRefPtrWillBeRawPtr<CSSValue> CSSPropertyParser::parseAnimationIterationCount ()
2986 {
2987 CSSParserValue* value = m_valueList->current();
2988 if (value->id == CSSValueInfinite)
2989 return cssValuePool().createIdentifierValue(value->id);
2990 if (validUnit(value, FNumber | FNonNeg))
2991 return createPrimitiveNumericValue(value);
2992 return nullptr;
2993 }
2994
2995 PassRefPtrWillBeRawPtr<CSSValue> CSSPropertyParser::parseAnimationName(bool allo wQuotedName)
2996 {
2997 CSSParserValue* value = m_valueList->current();
2998
2999 if (value->id == CSSValueNone)
3000 return cssValuePool().createIdentifierValue(CSSValueNone);
3001
3002 if (value->m_unit == CSSParserValue::Identifier)
3003 return createPrimitiveCustomIdentValue(value);
3004
3005 if (allowQuotedName && value->unit() == CSSPrimitiveValue::UnitType::String) {
3006 // Legacy support for strings in prefixed animations
3007 if (m_context.useCounter())
3008 m_context.useCounter()->count(UseCounter::QuotedAnimationName);
3009 if (equalIgnoringCase(value->string, "none"))
3010 return cssValuePool().createIdentifierValue(CSSValueNone);
3011 return createPrimitiveCustomIdentValue(value);
3012 }
3013
3014 return nullptr;
3015 }
3016
3017 PassRefPtrWillBeRawPtr<CSSValue> CSSPropertyParser::parseAnimationPlayState()
3018 {
3019 CSSParserValue* value = m_valueList->current();
3020 if (value->id == CSSValueRunning || value->id == CSSValuePaused)
3021 return cssValuePool().createIdentifierValue(value->id);
3022 return nullptr;
3023 }
3024
3025 PassRefPtrWillBeRawPtr<CSSValue> CSSPropertyParser::parseAnimationProperty()
3026 {
3027 CSSParserValue* value = m_valueList->current();
3028 if (value->m_unit != CSSParserValue::Identifier)
3029 return nullptr;
3030 CSSPropertyID property = unresolvedCSSPropertyID(value->string);
3031 if (property) {
3032 ASSERT(CSSPropertyMetadata::isEnabledProperty(property));
3033 return cssValuePool().createIdentifierValue(property);
3034 }
3035 if (value->id == CSSValueNone)
3036 return cssValuePool().createIdentifierValue(CSSValueNone);
3037 if (value->id == CSSValueInitial || value->id == CSSValueInherit)
3038 return nullptr;
3039 return createPrimitiveCustomIdentValue(value);
3040 }
3041
3042 bool CSSPropertyParser::parseCubicBezierTimingFunctionValue(CSSParserValueList*& args, double& result)
3043 {
3044 CSSParserValue* v = args->current();
3045 if (!validUnit(v, FNumber))
3046 return false;
3047 result = v->fValue;
3048 v = args->next();
3049 if (!v)
3050 // The last number in the function has no comma after it, so we're done.
3051 return true;
3052 return consumeComma(args);
3053 }
3054
3055 PassRefPtrWillBeRawPtr<CSSValue> CSSPropertyParser::parseAnimationTimingFunction ()
3056 {
3057 CSSParserValue* value = m_valueList->current();
3058 if (value->id == CSSValueEase || value->id == CSSValueLinear || value->id == CSSValueEaseIn || value->id == CSSValueEaseOut
3059 || value->id == CSSValueEaseInOut || value->id == CSSValueStepStart || v alue->id == CSSValueStepEnd
3060 || value->id == CSSValueStepMiddle)
3061 return cssValuePool().createIdentifierValue(value->id);
3062
3063 // We must be a function.
3064 if (value->m_unit != CSSParserValue::Function)
3065 return nullptr;
3066
3067 CSSParserValueList* args = value->function->args.get();
3068
3069 if (value->function->id == CSSValueSteps) {
3070 // For steps, 1 or 2 params must be specified (comma-separated)
3071 if (!args || (args->size() != 1 && args->size() != 3))
3072 return nullptr;
3073
3074 // There are two values.
3075 int numSteps;
3076 StepsTimingFunction::StepAtPosition stepAtPosition = StepsTimingFunction ::End;
3077
3078 CSSParserValue* v = args->current();
3079 if (!validUnit(v, FInteger))
3080 return nullptr;
3081 numSteps = clampTo<int>(v->fValue);
3082 if (numSteps < 1)
3083 return nullptr;
3084
3085 if (args->next()) {
3086 // There is a comma so we need to parse the second value
3087 if (!consumeComma(args))
3088 return nullptr;
3089 switch (args->current()->id) {
3090 case CSSValueMiddle:
3091 if (!RuntimeEnabledFeatures::webAnimationsAPIEnabled())
3092 return nullptr;
3093 stepAtPosition = StepsTimingFunction::Middle;
3094 break;
3095 case CSSValueStart:
3096 stepAtPosition = StepsTimingFunction::Start;
3097 break;
3098 case CSSValueEnd:
3099 stepAtPosition = StepsTimingFunction::End;
3100 break;
3101 default:
3102 return nullptr;
3103 }
3104 }
3105
3106 return CSSStepsTimingFunctionValue::create(numSteps, stepAtPosition);
3107 }
3108
3109 if (value->function->id == CSSValueCubicBezier) {
3110 // For cubic bezier, 4 values must be specified.
3111 if (!args || args->size() != 7)
3112 return nullptr;
3113
3114 // There are two points specified. The x values must be between 0 and 1 but the y values can exceed this range.
3115 double x1, y1, x2, y2;
3116
3117 if (!parseCubicBezierTimingFunctionValue(args, x1))
3118 return nullptr;
3119 if (x1 < 0 || x1 > 1)
3120 return nullptr;
3121 if (!parseCubicBezierTimingFunctionValue(args, y1))
3122 return nullptr;
3123 if (!parseCubicBezierTimingFunctionValue(args, x2))
3124 return nullptr;
3125 if (x2 < 0 || x2 > 1)
3126 return nullptr;
3127 if (!parseCubicBezierTimingFunctionValue(args, y2))
3128 return nullptr;
3129
3130 return CSSCubicBezierTimingFunctionValue::create(x1, y1, x2, y2);
3131 }
3132
3133 return nullptr;
3134 }
3135
3136 PassRefPtrWillBeRawPtr<CSSValue> CSSPropertyParser::parseAnimationProperty(CSSPr opertyID propId, bool useLegacyParsing)
3137 {
3138 RefPtrWillBeRawPtr<CSSValue> value = nullptr;
3139 switch (propId) {
3140 case CSSPropertyAnimationDelay:
3141 case CSSPropertyTransitionDelay:
3142 value = parseAnimationDelay();
3143 break;
3144 case CSSPropertyAnimationDirection:
3145 value = parseAnimationDirection();
3146 break;
3147 case CSSPropertyAnimationDuration:
3148 case CSSPropertyTransitionDuration:
3149 value = parseAnimationDuration();
3150 break;
3151 case CSSPropertyAnimationFillMode:
3152 value = parseAnimationFillMode();
3153 break;
3154 case CSSPropertyAnimationIterationCount:
3155 value = parseAnimationIterationCount();
3156 break;
3157 case CSSPropertyAnimationName:
3158 value = parseAnimationName(useLegacyParsing);
3159 break;
3160 case CSSPropertyAnimationPlayState:
3161 value = parseAnimationPlayState();
3162 break;
3163 case CSSPropertyTransitionProperty:
3164 value = parseAnimationProperty();
3165 break;
3166 case CSSPropertyAnimationTimingFunction:
3167 case CSSPropertyTransitionTimingFunction:
3168 value = parseAnimationTimingFunction();
3169 break;
3170 default:
3171 ASSERT_NOT_REACHED();
3172 return nullptr;
3173 }
3174
3175 if (value)
3176 m_valueList->next();
3177 return value.release();
3178 }
3179
3180 PassRefPtrWillBeRawPtr<CSSValueList> CSSPropertyParser::parseAnimationPropertyLi st(CSSPropertyID propId, bool useLegacyParsing)
3181 {
3182 RefPtrWillBeRawPtr<CSSValueList> list = CSSValueList::createCommaSeparated() ;
3183 while (true) {
3184 RefPtrWillBeRawPtr<CSSValue> value = parseAnimationProperty(propId, useL egacyParsing);
3185 if (!value)
3186 return nullptr;
3187 list->append(value.release());
3188 if (!m_valueList->current())
3189 break;
3190 if (!consumeComma(m_valueList) || !m_valueList->current())
3191 return nullptr;
3192 }
3193 if (propId == CSSPropertyTransitionProperty && !isValidTransitionPropertyLis t(list.get()))
3194 return nullptr;
3195 ASSERT(list->length());
3196 return list.release();
3197 }
3198
3199 static inline bool isCSSWideKeyword(const CSSParserValue& value)
3200 {
3201 return value.id == CSSValueInitial || value.id == CSSValueInherit || value.i d == CSSValueUnset || value.id == CSSValueDefault;
3202 }
3203
3204 static inline bool isValidCustomIdentForGridPositions(const CSSParserValue& valu e)
3205 {
3206 // FIXME: we need a more general solution for <custom-ident> in all properti es.
3207 return value.m_unit == CSSParserValue::Identifier && value.id != CSSValueSpa n && value.id != CSSValueAuto && !isCSSWideKeyword(value);
3208 }
3209
3210 // The function parses [ <integer> || <custom-ident> ] in <grid-line> (which can be stand alone or with 'span').
3211 bool CSSPropertyParser::parseIntegerOrCustomIdentFromGridPosition(RefPtrWillBeRa wPtr<CSSPrimitiveValue>& numericValue, RefPtrWillBeRawPtr<CSSPrimitiveValue>& gr idLineName)
3212 {
3213 CSSParserValue* value = m_valueList->current();
3214 if (validUnit(value, FInteger) && value->fValue) {
3215 numericValue = createPrimitiveNumericValue(value);
3216 value = m_valueList->next();
3217 if (value && isValidCustomIdentForGridPositions(*value)) {
3218 gridLineName = createPrimitiveCustomIdentValue(m_valueList->current( ));
3219 m_valueList->next();
3220 }
3221 return true;
3222 }
3223
3224 if (isValidCustomIdentForGridPositions(*value)) {
3225 gridLineName = createPrimitiveCustomIdentValue(m_valueList->current());
3226 value = m_valueList->next();
3227 if (value && validUnit(value, FInteger) && value->fValue) {
3228 numericValue = createPrimitiveNumericValue(value);
3229 m_valueList->next();
3230 }
3231 return true;
3232 }
3233
3234 return false;
3235 }
3236
3237 PassRefPtrWillBeRawPtr<CSSValue> CSSPropertyParser::parseGridPosition()
3238 {
3239 ASSERT(RuntimeEnabledFeatures::cssGridLayoutEnabled());
3240
3241 CSSParserValue* value = m_valueList->current();
3242 if (value->id == CSSValueAuto) {
3243 m_valueList->next();
3244 return cssValuePool().createIdentifierValue(CSSValueAuto);
3245 }
3246
3247 RefPtrWillBeRawPtr<CSSPrimitiveValue> numericValue = nullptr;
3248 RefPtrWillBeRawPtr<CSSPrimitiveValue> gridLineName = nullptr;
3249 bool hasSeenSpanKeyword = false;
3250
3251 if (parseIntegerOrCustomIdentFromGridPosition(numericValue, gridLineName)) {
3252 value = m_valueList->current();
3253 if (value && value->id == CSSValueSpan) {
3254 hasSeenSpanKeyword = true;
3255 m_valueList->next();
3256 }
3257 } else if (value->id == CSSValueSpan) {
3258 hasSeenSpanKeyword = true;
3259 if (CSSParserValue* nextValue = m_valueList->next()) {
3260 if (!isForwardSlashOperator(nextValue) && !parseIntegerOrCustomIdent FromGridPosition(numericValue, gridLineName))
3261 return nullptr;
3262 }
3263 }
3264
3265 // Check that we have consumed all the value list. For shorthands, the parse r will pass
3266 // the whole value list (including the opposite position).
3267 if (m_valueList->current() && !isForwardSlashOperator(m_valueList->current() ))
3268 return nullptr;
3269
3270 // If we didn't parse anything, this is not a valid grid position.
3271 if (!hasSeenSpanKeyword && !gridLineName && !numericValue)
3272 return nullptr;
3273
3274 // Negative numbers are not allowed for span (but are for <integer>).
3275 if (hasSeenSpanKeyword && numericValue && numericValue->getIntValue() < 0)
3276 return nullptr;
3277
3278 // For the <custom-ident> case.
3279 if (gridLineName && !numericValue && !hasSeenSpanKeyword)
3280 return cssValuePool().createValue(gridLineName->getStringValue(), CSSPri mitiveValue::UnitType::CustomIdentifier);
3281
3282 RefPtrWillBeRawPtr<CSSValueList> values = CSSValueList::createSpaceSeparated ();
3283 if (hasSeenSpanKeyword)
3284 values->append(cssValuePool().createIdentifierValue(CSSValueSpan));
3285 if (numericValue)
3286 values->append(numericValue.release());
3287 if (gridLineName)
3288 values->append(gridLineName.release());
3289 ASSERT(values->length());
3290 return values.release();
3291 }
3292
3293 static PassRefPtrWillBeRawPtr<CSSValue> gridMissingGridPositionValue(CSSValue* v alue)
3294 {
3295 if (value->isPrimitiveValue() && toCSSPrimitiveValue(value)->isCustomIdent() )
3296 return value;
3297
3298 return cssValuePool().createIdentifierValue(CSSValueAuto);
3299 }
3300
3301 bool CSSPropertyParser::parseGridItemPositionShorthand(CSSPropertyID shorthandId , bool important)
3302 {
3303 ShorthandScope scope(this, shorthandId);
3304 const StylePropertyShorthand& shorthand = shorthandForProperty(shorthandId);
3305 ASSERT(shorthand.length() == 2);
3306
3307 RefPtrWillBeRawPtr<CSSValue> startValue = parseGridPosition();
3308 if (!startValue)
3309 return false;
3310
3311 RefPtrWillBeRawPtr<CSSValue> endValue = nullptr;
3312 if (m_valueList->current()) {
3313 if (!isForwardSlashOperator(m_valueList->current()))
3314 return false;
3315
3316 if (!m_valueList->next())
3317 return false;
3318
3319 endValue = parseGridPosition();
3320 if (!endValue || m_valueList->current())
3321 return false;
3322 } else {
3323 endValue = gridMissingGridPositionValue(startValue.get());
3324 }
3325
3326 addProperty(shorthand.properties()[0], startValue, important);
3327 addProperty(shorthand.properties()[1], endValue, important);
3328 return true;
3329 }
3330
3331 bool CSSPropertyParser::parseGridTemplateRowsAndAreas(PassRefPtrWillBeRawPtr<CSS Value> templateColumns, bool important)
3332 {
3333 NamedGridAreaMap gridAreaMap;
3334 size_t rowCount = 0;
3335 size_t columnCount = 0;
3336 bool trailingIdentWasAdded = false;
3337 RefPtrWillBeRawPtr<CSSValueList> templateRows = CSSValueList::createSpaceSep arated();
3338
3339 // At least template-areas strings must be defined.
3340 if (!m_valueList->current())
3341 return false;
3342
3343 while (m_valueList->current()) {
3344 // Handle leading <custom-ident>*.
3345 if (!parseGridLineNames(*m_valueList, *templateRows, trailingIdentWasAdd ed ? toCSSGridLineNamesValue(templateRows->item(templateRows->length() - 1)) : n ullptr))
3346 return false;
3347
3348 // Handle a template-area's row.
3349 if (!parseGridTemplateAreasRow(gridAreaMap, rowCount, columnCount))
3350 return false;
3351 ++rowCount;
3352
3353 // Handle template-rows's track-size.
3354 if (m_valueList->current() && m_valueList->current()->unit() != CSSPrimi tiveValue::UnitType::String) {
3355 RefPtrWillBeRawPtr<CSSValue> value = parseGridTrackSize(*m_valueList );
3356 if (!value)
3357 return false;
3358 templateRows->append(value);
3359 } else {
3360 templateRows->append(cssValuePool().createIdentifierValue(CSSValueAu to));
3361 }
3362
3363 // This will handle the trailing/leading <custom-ident>* in the grammar.
3364 if (!parseGridLineNames(*m_valueList, *templateRows))
3365 return false;
3366 trailingIdentWasAdded = templateRows->item(templateRows->length() - 1)-> isGridLineNamesValue();
3367 }
3368
3369 // [<track-list> /]?
3370 if (templateColumns)
3371 addProperty(CSSPropertyGridTemplateColumns, templateColumns, important);
3372 else
3373 addProperty(CSSPropertyGridTemplateColumns, cssValuePool().createIdenti fierValue(CSSValueNone), important);
3374
3375 // [<line-names>? <string> [<track-size> <line-names>]? ]+
3376 RefPtrWillBeRawPtr<CSSValue> templateAreas = CSSGridTemplateAreasValue::crea te(gridAreaMap, rowCount, columnCount);
3377 addProperty(CSSPropertyGridTemplateAreas, templateAreas.release(), important );
3378 addProperty(CSSPropertyGridTemplateRows, templateRows.release(), important);
3379
3380 return true;
3381 }
3382
3383
3384 bool CSSPropertyParser::parseGridTemplateShorthand(bool important)
3385 {
3386 ASSERT(RuntimeEnabledFeatures::cssGridLayoutEnabled());
3387
3388 ShorthandScope scope(this, CSSPropertyGridTemplate);
3389 ASSERT(gridTemplateShorthand().length() == 3);
3390
3391 // At least "none" must be defined.
3392 if (!m_valueList->current())
3393 return false;
3394
3395 bool firstValueIsNone = m_valueList->current()->id == CSSValueNone;
3396
3397 // 1- 'none' case.
3398 if (firstValueIsNone && !m_valueList->next()) {
3399 addProperty(CSSPropertyGridTemplateColumns, cssValuePool().createIdentif ierValue(CSSValueNone), important);
3400 addProperty(CSSPropertyGridTemplateRows, cssValuePool().createIdentifier Value(CSSValueNone), important);
3401 addProperty(CSSPropertyGridTemplateAreas, cssValuePool().createIdentifie rValue(CSSValueNone), important);
3402 return true;
3403 }
3404
3405 unsigned index = 0;
3406 RefPtrWillBeRawPtr<CSSValue> columnsValue = nullptr;
3407 if (firstValueIsNone) {
3408 columnsValue = cssValuePool().createIdentifierValue(CSSValueNone);
3409 } else {
3410 columnsValue = parseGridTrackList();
3411 }
3412
3413 // 2- <grid-template-columns> / <grid-template-columns> syntax.
3414 if (columnsValue) {
3415 if (!(m_valueList->current() && isForwardSlashOperator(m_valueList->curr ent()) && m_valueList->next()))
3416 return false;
3417 index = m_valueList->currentIndex();
3418 if (RefPtrWillBeRawPtr<CSSValue> rowsValue = parseGridTrackList()) {
3419 if (m_valueList->current())
3420 return false;
3421 addProperty(CSSPropertyGridTemplateColumns, columnsValue, important) ;
3422 addProperty(CSSPropertyGridTemplateRows, rowsValue, important);
3423 addProperty(CSSPropertyGridTemplateAreas, cssValuePool().createIdent ifierValue(CSSValueNone), important);
3424 return true;
3425 }
3426 }
3427
3428
3429 // 3- [<track-list> /]? [<line-names>? <string> [<track-size> <line-names>]? ]+ syntax.
3430 // The template-columns <track-list> can't be 'none'.
3431 if (firstValueIsNone)
3432 return false;
3433 // It requires to rewind parsing due to previous syntax failures.
3434 m_valueList->setCurrentIndex(index);
3435 return parseGridTemplateRowsAndAreas(columnsValue, important);
3436 }
3437
3438 bool CSSPropertyParser::parseGridShorthand(bool important)
3439 {
3440 ShorthandScope scope(this, CSSPropertyGrid);
3441 ASSERT(shorthandForProperty(CSSPropertyGrid).length() == 6);
3442
3443 // 1- <grid-template>
3444 if (parseGridTemplateShorthand(important)) {
3445 // It can only be specified the explicit or the implicit grid properties in a single grid declaration.
3446 // The sub-properties not specified are set to their initial value, as n ormal for shorthands.
3447 addProperty(CSSPropertyGridAutoFlow, cssValuePool().createImplicitInitia lValue(), important);
3448 addProperty(CSSPropertyGridAutoColumns, cssValuePool().createImplicitIni tialValue(), important);
3449 addProperty(CSSPropertyGridAutoRows, cssValuePool().createImplicitInitia lValue(), important);
3450 return true;
3451 }
3452
3453 // Need to rewind parsing to explore the alternative syntax of this shorthan d.
3454 m_valueList->setCurrentIndex(0);
3455
3456 // 2- <grid-auto-flow> [ <grid-auto-columns> [ / <grid-auto-rows> ]? ]
3457 if (!parseValue(CSSPropertyGridAutoFlow, important))
3458 return false;
3459
3460 RefPtrWillBeRawPtr<CSSValue> autoColumnsValue = nullptr;
3461 RefPtrWillBeRawPtr<CSSValue> autoRowsValue = nullptr;
3462
3463 if (m_valueList->current()) {
3464 autoColumnsValue = parseGridTrackSize(*m_valueList);
3465 if (!autoColumnsValue)
3466 return false;
3467 if (m_valueList->current()) {
3468 if (!isForwardSlashOperator(m_valueList->current()) || !m_valueList- >next())
3469 return false;
3470 autoRowsValue = parseGridTrackSize(*m_valueList);
3471 if (!autoRowsValue)
3472 return false;
3473 }
3474 if (m_valueList->current())
3475 return false;
3476 } else {
3477 // Other omitted values are set to their initial values.
3478 autoColumnsValue = cssValuePool().createImplicitInitialValue();
3479 autoRowsValue = cssValuePool().createImplicitInitialValue();
3480 }
3481
3482 // if <grid-auto-rows> value is omitted, it is set to the value specified fo r grid-auto-columns.
3483 if (!autoRowsValue)
3484 autoRowsValue = autoColumnsValue;
3485
3486 addProperty(CSSPropertyGridAutoColumns, autoColumnsValue, important);
3487 addProperty(CSSPropertyGridAutoRows, autoRowsValue, important);
3488
3489 // It can only be specified the explicit or the implicit grid properties in a single grid declaration.
3490 // The sub-properties not specified are set to their initial value, as norma l for shorthands.
3491 addProperty(CSSPropertyGridTemplateColumns, cssValuePool().createImplicitIni tialValue(), important);
3492 addProperty(CSSPropertyGridTemplateRows, cssValuePool().createImplicitInitia lValue(), important);
3493 addProperty(CSSPropertyGridTemplateAreas, cssValuePool().createImplicitIniti alValue(), important);
3494
3495 return true;
3496 }
3497
3498 bool CSSPropertyParser::parseGridAreaShorthand(bool important)
3499 {
3500 ASSERT(RuntimeEnabledFeatures::cssGridLayoutEnabled());
3501
3502 ShorthandScope scope(this, CSSPropertyGridArea);
3503 const StylePropertyShorthand& shorthand = gridAreaShorthand();
3504 ASSERT_UNUSED(shorthand, shorthand.length() == 4);
3505
3506 RefPtrWillBeRawPtr<CSSValue> rowStartValue = parseGridPosition();
3507 if (!rowStartValue)
3508 return false;
3509
3510 RefPtrWillBeRawPtr<CSSValue> columnStartValue = nullptr;
3511 if (!parseSingleGridAreaLonghand(columnStartValue))
3512 return false;
3513
3514 RefPtrWillBeRawPtr<CSSValue> rowEndValue = nullptr;
3515 if (!parseSingleGridAreaLonghand(rowEndValue))
3516 return false;
3517
3518 RefPtrWillBeRawPtr<CSSValue> columnEndValue = nullptr;
3519 if (!parseSingleGridAreaLonghand(columnEndValue))
3520 return false;
3521
3522 if (!columnStartValue)
3523 columnStartValue = gridMissingGridPositionValue(rowStartValue.get());
3524
3525 if (!rowEndValue)
3526 rowEndValue = gridMissingGridPositionValue(rowStartValue.get());
3527
3528 if (!columnEndValue)
3529 columnEndValue = gridMissingGridPositionValue(columnStartValue.get());
3530
3531 addProperty(CSSPropertyGridRowStart, rowStartValue, important);
3532 addProperty(CSSPropertyGridColumnStart, columnStartValue, important);
3533 addProperty(CSSPropertyGridRowEnd, rowEndValue, important);
3534 addProperty(CSSPropertyGridColumnEnd, columnEndValue, important);
3535 return true;
3536 }
3537
3538 bool CSSPropertyParser::parseSingleGridAreaLonghand(RefPtrWillBeRawPtr<CSSValue> & property)
3539 {
3540 if (!m_valueList->current())
3541 return true;
3542
3543 if (!isForwardSlashOperator(m_valueList->current()))
3544 return false;
3545
3546 if (!m_valueList->next())
3547 return false;
3548
3549 property = parseGridPosition();
3550 return true;
3551 }
3552
3553 static inline bool isClosingBracket(const CSSParserValue& value)
3554 {
3555 return value.m_unit == CSSParserValue::Operator && value.iValue == ']';
3556 }
3557
3558 bool CSSPropertyParser::parseGridLineNames(CSSParserValueList& inputList, CSSVal ueList& valueList, CSSGridLineNamesValue* previousNamedAreaTrailingLineNames)
3559 {
3560 if (!inputList.current() || inputList.current()->m_unit != CSSParserValue::O perator || inputList.current()->iValue != '[')
3561 return true;
3562
3563 // Skip '['
3564 inputList.next();
3565
3566 RefPtrWillBeRawPtr<CSSGridLineNamesValue> lineNames = previousNamedAreaTrail ingLineNames;
3567 if (!lineNames)
3568 lineNames = CSSGridLineNamesValue::create();
3569
3570 while (CSSParserValue* identValue = inputList.current()) {
3571 if (isClosingBracket(*identValue))
3572 break;
3573
3574 if (!isValidCustomIdentForGridPositions(*identValue))
3575 return false;
3576
3577 RefPtrWillBeRawPtr<CSSPrimitiveValue> lineName = createPrimitiveCustomId entValue(identValue);
3578 lineNames->append(lineName.release());
3579 inputList.next();
3580 }
3581
3582 if (!inputList.current() || !isClosingBracket(*inputList.current()))
3583 return false;
3584
3585 if (!previousNamedAreaTrailingLineNames)
3586 valueList.append(lineNames.release());
3587
3588 // Consume ']'
3589 inputList.next();
3590 return true;
3591 }
3592
3593 PassRefPtrWillBeRawPtr<CSSValue> CSSPropertyParser::parseGridTrackList()
3594 {
3595 ASSERT(RuntimeEnabledFeatures::cssGridLayoutEnabled());
3596
3597 CSSParserValue* value = m_valueList->current();
3598 if (value->id == CSSValueNone) {
3599 m_valueList->next();
3600 return cssValuePool().createIdentifierValue(CSSValueNone);
3601 }
3602
3603 RefPtrWillBeRawPtr<CSSValueList> values = CSSValueList::createSpaceSeparated ();
3604 // Handle leading <custom-ident>*.
3605 if (!parseGridLineNames(*m_valueList, *values))
3606 return nullptr;
3607
3608 bool seenTrackSizeOrRepeatFunction = false;
3609 while (CSSParserValue* currentValue = m_valueList->current()) {
3610 if (isForwardSlashOperator(currentValue))
3611 break;
3612 if (currentValue->m_unit == CSSParserValue::Function && currentValue->fu nction->id == CSSValueRepeat) {
3613 if (!parseGridTrackRepeatFunction(*values))
3614 return nullptr;
3615 seenTrackSizeOrRepeatFunction = true;
3616 } else {
3617 RefPtrWillBeRawPtr<CSSValue> value = parseGridTrackSize(*m_valueList );
3618 if (!value)
3619 return nullptr;
3620 values->append(value);
3621 seenTrackSizeOrRepeatFunction = true;
3622 }
3623 // This will handle the trailing <custom-ident>* in the grammar.
3624 if (!parseGridLineNames(*m_valueList, *values))
3625 return nullptr;
3626 }
3627
3628 // We should have found a <track-size> or else it is not a valid <track-list >
3629 if (!seenTrackSizeOrRepeatFunction)
3630 return nullptr;
3631
3632 return values;
3633 }
3634
3635 bool CSSPropertyParser::parseGridTrackRepeatFunction(CSSValueList& list)
3636 {
3637 CSSParserValueList* arguments = m_valueList->current()->function->args.get() ;
3638 if (!arguments || arguments->size() < 3 || !validUnit(arguments->valueAt(0), FPositiveInteger) || !isComma(arguments->valueAt(1)))
3639 return false;
3640
3641 ASSERT(arguments->valueAt(0)->fValue > 0);
3642 size_t repetitions = clampTo<size_t>(arguments->valueAt(0)->fValue, 0, kGrid MaxTracks);
3643
3644 RefPtrWillBeRawPtr<CSSValueList> repeatedValues = CSSValueList::createSpaceS eparated();
3645 arguments->next(); // Skip the repetition count.
3646 arguments->next(); // Skip the comma.
3647
3648 // Handle leading <custom-ident>*.
3649 if (!parseGridLineNames(*arguments, *repeatedValues))
3650 return false;
3651
3652 size_t numberOfTracks = 0;
3653 while (arguments->current()) {
3654 RefPtrWillBeRawPtr<CSSValue> trackSize = parseGridTrackSize(*arguments);
3655 if (!trackSize)
3656 return false;
3657
3658 repeatedValues->append(trackSize);
3659 ++numberOfTracks;
3660
3661 // This takes care of any trailing <custom-ident>* in the grammar.
3662 if (!parseGridLineNames(*arguments, *repeatedValues))
3663 return false;
3664 }
3665
3666 // We should have found at least one <track-size> or else it is not a valid <track-list>.
3667 if (!numberOfTracks)
3668 return false;
3669
3670 // We clamp the number of repetitions to a multiple of the repeat() track li st's size, while staying below the max
3671 // grid size.
3672 repetitions = std::min(repetitions, kGridMaxTracks / numberOfTracks);
3673
3674 for (size_t i = 0; i < repetitions; ++i) {
3675 for (size_t j = 0; j < repeatedValues->length(); ++j)
3676 list.append(repeatedValues->item(j));
3677 }
3678
3679 // parseGridTrackSize iterated over the repeat arguments, move to the next v alue.
3680 m_valueList->next();
3681 return true;
3682 }
3683
3684
3685 PassRefPtrWillBeRawPtr<CSSValue> CSSPropertyParser::parseGridTrackSize(CSSParser ValueList& inputList)
3686 {
3687 ASSERT(RuntimeEnabledFeatures::cssGridLayoutEnabled());
3688
3689 CSSParserValue* currentValue = inputList.current();
3690 inputList.next();
3691
3692 if (currentValue->id == CSSValueAuto)
3693 return cssValuePool().createIdentifierValue(CSSValueAuto);
3694
3695 if (currentValue->m_unit == CSSParserValue::Function && currentValue->functi on->id == CSSValueMinmax) {
3696 // The spec defines the following grammar: minmax( <track-breadth> , <tr ack-breadth> )
3697 CSSParserValueList* arguments = currentValue->function->args.get();
3698 if (!arguments || arguments->size() != 3 || !isComma(arguments->valueAt( 1)))
3699 return nullptr;
3700
3701 RefPtrWillBeRawPtr<CSSPrimitiveValue> minTrackBreadth = parseGridBreadth (arguments->valueAt(0));
3702 if (!minTrackBreadth)
3703 return nullptr;
3704
3705 RefPtrWillBeRawPtr<CSSPrimitiveValue> maxTrackBreadth = parseGridBreadth (arguments->valueAt(2));
3706 if (!maxTrackBreadth)
3707 return nullptr;
3708
3709 RefPtrWillBeRawPtr<CSSFunctionValue> result = CSSFunctionValue::create(C SSValueMinmax);
3710 result->append(minTrackBreadth);
3711 result->append(maxTrackBreadth);
3712 return result.release();
3713 }
3714
3715 return parseGridBreadth(currentValue);
3716 }
3717
3718 PassRefPtrWillBeRawPtr<CSSPrimitiveValue> CSSPropertyParser::parseGridBreadth(CS SParserValue* currentValue)
3719 {
3720 if (currentValue->id == CSSValueMinContent || currentValue->id == CSSValueMa xContent || currentValue->id == CSSValueAuto)
3721 return cssValuePool().createIdentifierValue(currentValue->id);
3722
3723 if (currentValue->unit() == CSSPrimitiveValue::UnitType::Fraction) {
3724 double flexValue = currentValue->fValue;
3725
3726 // Fractional unit is a non-negative dimension.
3727 if (flexValue <= 0)
3728 return nullptr;
3729
3730 return cssValuePool().createValue(flexValue, CSSPrimitiveValue::UnitType ::Fraction);
3731 }
3732
3733 if (!validUnit(currentValue, FNonNeg | FLength | FPercent))
3734 return nullptr;
3735
3736 return createPrimitiveNumericValue(currentValue);
3737 }
3738
3739 static Vector<String> parseGridTemplateAreasColumnNames(const String& gridRowNam es)
3740 {
3741 ASSERT(!gridRowNames.isEmpty());
3742 Vector<String> columnNames;
3743 // Using StringImpl to avoid checks and indirection in every call to String: :operator[].
3744 StringImpl& text = *gridRowNames.impl();
3745
3746 StringBuilder areaName;
3747 for (unsigned i = 0; i < text.length(); ++i) {
3748 if (text[i] == ' ') {
3749 if (!areaName.isEmpty()) {
3750 columnNames.append(areaName.toString());
3751 areaName.clear();
3752 }
3753 continue;
3754 }
3755 if (text[i] == '.') {
3756 if (areaName == ".")
3757 continue;
3758 if (!areaName.isEmpty()) {
3759 columnNames.append(areaName.toString());
3760 areaName.clear();
3761 }
3762 } else {
3763 if (areaName == ".") {
3764 columnNames.append(areaName.toString());
3765 areaName.clear();
3766 }
3767 }
3768
3769 areaName.append(text[i]);
3770 }
3771
3772 if (!areaName.isEmpty())
3773 columnNames.append(areaName.toString());
3774
3775 return columnNames;
3776 }
3777
3778 bool CSSPropertyParser::parseGridTemplateAreasRow(NamedGridAreaMap& gridAreaMap, const size_t rowCount, size_t& columnCount)
3779 {
3780 CSSParserValue* currentValue = m_valueList->current();
3781 if (!currentValue || currentValue->unit() != CSSPrimitiveValue::UnitType::St ring)
3782 return false;
3783
3784 String gridRowNames = currentValue->string;
3785 if (gridRowNames.isEmpty() || gridRowNames.containsOnlyWhitespace())
3786 return false;
3787
3788 Vector<String> columnNames = parseGridTemplateAreasColumnNames(gridRowNames) ;
3789 if (!columnCount) {
3790 columnCount = columnNames.size();
3791 ASSERT(columnCount);
3792 } else if (columnCount != columnNames.size()) {
3793 // The declaration is invalid is all the rows don't have the number of c olumns.
3794 return false;
3795 }
3796
3797 for (size_t currentCol = 0; currentCol < columnCount; ++currentCol) {
3798 const String& gridAreaName = columnNames[currentCol];
3799
3800 // Unamed areas are always valid (we consider them to be 1x1).
3801 if (gridAreaName == ".")
3802 continue;
3803
3804 // We handle several grid areas with the same name at once to simplify t he validation code.
3805 size_t lookAheadCol;
3806 for (lookAheadCol = currentCol; lookAheadCol < (columnCount - 1); ++look AheadCol) {
3807 if (columnNames[lookAheadCol + 1] != gridAreaName)
3808 break;
3809 }
3810
3811 NamedGridAreaMap::iterator gridAreaIt = gridAreaMap.find(gridAreaName);
3812 if (gridAreaIt == gridAreaMap.end()) {
3813 gridAreaMap.add(gridAreaName, GridCoordinate(GridSpan(rowCount, rowC ount), GridSpan(currentCol, lookAheadCol)));
3814 } else {
3815 GridCoordinate& gridCoordinate = gridAreaIt->value;
3816
3817 // The following checks test that the grid area is a single filled-i n rectangle.
3818 // 1. The new row is adjacent to the previously parsed row.
3819 if (rowCount != gridCoordinate.rows.resolvedFinalPosition.next().toI nt())
3820 return false;
3821
3822 // 2. The new area starts at the same position as the previously par sed area.
3823 if (currentCol != gridCoordinate.columns.resolvedInitialPosition.toI nt())
3824 return false;
3825
3826 // 3. The new area ends at the same position as the previously parse d area.
3827 if (lookAheadCol != gridCoordinate.columns.resolvedFinalPosition.toI nt())
3828 return false;
3829
3830 ++gridCoordinate.rows.resolvedFinalPosition;
3831 }
3832 currentCol = lookAheadCol;
3833 }
3834
3835 m_valueList->next();
3836 return true;
3837 }
3838
3839 PassRefPtrWillBeRawPtr<CSSValue> CSSPropertyParser::parseGridTemplateAreas()
3840 {
3841 if (m_valueList->current() && m_valueList->current()->id == CSSValueNone) {
3842 m_valueList->next();
3843 return cssValuePool().createIdentifierValue(CSSValueNone);
3844 }
3845
3846 NamedGridAreaMap gridAreaMap;
3847 size_t rowCount = 0;
3848 size_t columnCount = 0;
3849
3850 while (m_valueList->current()) {
3851 if (!parseGridTemplateAreasRow(gridAreaMap, rowCount, columnCount))
3852 return nullptr;
3853 ++rowCount;
3854 }
3855
3856 if (!rowCount || !columnCount)
3857 return nullptr;
3858
3859 return CSSGridTemplateAreasValue::create(gridAreaMap, rowCount, columnCount) ;
3860 }
3861
3862 PassRefPtrWillBeRawPtr<CSSValue> CSSPropertyParser::parseGridAutoFlow(CSSParserV alueList& list)
3863 {
3864 // [ row | column ] || dense
3865 ASSERT(RuntimeEnabledFeatures::cssGridLayoutEnabled());
3866
3867 CSSParserValue* value = list.current();
3868 if (!value)
3869 return nullptr;
3870
3871 RefPtrWillBeRawPtr<CSSValueList> parsedValues = CSSValueList::createSpaceSep arated();
3872
3873 // First parameter.
3874 CSSValueID firstId = value->id;
3875 if (firstId != CSSValueRow && firstId != CSSValueColumn && firstId != CSSVal ueDense)
3876 return nullptr;
3877 parsedValues->append(cssValuePool().createIdentifierValue(firstId));
3878
3879 // Second parameter, if any.
3880 value = list.next();
3881 if (value) {
3882 switch (firstId) {
3883 case CSSValueRow:
3884 case CSSValueColumn:
3885 if (value->id != CSSValueDense)
3886 return parsedValues;
3887 break;
3888 case CSSValueDense:
3889 if (value->id != CSSValueRow && value->id != CSSValueColumn)
3890 return parsedValues;
3891 break;
3892 default:
3893 return parsedValues;
3894 }
3895 parsedValues->append(cssValuePool().createIdentifierValue(value->id));
3896 list.next();
3897 }
3898
3899 return parsedValues;
3900 }
3901
3902 PassRefPtrWillBeRawPtr<CSSValue> CSSPropertyParser::parseCounterContent(CSSParse rValueList* args, bool counters)
3903 {
3904 unsigned numArgs = args->size();
3905 if (counters && numArgs != 3 && numArgs != 5)
3906 return nullptr;
3907 if (!counters && numArgs != 1 && numArgs != 3)
3908 return nullptr;
3909
3910 CSSParserValue* i = args->current();
3911 if (i->m_unit != CSSParserValue::Identifier)
3912 return nullptr;
3913 RefPtrWillBeRawPtr<CSSPrimitiveValue> identifier = createPrimitiveCustomIden tValue(i);
3914
3915 RefPtrWillBeRawPtr<CSSPrimitiveValue> separator = nullptr;
3916 if (!counters)
3917 separator = cssValuePool().createValue(String(), CSSPrimitiveValue::Unit Type::CustomIdentifier);
3918 else {
3919 args->next();
3920 if (!consumeComma(args))
3921 return nullptr;
3922
3923 i = args->current();
3924 if (i->unit() != CSSPrimitiveValue::UnitType::String)
3925 return nullptr;
3926
3927 separator = createPrimitiveCustomIdentValue(i);
3928 }
3929
3930 RefPtrWillBeRawPtr<CSSPrimitiveValue> listStyle = nullptr;
3931 i = args->next();
3932 if (!i) // Make the list style default decimal
3933 listStyle = cssValuePool().createIdentifierValue(CSSValueDecimal);
3934 else {
3935 if (!consumeComma(args))
3936 return nullptr;
3937
3938 i = args->current();
3939 if (i->m_unit != CSSParserValue::Identifier)
3940 return nullptr;
3941
3942 CSSValueID listStyleID = CSSValueInvalid;
3943 if (i->id == CSSValueNone || (i->id >= CSSValueDisc && i->id <= CSSValue KatakanaIroha))
3944 listStyleID = i->id;
3945 else
3946 return nullptr;
3947
3948 listStyle = cssValuePool().createIdentifierValue(listStyleID);
3949 }
3950
3951 return CSSCounterValue::create(identifier.release(), listStyle.release(), se parator.release());
3952 }
3953
3954 PassRefPtrWillBeRawPtr<CSSQuadValue> CSSPropertyParser::parseClipShape()
3955 {
3956 CSSParserValue* value = m_valueList->current();
3957 CSSParserValueList* args = value->function->args.get();
3958
3959 if (value->function->id != CSSValueRect || !args)
3960 return nullptr;
3961
3962 // rect(t, r, b, l) || rect(t r b l)
3963 if (args->size() != 4 && args->size() != 7)
3964 return nullptr;
3965 int i = 0;
3966 CSSParserValue* a = args->current();
3967
3968 RefPtrWillBeRawPtr<CSSPrimitiveValue> top = nullptr;
3969 RefPtrWillBeRawPtr<CSSPrimitiveValue> right = nullptr;
3970 RefPtrWillBeRawPtr<CSSPrimitiveValue> bottom = nullptr;
3971 RefPtrWillBeRawPtr<CSSPrimitiveValue> left = nullptr;
3972 while (a) {
3973 if (a->id != CSSValueAuto && !validUnit(a, FLength | FUnitlessQuirk))
3974 return nullptr;
3975 RefPtrWillBeRawPtr<CSSPrimitiveValue> length = a->id == CSSValueAuto ?
3976 cssValuePool().createIdentifierValue(CSSValueAuto) :
3977 createPrimitiveNumericValue(a);
3978 if (i == 0)
3979 top = length;
3980 else if (i == 1)
3981 right = length;
3982 else if (i == 2)
3983 bottom = length;
3984 else
3985 left = length;
3986 a = args->next();
3987 if (a && args->size() == 7) {
3988 if (!consumeComma(args))
3989 return nullptr;
3990 a = args->current();
3991 }
3992 i++;
3993 }
3994 m_valueList->next();
3995 return CSSQuadValue::create(top.release(), right.release(), bottom.release() , left.release(), CSSQuadValue::SerializeAsRect);
3996 }
3997
3998 static void completeBorderRadii(RefPtrWillBeRawPtr<CSSPrimitiveValue> radii[4])
3999 {
4000 if (radii[3])
4001 return;
4002 if (!radii[2]) {
4003 if (!radii[1])
4004 radii[1] = radii[0];
4005 radii[2] = radii[0];
4006 }
4007 radii[3] = radii[1];
4008 }
4009
4010 // FIXME: This should be refactored with parseBorderRadius.
4011 // parseBorderRadius contains support for some legacy radius construction.
4012 PassRefPtrWillBeRawPtr<CSSBasicShape> CSSPropertyParser::parseInsetRoundedCorner s(PassRefPtrWillBeRawPtr<CSSBasicShapeInset> shape, CSSParserValueList* args)
4013 {
4014 CSSParserValue* argument = args->next();
4015
4016 if (!argument)
4017 return nullptr;
4018
4019 Vector<CSSParserValue*> radiusArguments;
4020 while (argument) {
4021 radiusArguments.append(argument);
4022 argument = args->next();
4023 }
4024
4025 unsigned num = radiusArguments.size();
4026 if (!num || num > 9)
4027 return nullptr;
4028
4029 // FIXME: Refactor completeBorderRadii and the array
4030 RefPtrWillBeRawPtr<CSSPrimitiveValue> radii[2][4];
4031 #if ENABLE(OILPAN)
4032 // Zero initialize the array of raw pointers.
4033 memset(&radii, 0, sizeof(radii));
4034 #endif
4035
4036 unsigned indexAfterSlash = 0;
4037 for (unsigned i = 0; i < num; ++i) {
4038 CSSParserValue* value = radiusArguments.at(i);
4039 if (value->m_unit == CSSParserValue::Operator) {
4040 if (value->iValue != '/')
4041 return nullptr;
4042
4043 if (!i || indexAfterSlash || i + 1 == num)
4044 return nullptr;
4045
4046 indexAfterSlash = i + 1;
4047 completeBorderRadii(radii[0]);
4048 continue;
4049 }
4050
4051 if (i - indexAfterSlash >= 4)
4052 return nullptr;
4053
4054 if (!validUnit(value, FLength | FPercent | FNonNeg))
4055 return nullptr;
4056
4057 RefPtrWillBeRawPtr<CSSPrimitiveValue> radius = createPrimitiveNumericVal ue(value);
4058
4059 if (!indexAfterSlash)
4060 radii[0][i] = radius;
4061 else
4062 radii[1][i - indexAfterSlash] = radius.release();
4063 }
4064
4065 if (!indexAfterSlash) {
4066 completeBorderRadii(radii[0]);
4067 for (unsigned i = 0; i < 4; ++i)
4068 radii[1][i] = radii[0][i];
4069 } else {
4070 completeBorderRadii(radii[1]);
4071 }
4072 shape->setTopLeftRadius(CSSValuePair::create(radii[0][0].release(), radii[1] [0].release(), CSSValuePair::DropIdenticalValues));
4073 shape->setTopRightRadius(CSSValuePair::create(radii[0][1].release(), radii[1 ][1].release(), CSSValuePair::DropIdenticalValues));
4074 shape->setBottomRightRadius(CSSValuePair::create(radii[0][2].release(), radi i[1][2].release(), CSSValuePair::DropIdenticalValues));
4075 shape->setBottomLeftRadius(CSSValuePair::create(radii[0][3].release(), radii [1][3].release(), CSSValuePair::DropIdenticalValues));
4076
4077 return shape;
4078 }
4079
4080 PassRefPtrWillBeRawPtr<CSSBasicShape> CSSPropertyParser::parseBasicShapeInset(CS SParserValueList* args)
4081 {
4082 ASSERT(args);
4083
4084 RefPtrWillBeRawPtr<CSSBasicShapeInset> shape = CSSBasicShapeInset::create();
4085
4086 CSSParserValue* argument = args->current();
4087 WillBeHeapVector<RefPtrWillBeMember<CSSPrimitiveValue>> widthArguments;
4088 bool hasRoundedInset = false;
4089
4090 while (argument) {
4091 if (argument->m_unit == CSSParserValue::Identifier && argument->id == CS SValueRound) {
4092 hasRoundedInset = true;
4093 break;
4094 }
4095
4096 Units unitFlags = FLength | FPercent;
4097 if (!validUnit(argument, unitFlags) || widthArguments.size() > 4)
4098 return nullptr;
4099
4100 widthArguments.append(createPrimitiveNumericValue(argument));
4101 argument = args->next();
4102 }
4103
4104 switch (widthArguments.size()) {
4105 case 1: {
4106 shape->updateShapeSize1Value(widthArguments[0].get());
4107 break;
4108 }
4109 case 2: {
4110 shape->updateShapeSize2Values(widthArguments[0].get(), widthArguments[1] .get());
4111 break;
4112 }
4113 case 3: {
4114 shape->updateShapeSize3Values(widthArguments[0].get(), widthArguments[1] .get(), widthArguments[2].get());
4115 break;
4116 }
4117 case 4: {
4118 shape->updateShapeSize4Values(widthArguments[0].get(), widthArguments[1] .get(), widthArguments[2].get(), widthArguments[3].get());
4119 break;
4120 }
4121 default:
4122 return nullptr;
4123 }
4124
4125 if (hasRoundedInset)
4126 return parseInsetRoundedCorners(shape, args);
4127 return shape;
4128 }
4129
4130 static bool isContentDistributionKeyword(CSSValueID id)
4131 {
4132 return id == CSSValueSpaceBetween || id == CSSValueSpaceAround
4133 || id == CSSValueSpaceEvenly || id == CSSValueStretch;
4134 }
4135
4136 static bool isContentPositionKeyword(CSSValueID id)
4137 {
4138 return id == CSSValueStart || id == CSSValueEnd || id == CSSValueCenter
4139 || id == CSSValueFlexStart || id == CSSValueFlexEnd
4140 || id == CSSValueLeft || id == CSSValueRight;
4141 }
4142
4143 static bool isBaselinePositionKeyword(CSSValueID id)
4144 {
4145 return id == CSSValueBaseline || id == CSSValueLastBaseline;
4146 }
4147
4148 static bool isAlignmentOverflowKeyword(CSSValueID id)
4149 {
4150 return id == CSSValueTrue || id == CSSValueSafe;
4151 }
4152
4153 static bool isItemPositionKeyword(CSSValueID id)
4154 {
4155 return id == CSSValueStart || id == CSSValueEnd || id == CSSValueCenter
4156 || id == CSSValueSelfStart || id == CSSValueSelfEnd || id == CSSValueFle xStart
4157 || id == CSSValueFlexEnd || id == CSSValueLeft || id == CSSValueRight;
4158 }
4159
4160 bool CSSPropertyParser::parseLegacyPosition(CSSPropertyID propId, bool important )
4161 {
4162 // [ legacy && [ left | right | center ]
4163
4164 CSSParserValue* value = m_valueList->current();
4165 ASSERT(value);
4166
4167 if (value->id == CSSValueLegacy) {
4168 value = m_valueList->next();
4169 if (!value)
4170 return false;
4171 if (value->id != CSSValueCenter && value->id != CSSValueLeft && value->i d != CSSValueRight)
4172 return false;
4173 } else if (value->id == CSSValueCenter || value->id == CSSValueLeft || value ->id == CSSValueRight) {
4174 if (!m_valueList->next() || m_valueList->current()->id != CSSValueLegacy )
4175 return false;
4176 } else {
4177 return false;
4178 }
4179
4180 addProperty(propId, CSSValuePair::create(cssValuePool().createIdentifierValu e(CSSValueLegacy), cssValuePool().createIdentifierValue(value->id), CSSValuePair ::DropIdenticalValues), important);
4181 return !m_valueList->next();
4182 }
4183
4184 PassRefPtrWillBeRawPtr<CSSValue> CSSPropertyParser::parseContentDistributionOver flowPosition()
4185 {
4186 // auto | <baseline-position> | <content-distribution> || [ <overflow-positi on>? && <content-position> ]
4187 // <baseline-position> = baseline | last-baseline;
4188 // <content-distribution> = space-between | space-around | space-evenly | st retch;
4189 // <content-position> = center | start | end | flex-start | flex-end | left | right;
4190 // <overflow-position> = true | safe
4191
4192 // auto | <baseline-position>
4193 CSSParserValue* value = m_valueList->current();
4194 if (value->id == CSSValueAuto || isBaselinePositionKeyword(value->id)) {
4195 m_valueList->next();
4196 return CSSContentDistributionValue::create(CSSValueInvalid, value->id, C SSValueInvalid);
4197 }
4198
4199 CSSValueID distribution = CSSValueInvalid;
4200 CSSValueID position = CSSValueInvalid;
4201 CSSValueID overflow = CSSValueInvalid;
4202 while (value) {
4203 if (isContentDistributionKeyword(value->id)) {
4204 if (distribution != CSSValueInvalid)
4205 return nullptr;
4206 distribution = value->id;
4207 } else if (isContentPositionKeyword(value->id)) {
4208 if (position != CSSValueInvalid)
4209 return nullptr;
4210 position = value->id;
4211 } else if (isAlignmentOverflowKeyword(value->id)) {
4212 if (overflow != CSSValueInvalid)
4213 return nullptr;
4214 overflow = value->id;
4215 } else {
4216 return nullptr;
4217 }
4218 value = m_valueList->next();
4219 }
4220
4221 // The grammar states that we should have at least <content-distribution> or
4222 // <content-position> ( <content-distribution> || <content-position> ).
4223 if (position == CSSValueInvalid && distribution == CSSValueInvalid)
4224 return nullptr;
4225
4226 // The grammar states that <overflow-position> must be associated to <conten t-position>.
4227 if (overflow != CSSValueInvalid && position == CSSValueInvalid)
4228 return nullptr;
4229
4230 return CSSContentDistributionValue::create(distribution, position, overflow) ;
4231 }
4232
4233 bool CSSPropertyParser::parseItemPositionOverflowPosition(CSSPropertyID propId, bool important)
4234 {
4235 // auto | stretch | <baseline-position> | [<item-position> && <overflow-posi tion>? ]
4236 // <baseline-position> = baseline | last-baseline;
4237 // <item-position> = center | start | end | self-start | self-end | flex-sta rt | flex-end | left | right;
4238 // <overflow-position> = true | safe
4239
4240 CSSParserValue* value = m_valueList->current();
4241 ASSERT(value);
4242
4243 if (value->id == CSSValueAuto || value->id == CSSValueStretch || isBaselineP ositionKeyword(value->id)) {
4244 if (m_valueList->next())
4245 return false;
4246
4247 addProperty(propId, cssValuePool().createIdentifierValue(value->id), imp ortant);
4248 return true;
4249 }
4250
4251 RefPtrWillBeRawPtr<CSSPrimitiveValue> position = nullptr;
4252 RefPtrWillBeRawPtr<CSSPrimitiveValue> overflowAlignmentKeyword = nullptr;
4253 if (isItemPositionKeyword(value->id)) {
4254 position = cssValuePool().createIdentifierValue(value->id);
4255 value = m_valueList->next();
4256 if (value) {
4257 if (isAlignmentOverflowKeyword(value->id))
4258 overflowAlignmentKeyword = cssValuePool().createIdentifierValue( value->id);
4259 else
4260 return false;
4261 }
4262 } else if (isAlignmentOverflowKeyword(value->id)) {
4263 overflowAlignmentKeyword = cssValuePool().createIdentifierValue(value->i d);
4264 value = m_valueList->next();
4265 if (value && isItemPositionKeyword(value->id))
4266 position = cssValuePool().createIdentifierValue(value->id);
4267 else
4268 return false;
4269 } else {
4270 return false;
4271 }
4272
4273 if (m_valueList->next())
4274 return false;
4275
4276 ASSERT(position);
4277 if (overflowAlignmentKeyword)
4278 addProperty(propId, CSSValuePair::create(position, overflowAlignmentKeyw ord, CSSValuePair::DropIdenticalValues), important);
4279 else
4280 addProperty(propId, position.release(), important);
4281
4282 return true;
4283 }
4284
4285 PassRefPtrWillBeRawPtr<CSSPrimitiveValue> CSSPropertyParser::parseShapeRadius(CS SParserValue* value)
4286 {
4287 if (value->id == CSSValueClosestSide || value->id == CSSValueFarthestSide)
4288 return cssValuePool().createIdentifierValue(value->id);
4289
4290 if (!validUnit(value, FLength | FPercent | FNonNeg))
4291 return nullptr;
4292
4293 return createPrimitiveNumericValue(value);
4294 }
4295
4296 PassRefPtrWillBeRawPtr<CSSBasicShape> CSSPropertyParser::parseBasicShapeCircle(C SSParserValueList* args)
4297 {
4298 ASSERT(args);
4299
4300 // circle(radius)
4301 // circle(radius at <position>)
4302 // circle(at <position>)
4303 // where position defines centerX and centerY using a CSS <position> data ty pe.
4304 RefPtrWillBeRawPtr<CSSBasicShapeCircle> shape = CSSBasicShapeCircle::create( );
4305
4306 for (CSSParserValue* argument = args->current(); argument; argument = args-> next()) {
4307 // The call to parseFillPosition below should consume all of the
4308 // arguments except the first two. Thus, and index greater than one
4309 // indicates an invalid production.
4310 if (args->currentIndex() > 1)
4311 return nullptr;
4312
4313 if (!args->currentIndex() && argument->id != CSSValueAt) {
4314 if (RefPtrWillBeRawPtr<CSSPrimitiveValue> radius = parseShapeRadius( argument)) {
4315 shape->setRadius(radius);
4316 continue;
4317 }
4318
4319 return nullptr;
4320 }
4321
4322 if (argument->id == CSSValueAt && args->next()) {
4323 RefPtrWillBeRawPtr<CSSValue> centerX = nullptr;
4324 RefPtrWillBeRawPtr<CSSValue> centerY = nullptr;
4325 parseFillPosition(args, centerX, centerY);
4326 if (centerX && centerY && !args->current()) {
4327 shape->setCenterX(centerX);
4328 shape->setCenterY(centerY);
4329 } else {
4330 return nullptr;
4331 }
4332 } else {
4333 return nullptr;
4334 }
4335 }
4336
4337 return shape;
4338 }
4339
4340 PassRefPtrWillBeRawPtr<CSSBasicShape> CSSPropertyParser::parseBasicShapeEllipse( CSSParserValueList* args)
4341 {
4342 ASSERT(args);
4343
4344 // ellipse(radiusX)
4345 // ellipse(radiusX at <position>)
4346 // ellipse(radiusX radiusY)
4347 // ellipse(radiusX radiusY at <position>)
4348 // ellipse(at <position>)
4349 // where position defines centerX and centerY using a CSS <position> data ty pe.
4350 RefPtrWillBeRawPtr<CSSBasicShapeEllipse> shape = CSSBasicShapeEllipse::creat e();
4351
4352 for (CSSParserValue* argument = args->current(); argument; argument = args-> next()) {
4353 // The call to parseFillPosition below should consume all of the
4354 // arguments except the first three. Thus, an index greater than two
4355 // indicates an invalid production.
4356 if (args->currentIndex() > 2)
4357 return nullptr;
4358
4359 if (args->currentIndex() < 2 && argument->id != CSSValueAt) {
4360 if (RefPtrWillBeRawPtr<CSSPrimitiveValue> radius = parseShapeRadius( argument)) {
4361 if (!shape->radiusX())
4362 shape->setRadiusX(radius);
4363 else
4364 shape->setRadiusY(radius);
4365 continue;
4366 }
4367
4368 return nullptr;
4369 }
4370
4371 if (argument->id != CSSValueAt || !args->next()) // expecting ellipse(.. at <position>)
4372 return nullptr;
4373 RefPtrWillBeRawPtr<CSSValue> centerX = nullptr;
4374 RefPtrWillBeRawPtr<CSSValue> centerY = nullptr;
4375 parseFillPosition(args, centerX, centerY);
4376 if (!centerX || !centerY || args->current())
4377 return nullptr;
4378
4379 shape->setCenterX(centerX);
4380 shape->setCenterY(centerY);
4381 }
4382
4383 return shape;
4384 }
4385
4386 PassRefPtrWillBeRawPtr<CSSBasicShape> CSSPropertyParser::parseBasicShapePolygon( CSSParserValueList* args)
4387 {
4388 ASSERT(args);
4389
4390 unsigned size = args->size();
4391 if (!size)
4392 return nullptr;
4393
4394 RefPtrWillBeRawPtr<CSSBasicShapePolygon> shape = CSSBasicShapePolygon::creat e();
4395
4396 CSSParserValue* argument = args->current();
4397 if (argument->id == CSSValueEvenodd || argument->id == CSSValueNonzero) {
4398 shape->setWindRule(argument->id == CSSValueEvenodd ? RULE_EVENODD : RULE _NONZERO);
4399 args->next();
4400
4401 if (!consumeComma(args))
4402 return nullptr;
4403
4404 size -= 2;
4405 }
4406
4407 // <length> <length>, ... <length> <length> -> each pair has 3 elements exce pt the last one
4408 if (!size || (size % 3) - 2)
4409 return nullptr;
4410
4411 while (true) {
4412 CSSParserValue* argumentX = args->current();
4413 if (!argumentX || !validUnit(argumentX, FLength | FPercent))
4414 return nullptr;
4415 RefPtrWillBeRawPtr<CSSPrimitiveValue> xLength = createPrimitiveNumericVa lue(argumentX);
4416
4417 CSSParserValue* argumentY = args->next();
4418 if (!argumentY || !validUnit(argumentY, FLength | FPercent))
4419 return nullptr;
4420 RefPtrWillBeRawPtr<CSSPrimitiveValue> yLength = createPrimitiveNumericVa lue(argumentY);
4421
4422 shape->appendPoint(xLength.release(), yLength.release());
4423
4424 if (!args->next())
4425 break;
4426 if (!consumeComma(args))
4427 return nullptr;
4428 }
4429
4430 return shape;
4431 }
4432
4433 static bool isBoxValue(CSSValueID valueId)
4434 {
4435 switch (valueId) {
4436 case CSSValueContentBox:
4437 case CSSValuePaddingBox:
4438 case CSSValueBorderBox:
4439 case CSSValueMarginBox:
4440 return true;
4441 default:
4442 break;
4443 }
4444
4445 return false;
4446 }
4447
4448 PassRefPtrWillBeRawPtr<CSSValue> CSSPropertyParser::parseShapeProperty(CSSProper tyID propId)
4449 {
4450 RefPtrWillBeRawPtr<CSSValue> imageValue = nullptr;
4451 if (parseFillImage(m_valueList, imageValue)) {
4452 m_valueList->next();
4453 return imageValue.release();
4454 }
4455
4456 return parseBasicShapeAndOrBox();
4457 }
4458
4459 PassRefPtrWillBeRawPtr<CSSValue> CSSPropertyParser::parseBasicShapeAndOrBox()
4460 {
4461 CSSParserValue* value = m_valueList->current();
4462
4463 bool shapeFound = false;
4464 bool boxFound = false;
4465 CSSValueID valueId;
4466
4467 RefPtrWillBeRawPtr<CSSValueList> list = CSSValueList::createSpaceSeparated() ;
4468 for (unsigned i = 0; i < 2; ++i) {
4469 if (!value)
4470 break;
4471 valueId = value->id;
4472 if (value->m_unit == CSSParserValue::Function && !shapeFound) {
4473 // parseBasicShape already asks for the next value list item.
4474 RefPtrWillBeRawPtr<CSSPrimitiveValue> shapeValue = parseBasicShape() ;
4475 if (!shapeValue)
4476 return nullptr;
4477 list->append(shapeValue.release());
4478 shapeFound = true;
4479 } else if (isBoxValue(valueId) && !boxFound) {
4480 list->append(parseValidPrimitive(valueId, value));
4481 boxFound = true;
4482 m_valueList->next();
4483 } else {
4484 return nullptr;
4485 }
4486
4487 value = m_valueList->current();
4488 }
4489
4490 if (m_valueList->current())
4491 return nullptr;
4492 return list.release();
4493 }
4494
4495 PassRefPtrWillBeRawPtr<CSSPrimitiveValue> CSSPropertyParser::parseBasicShape()
4496 {
4497 CSSParserValue* value = m_valueList->current();
4498 ASSERT(value->m_unit == CSSParserValue::Function);
4499 CSSParserValueList* args = value->function->args.get();
4500
4501 if (!args)
4502 return nullptr;
4503
4504 RefPtrWillBeRawPtr<CSSBasicShape> shape = nullptr;
4505 if (value->function->id == CSSValueCircle)
4506 shape = parseBasicShapeCircle(args);
4507 else if (value->function->id == CSSValueEllipse)
4508 shape = parseBasicShapeEllipse(args);
4509 else if (value->function->id == CSSValuePolygon)
4510 shape = parseBasicShapePolygon(args);
4511 else if (value->function->id == CSSValueInset)
4512 shape = parseBasicShapeInset(args);
4513
4514 if (!shape)
4515 return nullptr;
4516
4517 m_valueList->next();
4518
4519 return cssValuePool().createValue(shape.release());
4520 }
4521
4522 // [ 'font-style' || 'font-variant' || 'font-weight' ]? 'font-size' [ / 'line-he ight' ]? 'font-family'
4523 bool CSSPropertyParser::parseFont(bool important)
4524 {
4525 // Let's check if there is an inherit or initial somewhere in the shorthand.
4526 for (unsigned i = 0; i < m_valueList->size(); ++i) {
4527 if (m_valueList->valueAt(i)->id == CSSValueInherit || m_valueList->value At(i)->id == CSSValueInitial)
4528 return false;
4529 }
4530
4531 ShorthandScope scope(this, CSSPropertyFont);
4532 // Optional font-style, font-variant and font-weight.
4533 bool fontStyleParsed = false;
4534 bool fontVariantParsed = false;
4535 bool fontWeightParsed = false;
4536 bool fontStretchParsed = false;
4537 CSSParserValue* value = m_valueList->current();
4538 for (; value; value = m_valueList->next()) {
4539 if (!fontStyleParsed && CSSParserFastPaths::isValidKeywordPropertyAndVal ue(CSSPropertyFontStyle, value->id)) {
4540 addProperty(CSSPropertyFontStyle, cssValuePool().createIdentifierVal ue(value->id), important);
4541 fontStyleParsed = true;
4542 } else if (!fontVariantParsed && (value->id == CSSValueNormal || value-> id == CSSValueSmallCaps)) {
4543 // Font variant in the shorthand is particular, it only accepts norm al or small-caps.
4544 addProperty(CSSPropertyFontVariant, cssValuePool().createIdentifierV alue(value->id), important);
4545 fontVariantParsed = true;
4546 } else if (!fontWeightParsed && parseFontWeight(important)) {
4547 fontWeightParsed = true;
4548 } else if (!fontStretchParsed && CSSParserFastPaths::isValidKeywordPrope rtyAndValue(CSSPropertyFontStretch, value->id)) {
4549 addProperty(CSSPropertyFontStretch, cssValuePool().createIdentifierV alue(value->id), important);
4550 fontStretchParsed = true;
4551 } else {
4552 break;
4553 }
4554 }
4555
4556 if (!value)
4557 return false;
4558
4559 if (!fontStyleParsed)
4560 addProperty(CSSPropertyFontStyle, cssValuePool().createIdentifierValue(C SSValueNormal), important, true);
4561 if (!fontVariantParsed)
4562 addProperty(CSSPropertyFontVariant, cssValuePool().createIdentifierValue (CSSValueNormal), important, true);
4563 if (!fontWeightParsed)
4564 addProperty(CSSPropertyFontWeight, cssValuePool().createIdentifierValue( CSSValueNormal), important, true);
4565 if (!fontStretchParsed)
4566 addProperty(CSSPropertyFontStretch, cssValuePool().createIdentifierValue (CSSValueNormal), important, true);
4567
4568 // Now a font size _must_ come.
4569 // <absolute-size> | <relative-size> | <length> | <percentage> | inherit
4570 if (!parseFontSize(important))
4571 return false;
4572
4573 value = m_valueList->current();
4574 if (!value)
4575 return false;
4576
4577 if (isForwardSlashOperator(value)) {
4578 // The line-height property.
4579 value = m_valueList->next();
4580 if (!value)
4581 return false;
4582 RefPtrWillBeRawPtr<CSSPrimitiveValue> lineHeight = parseLineHeight();
4583 if (!lineHeight)
4584 return false;
4585 addProperty(CSSPropertyLineHeight, lineHeight.release(), important);
4586 } else {
4587 addProperty(CSSPropertyLineHeight, cssValuePool().createIdentifierValue( CSSValueNormal), important, true);
4588 }
4589
4590 // Font family must come now.
4591 RefPtrWillBeRawPtr<CSSValue> parsedFamilyValue = parseFontFamily();
4592 if (!parsedFamilyValue)
4593 return false;
4594
4595 addProperty(CSSPropertyFontFamily, parsedFamilyValue.release(), important);
4596
4597 // FIXME: http://www.w3.org/TR/2011/WD-css3-fonts-20110324/#font-prop requir es that
4598 // "font-stretch", "font-size-adjust", and "font-kerning" be reset to their initial values
4599 // but we don't seem to support them at the moment. They should also be adde d here once implemented.
4600 if (m_valueList->current())
4601 return false;
4602
4603 return true;
4604 }
4605
4606 bool CSSPropertyParser::parseSystemFont(bool important)
4607 {
4608 CSSValueID systemFontID = m_valueList->valueAt(0)->id;
4609 ASSERT(systemFontID >= CSSValueCaption && systemFontID <= CSSValueStatusBar) ;
4610 if (m_valueList->next())
4611 return false;
4612
4613 FontStyle fontStyle = FontStyleNormal;
4614 FontWeight fontWeight = FontWeightNormal;
4615 float fontSize = 0;
4616 AtomicString fontFamily;
4617 LayoutTheme::theme().systemFont(systemFontID, fontStyle, fontWeight, fontSiz e, fontFamily);
4618
4619 ShorthandScope scope(this, CSSPropertyFont);
4620 addProperty(CSSPropertyFontStyle, cssValuePool().createIdentifierValue(fontS tyle == FontStyleItalic ? CSSValueItalic : CSSValueNormal), important);
4621 addProperty(CSSPropertyFontWeight, cssValuePool().createValue(fontWeight), i mportant);
4622 addProperty(CSSPropertyFontSize, cssValuePool().createValue(fontSize, CSSPri mitiveValue::UnitType::Pixels), important);
4623 RefPtrWillBeRawPtr<CSSValueList> fontFamilyList = CSSValueList::createCommaS eparated();
4624 fontFamilyList->append(cssValuePool().createFontFamilyValue(fontFamily));
4625 addProperty(CSSPropertyFontFamily, fontFamilyList.release(), important);
4626
4627 addProperty(CSSPropertyFontStretch, cssValuePool().createIdentifierValue(CSS ValueNormal), important);
4628 addProperty(CSSPropertyFontVariant, cssValuePool().createIdentifierValue(CSS ValueNormal), important);
4629 addProperty(CSSPropertyLineHeight, cssValuePool().createIdentifierValue(CSSV alueNormal), important);
4630 return true;
4631 }
4632
4633 class FontFamilyValueBuilder {
4634 STACK_ALLOCATED();
4635 public:
4636 FontFamilyValueBuilder(CSSValueList* list)
4637 : m_list(list)
4638 {
4639 }
4640
4641 void add(const CSSParserString& string)
4642 {
4643 if (!m_builder.isEmpty())
4644 m_builder.append(' ');
4645
4646 if (string.is8Bit()) {
4647 m_builder.append(string.characters8(), string.length());
4648 return;
4649 }
4650
4651 m_builder.append(string.characters16(), string.length());
4652 }
4653
4654 void commit()
4655 {
4656 if (m_builder.isEmpty())
4657 return;
4658 m_list->append(cssValuePool().createFontFamilyValue(m_builder.toString() ));
4659 m_builder.clear();
4660 }
4661
4662 private:
4663 StringBuilder m_builder;
4664 RawPtrWillBeMember<CSSValueList> m_list;
4665 };
4666
4667 PassRefPtrWillBeRawPtr<CSSValueList> CSSPropertyParser::parseFontFamily()
4668 {
4669 RefPtrWillBeRawPtr<CSSValueList> list = CSSValueList::createCommaSeparated() ;
4670 CSSParserValue* value = m_valueList->current();
4671
4672 FontFamilyValueBuilder familyBuilder(list.get());
4673 bool inFamily = false;
4674
4675 while (value) {
4676 CSSParserValue* nextValue = m_valueList->next();
4677 bool nextValBreaksFont = !nextValue || isComma(nextValue);
4678 bool nextValIsFontName = nextValue &&
4679 ((nextValue->id >= CSSValueSerif && nextValue->id <= CSSValueWebkitB ody) ||
4680 (nextValue->unit() == CSSPrimitiveValue::UnitType::String || nextVal ue->m_unit == CSSParserValue::Identifier));
4681
4682 if (isCSSWideKeyword(*value) && !inFamily) {
4683 if (nextValBreaksFont)
4684 return nullptr;
4685 else if (nextValIsFontName)
4686 value = nextValue;
4687 continue;
4688 }
4689
4690 if (value->id >= CSSValueSerif && value->id <= CSSValueWebkitBody) {
4691 if (inFamily)
4692 familyBuilder.add(value->string);
4693 else if (nextValBreaksFont || !nextValIsFontName)
4694 list->append(cssValuePool().createIdentifierValue(value->id));
4695 else {
4696 familyBuilder.commit();
4697 familyBuilder.add(value->string);
4698 inFamily = true;
4699 }
4700 } else if (value->unit() == CSSPrimitiveValue::UnitType::String) {
4701 // Strings never share in a family name.
4702 inFamily = false;
4703 familyBuilder.commit();
4704 list->append(cssValuePool().createFontFamilyValue(value->string));
4705 } else if (value->m_unit == CSSParserValue::Identifier) {
4706 if (inFamily)
4707 familyBuilder.add(value->string);
4708 else if (nextValBreaksFont || !nextValIsFontName)
4709 list->append(cssValuePool().createFontFamilyValue(value->string) );
4710 else {
4711 familyBuilder.commit();
4712 familyBuilder.add(value->string);
4713 inFamily = true;
4714 }
4715 } else {
4716 break;
4717 }
4718
4719 if (!nextValue)
4720 break;
4721
4722 if (nextValBreaksFont) {
4723 value = m_valueList->next();
4724 familyBuilder.commit();
4725 inFamily = false;
4726 }
4727 else if (nextValIsFontName)
4728 value = nextValue;
4729 else
4730 break;
4731 }
4732 familyBuilder.commit();
4733 if (!list->length() || (m_ruleType == StyleRule::FontFace && list->length() > 1))
4734 list = nullptr;
4735 return list.release();
4736 }
4737
4738 PassRefPtrWillBeRawPtr<CSSPrimitiveValue> CSSPropertyParser::parseLineHeight()
4739 {
4740 CSSParserValue* value = m_valueList->current();
4741 CSSValueID id = value->id;
4742
4743 // normal | <number> | <length> | <percentage> | inherit
4744 if (id == CSSValueNormal) {
4745 m_valueList->next();
4746 return cssValuePool().createIdentifierValue(id);
4747 }
4748
4749 if (!validUnit(value, FNumber | FLength | FPercent | FNonNeg))
4750 return nullptr;
4751 // The line-height property can accept both percents and numbers but additiv e opertaions are
4752 // not permitted on them in calc() expressions.
4753 if (m_parsedCalculation && m_parsedCalculation->category() == CalcPercentNum ber) {
4754 m_parsedCalculation.release();
4755 return nullptr;
4756 }
4757 m_valueList->next();
4758 return createPrimitiveNumericValue(value);
4759 }
4760
4761 bool CSSPropertyParser::parseFontSize(bool important)
4762 {
4763 CSSParserValue* value = m_valueList->current();
4764 CSSValueID id = value->id;
4765 bool validPrimitive = false;
4766 // <absolute-size> | <relative-size> | <length> | <percentage> | inherit
4767 if (id >= CSSValueXxSmall && id <= CSSValueLarger)
4768 validPrimitive = true;
4769 else
4770 validPrimitive = validUnit(value, FLength | FPercent | FNonNeg | (inShor thand() ? FUnknown : FUnitlessQuirk));
4771 if (validPrimitive && (!m_valueList->next() || inShorthand()))
4772 addProperty(CSSPropertyFontSize, parseValidPrimitive(id, value), importa nt);
4773 return validPrimitive;
4774 }
4775
4776 bool CSSPropertyParser::parseFontVariant(bool important)
4777 {
4778 RefPtrWillBeRawPtr<CSSValueList> values = nullptr;
4779 if (m_valueList->size() > 1)
4780 values = CSSValueList::createCommaSeparated();
4781 bool expectComma = false;
4782 for (CSSParserValue* val = m_valueList->current(); val; val = m_valueList->c urrent()) {
4783 RefPtrWillBeRawPtr<CSSPrimitiveValue> parsedValue = nullptr;
4784 if (!expectComma) {
4785 expectComma = true;
4786 if (val->id == CSSValueNormal || val->id == CSSValueSmallCaps)
4787 parsedValue = cssValuePool().createIdentifierValue(val->id);
4788 else if (val->id == CSSValueAll && !values) {
4789 // FIXME: CSSPropertyParser::parseFontVariant() implements
4790 // the old css3 draft:
4791 // http://www.w3.org/TR/2002/WD-css3-webfonts-20020802/#font-var iant
4792 // 'all' is only allowed in @font-face and with no other values. Make a value list to
4793 // indicate that we are in the @font-face case.
4794 values = CSSValueList::createCommaSeparated();
4795 parsedValue = cssValuePool().createIdentifierValue(val->id);
4796 }
4797 } else if (consumeComma(m_valueList)) {
4798 expectComma = false;
4799 continue;
4800 }
4801
4802 if (!parsedValue)
4803 return false;
4804
4805 m_valueList->next();
4806
4807 if (values)
4808 values->append(parsedValue.release());
4809 else {
4810 addProperty(CSSPropertyFontVariant, parsedValue.release(), important );
4811 return true;
4812 }
4813 }
4814
4815 if (values && values->length()) {
4816 if (m_ruleType != StyleRule::FontFace)
4817 return false;
4818 addProperty(CSSPropertyFontVariant, values.release(), important);
4819 return true;
4820 }
4821
4822 return false;
4823 }
4824
4825 bool CSSPropertyParser::parseFontWeight(bool important)
4826 {
4827 CSSParserValue* value = m_valueList->current();
4828 if (value->id >= CSSValueNormal && value->id <= CSSValueLighter) {
4829 addProperty(CSSPropertyFontWeight, cssValuePool().createIdentifierValue( value->id), important);
4830 return true;
4831 }
4832 if (value->unit() == CSSPrimitiveValue::UnitType::Number) {
4833 int weight = static_cast<int>(value->fValue);
4834 if (!(weight % 100) && weight >= 100 && weight <= 900) {
4835 addProperty(CSSPropertyFontWeight, cssValuePool().createIdentifierVa lue(static_cast<CSSValueID>(CSSValue100 + weight / 100 - 1)), important);
4836 return true;
4837 }
4838 }
4839 return false;
4840 }
4841
4842 bool CSSPropertyParser::parseFontFaceSrcURI(CSSValueList* valueList)
4843 {
4844 RefPtrWillBeRawPtr<CSSFontFaceSrcValue> uriValue(CSSFontFaceSrcValue::create (completeURL(m_valueList->current()->string), m_context.shouldCheckContentSecuri tyPolicy()));
4845 uriValue->setReferrer(m_context.referrer());
4846
4847 CSSParserValue* value = m_valueList->next();
4848 if (!value || value->m_unit != CSSParserValue::Function || value->function-> id != CSSValueFormat) {
4849 valueList->append(uriValue.release());
4850 return true;
4851 }
4852
4853 // FIXME: http://www.w3.org/TR/2011/WD-css3-fonts-20111004/ says that format () contains a comma-separated list of strings,
4854 // but CSSFontFaceSrcValue stores only one format. Allowing one format for n ow.
4855 CSSParserValueList* args = value->function->args.get();
4856 if (!args || args->size() != 1 || (args->current()->unit() != CSSPrimitiveVa lue::UnitType::String && args->current()->m_unit != CSSParserValue::Identifier))
4857 return false;
4858 uriValue->setFormat(args->current()->string);
4859 valueList->append(uriValue.release());
4860 m_valueList->next();
4861 return true;
4862 }
4863
4864 bool CSSPropertyParser::parseFontFaceSrcLocal(CSSValueList* valueList)
4865 {
4866 CSSParserValueList* args = m_valueList->current()->function->args.get();
4867 if (!args || !args->size())
4868 return false;
4869 m_valueList->next();
4870
4871 ContentSecurityPolicyDisposition shouldCheckContentSecurityPolicy = m_contex t.shouldCheckContentSecurityPolicy();
4872 if (args->size() == 1 && args->current()->unit() == CSSPrimitiveValue::UnitT ype::String) {
4873 valueList->append(CSSFontFaceSrcValue::createLocal(args->current()->stri ng, shouldCheckContentSecurityPolicy));
4874 } else if (args->current()->m_unit == CSSParserValue::Identifier) {
4875 StringBuilder builder;
4876 for (CSSParserValue* localValue = args->current(); localValue; localValu e = args->next()) {
4877 if (localValue->m_unit != CSSParserValue::Identifier)
4878 return false;
4879 if (!builder.isEmpty())
4880 builder.append(' ');
4881 builder.append(localValue->string);
4882 }
4883 valueList->append(CSSFontFaceSrcValue::createLocal(builder.toString(), s houldCheckContentSecurityPolicy));
4884 } else
4885 return false;
4886
4887 return true;
4888 }
4889
4890 PassRefPtrWillBeRawPtr<CSSValueList> CSSPropertyParser::parseFontFaceSrc()
4891 {
4892 RefPtrWillBeRawPtr<CSSValueList> values(CSSValueList::createCommaSeparated() );
4893
4894 while (true) {
4895 CSSParserValue* value = m_valueList->current();
4896 if (!value)
4897 return nullptr;
4898 if (value->unit() == CSSPrimitiveValue::UnitType::URI) {
4899 if (!parseFontFaceSrcURI(values.get()))
4900 return nullptr;
4901 } else if (value->m_unit == CSSParserValue::Function && value->function- >id == CSSValueLocal) {
4902 if (!parseFontFaceSrcLocal(values.get()))
4903 return nullptr;
4904 } else {
4905 return nullptr;
4906 }
4907
4908 if (!m_valueList->current())
4909 return values.release();
4910 if (!consumeComma(m_valueList))
4911 return nullptr;
4912 }
4913 }
4914
4915 PassRefPtrWillBeRawPtr<CSSValueList> CSSPropertyParser::parseFontFaceUnicodeRang e()
4916 {
4917 RefPtrWillBeRawPtr<CSSValueList> values = CSSValueList::createCommaSeparated ();
4918
4919 do {
4920 CSSParserValue* current = m_valueList->current();
4921 if (!current || current->m_unit != CSSParserValue::UnicodeRange)
4922 return nullptr;
4923
4924 UChar32 start = current->m_unicodeRange.start;
4925 UChar32 end = current->m_unicodeRange.end;
4926 if (start > end)
4927 return nullptr;
4928 values->append(CSSUnicodeRangeValue::create(start, end));
4929 m_valueList->next();
4930 } while (consumeComma(m_valueList));
4931
4932 return values.release();
4933 }
4934
4935 inline int CSSPropertyParser::colorIntFromValue(CSSParserValue* v)
4936 {
4937 bool isPercent;
4938 double value;
4939
4940 if (m_parsedCalculation) {
4941 isPercent = m_parsedCalculation->category() == CalcPercent;
4942 value = m_parsedCalculation->doubleValue();
4943 m_parsedCalculation.release();
4944 } else {
4945 isPercent = v->unit() == CSSPrimitiveValue::UnitType::Percentage;
4946 value = v->fValue;
4947 }
4948
4949 if (value <= 0.0)
4950 return 0;
4951
4952 if (isPercent) {
4953 if (value >= 100.0)
4954 return 255;
4955 return static_cast<int>(value * 256.0 / 100.0);
4956 }
4957
4958 if (value >= 255.0)
4959 return 255;
4960
4961 return static_cast<int>(value);
4962 }
4963
4964 bool CSSPropertyParser::parseColorParameters(const CSSParserValue* value, int* c olorArray, bool parseAlpha)
4965 {
4966 CSSParserValueList* args = value->function->args.get();
4967 CSSParserValue* v = args->current();
4968 Units unitType = FUnknown;
4969 // Get the first value and its type
4970 if (validUnit(v, FInteger))
4971 unitType = FInteger;
4972 else if (validUnit(v, FPercent))
4973 unitType = FPercent;
4974 else
4975 return false;
4976
4977 colorArray[0] = colorIntFromValue(v);
4978 for (int i = 1; i < 3; i++) {
4979 args->next();
4980 if (!consumeComma(args))
4981 return false;
4982 v = args->current();
4983 if (!validUnit(v, unitType))
4984 return false;
4985 colorArray[i] = colorIntFromValue(v);
4986 }
4987 if (parseAlpha) {
4988 args->next();
4989 if (!consumeComma(args))
4990 return false;
4991 v = args->current();
4992 if (!validUnit(v, FNumber))
4993 return false;
4994 // Convert the floating pointer number of alpha to an integer in the ran ge [0, 256),
4995 // with an equal distribution across all 256 values.
4996 colorArray[3] = static_cast<int>(std::max(0.0, std::min(1.0, v->fValue)) * nextafter(256.0, 0.0));
4997 }
4998 return true;
4999 }
5000
5001 // The CSS3 specification defines the format of a HSL color as
5002 // hsl(<number>, <percent>, <percent>)
5003 // and with alpha, the format is
5004 // hsla(<number>, <percent>, <percent>, <number>)
5005 // The first value, HUE, is in an angle with a value between 0 and 360
5006 bool CSSPropertyParser::parseHSLParameters(const CSSParserValue* value, double* colorArray, bool parseAlpha)
5007 {
5008 CSSParserValueList* args = value->function->args.get();
5009 CSSParserValue* v = args->current();
5010 // Get the first value
5011 if (!validUnit(v, FNumber))
5012 return false;
5013 // normalize the Hue value and change it to be between 0 and 1.0
5014 colorArray[0] = (((static_cast<int>(v->fValue) % 360) + 360) % 360) / 360.0;
5015 for (int i = 1; i < 3; i++) {
5016 args->next();
5017 if (!consumeComma(args))
5018 return false;
5019 v = args->current();
5020 if (!validUnit(v, FPercent))
5021 return false;
5022 double percentValue = m_parsedCalculation ? m_parsedCalculation.release( )->doubleValue() : v->fValue;
5023 colorArray[i] = std::max(0.0, std::min(100.0, percentValue)) / 100.0; // needs to be value between 0 and 1.0
5024 }
5025 if (parseAlpha) {
5026 args->next();
5027 if (!consumeComma(args))
5028 return false;
5029 v = args->current();
5030 if (!validUnit(v, FNumber))
5031 return false;
5032 colorArray[3] = std::max(0.0, std::min(1.0, v->fValue));
5033 }
5034 return true;
5035 }
5036
5037 bool CSSPropertyParser::parseColorFromValue(const CSSParserValue* value, RGBA32& result, bool acceptQuirkyColors)
5038 {
5039 if (acceptQuirkyColors && value->unit() == CSSPrimitiveValue::UnitType::Numb er
5040 && value->fValue >= 0. && value->fValue < 1000000. && value->isInt) {
5041 String str = String::format("%06d", static_cast<int>(value->fValue));
5042 return Color::parseHexColor(str, result);
5043 }
5044 if (acceptQuirkyColors && value->m_unit == CSSParserValue::DimensionList) {
5045 CSSParserValue* numberToken = value->valueList->valueAt(0);
5046 CSSParserValue* unitToken = value->valueList->valueAt(1);
5047 ASSERT(numberToken->unit() == CSSPrimitiveValue::UnitType::Number);
5048 ASSERT(unitToken->m_unit == CSSParserValue::Identifier);
5049 if (!numberToken->isInt || numberToken->fValue < 0)
5050 return false;
5051 String color = String::number(numberToken->fValue) + String(unitToken->s tring);
5052 if (color.length() > 6)
5053 return false;
5054 while (color.length() < 6)
5055 color = "0" + color;
5056 return Color::parseHexColor(color, result);
5057 }
5058 if (value->m_unit == CSSParserValue::Identifier) {
5059 Color color;
5060 if (!color.setNamedColor(value->string))
5061 return acceptQuirkyColors && Color::parseHexColor(value->string, res ult);
5062 result = color.rgb();
5063 return true;
5064 }
5065 if (value->m_unit == CSSParserValue::HexColor) {
5066 if (value->string.is8Bit())
5067 return Color::parseHexColor(value->string.characters8(), value->stri ng.length(), result);
5068 return Color::parseHexColor(value->string.characters16(), value->string. length(), result);
5069 }
5070
5071 if (value->m_unit == CSSParserValue::Function
5072 && value->function->args != 0
5073 && value->function->args->size() == 5 /* rgb + two commas */
5074 && value->function->id == CSSValueRgb) {
5075 int colorValues[3];
5076 if (!parseColorParameters(value, colorValues, false))
5077 return false;
5078 result = makeRGB(colorValues[0], colorValues[1], colorValues[2]);
5079 } else {
5080 if (value->m_unit == CSSParserValue::Function
5081 && value->function->args != 0
5082 && value->function->args->size() == 7 /* rgba + three commas */
5083 && value->function->id == CSSValueRgba) {
5084 int colorValues[4];
5085 if (!parseColorParameters(value, colorValues, true))
5086 return false;
5087 result = makeRGBA(colorValues[0], colorValues[1], colorValues[2], co lorValues[3]);
5088 } else if (value->m_unit == CSSParserValue::Function
5089 && value->function->args != 0
5090 && value->function->args->size() == 5 /* hsl + two commas */
5091 && value->function->id == CSSValueHsl) {
5092 double colorValues[3];
5093 if (!parseHSLParameters(value, colorValues, false))
5094 return false;
5095 result = makeRGBAFromHSLA(colorValues[0], colorValues[1], colorValue s[2], 1.0);
5096 } else if (value->m_unit == CSSParserValue::Function
5097 && value->function->args != 0
5098 && value->function->args->size() == 7 /* hsla + three commas */
5099 && value->function->id == CSSValueHsla) {
5100 double colorValues[4];
5101 if (!parseHSLParameters(value, colorValues, true))
5102 return false;
5103 result = makeRGBAFromHSLA(colorValues[0], colorValues[1], colorValue s[2], colorValues[3]);
5104 } else {
5105 return false;
5106 }
5107 }
5108
5109 return true;
5110 }
5111
5112 PassRefPtrWillBeRawPtr<CSSValueList> CSSPropertyParser::parseShadow(CSSParserVal ueList* valueList, CSSPropertyID propID)
5113 {
5114 RefPtrWillBeRawPtr<CSSValueList> shadowValueList = CSSValueList::createComma Separated();
5115 const bool isBoxShadowProperty = propID == CSSPropertyBoxShadow;
5116 while (RefPtrWillBeRawPtr<CSSShadowValue> shadowValue = parseSingleShadow(va lueList, isBoxShadowProperty, isBoxShadowProperty)) {
5117 shadowValueList->append(shadowValue);
5118 if (!valueList->current())
5119 break;
5120 if (!consumeComma(valueList))
5121 return nullptr;
5122 }
5123 if (shadowValueList->length() == 0)
5124 return nullptr;
5125 return shadowValueList;
5126 }
5127
5128 PassRefPtrWillBeRawPtr<CSSShadowValue> CSSPropertyParser::parseSingleShadow(CSSP arserValueList* valueList, bool allowInset, bool allowSpread)
5129 {
5130 RefPtrWillBeMember<CSSPrimitiveValue> style;
5131 RefPtrWillBeMember<CSSPrimitiveValue> color;
5132 Vector<RefPtrWillBeRawPtr<CSSPrimitiveValue>, 4> lengths;
5133
5134 CSSParserValue* val = valueList->current();
5135 if (!val)
5136 return nullptr;
5137 if (val->id == CSSValueInset) {
5138 if (!allowInset)
5139 return nullptr;
5140 style = cssValuePool().createIdentifierValue(val->id);
5141 val = valueList->next();
5142 if (!val)
5143 return nullptr;
5144 }
5145 if ((color = parseColor(val)))
5146 val = valueList->next();
5147
5148 if (!val || !validUnit(val, FLength, HTMLStandardMode))
5149 return nullptr;
5150 lengths.append(createPrimitiveNumericValue(val));
5151 val = valueList->next();
5152
5153 if (!val || !validUnit(val, FLength, HTMLStandardMode))
5154 return nullptr;
5155 lengths.append(createPrimitiveNumericValue(val));
5156 val = valueList->next();
5157
5158 if (val && validUnit(val, FLength, HTMLStandardMode)) {
5159 // Blur radius must be non-negative.
5160 if (m_parsedCalculation ? m_parsedCalculation->isNegative() : !validUnit (val, FLength | FNonNeg, HTMLStandardMode)) {
5161 m_parsedCalculation.release();
5162 return nullptr;
5163 }
5164 lengths.append(createPrimitiveNumericValue(val));
5165 val = valueList->next();
5166 if (val && validUnit(val, FLength, HTMLStandardMode)) {
5167 if (!allowSpread)
5168 return nullptr;
5169 lengths.append(createPrimitiveNumericValue(val));
5170 val = valueList->next();
5171 }
5172 }
5173
5174 if (val) {
5175 if (RefPtrWillBeMember<CSSPrimitiveValue> colorValue = parseColor(val)) {
5176 if (color)
5177 return nullptr;
5178 color = colorValue;
5179 val = valueList->next();
5180 }
5181 if (val && val->id == CSSValueInset) {
5182 if (!allowInset || style)
5183 return nullptr;
5184 style = cssValuePool().createIdentifierValue(val->id);
5185 val = valueList->next();
5186 }
5187 }
5188 unsigned lengthsSeen = lengths.size();
5189 return CSSShadowValue::create(lengths.at(0), lengths.at(1),
5190 lengthsSeen > 2 ? lengths.at(2) : nullptr,
5191 lengthsSeen > 3 ? lengths.at(3) : nullptr,
5192 style.release(), color.release());
5193 }
5194
5195 PassRefPtrWillBeRawPtr<CSSValue> CSSPropertyParser::parseReflect()
5196 {
5197 // box-reflect: <direction> <offset> <mask>
5198
5199 // Direction comes first.
5200 CSSParserValue* val = m_valueList->current();
5201 RefPtrWillBeRawPtr<CSSPrimitiveValue> direction = nullptr;
5202 switch (val->id) {
5203 case CSSValueAbove:
5204 case CSSValueBelow:
5205 case CSSValueLeft:
5206 case CSSValueRight:
5207 direction = cssValuePool().createIdentifierValue(val->id);
5208 break;
5209 default:
5210 return nullptr;
5211 }
5212
5213 // The offset comes next.
5214 val = m_valueList->next();
5215 RefPtrWillBeRawPtr<CSSPrimitiveValue> offset = nullptr;
5216 if (!val)
5217 offset = cssValuePool().createValue(0, CSSPrimitiveValue::UnitType::Pixe ls);
5218 else {
5219 if (!validUnit(val, FLength | FPercent))
5220 return nullptr;
5221 offset = createPrimitiveNumericValue(val);
5222 }
5223
5224 // Now for the mask.
5225 RefPtrWillBeRawPtr<CSSValue> mask = nullptr;
5226 val = m_valueList->next();
5227 if (val) {
5228 mask = parseBorderImage(CSSPropertyWebkitBoxReflect);
5229 if (!mask)
5230 return nullptr;
5231 }
5232
5233 return CSSReflectValue::create(direction.release(), offset.release(), mask.r elease());
5234 }
5235
5236 static bool isFlexBasisMiddleArg(double flexGrow, double flexShrink, double unse tValue, int argSize)
5237 {
5238 return flexGrow != unsetValue && flexShrink == unsetValue && argSize == 3;
5239 }
5240
5241 bool CSSPropertyParser::parseFlex(CSSParserValueList* args, bool important)
5242 {
5243 if (!args || !args->size() || args->size() > 3)
5244 return false;
5245 static const double unsetValue = -1;
5246 double flexGrow = unsetValue;
5247 double flexShrink = unsetValue;
5248 RefPtrWillBeRawPtr<CSSPrimitiveValue> flexBasis = nullptr;
5249
5250 while (CSSParserValue* arg = args->current()) {
5251 if (validUnit(arg, FNumber | FNonNeg)) {
5252 if (flexGrow == unsetValue)
5253 flexGrow = arg->fValue;
5254 else if (flexShrink == unsetValue)
5255 flexShrink = arg->fValue;
5256 else if (!arg->fValue) {
5257 // flex only allows a basis of 0 (sans units) if flex-grow and f lex-shrink values have already been set.
5258 flexBasis = cssValuePool().createValue(0, CSSPrimitiveValue::Uni tType::Pixels);
5259 } else {
5260 // We only allow 3 numbers without units if the last value is 0. E.g., flex:1 1 1 is invalid.
5261 return false;
5262 }
5263 } else if (!flexBasis && (arg->id == CSSValueAuto || validUnit(arg, FLen gth | FPercent | FNonNeg)) && !isFlexBasisMiddleArg(flexGrow, flexShrink, unsetV alue, args->size()))
5264 flexBasis = parseValidPrimitive(arg->id, arg);
5265 else {
5266 // Not a valid arg for flex.
5267 return false;
5268 }
5269 args->next();
5270 }
5271
5272 if (flexGrow == unsetValue)
5273 flexGrow = 1;
5274 if (flexShrink == unsetValue)
5275 flexShrink = 1;
5276 if (!flexBasis)
5277 flexBasis = cssValuePool().createValue(0, CSSPrimitiveValue::UnitType::P ercentage);
5278
5279 addProperty(CSSPropertyFlexGrow, cssValuePool().createValue(clampTo<float>(f lexGrow), CSSPrimitiveValue::UnitType::Number), important);
5280 addProperty(CSSPropertyFlexShrink, cssValuePool().createValue(clampTo<float> (flexShrink), CSSPrimitiveValue::UnitType::Number), important);
5281 addProperty(CSSPropertyFlexBasis, flexBasis, important);
5282 return true;
5283 }
5284
5285 PassRefPtrWillBeRawPtr<CSSValue> CSSPropertyParser::parsePosition(CSSParserValue List* valueList)
5286 {
5287 RefPtrWillBeRawPtr<CSSValue> xValue = nullptr;
5288 RefPtrWillBeRawPtr<CSSValue> yValue = nullptr;
5289 parseFillPosition(valueList, xValue, yValue);
5290 if (!xValue || !yValue)
5291 return nullptr;
5292 return CSSValuePair::create(xValue.release(), yValue.release(), CSSValuePair ::KeepIdenticalValues);
5293 }
5294
5295 // Parses a list of comma separated positions. i.e., <position>#
5296 PassRefPtrWillBeRawPtr<CSSValueList> CSSPropertyParser::parsePositionList(CSSPar serValueList* valueList)
5297 {
5298 RefPtrWillBeRawPtr<CSSValueList> positions = CSSValueList::createCommaSepara ted();
5299 while (true) {
5300 // parsePosition consumes values until it reaches a separator [,/],
5301 // an invalid token, or end of the list
5302 RefPtrWillBeRawPtr<CSSValue> position = parsePosition(valueList);
5303 if (!position)
5304 return nullptr;
5305 positions->append(position);
5306
5307 if (!valueList->current())
5308 break;
5309 if (!consumeComma(valueList) || !valueList->current())
5310 return nullptr;
5311 }
5312
5313 return positions.release();
5314 }
5315
5316 class BorderImageParseContext {
5317 STACK_ALLOCATED();
5318 public:
5319 BorderImageParseContext()
5320 : m_canAdvance(false)
5321 , m_allowCommit(true)
5322 , m_allowImage(true)
5323 , m_allowImageSlice(true)
5324 , m_allowRepeat(true)
5325 , m_allowForwardSlashOperator(false)
5326 , m_allowWidth(false)
5327 , m_requireOutset(false)
5328 {}
5329
5330 bool canAdvance() const { return m_canAdvance; }
5331 void setCanAdvance(bool canAdvance) { m_canAdvance = canAdvance; }
5332
5333 bool allowCommit() const { return m_allowCommit; }
5334 bool allowImage() const { return m_allowImage; }
5335 bool allowImageSlice() const { return m_allowImageSlice; }
5336 bool allowRepeat() const { return m_allowRepeat; }
5337 bool allowForwardSlashOperator() const { return m_allowForwardSlashOperator; }
5338
5339 bool allowWidth() const { return m_allowWidth; }
5340 bool requireOutset() const { return m_requireOutset; }
5341
5342 void commitImage(PassRefPtrWillBeRawPtr<CSSValue> image)
5343 {
5344 m_image = image;
5345 m_canAdvance = true;
5346 m_allowCommit = true;
5347 m_allowImage = false;
5348 m_allowForwardSlashOperator = false;
5349 m_allowWidth = false;
5350 m_requireOutset = false;
5351 m_allowImageSlice = !m_imageSlice;
5352 m_allowRepeat = !m_repeat;
5353 }
5354 void commitImageSlice(PassRefPtrWillBeRawPtr<CSSBorderImageSliceValue> slice )
5355 {
5356 m_imageSlice = slice;
5357 m_canAdvance = true;
5358 m_allowCommit = true;
5359 m_allowForwardSlashOperator = true;
5360 m_allowImageSlice = false;
5361 m_allowWidth = false;
5362 m_requireOutset = false;
5363 m_allowImage = !m_image;
5364 m_allowRepeat = !m_repeat;
5365 }
5366 void commitForwardSlashOperator()
5367 {
5368 m_canAdvance = true;
5369 m_allowCommit = false;
5370 m_allowImage = false;
5371 m_allowImageSlice = false;
5372 m_allowRepeat = false;
5373 if (!m_borderWidth && !m_allowWidth) {
5374 m_allowForwardSlashOperator = true;
5375 m_allowWidth = true;
5376 m_requireOutset = false;
5377 } else {
5378 m_allowForwardSlashOperator = false;
5379 m_requireOutset = true;
5380 m_allowWidth = false;
5381 }
5382 }
5383 void commitBorderWidth(PassRefPtrWillBeRawPtr<CSSQuadValue> width)
5384 {
5385 m_borderWidth = width;
5386 m_canAdvance = true;
5387 m_allowCommit = true;
5388 m_allowForwardSlashOperator = true;
5389 m_allowImageSlice = false;
5390 m_allowWidth = false;
5391 m_requireOutset = false;
5392 m_allowImage = !m_image;
5393 m_allowRepeat = !m_repeat;
5394 }
5395 void commitBorderOutset(PassRefPtrWillBeRawPtr<CSSQuadValue> outset)
5396 {
5397 m_outset = outset;
5398 m_canAdvance = true;
5399 m_allowCommit = true;
5400 m_allowImageSlice = false;
5401 m_allowForwardSlashOperator = false;
5402 m_allowWidth = false;
5403 m_requireOutset = false;
5404 m_allowImage = !m_image;
5405 m_allowRepeat = !m_repeat;
5406 }
5407 void commitRepeat(PassRefPtrWillBeRawPtr<CSSValue> repeat)
5408 {
5409 m_repeat = repeat;
5410 m_canAdvance = true;
5411 m_allowCommit = true;
5412 m_allowRepeat = false;
5413 m_allowForwardSlashOperator = false;
5414 m_allowWidth = false;
5415 m_requireOutset = false;
5416 m_allowImageSlice = !m_imageSlice;
5417 m_allowImage = !m_image;
5418 }
5419
5420 PassRefPtrWillBeRawPtr<CSSValue> commitCSSValue()
5421 {
5422 return createBorderImageValue(m_image, m_imageSlice.get(), m_borderWidth .get(), m_outset.get(), m_repeat.get());
5423 }
5424
5425 bool m_canAdvance;
5426
5427 bool m_allowCommit;
5428 bool m_allowImage;
5429 bool m_allowImageSlice;
5430 bool m_allowRepeat;
5431 bool m_allowForwardSlashOperator;
5432
5433 bool m_allowWidth;
5434 bool m_requireOutset;
5435
5436 RefPtrWillBeMember<CSSValue> m_image;
5437 RefPtrWillBeMember<CSSBorderImageSliceValue> m_imageSlice;
5438 RefPtrWillBeMember<CSSQuadValue> m_borderWidth;
5439 RefPtrWillBeMember<CSSQuadValue> m_outset;
5440
5441 RefPtrWillBeMember<CSSValue> m_repeat;
5442 };
5443
5444 bool CSSPropertyParser::buildBorderImageParseContext(CSSPropertyID propId, Borde rImageParseContext& context)
5445 {
5446 CSSPropertyParser::ShorthandScope scope(this, propId);
5447 while (CSSParserValue* val = m_valueList->current()) {
5448 context.setCanAdvance(false);
5449
5450 if (!context.canAdvance() && context.allowForwardSlashOperator() && isFo rwardSlashOperator(val))
5451 context.commitForwardSlashOperator();
5452
5453 if (!context.canAdvance() && context.allowImage()) {
5454 if (val->unit() == CSSPrimitiveValue::UnitType::URI) {
5455 context.commitImage(createCSSImageValueWithReferrer(val->string, m_context.completeURL(val->string)));
5456 } else if (isGeneratedImageValue(val)) {
5457 RefPtrWillBeRawPtr<CSSValue> value = nullptr;
5458 if (parseGeneratedImage(m_valueList, value))
5459 context.commitImage(value.release());
5460 else
5461 return false;
5462 } else if (val->m_unit == CSSParserValue::Function && val->function- >id == CSSValueWebkitImageSet) {
5463 RefPtrWillBeRawPtr<CSSValue> value = parseImageSet(m_valueList);
5464 if (value)
5465 context.commitImage(value.release());
5466 else
5467 return false;
5468 } else if (val->id == CSSValueNone)
5469 context.commitImage(cssValuePool().createIdentifierValue(CSSValu eNone));
5470 }
5471
5472 if (!context.canAdvance() && context.allowImageSlice()) {
5473 RefPtrWillBeRawPtr<CSSBorderImageSliceValue> imageSlice = nullptr;
5474 if (parseBorderImageSlice(propId, imageSlice))
5475 context.commitImageSlice(imageSlice.release());
5476 }
5477
5478 if (!context.canAdvance() && context.allowRepeat()) {
5479 RefPtrWillBeRawPtr<CSSValue> repeat = nullptr;
5480 if (parseBorderImageRepeat(repeat))
5481 context.commitRepeat(repeat.release());
5482 }
5483
5484 if (!context.canAdvance() && context.allowWidth()) {
5485 RefPtrWillBeRawPtr<CSSQuadValue> borderWidth = nullptr;
5486 if (parseBorderImageWidth(borderWidth))
5487 context.commitBorderWidth(borderWidth.release());
5488 }
5489
5490 if (!context.canAdvance() && context.requireOutset()) {
5491 RefPtrWillBeRawPtr<CSSQuadValue> borderOutset = nullptr;
5492 if (parseBorderImageOutset(borderOutset))
5493 context.commitBorderOutset(borderOutset.release());
5494 }
5495
5496 if (!context.canAdvance())
5497 return false;
5498
5499 m_valueList->next();
5500 }
5501
5502 return context.allowCommit();
5503 }
5504
5505 void CSSPropertyParser::commitBorderImageProperty(CSSPropertyID propId, PassRefP trWillBeRawPtr<CSSValue> value, bool important)
5506 {
5507 if (value)
5508 addProperty(propId, value, important);
5509 else
5510 addProperty(propId, cssValuePool().createImplicitInitialValue(), importa nt, true);
5511 }
5512
5513 bool CSSPropertyParser::parseBorderImageShorthand(CSSPropertyID propId, bool imp ortant)
5514 {
5515 BorderImageParseContext context;
5516 if (buildBorderImageParseContext(propId, context)) {
5517 switch (propId) {
5518 case CSSPropertyWebkitMaskBoxImage:
5519 commitBorderImageProperty(CSSPropertyWebkitMaskBoxImageSource, conte xt.m_image, important);
5520 commitBorderImageProperty(CSSPropertyWebkitMaskBoxImageSlice, contex t.m_imageSlice.get(), important);
5521 commitBorderImageProperty(CSSPropertyWebkitMaskBoxImageWidth, contex t.m_borderWidth.get(), important);
5522 commitBorderImageProperty(CSSPropertyWebkitMaskBoxImageOutset, conte xt.m_outset.get(), important);
5523 commitBorderImageProperty(CSSPropertyWebkitMaskBoxImageRepeat, conte xt.m_repeat.get(), important);
5524 return true;
5525 case CSSPropertyBorderImage:
5526 commitBorderImageProperty(CSSPropertyBorderImageSource, context.m_im age, important);
5527 commitBorderImageProperty(CSSPropertyBorderImageSlice, context.m_ima geSlice.get(), important);
5528 commitBorderImageProperty(CSSPropertyBorderImageWidth, context.m_bor derWidth.get(), important);
5529 commitBorderImageProperty(CSSPropertyBorderImageOutset, context.m_ou tset.get(), important);
5530 commitBorderImageProperty(CSSPropertyBorderImageRepeat, context.m_re peat, important);
5531 return true;
5532 default:
5533 ASSERT_NOT_REACHED();
5534 return false;
5535 }
5536 }
5537 return false;
5538 }
5539
5540 PassRefPtrWillBeRawPtr<CSSValue> CSSPropertyParser::parseBorderImage(CSSProperty ID propId)
5541 {
5542 BorderImageParseContext context;
5543 if (buildBorderImageParseContext(propId, context)) {
5544 return context.commitCSSValue();
5545 }
5546 return nullptr;
5547 }
5548
5549 static bool isBorderImageRepeatKeyword(int id)
5550 {
5551 return id == CSSValueStretch || id == CSSValueRepeat || id == CSSValueSpace || id == CSSValueRound;
5552 }
5553
5554 bool CSSPropertyParser::parseBorderImageRepeat(RefPtrWillBeRawPtr<CSSValue>& res ult)
5555 {
5556 RefPtrWillBeRawPtr<CSSPrimitiveValue> firstValue = nullptr;
5557 RefPtrWillBeRawPtr<CSSPrimitiveValue> secondValue = nullptr;
5558 CSSParserValue* val = m_valueList->current();
5559 if (!val)
5560 return false;
5561 if (isBorderImageRepeatKeyword(val->id))
5562 firstValue = cssValuePool().createIdentifierValue(val->id);
5563 else
5564 return false;
5565
5566 val = m_valueList->next();
5567 if (val) {
5568 if (isBorderImageRepeatKeyword(val->id))
5569 secondValue = cssValuePool().createIdentifierValue(val->id);
5570 else if (!inShorthand()) {
5571 // If we're not parsing a shorthand then we are invalid.
5572 return false;
5573 } else {
5574 // We need to rewind the value list, so that when its advanced we'll
5575 // end up back at this value.
5576 m_valueList->previous();
5577 secondValue = firstValue;
5578 }
5579 } else
5580 secondValue = firstValue;
5581
5582 result = CSSValuePair::create(firstValue, secondValue, CSSValuePair::DropIde nticalValues);
5583 return true;
5584 }
5585
5586 class BorderImageSliceParseContext {
5587 STACK_ALLOCATED();
5588 public:
5589 BorderImageSliceParseContext()
5590 : m_allowNumber(true)
5591 , m_allowFill(true)
5592 , m_allowFinalCommit(false)
5593 , m_fill(false)
5594 { }
5595
5596 bool allowNumber() const { return m_allowNumber; }
5597 bool allowFill() const { return m_allowFill; }
5598 bool allowFinalCommit() const { return m_allowFinalCommit; }
5599 CSSPrimitiveValue* top() const { return m_top.get(); }
5600
5601 void commitNumber(PassRefPtrWillBeRawPtr<CSSPrimitiveValue> val)
5602 {
5603 if (!m_top)
5604 m_top = val;
5605 else if (!m_right)
5606 m_right = val;
5607 else if (!m_bottom)
5608 m_bottom = val;
5609 else {
5610 ASSERT(!m_left);
5611 m_left = val;
5612 }
5613
5614 m_allowNumber = !m_left;
5615 m_allowFinalCommit = true;
5616 }
5617
5618 void commitFill() { m_fill = true; m_allowFill = false; m_allowNumber = !m_t op; }
5619
5620 PassRefPtrWillBeRawPtr<CSSBorderImageSliceValue> commitBorderImageSlice()
5621 {
5622 // We need to clone and repeat values for any omissions.
5623 ASSERT(m_top);
5624 if (!m_right) {
5625 m_right = m_top;
5626 m_bottom = m_top;
5627 m_left = m_top;
5628 }
5629 if (!m_bottom) {
5630 m_bottom = m_top;
5631 m_left = m_right;
5632 }
5633 if (!m_left)
5634 m_left = m_right;
5635
5636 return CSSBorderImageSliceValue::create(CSSQuadValue::create(m_top.relea se(), m_right.release(), m_bottom.release(), m_left.release(), CSSQuadValue::Ser ializeAsQuad), m_fill);
5637 }
5638
5639 private:
5640 bool m_allowNumber;
5641 bool m_allowFill;
5642 bool m_allowFinalCommit;
5643
5644 RefPtrWillBeMember<CSSPrimitiveValue> m_top;
5645 RefPtrWillBeMember<CSSPrimitiveValue> m_right;
5646 RefPtrWillBeMember<CSSPrimitiveValue> m_bottom;
5647 RefPtrWillBeMember<CSSPrimitiveValue> m_left;
5648
5649 bool m_fill;
5650 };
5651
5652 bool CSSPropertyParser::parseBorderImageSlice(CSSPropertyID propId, RefPtrWillBe RawPtr<CSSBorderImageSliceValue>& result)
5653 {
5654 BorderImageSliceParseContext context;
5655 for (CSSParserValue* val = m_valueList->current(); val; val = m_valueList->n ext()) {
5656 // FIXME calc() http://webkit.org/b/16662 : calc is parsed but values ar e not created yet.
5657 if (context.allowNumber() && !isCalculation(val) && validUnit(val, FInte ger | FNonNeg | FPercent)) {
5658 context.commitNumber(createPrimitiveNumericValue(val));
5659 } else if (context.allowFill() && val->id == CSSValueFill) {
5660 context.commitFill();
5661 } else if (!inShorthand()) {
5662 // If we're not parsing a shorthand then we are invalid.
5663 return false;
5664 } else {
5665 if (context.allowFinalCommit()) {
5666 // We're going to successfully parse, but we don't want to consu me this token.
5667 m_valueList->previous();
5668 }
5669 break;
5670 }
5671 }
5672
5673 if (context.allowFinalCommit()) {
5674 // FIXME: For backwards compatibility, -webkit-border-image, -webkit-mas k-box-image and -webkit-box-reflect have to do a fill by default.
5675 // FIXME: What do we do with -webkit-box-reflect and -webkit-mask-box-im age? Probably just have to leave them filling...
5676 if (propId == CSSPropertyWebkitBorderImage || propId == CSSPropertyWebki tMaskBoxImage || propId == CSSPropertyWebkitBoxReflect)
5677 context.commitFill();
5678
5679 // Need to fully commit as a single value.
5680 result = context.commitBorderImageSlice();
5681 return true;
5682 }
5683
5684 return false;
5685 }
5686
5687 class BorderImageQuadParseContext {
5688 STACK_ALLOCATED();
5689 public:
5690 BorderImageQuadParseContext()
5691 : m_allowNumber(true)
5692 , m_allowFinalCommit(false)
5693 { }
5694
5695 bool allowNumber() const { return m_allowNumber; }
5696 bool allowFinalCommit() const { return m_allowFinalCommit; }
5697 CSSPrimitiveValue* top() const { return m_top.get(); }
5698
5699 void commitNumber(PassRefPtrWillBeRawPtr<CSSPrimitiveValue> val)
5700 {
5701 if (!m_top)
5702 m_top = val;
5703 else if (!m_right)
5704 m_right = val;
5705 else if (!m_bottom)
5706 m_bottom = val;
5707 else {
5708 ASSERT(!m_left);
5709 m_left = val;
5710 }
5711
5712 m_allowNumber = !m_left;
5713 m_allowFinalCommit = true;
5714 }
5715
5716 void setTop(PassRefPtrWillBeRawPtr<CSSPrimitiveValue> val) { m_top = val; }
5717
5718 PassRefPtrWillBeRawPtr<CSSQuadValue> commitBorderImageQuad()
5719 {
5720 // We need to clone and repeat values for any omissions.
5721 ASSERT(m_top);
5722 if (!m_right) {
5723 m_right = m_top;
5724 m_bottom = m_top;
5725 m_left = m_top;
5726 }
5727 if (!m_bottom) {
5728 m_bottom = m_top;
5729 m_left = m_right;
5730 }
5731 if (!m_left)
5732 m_left = m_right;
5733
5734 return CSSQuadValue::create(m_top.release(), m_right.release(), m_bottom .release(), m_left.release(), CSSQuadValue::SerializeAsQuad);
5735 }
5736
5737 private:
5738 bool m_allowNumber;
5739 bool m_allowFinalCommit;
5740
5741 RefPtrWillBeMember<CSSPrimitiveValue> m_top;
5742 RefPtrWillBeMember<CSSPrimitiveValue> m_right;
5743 RefPtrWillBeMember<CSSPrimitiveValue> m_bottom;
5744 RefPtrWillBeMember<CSSPrimitiveValue> m_left;
5745 };
5746
5747 bool CSSPropertyParser::parseBorderImageQuad(Units validUnits, RefPtrWillBeRawPt r<CSSQuadValue>& result)
5748 {
5749 BorderImageQuadParseContext context;
5750 for (CSSParserValue* val = m_valueList->current(); val; val = m_valueList->n ext()) {
5751 if (context.allowNumber() && (validUnit(val, validUnits, HTMLStandardMod e) || val->id == CSSValueAuto)) {
5752 if (val->id == CSSValueAuto)
5753 context.commitNumber(cssValuePool().createIdentifierValue(val->i d));
5754 else
5755 context.commitNumber(createPrimitiveNumericValue(val));
5756 } else if (!inShorthand()) {
5757 // If we're not parsing a shorthand then we are invalid.
5758 return false;
5759 } else {
5760 if (context.allowFinalCommit())
5761 m_valueList->previous(); // The shorthand loop will advance back to this point.
5762 break;
5763 }
5764 }
5765
5766 if (context.allowFinalCommit()) {
5767 // Need to fully commit as a single value.
5768 result = context.commitBorderImageQuad();
5769 return true;
5770 }
5771 return false;
5772 }
5773
5774 bool CSSPropertyParser::parseBorderImageWidth(RefPtrWillBeRawPtr<CSSQuadValue>& result)
5775 {
5776 return parseBorderImageQuad(FLength | FNumber | FNonNeg | FPercent, result);
5777 }
5778
5779 bool CSSPropertyParser::parseBorderImageOutset(RefPtrWillBeRawPtr<CSSQuadValue>& result)
5780 {
5781 return parseBorderImageQuad(FLength | FNumber | FNonNeg, result);
5782 }
5783
5784 bool CSSPropertyParser::parseBorderRadius(CSSPropertyID unresolvedProperty, bool important)
5785 {
5786 unsigned num = m_valueList->size();
5787 if (num > 9)
5788 return false;
5789
5790 ShorthandScope scope(this, unresolvedProperty);
5791 RefPtrWillBeRawPtr<CSSPrimitiveValue> radii[2][4];
5792 #if ENABLE(OILPAN)
5793 // Zero initialize the array of raw pointers.
5794 memset(&radii, 0, sizeof(radii));
5795 #endif
5796
5797 unsigned indexAfterSlash = 0;
5798 for (unsigned i = 0; i < num; ++i) {
5799 CSSParserValue* value = m_valueList->valueAt(i);
5800 if (value->m_unit == CSSParserValue::Operator) {
5801 if (value->iValue != '/')
5802 return false;
5803
5804 if (!i || indexAfterSlash || i + 1 == num || num > i + 5)
5805 return false;
5806
5807 indexAfterSlash = i + 1;
5808 completeBorderRadii(radii[0]);
5809 continue;
5810 }
5811
5812 if (i - indexAfterSlash >= 4)
5813 return false;
5814
5815 if (!validUnit(value, FLength | FPercent | FNonNeg))
5816 return false;
5817
5818 RefPtrWillBeRawPtr<CSSPrimitiveValue> radius = createPrimitiveNumericVal ue(value);
5819
5820 if (!indexAfterSlash) {
5821 radii[0][i] = radius;
5822
5823 // Legacy syntax: -webkit-border-radius: l1 l2; is equivalent to bor der-radius: l1 / l2;
5824 if (num == 2 && unresolvedProperty == CSSPropertyAliasWebkitBorderRa dius) {
5825 indexAfterSlash = 1;
5826 completeBorderRadii(radii[0]);
5827 }
5828 } else
5829 radii[1][i - indexAfterSlash] = radius.release();
5830 }
5831
5832 if (!indexAfterSlash) {
5833 completeBorderRadii(radii[0]);
5834 for (unsigned i = 0; i < 4; ++i)
5835 radii[1][i] = radii[0][i];
5836 } else
5837 completeBorderRadii(radii[1]);
5838
5839 ImplicitScope implicitScope(this);
5840 addProperty(CSSPropertyBorderTopLeftRadius, CSSValuePair::create(radii[0][0] .release(), radii[1][0].release(), CSSValuePair::DropIdenticalValues), important );
5841 addProperty(CSSPropertyBorderTopRightRadius, CSSValuePair::create(radii[0][1 ].release(), radii[1][1].release(), CSSValuePair::DropIdenticalValues), importan t);
5842 addProperty(CSSPropertyBorderBottomRightRadius, CSSValuePair::create(radii[0 ][2].release(), radii[1][2].release(), CSSValuePair::DropIdenticalValues), impor tant);
5843 addProperty(CSSPropertyBorderBottomLeftRadius, CSSValuePair::create(radii[0] [3].release(), radii[1][3].release(), CSSValuePair::DropIdenticalValues), import ant);
5844 return true;
5845 }
5846
5847 PassRefPtrWillBeRawPtr<CSSValue> CSSPropertyParser::parseCounter(int defaultValu e)
5848 {
5849 RefPtrWillBeRawPtr<CSSValueList> list = CSSValueList::createCommaSeparated() ;
5850
5851 while (m_valueList->current()) {
5852 CSSParserValue* val = m_valueList->current();
5853 if (val->m_unit != CSSParserValue::Identifier)
5854 return nullptr;
5855 RefPtrWillBeRawPtr<CSSPrimitiveValue> counterName = createPrimitiveCusto mIdentValue(val);
5856 m_valueList->next();
5857
5858 val = m_valueList->current();
5859 int i = defaultValue;
5860 if (val && validUnit(val, FInteger)) {
5861 i = clampTo<int>(val->fValue);
5862 m_valueList->next();
5863 }
5864
5865 list->append(CSSValuePair::create(counterName.release(),
5866 cssValuePool().createValue(i, CSSPrimitiveValue::UnitType::Number),
5867 CSSValuePair::DropIdenticalValues));
5868 }
5869
5870 if (!list->length())
5871 return nullptr;
5872 return list.release();
5873 }
5874
5875 // This should go away once we drop support for -webkit-gradient
5876 static PassRefPtrWillBeRawPtr<CSSPrimitiveValue> parseDeprecatedGradientPoint(CS SParserValue* a, bool horizontal)
5877 {
5878 RefPtrWillBeRawPtr<CSSPrimitiveValue> result = nullptr;
5879 if (a->m_unit == CSSParserValue::Identifier) {
5880 if ((a->id == CSSValueLeft && horizontal)
5881 || (a->id == CSSValueTop && !horizontal))
5882 result = cssValuePool().createValue(0., CSSPrimitiveValue::UnitType: :Percentage);
5883 else if ((a->id == CSSValueRight && horizontal)
5884 || (a->id == CSSValueBottom && !horizontal))
5885 result = cssValuePool().createValue(100., CSSPrimitiveValue::UnitTyp e::Percentage);
5886 else if (a->id == CSSValueCenter)
5887 result = cssValuePool().createValue(50., CSSPrimitiveValue::UnitType ::Percentage);
5888 } else if (a->unit() == CSSPrimitiveValue::UnitType::Number || a->unit() == CSSPrimitiveValue::UnitType::Percentage) {
5889 result = cssValuePool().createValue(a->fValue, a->unit());
5890 }
5891 return result;
5892 }
5893
5894 // Used to parse colors for -webkit-gradient(...).
5895 PassRefPtrWillBeRawPtr<CSSPrimitiveValue> CSSPropertyParser::parseDeprecatedGrad ientStopColor(const CSSParserValue* value)
5896 {
5897 // Disallow currentcolor.
5898 if (value->id == CSSValueCurrentcolor)
5899 return nullptr;
5900 return parseColor(value);
5901 }
5902
5903 bool CSSPropertyParser::parseDeprecatedGradientColorStop(CSSParserValue* a, CSSG radientColorStop& stop)
5904 {
5905 if (a->m_unit != CSSParserValue::Function)
5906 return false;
5907
5908 if (a->function->id != CSSValueFrom
5909 && a->function->id != CSSValueTo
5910 && a->function->id != CSSValueColorStop)
5911 return false;
5912
5913 CSSParserValueList* args = a->function->args.get();
5914 if (!args)
5915 return false;
5916
5917 if (a->function->id == CSSValueFrom || a->function->id == CSSValueTo) {
5918 // The "from" and "to" stops expect 1 argument.
5919 if (args->size() != 1)
5920 return false;
5921
5922 if (a->function->id == CSSValueFrom)
5923 stop.m_position = cssValuePool().createValue(0, CSSPrimitiveValue::U nitType::Number);
5924 else
5925 stop.m_position = cssValuePool().createValue(1, CSSPrimitiveValue::U nitType::Number);
5926
5927 stop.m_color = parseDeprecatedGradientStopColor(args->current());
5928 if (!stop.m_color)
5929 return false;
5930 }
5931
5932 // The "color-stop" function expects 3 arguments.
5933 if (a->function->id == CSSValueColorStop) {
5934 if (args->size() != 3)
5935 return false;
5936
5937 CSSParserValue* stopArg = args->current();
5938 if (stopArg->unit() == CSSPrimitiveValue::UnitType::Percentage)
5939 stop.m_position = cssValuePool().createValue(stopArg->fValue / 100, CSSPrimitiveValue::UnitType::Number);
5940 else if (stopArg->unit() == CSSPrimitiveValue::UnitType::Number)
5941 stop.m_position = cssValuePool().createValue(stopArg->fValue, CSSPri mitiveValue::UnitType::Number);
5942 else
5943 return false;
5944
5945 args->next();
5946 if (!consumeComma(args))
5947 return false;
5948
5949 stop.m_color = parseDeprecatedGradientStopColor(args->current());
5950 if (!stop.m_color)
5951 return false;
5952 }
5953
5954 return true;
5955 }
5956
5957 bool CSSPropertyParser::parseDeprecatedGradient(CSSParserValueList* valueList, R efPtrWillBeRawPtr<CSSValue>& gradient)
5958 {
5959 // Walk the arguments.
5960 CSSParserValueList* args = valueList->current()->function->args.get();
5961 if (!args || args->size() == 0)
5962 return false;
5963
5964 // The first argument is the gradient type. It is an identifier.
5965 CSSGradientType gradientType;
5966 CSSParserValue* a = args->current();
5967 if (!a || a->m_unit != CSSParserValue::Identifier)
5968 return false;
5969 if (a->id == CSSValueLinear)
5970 gradientType = CSSDeprecatedLinearGradient;
5971 else if (a->id == CSSValueRadial)
5972 gradientType = CSSDeprecatedRadialGradient;
5973 else
5974 return false;
5975
5976 RefPtrWillBeRawPtr<CSSGradientValue> result = nullptr;
5977 switch (gradientType) {
5978 case CSSDeprecatedLinearGradient:
5979 result = CSSLinearGradientValue::create(NonRepeating, gradientType);
5980 break;
5981 case CSSDeprecatedRadialGradient:
5982 result = CSSRadialGradientValue::create(NonRepeating, gradientType);
5983 break;
5984 default:
5985 // The rest of the gradient types shouldn't appear here.
5986 ASSERT_NOT_REACHED();
5987 }
5988 args->next();
5989
5990 if (!consumeComma(args))
5991 return false;
5992
5993 // Next comes the starting point for the gradient as an x y pair. There is no
5994 // comma between the x and the y values.
5995 // First X. It can be left, right, number or percent.
5996 a = args->current();
5997 if (!a)
5998 return false;
5999 RefPtrWillBeRawPtr<CSSPrimitiveValue> point = parseDeprecatedGradientPoint(a , true);
6000 if (!point)
6001 return false;
6002 result->setFirstX(point.release());
6003
6004 // First Y. It can be top, bottom, number or percent.
6005 a = args->next();
6006 if (!a)
6007 return false;
6008 point = parseDeprecatedGradientPoint(a, false);
6009 if (!point)
6010 return false;
6011 result->setFirstY(point.release());
6012
6013 // Comma after the first point.
6014 args->next();
6015 if (!consumeComma(args))
6016 return false;
6017
6018 // For radial gradients only, we now expect a numeric radius.
6019 if (gradientType == CSSDeprecatedRadialGradient) {
6020 a = args->current();
6021 if (!a || a->unit() != CSSPrimitiveValue::UnitType::Number)
6022 return false;
6023 toCSSRadialGradientValue(result.get())->setFirstRadius(createPrimitiveNu mericValue(a));
6024
6025 // Comma after the first radius.
6026 args->next();
6027 if (!consumeComma(args))
6028 return false;
6029 }
6030
6031 // Next is the ending point for the gradient as an x, y pair.
6032 // Second X. It can be left, right, number or percent.
6033 a = args->current();
6034 if (!a)
6035 return false;
6036 point = parseDeprecatedGradientPoint(a, true);
6037 if (!point)
6038 return false;
6039 result->setSecondX(point.release());
6040
6041 // Second Y. It can be top, bottom, number or percent.
6042 a = args->next();
6043 if (!a)
6044 return false;
6045 point = parseDeprecatedGradientPoint(a, false);
6046 if (!point)
6047 return false;
6048 result->setSecondY(point.release());
6049 args->next();
6050
6051 // For radial gradients only, we now expect the second radius.
6052 if (gradientType == CSSDeprecatedRadialGradient) {
6053 // Comma after the second point.
6054 if (!consumeComma(args))
6055 return false;
6056
6057 a = args->current();
6058 if (!a || a->unit() != CSSPrimitiveValue::UnitType::Number)
6059 return false;
6060 toCSSRadialGradientValue(result.get())->setSecondRadius(createPrimitiveN umericValue(a));
6061 args->next();
6062 }
6063
6064 // We now will accept any number of stops (0 or more).
6065 a = args->current();
6066 while (a) {
6067 // Look for the comma before the next stop.
6068 if (!consumeComma(args))
6069 return false;
6070
6071 // Now examine the stop itself.
6072 a = args->current();
6073 if (!a)
6074 return false;
6075
6076 // The function name needs to be one of "from", "to", or "color-stop."
6077 CSSGradientColorStop stop;
6078 if (!parseDeprecatedGradientColorStop(a, stop))
6079 return false;
6080 result->addStop(stop);
6081
6082 // Advance
6083 a = args->next();
6084 }
6085
6086 gradient = result.release();
6087 return true;
6088 }
6089
6090 static PassRefPtrWillBeRawPtr<CSSPrimitiveValue> valueFromSideKeyword(CSSParserV alue* a, bool& isHorizontal)
6091 {
6092 if (a->m_unit != CSSParserValue::Identifier)
6093 return nullptr;
6094
6095 switch (a->id) {
6096 case CSSValueLeft:
6097 case CSSValueRight:
6098 isHorizontal = true;
6099 break;
6100 case CSSValueTop:
6101 case CSSValueBottom:
6102 isHorizontal = false;
6103 break;
6104 default:
6105 return nullptr;
6106 }
6107 return cssValuePool().createIdentifierValue(a->id);
6108 }
6109
6110 bool CSSPropertyParser::parseDeprecatedLinearGradient(CSSParserValueList* valueL ist, RefPtrWillBeRawPtr<CSSValue>& gradient, CSSGradientRepeat repeating)
6111 {
6112 RefPtrWillBeRawPtr<CSSLinearGradientValue> result = CSSLinearGradientValue:: create(repeating, CSSPrefixedLinearGradient);
6113
6114 // Walk the arguments.
6115 CSSParserValueList* args = valueList->current()->function->args.get();
6116 if (!args || !args->size())
6117 return false;
6118
6119 CSSParserValue* a = args->current();
6120 if (!a)
6121 return false;
6122
6123 bool expectComma = false;
6124 // Look for angle.
6125 if (validUnit(a, FAngle, HTMLStandardMode)) {
6126 result->setAngle(createPrimitiveNumericValue(a));
6127
6128 args->next();
6129 expectComma = true;
6130 } else {
6131 // Look one or two optional keywords that indicate a side or corner.
6132 RefPtrWillBeRawPtr<CSSPrimitiveValue> startX = nullptr;
6133 RefPtrWillBeRawPtr<CSSPrimitiveValue> startY = nullptr;
6134
6135 RefPtrWillBeRawPtr<CSSPrimitiveValue> location = nullptr;
6136 bool isHorizontal = false;
6137 if ((location = valueFromSideKeyword(a, isHorizontal))) {
6138 if (isHorizontal)
6139 startX = location;
6140 else
6141 startY = location;
6142
6143 a = args->next();
6144 if (a) {
6145 if ((location = valueFromSideKeyword(a, isHorizontal))) {
6146 if (isHorizontal) {
6147 if (startX)
6148 return false;
6149 startX = location;
6150 } else {
6151 if (startY)
6152 return false;
6153 startY = location;
6154 }
6155
6156 args->next();
6157 }
6158 }
6159
6160 expectComma = true;
6161 }
6162
6163 if (!startX && !startY)
6164 startY = cssValuePool().createIdentifierValue(CSSValueTop);
6165
6166 result->setFirstX(startX.release());
6167 result->setFirstY(startY.release());
6168 }
6169
6170 if (!parseGradientColorStops(args, result.get(), expectComma))
6171 return false;
6172
6173 if (!result->stopCount())
6174 return false;
6175
6176 gradient = result.release();
6177 return true;
6178 }
6179
6180 bool CSSPropertyParser::parseDeprecatedRadialGradient(CSSParserValueList* valueL ist, RefPtrWillBeRawPtr<CSSValue>& gradient, CSSGradientRepeat repeating)
6181 {
6182 RefPtrWillBeRawPtr<CSSRadialGradientValue> result = CSSRadialGradientValue:: create(repeating, CSSPrefixedRadialGradient);
6183
6184 // Walk the arguments.
6185 CSSParserValueList* args = valueList->current()->function->args.get();
6186 if (!args || !args->size())
6187 return false;
6188
6189 CSSParserValue* a = args->current();
6190 if (!a)
6191 return false;
6192
6193 bool expectComma = false;
6194
6195 // Optional background-position
6196 RefPtrWillBeRawPtr<CSSValue> centerX = nullptr;
6197 RefPtrWillBeRawPtr<CSSValue> centerY = nullptr;
6198 // parse2ValuesFillPosition advances the args next pointer.
6199 parse2ValuesFillPosition(args, centerX, centerY);
6200
6201 if ((centerX || centerY) && !consumeComma(args))
6202 return false;
6203
6204 a = args->current();
6205 if (!a)
6206 return false;
6207
6208 result->setFirstX(toCSSPrimitiveValue(centerX.get()));
6209 result->setSecondX(toCSSPrimitiveValue(centerX.get()));
6210 // CSS3 radial gradients always share the same start and end point.
6211 result->setFirstY(toCSSPrimitiveValue(centerY.get()));
6212 result->setSecondY(toCSSPrimitiveValue(centerY.get()));
6213
6214 RefPtrWillBeRawPtr<CSSPrimitiveValue> shapeValue = nullptr;
6215 RefPtrWillBeRawPtr<CSSPrimitiveValue> sizeValue = nullptr;
6216
6217 // Optional shape and/or size in any order.
6218 for (int i = 0; i < 2; ++i) {
6219 if (a->m_unit != CSSParserValue::Identifier)
6220 break;
6221
6222 bool foundValue = false;
6223 switch (a->id) {
6224 case CSSValueCircle:
6225 case CSSValueEllipse:
6226 shapeValue = cssValuePool().createIdentifierValue(a->id);
6227 foundValue = true;
6228 break;
6229 case CSSValueClosestSide:
6230 case CSSValueClosestCorner:
6231 case CSSValueFarthestSide:
6232 case CSSValueFarthestCorner:
6233 case CSSValueContain:
6234 case CSSValueCover:
6235 sizeValue = cssValuePool().createIdentifierValue(a->id);
6236 foundValue = true;
6237 break;
6238 default:
6239 break;
6240 }
6241
6242 if (foundValue) {
6243 a = args->next();
6244 if (!a)
6245 return false;
6246
6247 expectComma = true;
6248 }
6249 }
6250
6251 result->setShape(shapeValue);
6252 result->setSizingBehavior(sizeValue);
6253
6254 // Or, two lengths or percentages
6255 RefPtrWillBeRawPtr<CSSPrimitiveValue> horizontalSize = nullptr;
6256 RefPtrWillBeRawPtr<CSSPrimitiveValue> verticalSize = nullptr;
6257
6258 if (!shapeValue && !sizeValue) {
6259 if (validUnit(a, FLength | FPercent)) {
6260 horizontalSize = createPrimitiveNumericValue(a);
6261 a = args->next();
6262 if (!a)
6263 return false;
6264
6265 expectComma = true;
6266 }
6267
6268 if (validUnit(a, FLength | FPercent)) {
6269 verticalSize = createPrimitiveNumericValue(a);
6270
6271 a = args->next();
6272 if (!a)
6273 return false;
6274 expectComma = true;
6275 }
6276 }
6277
6278 // Must have neither or both.
6279 if (!horizontalSize != !verticalSize)
6280 return false;
6281
6282 result->setEndHorizontalSize(horizontalSize);
6283 result->setEndVerticalSize(verticalSize);
6284
6285 if (!parseGradientColorStops(args, result.get(), expectComma))
6286 return false;
6287
6288 gradient = result.release();
6289 return true;
6290 }
6291
6292 bool CSSPropertyParser::parseLinearGradient(CSSParserValueList* valueList, RefPt rWillBeRawPtr<CSSValue>& gradient, CSSGradientRepeat repeating)
6293 {
6294 RefPtrWillBeRawPtr<CSSLinearGradientValue> result = CSSLinearGradientValue:: create(repeating, CSSLinearGradient);
6295
6296 CSSParserFunction* function = valueList->current()->function;
6297 CSSParserValueList* args = function->args.get();
6298 if (!args || !args->size())
6299 return false;
6300
6301 CSSParserValue* a = args->current();
6302 if (!a)
6303 return false;
6304
6305 bool expectComma = false;
6306 // Look for angle.
6307 if (validUnit(a, FAngle, HTMLStandardMode)) {
6308 result->setAngle(createPrimitiveNumericValue(a));
6309
6310 args->next();
6311 expectComma = true;
6312 } else if (a->m_unit == CSSParserValue::Identifier && a->id == CSSValueTo) {
6313 // to [ [left | right] || [top | bottom] ]
6314 a = args->next();
6315 if (!a)
6316 return false;
6317
6318 RefPtrWillBeRawPtr<CSSPrimitiveValue> endX = nullptr;
6319 RefPtrWillBeRawPtr<CSSPrimitiveValue> endY = nullptr;
6320 RefPtrWillBeRawPtr<CSSPrimitiveValue> location = nullptr;
6321 bool isHorizontal = false;
6322
6323 location = valueFromSideKeyword(a, isHorizontal);
6324 if (!location)
6325 return false;
6326
6327 if (isHorizontal)
6328 endX = location;
6329 else
6330 endY = location;
6331
6332 a = args->next();
6333 if (!a)
6334 return false;
6335
6336 location = valueFromSideKeyword(a, isHorizontal);
6337 if (location) {
6338 if (isHorizontal) {
6339 if (endX)
6340 return false;
6341 endX = location;
6342 } else {
6343 if (endY)
6344 return false;
6345 endY = location;
6346 }
6347
6348 args->next();
6349 }
6350
6351 expectComma = true;
6352 result->setFirstX(endX.release());
6353 result->setFirstY(endY.release());
6354 }
6355
6356 if (!parseGradientColorStops(args, result.get(), expectComma))
6357 return false;
6358
6359 if (!result->stopCount())
6360 return false;
6361
6362 gradient = result.release();
6363 return true;
6364 }
6365
6366 bool CSSPropertyParser::parseRadialGradient(CSSParserValueList* valueList, RefPt rWillBeRawPtr<CSSValue>& gradient, CSSGradientRepeat repeating)
6367 {
6368 RefPtrWillBeRawPtr<CSSRadialGradientValue> result = CSSRadialGradientValue:: create(repeating, CSSRadialGradient);
6369
6370 CSSParserValueList* args = valueList->current()->function->args.get();
6371 if (!args || !args->size())
6372 return false;
6373
6374 CSSParserValue* a = args->current();
6375 if (!a)
6376 return false;
6377
6378 bool expectComma = false;
6379
6380 RefPtrWillBeRawPtr<CSSPrimitiveValue> shapeValue = nullptr;
6381 RefPtrWillBeRawPtr<CSSPrimitiveValue> sizeValue = nullptr;
6382 RefPtrWillBeRawPtr<CSSPrimitiveValue> horizontalSize = nullptr;
6383 RefPtrWillBeRawPtr<CSSPrimitiveValue> verticalSize = nullptr;
6384
6385 // First part of grammar, the size/shape clause:
6386 // [ circle || <length> ] |
6387 // [ ellipse || [ <length> | <percentage> ]{2} ] |
6388 // [ [ circle | ellipse] || <size-keyword> ]
6389 for (int i = 0; i < 3; ++i) {
6390 if (a->m_unit == CSSParserValue::Identifier) {
6391 bool badIdent = false;
6392 switch (a->id) {
6393 case CSSValueCircle:
6394 case CSSValueEllipse:
6395 if (shapeValue)
6396 return false;
6397 shapeValue = cssValuePool().createIdentifierValue(a->id);
6398 break;
6399 case CSSValueClosestSide:
6400 case CSSValueClosestCorner:
6401 case CSSValueFarthestSide:
6402 case CSSValueFarthestCorner:
6403 if (sizeValue || horizontalSize)
6404 return false;
6405 sizeValue = cssValuePool().createIdentifierValue(a->id);
6406 break;
6407 default:
6408 badIdent = true;
6409 }
6410
6411 if (badIdent)
6412 break;
6413
6414 a = args->next();
6415 if (!a)
6416 return false;
6417 } else if (validUnit(a, FLength | FPercent)) {
6418
6419 if (sizeValue || horizontalSize)
6420 return false;
6421 horizontalSize = createPrimitiveNumericValue(a);
6422
6423 a = args->next();
6424 if (!a)
6425 return false;
6426
6427 if (validUnit(a, FLength | FPercent)) {
6428 verticalSize = createPrimitiveNumericValue(a);
6429 ++i;
6430 a = args->next();
6431 if (!a)
6432 return false;
6433 }
6434 } else
6435 break;
6436 }
6437
6438 // You can specify size as a keyword or a length/percentage, not both.
6439 if (sizeValue && horizontalSize)
6440 return false;
6441 // Circles must have 0 or 1 lengths.
6442 if (shapeValue && shapeValue->getValueID() == CSSValueCircle && verticalSize )
6443 return false;
6444 // Ellipses must have 0 or 2 length/percentages.
6445 if (shapeValue && shapeValue->getValueID() == CSSValueEllipse && horizontalS ize && !verticalSize)
6446 return false;
6447 // If there's only one size, it must be a length.
6448 if (!verticalSize && horizontalSize && horizontalSize->isPercentage())
6449 return false;
6450
6451 result->setShape(shapeValue);
6452 result->setSizingBehavior(sizeValue);
6453 result->setEndHorizontalSize(horizontalSize);
6454 result->setEndVerticalSize(verticalSize);
6455
6456 // Second part of grammar, the center-position clause:
6457 // at <position>
6458 RefPtrWillBeRawPtr<CSSValue> centerX = nullptr;
6459 RefPtrWillBeRawPtr<CSSValue> centerY = nullptr;
6460 if (a->m_unit == CSSParserValue::Identifier && a->id == CSSValueAt) {
6461 a = args->next();
6462 if (!a)
6463 return false;
6464
6465 parseFillPosition(args, centerX, centerY);
6466 if (!(centerX && centerY))
6467 return false;
6468
6469 a = args->current();
6470 if (!a)
6471 return false;
6472 result->setFirstX(centerX);
6473 result->setFirstY(centerY);
6474 // Right now, CSS radial gradients have the same start and end centers.
6475 result->setSecondX(centerX);
6476 result->setSecondY(centerY);
6477 }
6478
6479 if (shapeValue || sizeValue || horizontalSize || centerX || centerY)
6480 expectComma = true;
6481
6482 if (!parseGradientColorStops(args, result.get(), expectComma))
6483 return false;
6484
6485 gradient = result.release();
6486 return true;
6487 }
6488
6489 bool CSSPropertyParser::parseGradientColorStops(CSSParserValueList* valueList, C SSGradientValue* gradient, bool expectComma)
6490 {
6491 CSSParserValue* a = valueList->current();
6492
6493 // Now look for color stops.
6494 // <color-stop-list> = [ <color-stop> , <color-hint>? ]# , <color-stop>
6495 bool supportsColorHints = gradient->gradientType() == CSSLinearGradient
6496 || gradient->gradientType() == CSSRadialGradient;
6497
6498 // The first color stop cannot be a color hint.
6499 bool previousStopWasColorHint = true;
6500 while (a) {
6501 // Look for the comma before the next stop.
6502 if (expectComma) {
6503 if (!isComma(a))
6504 return false;
6505
6506 a = valueList->next();
6507 if (!a)
6508 return false;
6509 }
6510
6511 // <color-stop> = <color> [ <percentage> | <length> ]?
6512 // <color-hint> = <length> | <percentage>
6513 CSSGradientColorStop stop;
6514 stop.m_color = parseColor(a);
6515
6516 // Two hints in a row are not allowed.
6517 if (!stop.m_color && (!supportsColorHints || previousStopWasColorHint))
6518 return false;
6519 previousStopWasColorHint = !stop.m_color;
6520
6521 if (stop.m_color)
6522 a = valueList->next();
6523
6524 if (a) {
6525 if (validUnit(a, FLength | FPercent)) {
6526 stop.m_position = createPrimitiveNumericValue(a);
6527 a = valueList->next();
6528 }
6529 }
6530
6531 if (!stop.m_color && !stop.m_position)
6532 return false;
6533
6534 gradient->addStop(stop);
6535 expectComma = true;
6536 }
6537
6538 // The last color stop cannot be a color hint.
6539 if (previousStopWasColorHint)
6540 return false;
6541
6542 // Must have 2 or more stops to be valid.
6543 return gradient->stopCount() >= 2;
6544 }
6545
6546 bool CSSPropertyParser::parseGeneratedImage(CSSParserValueList* valueList, RefPt rWillBeRawPtr<CSSValue>& value)
6547 {
6548 CSSParserValue* val = valueList->current();
6549
6550 if (val->m_unit != CSSParserValue::Function)
6551 return false;
6552
6553 if (val->function->id == CSSValueWebkitGradient) {
6554 // FIXME: This should send a deprecation message.
6555 if (m_context.useCounter())
6556 m_context.useCounter()->count(UseCounter::DeprecatedWebKitGradient);
6557 return parseDeprecatedGradient(valueList, value);
6558 }
6559
6560 if (val->function->id == CSSValueWebkitLinearGradient) {
6561 // FIXME: This should send a deprecation message.
6562 if (m_context.useCounter())
6563 m_context.useCounter()->count(UseCounter::DeprecatedWebKitLinearGrad ient);
6564 return parseDeprecatedLinearGradient(valueList, value, NonRepeating);
6565 }
6566
6567 if (val->function->id == CSSValueLinearGradient)
6568 return parseLinearGradient(valueList, value, NonRepeating);
6569
6570 if (val->function->id == CSSValueWebkitRepeatingLinearGradient) {
6571 // FIXME: This should send a deprecation message.
6572 if (m_context.useCounter())
6573 m_context.useCounter()->count(UseCounter::DeprecatedWebKitRepeatingL inearGradient);
6574 return parseDeprecatedLinearGradient(valueList, value, Repeating);
6575 }
6576
6577 if (val->function->id == CSSValueRepeatingLinearGradient)
6578 return parseLinearGradient(valueList, value, Repeating);
6579
6580 if (val->function->id == CSSValueWebkitRadialGradient) {
6581 // FIXME: This should send a deprecation message.
6582 if (m_context.useCounter())
6583 m_context.useCounter()->count(UseCounter::DeprecatedWebKitRadialGrad ient);
6584 return parseDeprecatedRadialGradient(valueList, value, NonRepeating);
6585 }
6586
6587 if (val->function->id == CSSValueRadialGradient)
6588 return parseRadialGradient(valueList, value, NonRepeating);
6589
6590 if (val->function->id == CSSValueWebkitRepeatingRadialGradient) {
6591 if (m_context.useCounter())
6592 m_context.useCounter()->count(UseCounter::DeprecatedWebKitRepeatingR adialGradient);
6593 return parseDeprecatedRadialGradient(valueList, value, Repeating);
6594 }
6595
6596 if (val->function->id == CSSValueRepeatingRadialGradient)
6597 return parseRadialGradient(valueList, value, Repeating);
6598
6599 if (val->function->id == CSSValueWebkitCanvas)
6600 return parseCanvas(valueList, value);
6601
6602 if (val->function->id == CSSValueWebkitCrossFade)
6603 return parseCrossfade(valueList, value);
6604
6605 return false;
6606 }
6607
6608 bool CSSPropertyParser::parseCrossfade(CSSParserValueList* valueList, RefPtrWill BeRawPtr<CSSValue>& crossfade)
6609 {
6610 // Walk the arguments.
6611 CSSParserValueList* args = valueList->current()->function->args.get();
6612 if (!args || args->size() != 5)
6613 return false;
6614 RefPtrWillBeRawPtr<CSSValue> fromImageValue = nullptr;
6615 RefPtrWillBeRawPtr<CSSValue> toImageValue = nullptr;
6616
6617 // The first argument is the "from" image. It is a fill image.
6618 if (!args->current() || !parseFillImage(args, fromImageValue))
6619 return false;
6620 args->next();
6621
6622 if (!consumeComma(args))
6623 return false;
6624
6625 // The second argument is the "to" image. It is a fill image.
6626 if (!args->current() || !parseFillImage(args, toImageValue))
6627 return false;
6628 args->next();
6629
6630 if (!consumeComma(args))
6631 return false;
6632
6633 // The third argument is the crossfade value. It is a percentage or a fracti onal number.
6634 RefPtrWillBeRawPtr<CSSPrimitiveValue> percentage = nullptr;
6635 CSSParserValue* value = args->current();
6636 if (!value)
6637 return false;
6638
6639 if (value->unit() == CSSPrimitiveValue::UnitType::Percentage)
6640 percentage = cssValuePool().createValue(clampTo<double>(value->fValue / 100, 0, 1), CSSPrimitiveValue::UnitType::Number);
6641 else if (value->unit() == CSSPrimitiveValue::UnitType::Number)
6642 percentage = cssValuePool().createValue(clampTo<double>(value->fValue, 0 , 1), CSSPrimitiveValue::UnitType::Number);
6643 else
6644 return false;
6645
6646 RefPtrWillBeRawPtr<CSSCrossfadeValue> result = CSSCrossfadeValue::create(fro mImageValue, toImageValue);
6647 result->setPercentage(percentage);
6648
6649 crossfade = result;
6650
6651 return true;
6652 }
6653
6654 bool CSSPropertyParser::parseCanvas(CSSParserValueList* valueList, RefPtrWillBeR awPtr<CSSValue>& canvas)
6655 {
6656 // Walk the arguments.
6657 CSSParserValueList* args = valueList->current()->function->args.get();
6658 if (!args || args->size() != 1)
6659 return false;
6660
6661 // The first argument is the canvas name. It is an identifier.
6662 CSSParserValue* value = args->current();
6663 if (!value || value->m_unit != CSSParserValue::Identifier)
6664 return false;
6665
6666 canvas = CSSCanvasValue::create(value->string);
6667 return true;
6668 }
6669
6670 PassRefPtrWillBeRawPtr<CSSValue> CSSPropertyParser::parseImageSet(CSSParserValue List* valueList)
6671 {
6672 CSSParserValue* function = valueList->current();
6673
6674 if (function->m_unit != CSSParserValue::Function)
6675 return nullptr;
6676
6677 CSSParserValueList* functionArgs = valueList->current()->function->args.get( );
6678 if (!functionArgs || !functionArgs->size() || !functionArgs->current())
6679 return nullptr;
6680
6681 RefPtrWillBeRawPtr<CSSImageSetValue> imageSet = CSSImageSetValue::create();
6682
6683 while (functionArgs->current()) {
6684 CSSParserValue* arg = functionArgs->current();
6685 if (arg->unit() != CSSPrimitiveValue::UnitType::URI)
6686 return nullptr;
6687
6688 RefPtrWillBeRawPtr<CSSValue> image = createCSSImageValueWithReferrer(arg ->string, completeURL(arg->string));
6689 imageSet->append(image);
6690
6691 arg = functionArgs->next();
6692 if (!arg)
6693 return nullptr;
6694
6695 if (arg->m_unit != CSSParserValue::DimensionList)
6696 return nullptr;
6697 ASSERT(arg->valueList->valueAt(0)->unit() == CSSPrimitiveValue::UnitType ::Number);
6698 ASSERT(arg->valueList->valueAt(1)->m_unit == CSSParserValue::Identifier) ;
6699 if (String(arg->valueList->valueAt(1)->string) != "x")
6700 return nullptr;
6701 double imageScaleFactor = arg->valueList->valueAt(0)->fValue;
6702 if (imageScaleFactor <= 0)
6703 return nullptr;
6704 imageSet->append(cssValuePool().createValue(imageScaleFactor, CSSPrimiti veValue::UnitType::Number));
6705 functionArgs->next();
6706
6707 // If there are no more arguments, we're done.
6708 if (!functionArgs->current())
6709 break;
6710
6711 // If there are more arguments, they should be after a comma.
6712 if (!consumeComma(functionArgs))
6713 return nullptr;
6714 }
6715
6716 return imageSet.release();
6717 }
6718
6719 PassRefPtrWillBeRawPtr<CSSValue> CSSPropertyParser::parseWillChange()
6720 {
6721 RefPtrWillBeRawPtr<CSSValueList> values = CSSValueList::createCommaSeparated ();
6722 if (m_valueList->current()->id == CSSValueAuto) {
6723 // FIXME: This will be read back as an empty string instead of auto
6724 return values.release();
6725 }
6726
6727 // Every comma-separated list of identifiers is a valid will-change value,
6728 // unless the list includes an explicitly disallowed identifier.
6729 while (true) {
6730 CSSParserValue* currentValue = m_valueList->current();
6731 if (!currentValue || currentValue->m_unit != CSSParserValue::Identifier)
6732 return nullptr;
6733
6734 CSSPropertyID unresolvedProperty = unresolvedCSSPropertyID(currentValue- >string);
6735 if (unresolvedProperty) {
6736 ASSERT(CSSPropertyMetadata::isEnabledProperty(unresolvedProperty));
6737 // Now "all" is used by both CSSValue and CSSPropertyValue.
6738 // Need to return nullptr when currentValue is CSSPropertyAll.
6739 if (unresolvedProperty == CSSPropertyWillChange || unresolvedPropert y == CSSPropertyAll)
6740 return nullptr;
6741 values->append(cssValuePool().createIdentifierValue(unresolvedProper ty));
6742 } else {
6743 switch (currentValue->id) {
6744 case CSSValueNone:
6745 case CSSValueAll:
6746 case CSSValueAuto:
6747 case CSSValueDefault:
6748 case CSSValueInitial:
6749 case CSSValueInherit:
6750 return nullptr;
6751 case CSSValueContents:
6752 case CSSValueScrollPosition:
6753 values->append(cssValuePool().createIdentifierValue(currentValue ->id));
6754 break;
6755 default:
6756 break;
6757 }
6758 }
6759
6760 if (!m_valueList->next())
6761 break;
6762 if (!consumeComma(m_valueList))
6763 return nullptr;
6764 }
6765
6766 return values.release();
6767 }
6768
6769 PassRefPtrWillBeRawPtr<CSSFunctionValue> CSSPropertyParser::parseBuiltinFilterAr guments(CSSParserValueList* args, CSSValueID filterType)
6770 {
6771 RefPtrWillBeRawPtr<CSSFunctionValue> filterValue = CSSFunctionValue::create( filterType);
6772 ASSERT(args);
6773
6774 switch (filterType) {
6775 case CSSValueGrayscale:
6776 case CSSValueSepia:
6777 case CSSValueSaturate:
6778 case CSSValueInvert:
6779 case CSSValueOpacity:
6780 case CSSValueContrast: {
6781 // One optional argument, 0-1 or 0%-100%, if missing use 100%.
6782 if (args->size()) {
6783 CSSParserValue* value = args->current();
6784 // FIXME (crbug.com/397061): Support calc expressions like calc(10% + 0.5)
6785 if (value->unit() != CSSPrimitiveValue::UnitType::Percentage && !val idUnit(value, FNumber | FNonNeg))
6786 return nullptr;
6787
6788 double amount = value->fValue;
6789 if (amount < 0)
6790 return nullptr;
6791
6792 // Saturate and Contrast allow values over 100%.
6793 if (filterType != CSSValueSaturate
6794 && filterType != CSSValueContrast) {
6795 double maxAllowed = value->unit() == CSSPrimitiveValue::UnitType ::Percentage ? 100.0 : 1.0;
6796 if (amount > maxAllowed)
6797 return nullptr;
6798 }
6799
6800 filterValue->append(cssValuePool().createValue(amount, value->unit() ));
6801 }
6802 break;
6803 }
6804 case CSSValueBrightness: {
6805 // One optional argument, if missing use 100%.
6806 if (args->size()) {
6807 CSSParserValue* value = args->current();
6808 // FIXME (crbug.com/397061): Support calc expressions like calc(10% + 0.5)
6809 if (value->unit() != CSSPrimitiveValue::UnitType::Percentage && !val idUnit(value, FNumber))
6810 return nullptr;
6811
6812 filterValue->append(cssValuePool().createValue(value->fValue, value- >unit()));
6813 }
6814 break;
6815 }
6816 case CSSValueHueRotate: {
6817 // hue-rotate() takes one optional angle.
6818 if (args->size()) {
6819 CSSParserValue* argument = args->current();
6820 if (!validUnit(argument, FAngle, HTMLStandardMode))
6821 return nullptr;
6822
6823 filterValue->append(createPrimitiveNumericValue(argument));
6824 }
6825 break;
6826 }
6827 case CSSValueBlur: {
6828 // Blur takes a single length. Zero parameters are allowed.
6829 if (args->size()) {
6830 CSSParserValue* argument = args->current();
6831 if (!validUnit(argument, FLength | FNonNeg, HTMLStandardMode))
6832 return nullptr;
6833
6834 filterValue->append(createPrimitiveNumericValue(argument));
6835 }
6836 break;
6837 }
6838 case CSSValueDropShadow: {
6839 // drop-shadow() takes a single shadow.
6840 RefPtrWillBeRawPtr<CSSShadowValue> shadowValue = parseSingleShadow(args, false, true);
6841 if (!shadowValue)
6842 return nullptr;
6843 filterValue->append(shadowValue.release());
6844 break;
6845 }
6846 default:
6847 return nullptr;
6848 }
6849 return filterValue.release();
6850 }
6851
6852 PassRefPtrWillBeRawPtr<CSSValueList> CSSPropertyParser::parseFilter()
6853 {
6854 if (!m_valueList)
6855 return nullptr;
6856
6857 // The filter is a list of functional primitives that specify individual ope rations.
6858 RefPtrWillBeRawPtr<CSSValueList> list = CSSValueList::createSpaceSeparated() ;
6859 for (CSSParserValue* value = m_valueList->current(); value; value = m_valueL ist->next()) {
6860 if (value->unit() != CSSPrimitiveValue::UnitType::URI && (value->m_unit != CSSParserValue::Function || !value->function))
6861 return nullptr;
6862
6863 // See if the specified primitive is one we understand.
6864 if (value->unit() == CSSPrimitiveValue::UnitType::URI) {
6865 RefPtrWillBeRawPtr<CSSFunctionValue> referenceFilterValue = CSSFunct ionValue::create(CSSValueUrl);
6866 referenceFilterValue->append(CSSSVGDocumentValue::create(value->stri ng));
6867 list->append(referenceFilterValue.release());
6868 } else {
6869 CSSValueID filterType = value->function->id;
6870 unsigned maximumArgumentCount = filterType == CSSValueDropShadow ? 4 : 1;
6871
6872 CSSParserValueList* args = value->function->args.get();
6873 if (!args || args->size() > maximumArgumentCount)
6874 return nullptr;
6875
6876 RefPtrWillBeRawPtr<CSSFunctionValue> filterValue = parseBuiltinFilte rArguments(args, filterType);
6877 if (!filterValue)
6878 return nullptr;
6879
6880 list->append(filterValue);
6881 }
6882 }
6883
6884 return list.release();
6885 }
6886
6887 PassRefPtrWillBeRawPtr<CSSValueList> CSSPropertyParser::parseTransformOrigin()
6888 {
6889 CSSParserValue* value = m_valueList->current();
6890 CSSValueID id = value->id;
6891 RefPtrWillBeRawPtr<CSSValue> xValue = nullptr;
6892 RefPtrWillBeRawPtr<CSSValue> yValue = nullptr;
6893 RefPtrWillBeRawPtr<CSSValue> zValue = nullptr;
6894 if (id == CSSValueLeft || id == CSSValueRight) {
6895 xValue = cssValuePool().createIdentifierValue(id);
6896 } else if (id == CSSValueTop || id == CSSValueBottom) {
6897 yValue = cssValuePool().createIdentifierValue(id);
6898 } else if (id == CSSValueCenter) {
6899 // Unresolved as to whether this is X or Y.
6900 } else if (validUnit(value, FPercent | FLength)) {
6901 xValue = createPrimitiveNumericValue(value);
6902 } else {
6903 return nullptr;
6904 }
6905
6906 value = m_valueList->next();
6907 if (value) {
6908 id = value->id;
6909 if (!xValue && (id == CSSValueLeft || id == CSSValueRight)) {
6910 xValue = cssValuePool().createIdentifierValue(id);
6911 } else if (!yValue && (id == CSSValueTop || id == CSSValueBottom)) {
6912 yValue = cssValuePool().createIdentifierValue(id);
6913 } else if (id == CSSValueCenter) {
6914 // Resolved below.
6915 } else if (!yValue && validUnit(value, FPercent | FLength)) {
6916 yValue = createPrimitiveNumericValue(value);
6917 } else {
6918 return nullptr;
6919 }
6920
6921 // If X or Y have not been resolved, they must be center.
6922 if (!xValue)
6923 xValue = cssValuePool().createIdentifierValue(CSSValueCenter);
6924 if (!yValue)
6925 yValue = cssValuePool().createIdentifierValue(CSSValueCenter);
6926
6927 value = m_valueList->next();
6928 if (value) {
6929 if (!validUnit(value, FLength))
6930 return nullptr;
6931 zValue = createPrimitiveNumericValue(value);
6932
6933 value = m_valueList->next();
6934 if (value)
6935 return nullptr;
6936 }
6937 } else if (!xValue) {
6938 if (yValue) {
6939 xValue = cssValuePool().createValue(50, CSSPrimitiveValue::UnitType: :Percentage);
6940 } else {
6941 xValue = cssValuePool().createIdentifierValue(CSSValueCenter);
6942 }
6943 }
6944
6945 RefPtrWillBeRawPtr<CSSValueList> list = CSSValueList::createSpaceSeparated() ;
6946 list->append(xValue.release());
6947 if (yValue)
6948 list->append(yValue.release());
6949 if (zValue)
6950 list->append(zValue.release());
6951 return list.release();
6952 }
6953
6954 PassRefPtrWillBeRawPtr<CSSValue> CSSPropertyParser::parseTouchAction()
6955 {
6956 CSSParserValue* value = m_valueList->current();
6957 RefPtrWillBeRawPtr<CSSValueList> list = CSSValueList::createSpaceSeparated() ;
6958 if (m_valueList->size() == 1 && value && (value->id == CSSValueAuto || value ->id == CSSValueNone || value->id == CSSValueManipulation)) {
6959 list->append(cssValuePool().createIdentifierValue(value->id));
6960 m_valueList->next();
6961 return list.release();
6962 }
6963
6964 bool xSet = false;
6965 bool ySet = false;
6966 while (value) {
6967 switch (value->id) {
6968 case CSSValuePanX:
6969 case CSSValuePanRight:
6970 case CSSValuePanLeft: {
6971 if (xSet)
6972 return nullptr;
6973 xSet = true;
6974 if (value->id != CSSValuePanX && !RuntimeEnabledFeatures::cssTouchAc tionPanDirectionsEnabled())
6975 return nullptr;
6976
6977 RefPtrWillBeRawPtr<CSSValue> panValue = cssValuePool().createIdentif ierValue(value->id);
6978 list->append(panValue.release());
6979 break;
6980 }
6981 case CSSValuePanY:
6982 case CSSValuePanDown:
6983 case CSSValuePanUp: {
6984 if (ySet)
6985 return nullptr;
6986 ySet = true;
6987 if (value->id != CSSValuePanY && !RuntimeEnabledFeatures::cssTouchAc tionPanDirectionsEnabled())
6988 return nullptr;
6989 RefPtrWillBeRawPtr<CSSValue> panValue = cssValuePool().createIdentif ierValue(value->id);
6990 list->append(panValue.release());
6991 break;
6992 }
6993 default:
6994 return nullptr;
6995 }
6996 value = m_valueList->next();
6997 }
6998
6999 if (list->length())
7000 return list.release();
7001
7002 return nullptr;
7003 }
7004
7005 PassRefPtrWillBeRawPtr<CSSValue> CSSPropertyParser::parseTextDecoration()
7006 {
7007 CSSParserValue* value = m_valueList->current();
7008 if (value && value->id == CSSValueNone) {
7009 m_valueList->next();
7010 return cssValuePool().createIdentifierValue(CSSValueNone);
7011 }
7012
7013 RefPtrWillBeRawPtr<CSSValueList> list = CSSValueList::createSpaceSeparated() ;
7014 bool isValid = true;
7015 while (isValid && value) {
7016 switch (value->id) {
7017 case CSSValueUnderline:
7018 case CSSValueOverline:
7019 case CSSValueLineThrough:
7020 case CSSValueBlink:
7021 // TODO(timloh): This will incorrectly accept "blink blink"
7022 list->append(cssValuePool().createIdentifierValue(value->id));
7023 break;
7024 default:
7025 isValid = false;
7026 break;
7027 }
7028 if (isValid)
7029 value = m_valueList->next();
7030 }
7031
7032 // Values are either valid or in shorthand scope.
7033 if (list->length())
7034 return list.release();
7035 return nullptr;
7036 }
7037
7038 PassRefPtrWillBeRawPtr<CSSValue> CSSPropertyParser::parseTextEmphasisStyle()
7039 {
7040 RefPtrWillBeRawPtr<CSSPrimitiveValue> fill = nullptr;
7041 RefPtrWillBeRawPtr<CSSPrimitiveValue> shape = nullptr;
7042
7043 for (CSSParserValue* value = m_valueList->current(); value; value = m_valueL ist->next()) {
7044 if (value->unit() == CSSPrimitiveValue::UnitType::String) {
7045 if (fill || shape)
7046 return nullptr;
7047 m_valueList->next();
7048 return createPrimitiveStringValue(value);
7049 }
7050
7051 if (value->id == CSSValueNone) {
7052 if (fill || shape)
7053 return nullptr;
7054 m_valueList->next();
7055 return cssValuePool().createIdentifierValue(CSSValueNone);
7056 }
7057
7058 if (value->id == CSSValueOpen || value->id == CSSValueFilled) {
7059 if (fill)
7060 return nullptr;
7061 fill = cssValuePool().createIdentifierValue(value->id);
7062 } else if (value->id == CSSValueDot || value->id == CSSValueCircle || va lue->id == CSSValueDoubleCircle || value->id == CSSValueTriangle || value->id == CSSValueSesame) {
7063 if (shape)
7064 return nullptr;
7065 shape = cssValuePool().createIdentifierValue(value->id);
7066 } else {
7067 break;
7068 }
7069 }
7070
7071 if (fill && shape) {
7072 RefPtrWillBeRawPtr<CSSValueList> parsedValues = CSSValueList::createSpac eSeparated();
7073 parsedValues->append(fill.release());
7074 parsedValues->append(shape.release());
7075 return parsedValues.release();
7076 }
7077 if (fill)
7078 return fill.release();
7079 if (shape)
7080 return shape.release();
7081
7082 return nullptr;
7083 }
7084
7085 PassRefPtrWillBeRawPtr<CSSValue> CSSPropertyParser::parseTextIndent()
7086 {
7087 RefPtrWillBeRawPtr<CSSValueList> list = CSSValueList::createSpaceSeparated() ;
7088
7089 bool hasLengthOrPercentage = false;
7090 bool hasEachLine = false;
7091 bool hasHanging = false;
7092
7093 for (CSSParserValue* value = m_valueList->current(); value; value = m_valueL ist->next()) {
7094 // <length> | <percentage> | inherit when RuntimeEnabledFeatures::css3Te xtEnabled() returns false
7095 if (!hasLengthOrPercentage && validUnit(value, FLength | FPercent | FUni tlessQuirk)) {
7096 list->append(createPrimitiveNumericValue(value));
7097 hasLengthOrPercentage = true;
7098 continue;
7099 }
7100
7101 // [ <length> | <percentage> ] && hanging? && each-line? | inherit
7102 // when RuntimeEnabledFeatures::css3TextEnabled() returns true
7103 if (RuntimeEnabledFeatures::css3TextEnabled()) {
7104 if (!hasEachLine && value->id == CSSValueEachLine) {
7105 list->append(cssValuePool().createIdentifierValue(CSSValueEachLi ne));
7106 hasEachLine = true;
7107 continue;
7108 }
7109 if (!hasHanging && value->id == CSSValueHanging) {
7110 list->append(cssValuePool().createIdentifierValue(CSSValueHangin g));
7111 hasHanging = true;
7112 continue;
7113 }
7114 }
7115 return nullptr;
7116 }
7117
7118 if (!hasLengthOrPercentage)
7119 return nullptr;
7120
7121 return list.release();
7122 }
7123
7124 bool CSSPropertyParser::parseFontFeatureTag(CSSValueList* settings)
7125 {
7126 // Feature tag name consists of 4-letter characters.
7127 static const unsigned tagNameLength = 4;
7128
7129 CSSParserValue* value = m_valueList->current();
7130 // Feature tag name comes first
7131 if (value->unit() != CSSPrimitiveValue::UnitType::String)
7132 return false;
7133 if (value->string.length() != tagNameLength)
7134 return false;
7135 for (unsigned i = 0; i < tagNameLength; ++i) {
7136 // Limits the range of characters to 0x20-0x7E, following the tag name r ules defiend in the OpenType specification.
7137 UChar character = value->string[i];
7138 if (character < 0x20 || character > 0x7E)
7139 return false;
7140 }
7141
7142 AtomicString tag = value->string;
7143 int tagValue = 1;
7144 // Feature tag values could follow: <integer> | on | off
7145 value = m_valueList->next();
7146 if (value) {
7147 if (value->unit() == CSSPrimitiveValue::UnitType::Number && value->isInt && value->fValue >= 0) {
7148 tagValue = clampTo<int>(value->fValue);
7149 if (tagValue < 0)
7150 return false;
7151 m_valueList->next();
7152 } else if (value->id == CSSValueOn || value->id == CSSValueOff) {
7153 tagValue = value->id == CSSValueOn;
7154 m_valueList->next();
7155 }
7156 }
7157 settings->append(CSSFontFeatureValue::create(tag, tagValue));
7158 return true;
7159 }
7160
7161 PassRefPtrWillBeRawPtr<CSSValue> CSSPropertyParser::parseFontFeatureSettings()
7162 {
7163 RefPtrWillBeRawPtr<CSSValueList> settings = CSSValueList::createCommaSeparat ed();
7164 while (true) {
7165 if (!m_valueList->current() || !parseFontFeatureTag(settings.get()))
7166 return nullptr;
7167 if (!m_valueList->current())
7168 break;
7169 if (!consumeComma(m_valueList))
7170 return nullptr;
7171 }
7172 return settings.release();
7173 }
7174
7175 bool CSSPropertyParser::parseFontVariantLigatures(bool important)
7176 {
7177 RefPtrWillBeRawPtr<CSSValueList> ligatureValues = CSSValueList::createSpaceS eparated();
7178 bool sawCommonLigaturesValue = false;
7179 bool sawDiscretionaryLigaturesValue = false;
7180 bool sawHistoricalLigaturesValue = false;
7181 bool sawContextualLigaturesValue = false;
7182
7183 for (CSSParserValue* value = m_valueList->current(); value; value = m_valueL ist->next()) {
7184 if (value->m_unit != CSSParserValue::Identifier)
7185 return false;
7186
7187 switch (value->id) {
7188 case CSSValueNoCommonLigatures:
7189 case CSSValueCommonLigatures:
7190 if (sawCommonLigaturesValue)
7191 return false;
7192 sawCommonLigaturesValue = true;
7193 ligatureValues->append(cssValuePool().createIdentifierValue(value->i d));
7194 break;
7195 case CSSValueNoDiscretionaryLigatures:
7196 case CSSValueDiscretionaryLigatures:
7197 if (sawDiscretionaryLigaturesValue)
7198 return false;
7199 sawDiscretionaryLigaturesValue = true;
7200 ligatureValues->append(cssValuePool().createIdentifierValue(value->i d));
7201 break;
7202 case CSSValueNoHistoricalLigatures:
7203 case CSSValueHistoricalLigatures:
7204 if (sawHistoricalLigaturesValue)
7205 return false;
7206 sawHistoricalLigaturesValue = true;
7207 ligatureValues->append(cssValuePool().createIdentifierValue(value->i d));
7208 break;
7209 case CSSValueNoContextual:
7210 case CSSValueContextual:
7211 if (sawContextualLigaturesValue)
7212 return false;
7213 sawContextualLigaturesValue = true;
7214 ligatureValues->append(cssValuePool().createIdentifierValue(value->i d));
7215 break;
7216 default:
7217 return false;
7218 }
7219 }
7220
7221 if (!ligatureValues->length())
7222 return false;
7223
7224 addProperty(CSSPropertyFontVariantLigatures, ligatureValues.release(), impor tant);
7225 return true;
7226 }
7227
7228 bool CSSPropertyParser::parseCalculation(CSSParserValue* value, ValueRange range )
7229 {
7230 ASSERT(isCalculation(value));
7231
7232 CSSParserTokenRange args = value->calcFunction->args;
7233
7234 ASSERT(!m_parsedCalculation);
7235 m_parsedCalculation = CSSCalcValue::create(args, range);
7236
7237 if (!m_parsedCalculation)
7238 return false;
7239
7240 return true;
7241 }
7242
7243 bool CSSPropertyParser::parseFontFaceDescriptor(CSSPropertyID propId)
7244 {
7245 CSSParserValue* value = m_valueList->current();
7246 ASSERT(value);
7247 CSSValueID id = value->id;
7248 RefPtrWillBeRawPtr<CSSValue> parsedValue = nullptr;
7249
7250 switch (propId) {
7251 case CSSPropertyFontFamily:
7252 // <family-name>
7253 // TODO(rwlbuis): check there is only one family-name
7254 parsedValue = parseFontFamily();
7255 break;
7256 case CSSPropertySrc: // This is a list of urls or local references.
7257 parsedValue = parseFontFaceSrc();
7258 break;
7259 case CSSPropertyUnicodeRange:
7260 parsedValue = parseFontFaceUnicodeRange();
7261 break;
7262 case CSSPropertyFontWeight: // normal | bold | 100 | 200 | 300 | 400 | 500 | 600 | 700 | 800 | 900
7263 return parseFontWeight(false) && !m_valueList->next();
7264 case CSSPropertyFontStretch:
7265 case CSSPropertyFontStyle:
7266 if (!CSSParserFastPaths::isValidKeywordPropertyAndValue(propId, id))
7267 return false;
7268 addProperty(propId, cssValuePool().createIdentifierValue(id), false);
7269 return true;
7270 case CSSPropertyFontVariant: // normal | small-caps | inherit
7271 return parseFontVariant(false);
7272 case CSSPropertyWebkitFontFeatureSettings:
7273 if (id == CSSValueNormal) {
7274 parsedValue = cssValuePool().createIdentifierValue(CSSValueNormal);
7275 m_valueList->next();
7276 } else {
7277 parsedValue = parseFontFeatureSettings();
7278 }
7279 break;
7280 default:
7281 break;
7282 }
7283
7284 if (!parsedValue || m_valueList->current())
7285 return false;
7286
7287 addProperty(propId, parsedValue.release(), false);
7288 return true;
7289 }
7290
7291 bool CSSPropertyParser::parseViewportProperty(CSSPropertyID propId, bool importa nt)
7292 {
7293 ASSERT(RuntimeEnabledFeatures::cssViewportEnabled() || isUASheetBehavior(m_c ontext.mode()));
7294
7295 CSSParserValue* value = m_valueList->current();
7296 if (!value)
7297 return false;
7298
7299 CSSValueID id = value->id;
7300 bool validPrimitive = false;
7301
7302 switch (propId) {
7303 case CSSPropertyMinWidth: // auto | extend-to-zoom | <length> | <percentage>
7304 case CSSPropertyMaxWidth:
7305 case CSSPropertyMinHeight:
7306 case CSSPropertyMaxHeight:
7307 if (id == CSSValueAuto || id == CSSValueInternalExtendToZoom)
7308 validPrimitive = true;
7309 else
7310 validPrimitive = validUnit(value, FLength | FPercent | FNonNeg);
7311 break;
7312 case CSSPropertyWidth: // shorthand
7313 return parseViewportShorthand(propId, CSSPropertyMinWidth, CSSPropertyMa xWidth, important);
7314 case CSSPropertyHeight:
7315 return parseViewportShorthand(propId, CSSPropertyMinHeight, CSSPropertyM axHeight, important);
7316 case CSSPropertyMinZoom: // auto | <number> | <percentage>
7317 case CSSPropertyMaxZoom:
7318 case CSSPropertyZoom:
7319 if (id == CSSValueAuto)
7320 validPrimitive = true;
7321 else
7322 validPrimitive = validUnit(value, FNumber | FPercent | FNonNeg);
7323 break;
7324 case CSSPropertyUserZoom: // zoom | fixed
7325 if (id == CSSValueZoom || id == CSSValueFixed)
7326 validPrimitive = true;
7327 break;
7328 case CSSPropertyOrientation: // auto | portrait | landscape
7329 if (id == CSSValueAuto || id == CSSValuePortrait || id == CSSValueLandsc ape)
7330 validPrimitive = true;
7331 default:
7332 break;
7333 }
7334
7335 RefPtrWillBeRawPtr<CSSValue> parsedValue = nullptr;
7336 if (validPrimitive) {
7337 parsedValue = parseValidPrimitive(id, value);
7338 m_valueList->next();
7339 }
7340
7341 if (parsedValue) {
7342 if (!m_valueList->current() || inShorthand()) {
7343 addProperty(propId, parsedValue.release(), important);
7344 return true;
7345 }
7346 }
7347
7348 return false;
7349 }
7350
7351 bool CSSPropertyParser::parseViewportShorthand(CSSPropertyID propId, CSSProperty ID first, CSSPropertyID second, bool important)
7352 {
7353 ASSERT(RuntimeEnabledFeatures::cssViewportEnabled() || isUASheetBehavior(m_c ontext.mode()));
7354 unsigned numValues = m_valueList->size();
7355
7356 if (numValues > 2)
7357 return false;
7358
7359 ShorthandScope scope(this, propId);
7360
7361 if (!parseViewportProperty(first, important))
7362 return false;
7363
7364 // If just one value is supplied, the second value
7365 // is implicitly initialized with the first value.
7366 if (numValues == 1)
7367 m_valueList->previous();
7368
7369 return parseViewportProperty(second, important);
7370 }
7371
7372 template <typename CharacterType>
7373 static CSSPropertyID unresolvedCSSPropertyID(const CharacterType* propertyName, unsigned length)
7374 {
7375 char buffer[maxCSSPropertyNameLength + 1]; // 1 for null character
7376
7377 for (unsigned i = 0; i != length; ++i) {
7378 CharacterType c = propertyName[i];
7379 if (c == 0 || c >= 0x7F)
7380 return CSSPropertyInvalid; // illegal character
7381 buffer[i] = toASCIILower(c);
7382 }
7383 buffer[length] = '\0';
7384
7385 const char* name = buffer;
7386 const Property* hashTableEntry = findProperty(name, length);
7387 if (!hashTableEntry)
7388 return CSSPropertyInvalid;
7389 CSSPropertyID property = static_cast<CSSPropertyID>(hashTableEntry->id);
7390 if (!CSSPropertyMetadata::isEnabledProperty(property))
7391 return CSSPropertyInvalid;
7392 return property;
7393 }
7394
7395 CSSPropertyID unresolvedCSSPropertyID(const String& string)
7396 {
7397 unsigned length = string.length();
7398
7399 if (!length)
7400 return CSSPropertyInvalid;
7401 if (length > maxCSSPropertyNameLength)
7402 return CSSPropertyInvalid;
7403
7404 return string.is8Bit() ? unresolvedCSSPropertyID(string.characters8(), lengt h) : unresolvedCSSPropertyID(string.characters16(), length);
7405 }
7406
7407 CSSPropertyID unresolvedCSSPropertyID(const CSSParserString& string)
7408 {
7409 unsigned length = string.length();
7410
7411 if (!length)
7412 return CSSPropertyInvalid;
7413 if (length > maxCSSPropertyNameLength)
7414 return CSSPropertyInvalid;
7415
7416 return string.is8Bit() ? unresolvedCSSPropertyID(string.characters8(), lengt h) : unresolvedCSSPropertyID(string.characters16(), length);
7417 }
7418
7419 template <typename CharacterType>
7420 static CSSValueID cssValueKeywordID(const CharacterType* valueKeyword, unsigned length)
7421 {
7422 char buffer[maxCSSValueKeywordLength + 1]; // 1 for null character
7423
7424 for (unsigned i = 0; i != length; ++i) {
7425 CharacterType c = valueKeyword[i];
7426 if (c == 0 || c >= 0x7F)
7427 return CSSValueInvalid; // illegal character
7428 buffer[i] = WTF::toASCIILower(c);
7429 }
7430 buffer[length] = '\0';
7431
7432 const Value* hashTableEntry = findValue(buffer, length);
7433 return hashTableEntry ? static_cast<CSSValueID>(hashTableEntry->id) : CSSVal ueInvalid;
7434 }
7435
7436 CSSValueID cssValueKeywordID(const CSSParserString& string)
7437 {
7438 unsigned length = string.length();
7439 if (!length)
7440 return CSSValueInvalid;
7441 if (length > maxCSSValueKeywordLength)
7442 return CSSValueInvalid;
7443
7444 return string.is8Bit() ? cssValueKeywordID(string.characters8(), length) : c ssValueKeywordID(string.characters16(), length);
7445 }
7446
7447 bool CSSPropertyParser::isSystemColor(CSSValueID id)
7448 {
7449 return (id >= CSSValueActiveborder && id <= CSSValueWindowtext) || id == CSS ValueMenu;
7450 }
7451
7452 bool CSSPropertyParser::parseSVGValue(CSSPropertyID propId, bool important)
7453 {
7454 CSSParserValue* value = m_valueList->current();
7455 ASSERT(value);
7456
7457 CSSValueID id = value->id;
7458
7459 bool validPrimitive = false;
7460 RefPtrWillBeRawPtr<CSSValue> parsedValue = nullptr;
7461
7462 switch (propId) {
7463 /* The comment to the right defines all valid value of these
7464 * properties as defined in SVG 1.1, Appendix N. Property index */
7465 case CSSPropertyBaselineShift:
7466 // baseline | super | sub | <percentage> | <length> | inherit
7467 if (id == CSSValueBaseline || id == CSSValueSub || id == CSSValueSuper)
7468 validPrimitive = true;
7469 else
7470 validPrimitive = validUnit(value, FLength | FPercent, SVGAttributeMo de);
7471 break;
7472
7473 case CSSPropertyClipPath:
7474 case CSSPropertyFilter:
7475 case CSSPropertyMarkerStart:
7476 case CSSPropertyMarkerMid:
7477 case CSSPropertyMarkerEnd:
7478 case CSSPropertyMask:
7479 if (id == CSSValueNone) {
7480 validPrimitive = true;
7481 } else if (value->unit() == CSSPrimitiveValue::UnitType::URI) {
7482 parsedValue = CSSPrimitiveValue::create(value->string, CSSPrimitiveV alue::UnitType::URI);
7483 if (parsedValue)
7484 m_valueList->next();
7485 }
7486 break;
7487
7488 case CSSPropertyStrokeMiterlimit: // <miterlimit> | inherit
7489 validPrimitive = validUnit(value, FNumber | FNonNeg, SVGAttributeMode);
7490 break;
7491
7492 case CSSPropertyStrokeOpacity: // <opacity-value> | inherit
7493 case CSSPropertyFillOpacity:
7494 case CSSPropertyStopOpacity:
7495 case CSSPropertyFloodOpacity:
7496 validPrimitive = validUnit(value, FNumber | FPercent, SVGAttributeMode);
7497 break;
7498
7499 /* Start of supported CSS properties with validation. This is needed for par seShortHand to work
7500 * correctly and allows optimization in applyRule(..)
7501 */
7502
7503 case CSSPropertyGlyphOrientationVertical: // auto | <angle> | inherit
7504 if (id == CSSValueAuto) {
7505 validPrimitive = true;
7506 break;
7507 }
7508 /* fallthrough intentional */
7509 case CSSPropertyGlyphOrientationHorizontal: // <angle> (restricted to _deg_ per SVG 1.1 spec) | inherit
7510 if (value->unit() == CSSPrimitiveValue::UnitType::Degrees || value->unit () == CSSPrimitiveValue::UnitType::Number) {
7511 parsedValue = CSSPrimitiveValue::create(value->fValue, CSSPrimitiveV alue::UnitType::Degrees);
7512
7513 if (parsedValue)
7514 m_valueList->next();
7515 }
7516 break;
7517
7518 case CSSPropertyFill: // <paint> | inherit
7519 case CSSPropertyStroke: // <paint> | inherit
7520 {
7521 if (id == CSSValueNone) {
7522 parsedValue = cssValuePool().createIdentifierValue(id);
7523 } else if (value->unit() == CSSPrimitiveValue::UnitType::URI) {
7524 if (m_valueList->next()) {
7525 RefPtrWillBeRawPtr<CSSValueList> values = CSSValueList::crea teSpaceSeparated();
7526 values->append(CSSPrimitiveValue::create(value->string, CSSP rimitiveValue::UnitType::URI));
7527 if (m_valueList->current()->id == CSSValueNone)
7528 parsedValue = cssValuePool().createIdentifierValue(m_val ueList->current()->id);
7529 else
7530 parsedValue = parseColor(m_valueList->current());
7531 if (parsedValue) {
7532 values->append(parsedValue);
7533 parsedValue = values;
7534 }
7535 }
7536 if (!parsedValue)
7537 parsedValue = CSSPrimitiveValue::create(value->string, CSSPr imitiveValue::UnitType::URI);
7538 } else {
7539 parsedValue = parseColor(m_valueList->current());
7540 }
7541
7542 if (parsedValue)
7543 m_valueList->next();
7544 }
7545 break;
7546
7547 case CSSPropertyStopColor: // TODO : icccolor
7548 case CSSPropertyFloodColor:
7549 case CSSPropertyLightingColor:
7550 parsedValue = parseColor(m_valueList->current());
7551 if (parsedValue)
7552 m_valueList->next();
7553
7554 break;
7555
7556 case CSSPropertyPaintOrder:
7557 if (m_valueList->size() == 1 && id == CSSValueNormal)
7558 validPrimitive = true;
7559 else if ((parsedValue = parsePaintOrder()))
7560 m_valueList->next();
7561 break;
7562
7563 case CSSPropertyStrokeWidth: // <length> | inherit
7564 case CSSPropertyStrokeDashoffset:
7565 case CSSPropertyCx:
7566 case CSSPropertyCy:
7567 case CSSPropertyX:
7568 case CSSPropertyY:
7569 case CSSPropertyR:
7570 case CSSPropertyRx:
7571 case CSSPropertyRy:
7572 validPrimitive = validUnit(value, FLength | FPercent, SVGAttributeMode);
7573 break;
7574 case CSSPropertyStrokeDasharray: // none | <dasharray> | inherit
7575 if (id == CSSValueNone)
7576 validPrimitive = true;
7577 else
7578 parsedValue = parseSVGStrokeDasharray();
7579 break;
7580
7581 /* shorthand properties */
7582 case CSSPropertyMarker: {
7583 ShorthandScope scope(this, propId);
7584 CSSPropertyParser::ImplicitScope implicitScope(this);
7585 if (!parseValue(CSSPropertyMarkerStart, important))
7586 return false;
7587 if (m_valueList->current()) {
7588 rollbackLastProperties(1);
7589 return false;
7590 }
7591 CSSValue* value = m_parsedProperties.last().value();
7592 addProperty(CSSPropertyMarkerMid, value, important);
7593 addProperty(CSSPropertyMarkerEnd, value, important);
7594 return true;
7595 }
7596 default:
7597 // If you crash here, it's because you added a css property and are not handling it
7598 // in either this switch statement or the one in CSSPropertyParser::pars eValue
7599 ASSERT_WITH_MESSAGE(0, "unimplemented propertyID: %d", propId);
7600 return false;
7601 }
7602
7603 if (validPrimitive) {
7604 if (id)
7605 parsedValue = CSSPrimitiveValue::createIdentifier(id);
7606 else if (value->unit() == CSSPrimitiveValue::UnitType::String)
7607 parsedValue = CSSPrimitiveValue::create(value->string, value->unit() );
7608 else if (value->unit() >= CSSPrimitiveValue::UnitType::Number && value-> unit() <= CSSPrimitiveValue::UnitType::Kilohertz)
7609 parsedValue = CSSPrimitiveValue::create(value->fValue, value->unit() );
7610 else if (value->unit() == CSSPrimitiveValue::UnitType::Rems || value->un it() == CSSPrimitiveValue::UnitType::Chs)
7611 parsedValue = CSSPrimitiveValue::create(value->fValue, value->unit() );
7612 else if (value->unit() == CSSPrimitiveValue::UnitType::QuirkyEms)
7613 parsedValue = CSSPrimitiveValue::create(value->fValue, CSSPrimitiveV alue::UnitType::QuirkyEms);
7614 if (isCalculation(value)) {
7615 // FIXME calc() http://webkit.org/b/16662 : actually create a CSSPri mitiveValue here, ie
7616 // parsedValue = CSSPrimitiveValue::create(m_parsedCalculation.relea se());
7617 m_parsedCalculation.release();
7618 parsedValue = nullptr;
7619 }
7620 m_valueList->next();
7621 }
7622 if (!parsedValue || (m_valueList->current() && !inShorthand()))
7623 return false;
7624
7625 addProperty(propId, parsedValue.release(), important);
7626 return true;
7627 }
7628
7629 PassRefPtrWillBeRawPtr<CSSValue> CSSPropertyParser::parseSVGStrokeDasharray()
7630 {
7631 RefPtrWillBeRawPtr<CSSValueList> ret = CSSValueList::createCommaSeparated();
7632 CSSParserValue* value = m_valueList->current();
7633 bool validPrimitive = true;
7634 while (value) {
7635 validPrimitive = validUnit(value, FLength | FPercent | FNonNeg, SVGAttri buteMode);
7636 if (!validPrimitive)
7637 break;
7638 if (value->id)
7639 ret->append(CSSPrimitiveValue::createIdentifier(value->id));
7640 else if (value->unit() >= CSSPrimitiveValue::UnitType::Number && value-> unit() <= CSSPrimitiveValue::UnitType::Kilohertz)
7641 ret->append(CSSPrimitiveValue::create(value->fValue, value->unit())) ;
7642 else if (value->unit() == CSSPrimitiveValue::UnitType::Rems || value->un it() == CSSPrimitiveValue::UnitType::Chs)
7643 ret->append(CSSPrimitiveValue::create(value->fValue, value->unit())) ;
7644 value = m_valueList->next();
7645 bool commaConsumed = consumeComma(m_valueList);
7646 value = m_valueList->current();
7647 if (commaConsumed && !value)
7648 return nullptr;
7649 }
7650 if (!validPrimitive)
7651 return nullptr;
7652 return ret.release();
7653 }
7654
7655 // normal | [ fill || stroke || markers ]
7656 PassRefPtrWillBeRawPtr<CSSValue> CSSPropertyParser::parsePaintOrder() const
7657 {
7658 if (m_valueList->size() > 3)
7659 return nullptr;
7660
7661 CSSParserValue* value = m_valueList->current();
7662 ASSERT(value);
7663
7664 Vector<CSSValueID, 3> paintTypeList;
7665 RefPtrWillBeRawPtr<CSSPrimitiveValue> fill = nullptr;
7666 RefPtrWillBeRawPtr<CSSPrimitiveValue> stroke = nullptr;
7667 RefPtrWillBeRawPtr<CSSPrimitiveValue> markers = nullptr;
7668 while (value) {
7669 if (value->id == CSSValueFill && !fill)
7670 fill = CSSPrimitiveValue::createIdentifier(value->id);
7671 else if (value->id == CSSValueStroke && !stroke)
7672 stroke = CSSPrimitiveValue::createIdentifier(value->id);
7673 else if (value->id == CSSValueMarkers && !markers)
7674 markers = CSSPrimitiveValue::createIdentifier(value->id);
7675 else
7676 return nullptr;
7677 paintTypeList.append(value->id);
7678 value = m_valueList->next();
7679 }
7680
7681 // After parsing we serialize the paint-order list. Since it is not possible to
7682 // pop a last list items from CSSValueList without bigger cost, we create th e
7683 // list after parsing.
7684 CSSValueID firstPaintOrderType = paintTypeList.at(0);
7685 RefPtrWillBeRawPtr<CSSValueList> paintOrderList = CSSValueList::createSpaceS eparated();
7686 switch (firstPaintOrderType) {
7687 case CSSValueFill:
7688 case CSSValueStroke:
7689 paintOrderList->append(firstPaintOrderType == CSSValueFill ? fill.releas e() : stroke.release());
7690 if (paintTypeList.size() > 1) {
7691 if (paintTypeList.at(1) == CSSValueMarkers)
7692 paintOrderList->append(markers.release());
7693 }
7694 break;
7695 case CSSValueMarkers:
7696 paintOrderList->append(markers.release());
7697 if (paintTypeList.size() > 1) {
7698 if (paintTypeList.at(1) == CSSValueStroke)
7699 paintOrderList->append(stroke.release());
7700 }
7701 break;
7702 default:
7703 ASSERT_NOT_REACHED();
7704 }
7705
7706 return paintOrderList.release();
7707 }
7708
7709 class TransformOperationInfo {
7710 public:
7711 TransformOperationInfo(CSSValueID id)
7712 : m_validID(true)
7713 , m_allowSingleArgument(false)
7714 , m_argCount(1)
7715 , m_unit(CSSPropertyParser::FUnknown)
7716 {
7717 switch (id) {
7718 case CSSValueSkew:
7719 m_unit = CSSPropertyParser::FAngle;
7720 m_allowSingleArgument = true;
7721 m_argCount = 3;
7722 break;
7723 case CSSValueScale:
7724 m_unit = CSSPropertyParser::FNumber;
7725 m_allowSingleArgument = true;
7726 m_argCount = 3;
7727 break;
7728 case CSSValueSkewX:
7729 m_unit = CSSPropertyParser::FAngle;
7730 break;
7731 case CSSValueSkewY:
7732 m_unit = CSSPropertyParser::FAngle;
7733 break;
7734 case CSSValueMatrix:
7735 m_unit = CSSPropertyParser::FNumber;
7736 m_argCount = 11;
7737 break;
7738 case CSSValueRotate:
7739 m_unit = CSSPropertyParser::FAngle;
7740 break;
7741 case CSSValueScaleX:
7742 m_unit = CSSPropertyParser::FNumber;
7743 break;
7744 case CSSValueScaleY:
7745 m_unit = CSSPropertyParser::FNumber;
7746 break;
7747 case CSSValueScaleZ:
7748 m_unit = CSSPropertyParser::FNumber;
7749 break;
7750 case CSSValueScale3d:
7751 m_unit = CSSPropertyParser::FNumber;
7752 m_argCount = 5;
7753 break;
7754 case CSSValueRotateX:
7755 m_unit = CSSPropertyParser::FAngle;
7756 break;
7757 case CSSValueRotateY:
7758 m_unit = CSSPropertyParser::FAngle;
7759 break;
7760 case CSSValueRotateZ:
7761 m_unit = CSSPropertyParser::FAngle;
7762 break;
7763 case CSSValueMatrix3d:
7764 m_unit = CSSPropertyParser::FNumber;
7765 m_argCount = 31;
7766 break;
7767 case CSSValueRotate3d:
7768 m_unit = CSSPropertyParser::FNumber;
7769 m_argCount = 7;
7770 break;
7771 case CSSValueTranslate:
7772 m_unit = CSSPropertyParser::FLength | CSSPropertyParser::FPercent;
7773 m_allowSingleArgument = true;
7774 m_argCount = 3;
7775 break;
7776 case CSSValueTranslateX:
7777 m_unit = CSSPropertyParser::FLength | CSSPropertyParser::FPercent;
7778 break;
7779 case CSSValueTranslateY:
7780 m_unit = CSSPropertyParser::FLength | CSSPropertyParser::FPercent;
7781 break;
7782 case CSSValueTranslateZ:
7783 m_unit = CSSPropertyParser::FLength | CSSPropertyParser::FPercent;
7784 break;
7785 case CSSValuePerspective:
7786 m_unit = CSSPropertyParser::FNumber;
7787 break;
7788 case CSSValueTranslate3d:
7789 m_unit = CSSPropertyParser::FLength | CSSPropertyParser::FPercent;
7790 m_argCount = 5;
7791 break;
7792 default:
7793 m_validID = false;
7794 break;
7795 }
7796 }
7797
7798 bool validID() const { return m_validID; }
7799 unsigned argCount() const { return m_argCount; }
7800 CSSPropertyParser::Units unit() const { return m_unit; }
7801
7802 bool hasCorrectArgCount(unsigned argCount) { return m_argCount == argCount | | (m_allowSingleArgument && argCount == 1); }
7803
7804 private:
7805 bool m_validID;
7806 bool m_allowSingleArgument;
7807 unsigned m_argCount;
7808 CSSPropertyParser::Units m_unit;
7809 };
7810
7811 PassRefPtrWillBeRawPtr<CSSValueList> CSSPropertyParser::parseTransform(bool useL egacyParsing)
7812 {
7813 if (!m_valueList)
7814 return nullptr;
7815
7816 RefPtrWillBeRawPtr<CSSValueList> list = CSSValueList::createSpaceSeparated() ;
7817 for (CSSParserValue* value = m_valueList->current(); value; value = m_valueL ist->next()) {
7818 RefPtrWillBeRawPtr<CSSValue> parsedTransformValue = parseTransformValue( useLegacyParsing, value);
7819 if (!parsedTransformValue)
7820 return nullptr;
7821
7822 list->append(parsedTransformValue.release());
7823 }
7824
7825 return list.release();
7826 }
7827
7828 PassRefPtrWillBeRawPtr<CSSValue> CSSPropertyParser::parseTransformValue(bool use LegacyParsing, CSSParserValue *value)
7829 {
7830 if (value->m_unit != CSSParserValue::Function || !value->function)
7831 return nullptr;
7832
7833 // Every primitive requires at least one argument.
7834 CSSParserValueList* args = value->function->args.get();
7835 if (!args)
7836 return nullptr;
7837
7838 // See if the specified primitive is one we understand.
7839 CSSValueID type = value->function->id;
7840 TransformOperationInfo info(type);
7841 if (!info.validID())
7842 return nullptr;
7843
7844 if (!info.hasCorrectArgCount(args->size()))
7845 return nullptr;
7846
7847 // The transform is a list of functional primitives that specify transform o perations.
7848 // We collect a list of CSSFunctionValues, where each value specifies a sing le operation.
7849
7850 // Create the new CSSFunctionValue for this operation and add it to our list .
7851 RefPtrWillBeRawPtr<CSSFunctionValue> transformValue = CSSFunctionValue::crea te(type);
7852
7853 // Snag our values.
7854 CSSParserValue* a = args->current();
7855 unsigned argNumber = 0;
7856 while (a) {
7857 CSSPropertyParser::Units unit = info.unit();
7858
7859 if (type == CSSValueRotate3d && argNumber == 3) {
7860 // 4th param of rotate3d() is an angle rather than a bare number, va lidate it as such
7861 if (!validUnit(a, FAngle, HTMLStandardMode))
7862 return nullptr;
7863 } else if (type == CSSValueTranslate3d && argNumber == 2) {
7864 // 3rd param of translate3d() cannot be a percentage
7865 if (!validUnit(a, FLength, HTMLStandardMode))
7866 return nullptr;
7867 } else if (type == CSSValueTranslateZ && !argNumber) {
7868 // 1st param of translateZ() cannot be a percentage
7869 if (!validUnit(a, FLength, HTMLStandardMode))
7870 return nullptr;
7871 } else if (type == CSSValuePerspective && !argNumber) {
7872 // 1st param of perspective() must be a non-negative number (depreca ted) or length.
7873 if (!validUnit(a, FLength | FNonNeg, HTMLStandardMode)) {
7874 if (useLegacyParsing && validUnit(a, FNumber | FNonNeg, HTMLStan dardMode)) {
7875 a->setUnit(CSSPrimitiveValue::UnitType::Pixels);
7876 } else {
7877 return nullptr;
7878 }
7879 }
7880 } else if (!validUnit(a, unit, HTMLStandardMode)) {
7881 return nullptr;
7882 }
7883
7884 // Add the value to the current transform operation.
7885 transformValue->append(createPrimitiveNumericValue(a));
7886
7887 a = args->next();
7888 if (!a)
7889 break;
7890 if (!isComma(a))
7891 return nullptr;
7892 a = args->next();
7893
7894 argNumber++;
7895 }
7896
7897 return transformValue.release();
7898 }
7899
7900 PassRefPtrWillBeRawPtr<CSSValue> CSSPropertyParser::parseMotionPath()
7901 {
7902 CSSParserValue* value = m_valueList->current();
7903
7904 // FIXME: Add support for <url>, <basic-shape>, <geometry-box>.
7905 if (value->m_unit != CSSParserValue::Function || value->function->id != CSSV aluePath)
7906 return nullptr;
7907
7908 // FIXME: Add support for <fill-rule>.
7909 CSSParserValueList* functionArgs = value->function->args.get();
7910 if (!functionArgs || functionArgs->size() != 1 || !functionArgs->current())
7911 return nullptr;
7912
7913 CSSParserValue* arg = functionArgs->current();
7914 if (arg->unit() != CSSPrimitiveValue::UnitType::String)
7915 return nullptr;
7916
7917 String pathString = arg->string;
7918 Path path;
7919 if (!buildPathFromString(pathString, path))
7920 return nullptr;
7921
7922 m_valueList->next();
7923 return CSSPathValue::create(pathString);
7924 }
7925
7926 PassRefPtrWillBeRawPtr<CSSValue> CSSPropertyParser::parseMotionRotation()
7927 {
7928 RefPtrWillBeRawPtr<CSSValueList> list = CSSValueList::createSpaceSeparated() ;
7929 bool hasAutoOrReverse = false;
7930 bool hasAngle = false;
7931
7932 for (CSSParserValue* value = m_valueList->current(); value; value = m_valueL ist->next()) {
7933 if ((value->id == CSSValueAuto || value->id == CSSValueReverse) && !hasA utoOrReverse) {
7934 list->append(cssValuePool().createIdentifierValue(value->id));
7935 hasAutoOrReverse = true;
7936 } else if (!hasAngle && validUnit(value, FAngle)) {
7937 list->append(createPrimitiveNumericValue(value));
7938 hasAngle = true;
7939 } else {
7940 break;
7941 }
7942 }
7943
7944 if (!list->length())
7945 return nullptr;
7946
7947 return list.release();
7948 }
7949
7950 } // namespace blink 242 } // namespace blink
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698