OLD | NEW |
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" | 9 #include "core/css/CSSCalculationValue.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" | 10 #include "core/css/CSSValuePool.h" |
56 #include "core/css/HashTools.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 if (range.peek().type() != IdentToken) |
| 76 return nullptr; |
| 77 return cssValuePool().createIdentifierValue(range.consumeIncludingWhitespace
().id()); |
| 78 } |
125 | 79 |
126 if (m_currentShorthand) { | 80 static PassRefPtrWillBeRawPtr<CSSPrimitiveValue> consumeCustomIdent(CSSParserTok
enRange& range) |
127 Vector<StylePropertyShorthand, 4> shorthands; | 81 { |
128 getMatchingShorthandsForLonghand(propId, &shorthands); | 82 if (range.peek().type() != IdentToken) |
129 // Viewport descriptors have width and height as shorthands, but it does
n't | 83 return nullptr; |
130 // make sense for CSSProperties.in to consider them as such. The shortha
nd | 84 return cssValuePool().createValue(range.consumeIncludingWhitespace().value()
, CSSPrimitiveValue::UnitType::CustomIdentifier); |
131 // index is only used by the inspector and doesn't affect viewport | 85 } |
132 // descriptors. | |
133 if (shorthands.isEmpty()) | |
134 ASSERT(m_currentShorthand == CSSPropertyWidth || m_currentShorthand
== CSSPropertyHeight); | |
135 else | |
136 setFromShorthand = true; | |
137 | 86 |
138 if (shorthands.size() > 1) | 87 static PassRefPtrWillBeRawPtr<CSSPrimitiveValue> consumeString(CSSParserTokenRan
ge& range) |
139 shorthandIndex = indexOfShorthandForLonghand(m_currentShorthand, sho
rthands); | 88 { |
| 89 if (range.peek().type() != StringToken) |
| 90 return nullptr; |
| 91 return cssValuePool().createValue(range.consumeIncludingWhitespace().value()
, CSSPrimitiveValue::UnitType::String); |
| 92 } |
| 93 |
| 94 // Methods for consuming non-shorthand properties starts here. |
| 95 static PassRefPtrWillBeRawPtr<CSSValue> consumeWillChange(CSSParserTokenRange& r
ange) |
| 96 { |
| 97 RefPtrWillBeRawPtr<CSSValueList> values = CSSValueList::createCommaSeparated
(); |
| 98 if (range.peek().id() == CSSValueAuto) { |
| 99 // FIXME: This will be read back as an empty string instead of auto |
| 100 return values.release(); |
140 } | 101 } |
141 | 102 |
142 m_parsedProperties.append(CSSProperty(propId, value, important, setFromShort
hand, shorthandIndex, m_implicitShorthand || implicit)); | 103 // Every comma-separated list of identifiers is a valid will-change value, |
| 104 // unless the list includes an explicitly disallowed identifier. |
| 105 while (true) { |
| 106 if (range.peek().type() != IdentToken) |
| 107 return nullptr; |
| 108 CSSPropertyID unresolvedProperty = unresolvedCSSPropertyID(range.peek().
value()); |
| 109 if (unresolvedProperty) { |
| 110 ASSERT(CSSPropertyMetadata::isEnabledProperty(unresolvedProperty)); |
| 111 // Now "all" is used by both CSSValue and CSSPropertyValue. |
| 112 // Need to return nullptr when currentValue is CSSPropertyAll. |
| 113 if (unresolvedProperty == CSSPropertyWillChange || unresolvedPropert
y == CSSPropertyAll) |
| 114 return nullptr; |
| 115 values->append(cssValuePool().createIdentifierValue(unresolvedProper
ty)); |
| 116 range.consumeIncludingWhitespace(); |
| 117 } else { |
| 118 switch (range.peek().id()) { |
| 119 case CSSValueNone: |
| 120 case CSSValueAll: |
| 121 case CSSValueAuto: |
| 122 case CSSValueDefault: |
| 123 case CSSValueInitial: |
| 124 case CSSValueInherit: |
| 125 return nullptr; |
| 126 case CSSValueContents: |
| 127 case CSSValueScrollPosition: |
| 128 values->append(consumeIdent(range)); |
| 129 break; |
| 130 default: |
| 131 range.consumeIncludingWhitespace(); |
| 132 break; |
| 133 } |
| 134 } |
| 135 |
| 136 if (range.atEnd()) |
| 137 break; |
| 138 if (!consumeCommaIncludingWhitespace(range)) |
| 139 return nullptr; |
| 140 } |
| 141 |
| 142 return values.release(); |
143 } | 143 } |
144 | 144 |
145 void CSSPropertyParser::rollbackLastProperties(int num) | 145 static PassRefPtrWillBeRawPtr<CSSPrimitiveValue> consumePage(CSSParserTokenRange
& range) |
146 { | 146 { |
147 ASSERT(num >= 0); | 147 if (range.peek().id() == CSSValueAuto) |
148 ASSERT(m_parsedProperties.size() >= static_cast<unsigned>(num)); | 148 return consumeIdent(range); |
149 m_parsedProperties.shrink(m_parsedProperties.size() - num); | 149 return consumeCustomIdent(range); |
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 RefPtrWillBeRawPtr<CSSValue> parsedValue = consumeString(range); |
| 160 if (!parsedValue) |
| 161 return nullptr; |
| 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 return consumeString(range); |
162 return false; | |
163 | |
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 } | 174 } |
217 | 175 |
218 inline bool CSSPropertyParser::shouldAcceptUnitLessValues(CSSParserValue* value,
Units unitflags, CSSParserMode cssParserMode) | 176 PassRefPtrWillBeRawPtr<CSSValue> CSSPropertyParser::parseSingleValue(CSSProperty
ID propId) |
219 { | 177 { |
220 // Quirks mode for certain properties and presentation attributes accept uni
t-less values for certain units. | 178 m_range.consumeWhitespace(); |
221 return (unitflags & (FLength | FAngle)) | 179 switch (propId) { |
222 && (!value->fValue // 0 can always be unitless. | 180 case CSSPropertyWillChange: |
223 || isUnitLessLengthParsingEnabledForMode(cssParserMode) // HTML and
SVG attribute values can always be unitless. | 181 return consumeWillChange(m_range); |
224 || (cssParserMode == HTMLQuirksMode && (unitflags & FUnitlessQuirk))
); | 182 case CSSPropertyPage: |
225 } | 183 return consumePage(m_range); |
226 | 184 case CSSPropertyQuotes: |
227 inline bool isCalculation(CSSParserValue* value) | 185 return consumeQuotes(m_range); |
228 { | 186 case CSSPropertyWebkitHighlight: |
229 return value->m_unit == CSSParserValue::CalcFunction; | 187 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: | 188 default: |
286 return false; | 189 return nullptr; |
287 } | 190 } |
288 } | 191 } |
289 | 192 |
290 PassRefPtrWillBeRawPtr<CSSPrimitiveValue> CSSPropertyParser::createPrimitiveNume
ricValue(CSSParserValue* value) | 193 bool CSSPropertyParser::parseShorthand(CSSPropertyID propId, bool important) |
291 { | 194 { |
292 if (m_parsedCalculation) { | 195 m_range.consumeWhitespace(); |
293 ASSERT(isCalculation(value)); | 196 switch (propId) { |
294 return CSSPrimitiveValue::create(m_parsedCalculation.release()); | 197 case CSSPropertyWebkitMarginCollapse: { |
295 } | 198 CSSValueID id = m_range.consumeIncludingWhitespace().id(); |
296 | 199 if (!CSSParserFastPaths::isValidKeywordPropertyAndValue(CSSPropertyWebki
tMarginBeforeCollapse, id)) |
297 ASSERT((value->unit() >= CSSPrimitiveValue::UnitType::Number && value->unit(
) <= CSSPrimitiveValue::UnitType::Kilohertz) | 200 return false; |
298 || (value->unit() >= CSSPrimitiveValue::UnitType::Turns && value->unit()
<= CSSPrimitiveValue::UnitType::Chs) | 201 RefPtrWillBeRawPtr<CSSValue> beforeCollapse = cssValuePool().createIdent
ifierValue(id); |
299 || (value->unit() >= CSSPrimitiveValue::UnitType::ViewportWidth && value
->unit() <= CSSPrimitiveValue::UnitType::ViewportMax) | 202 addProperty(CSSPropertyWebkitMarginBeforeCollapse, beforeCollapse, impor
tant); |
300 || (value->unit() >= CSSPrimitiveValue::UnitType::DotsPerPixel && value-
>unit() <= CSSPrimitiveValue::UnitType::DotsPerCentimeter)); | 203 if (m_range.atEnd()) { |
301 return cssValuePool().createValue(value->fValue, value->unit()); | 204 addProperty(CSSPropertyWebkitMarginAfterCollapse, beforeCollapse, im
portant); |
302 } | 205 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 } | 206 } |
| 207 id = m_range.consumeIncludingWhitespace().id(); |
| 208 if (!CSSParserFastPaths::isValidKeywordPropertyAndValue(CSSPropertyWebki
tMarginAfterCollapse, id)) |
| 209 return false; |
| 210 addProperty(CSSPropertyWebkitMarginAfterCollapse, cssValuePool().createI
dentifierValue(id), important); |
393 return true; | 211 return true; |
394 } | 212 } |
395 return validUnit(value, FLength | FPercent | FNonNeg | unitless); | 213 case CSSPropertyOverflow: { |
396 } | 214 CSSValueID id = m_range.consumeIncludingWhitespace().id(); |
397 | 215 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; | 216 return false; |
449 addExpandedPropertyForValue(propId, cssValuePool().createInheritedValue(
), important); | 217 if (!m_range.atEnd()) |
450 return true; | |
451 } else if (id == CSSValueInitial) { | |
452 if (m_valueList->size() != 1) | |
453 return false; | 218 return false; |
454 addExpandedPropertyForValue(propId, cssValuePool().createExplicitInitial
Value(), important); | 219 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 | 220 |
506 RefPtrWillBeRawPtr<CSSValue> overflowXValue = nullptr; | 221 RefPtrWillBeRawPtr<CSSValue> overflowXValue = nullptr; |
507 | 222 |
508 // FIXME: -webkit-paged-x or -webkit-paged-y only apply to overflow-y. I
f this value has been | 223 // 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 | 224 // 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 | 225 // 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. | 226 // paged-x or paged-y, then overflow-x and overflow-y should have the sa
me value. |
512 if (id == CSSValueWebkitPagedX || id == CSSValueWebkitPagedY) | 227 if (id == CSSValueWebkitPagedX || id == CSSValueWebkitPagedY) |
513 overflowXValue = cssValuePool().createIdentifierValue(CSSValueAuto); | 228 overflowXValue = cssValuePool().createIdentifierValue(CSSValueAuto); |
514 else | 229 else |
515 overflowXValue = m_parsedProperties.last().value(); | 230 overflowXValue = overflowYValue; |
516 addProperty(CSSPropertyOverflowX, overflowXValue.release(), important); | 231 addProperty(CSSPropertyOverflowX, overflowXValue.release(), important); |
| 232 addProperty(CSSPropertyOverflowY, overflowYValue.release(), important); |
517 return true; | 233 return true; |
518 } | 234 } |
519 | 235 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; | 236 return false; |
926 } | 237 } |
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 } | 238 } |
2145 | 239 |
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 | 240 } // namespace blink |
OLD | NEW |