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