2 * Copyright (C) 2003 Lars Knoll (knoll@kde.org)
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.
5 * Copyright (C) 2007 Nicholas Shanks <webkit@nickshanks.com>
6 * Copyright (C) 2008 Eric Seidel <eric@webkit.org>
7 * Copyright (C) 2009 Torch Mobile Inc. All rights reserved. (http://www.torchmobile.com/)
8 * Copyright (C) 2012 Adobe Systems Incorporated. All rights reserved.
10 * This library is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU Library General Public
12 * License as published by the Free Software Foundation; either
13 * version 2 of the License, or (at your option) any later version.
15 * This library is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 * Library General Public License for more details.
20 * You should have received a copy of the GNU Library General Public License
21 * along with this library; see the file COPYING.LIB. If not, write to
22 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
23 * Boston, MA 02110-1301, USA.
27 #include "CSSParser.h"
29 #include "CSSAspectRatioValue.h"
30 #include "CSSBasicShapes.h"
31 #include "CSSBorderImage.h"
32 #include "CSSCanvasValue.h"
33 #include "CSSCrossfadeValue.h"
34 #include "CSSCursorImageValue.h"
35 #include "CSSFontFaceRule.h"
36 #include "CSSFontFaceSrcValue.h"
37 #include "CSSFunctionValue.h"
38 #include "CSSGradientValue.h"
39 #include "CSSImageValue.h"
40 #include "CSSInheritedValue.h"
41 #include "CSSInitialValue.h"
42 #include "CSSLineBoxContainValue.h"
43 #include "CSSMediaRule.h"
44 #include "CSSPageRule.h"
45 #include "CSSPrimitiveValue.h"
46 #include "CSSProperty.h"
47 #include "CSSPropertySourceData.h"
48 #include "CSSReflectValue.h"
49 #include "CSSSelector.h"
50 #include "CSSTimingFunctionValue.h"
51 #include "CSSUnicodeRangeValue.h"
52 #include "CSSValueKeywords.h"
53 #include "CSSValueList.h"
54 #include "CSSValuePool.h"
55 #if ENABLE(CSS_VARIABLES)
56 #include "CSSVariableValue.h"
60 #include "FloatConversion.h"
61 #include "FontFeatureValue.h"
62 #include "FontValue.h"
63 #include "HTMLParserIdioms.h"
64 #include "HashTools.h"
65 #include "MediaList.h"
66 #include "MediaQueryExp.h"
70 #include "RenderTheme.h"
71 #include "RuntimeEnabledFeatures.h"
72 #include "SVGParserUtilities.h"
74 #include "ShadowValue.h"
75 #include "StylePropertySet.h"
76 #include "StylePropertyShorthand.h"
77 #include "StyleRule.h"
78 #include "StyleRuleImport.h"
79 #include "StyleSheetContents.h"
80 #include "TextEncoding.h"
81 #include "WebKitCSSKeyframeRule.h"
82 #include "WebKitCSSKeyframesRule.h"
83 #include "WebKitCSSRegionRule.h"
84 #include "WebKitCSSTransformValue.h"
86 #include <wtf/BitArray.h>
87 #include <wtf/HexNumber.h>
89 #include <wtf/text/StringBuffer.h>
90 #include <wtf/text/StringBuilder.h>
92 #if ENABLE(CSS_IMAGE_SET)
93 #include "CSSImageSetValue.h"
96 #if ENABLE(CSS_FILTERS)
97 #include "WebKitCSSFilterValue.h"
99 #include "WebKitCSSSVGDocumentValue.h"
103 #if ENABLE(CSS_SHADERS)
104 #include "WebKitCSSShaderValue.h"
107 #if ENABLE(DASHBOARD_SUPPORT)
108 #include "DashboardRegion.h"
114 extern int cssyydebug;
117 extern int cssyyparse(void* parser);
129 class ImplicitScope {
130 WTF_MAKE_NONCOPYABLE(ImplicitScope);
132 ImplicitScope(WebCore::CSSParser* parser, PropertyType propertyType)
135 m_parser->m_implicitShorthand = propertyType == PropertyImplicit;
140 m_parser->m_implicitShorthand = false;
144 WebCore::CSSParser* m_parser;
151 static const unsigned INVALID_NUM_PARSED_PROPERTIES = UINT_MAX;
152 static const double MAX_SCALE = 1000000;
154 static bool equal(const CSSParserString& a, const char* b)
156 for (int i = 0; i < a.length; ++i) {
159 if (a.characters[i] != b[i])
165 static bool equalIgnoringCase(const CSSParserString& a, const char* b)
167 for (int i = 0; i < a.length; ++i) {
170 ASSERT(!isASCIIUpper(b[i]));
171 if (toASCIILower(a.characters[i]) != b[i])
177 static bool hasPrefix(const char* string, unsigned length, const char* prefix)
179 for (unsigned i = 0; i < length; ++i) {
182 if (string[i] != prefix[i])
188 const CSSParserContext& strictCSSParserContext()
190 DEFINE_STATIC_LOCAL(CSSParserContext, strictContext, (CSSStrictMode));
191 return strictContext;
194 CSSParserContext::CSSParserContext(CSSParserMode mode, const KURL& baseURL)
197 , isHTMLDocument(false)
198 , isCSSCustomFilterEnabled(false)
199 , isCSSRegionsEnabled(false)
200 , isCSSGridLayoutEnabled(false)
201 #if ENABLE(CSS_VARIABLES)
202 , isCSSVariablesEnabled(false)
204 , needsSiteSpecificQuirks(false)
205 , enforcesCSSMIMETypeInNoQuirksMode(true)
209 CSSParserContext::CSSParserContext(Document* document, const KURL& baseURL, const String& charset)
210 : baseURL(baseURL.isNull() ? document->baseURL() : baseURL)
212 , mode(document->inQuirksMode() ? CSSQuirksMode : CSSStrictMode)
213 , isHTMLDocument(document->isHTMLDocument())
214 , isCSSCustomFilterEnabled(document->settings() ? document->settings()->isCSSCustomFilterEnabled() : false)
215 , isCSSRegionsEnabled(document->cssRegionsEnabled())
216 , isCSSGridLayoutEnabled(document->cssGridLayoutEnabled())
217 #if ENABLE(CSS_VARIABLES)
218 , isCSSVariablesEnabled(document->settings() ? document->settings()->cssVariablesEnabled() : false)
220 , needsSiteSpecificQuirks(document->settings() ? document->settings()->needsSiteSpecificQuirks() : false)
221 , enforcesCSSMIMETypeInNoQuirksMode(!document->settings() || document->settings()->enforceCSSMIMETypeInNoQuirksMode())
225 bool operator==(const CSSParserContext& a, const CSSParserContext& b)
227 return a.baseURL == b.baseURL
228 && a.charset == b.charset
230 && a.isHTMLDocument == b.isHTMLDocument
231 && a.isCSSCustomFilterEnabled == b.isCSSCustomFilterEnabled
232 && a.isCSSRegionsEnabled == b.isCSSRegionsEnabled
233 && a.isCSSGridLayoutEnabled == b.isCSSGridLayoutEnabled
234 #if ENABLE(CSS_VARIABLES)
235 && a.isCSSVariablesEnabled == b.isCSSVariablesEnabled
237 && a.needsSiteSpecificQuirks == b.needsSiteSpecificQuirks
238 && a.enforcesCSSMIMETypeInNoQuirksMode == b.enforcesCSSMIMETypeInNoQuirksMode;
241 CSSParser::CSSParser(const CSSParserContext& context)
244 , m_id(CSSPropertyInvalid)
246 , m_selectorListForParseSelector(0)
247 , m_numParsedPropertiesBeforeMarginBox(INVALID_NUM_PARSED_PROPERTIES)
248 , m_inParseShorthand(0)
249 , m_currentShorthand(CSSPropertyInvalid)
250 , m_implicitShorthand(false)
251 , m_hasFontFaceOnlyValues(false)
252 , m_hadSyntacticallyValidCSSRule(false)
253 , m_defaultNamespace(starAtom)
254 , m_parsedTextPrefixLength(0)
255 , m_propertyRange(UINT_MAX, UINT_MAX)
256 , m_ruleSourceDataResult(0)
257 , m_parsingMode(NormalMode)
258 , m_currentCharacter(0)
262 , m_lastSelectorLineNumber(0)
263 , m_allowImportRules(true)
264 , m_allowNamespaceDeclarations(true)
269 CSSPropertySourceData::init();
272 CSSParser::~CSSParser()
276 fastDeleteAllValues(m_floatingSelectors);
277 deleteAllValues(m_floatingSelectorVectors);
278 deleteAllValues(m_floatingValueLists);
279 deleteAllValues(m_floatingFunctions);
282 void CSSParserString::lower()
284 // FIXME: If we need Unicode lowercasing here, then we probably want the real kind
285 // that can potentially change the length of the string rather than the character
286 // by character kind. If we don't need Unicode lowercasing, it would be good to
287 // simplify this function.
289 if (charactersAreAllASCII(characters, length)) {
290 // Fast case for all-ASCII.
291 for (int i = 0; i < length; i++)
292 characters[i] = toASCIILower(characters[i]);
294 for (int i = 0; i < length; i++)
295 characters[i] = Unicode::toLower(characters[i]);
299 void CSSParser::setupParser(const char* prefix, const String& string, const char* suffix)
301 m_parsedTextPrefixLength = strlen(prefix);
302 int length = string.length() + m_parsedTextPrefixLength + strlen(suffix) + 1;
304 m_dataStart = adoptArrayPtr(new UChar[length]);
305 for (unsigned i = 0; i < m_parsedTextPrefixLength; i++)
306 m_dataStart[i] = prefix[i];
308 memcpy(m_dataStart.get() + m_parsedTextPrefixLength, string.characters(), string.length() * sizeof(UChar));
310 unsigned start = m_parsedTextPrefixLength + string.length();
311 unsigned end = start + strlen(suffix);
312 for (unsigned i = start; i < end; i++)
313 m_dataStart[i] = suffix[i - start];
315 m_dataStart[length - 1] = 0;
317 m_currentCharacter = m_tokenStart = m_dataStart.get();
320 void CSSParser::parseSheet(StyleSheetContents* sheet, const String& string, int startLineNumber, RuleSourceDataList* ruleSourceDataResult)
322 setStyleSheet(sheet);
323 m_defaultNamespace = starAtom; // Reset the default namespace.
324 if (ruleSourceDataResult)
325 m_currentRuleDataStack = adoptPtr(new RuleSourceDataList());
326 m_ruleSourceDataResult = ruleSourceDataResult;
328 m_lineNumber = startLineNumber;
329 setupParser("", string, "");
331 m_currentRuleDataStack.clear();
332 m_ruleSourceDataResult = 0;
336 PassRefPtr<StyleRuleBase> CSSParser::parseRule(StyleSheetContents* sheet, const String& string)
338 setStyleSheet(sheet);
339 m_allowNamespaceDeclarations = false;
340 setupParser("@-webkit-rule{", string, "} ");
342 return m_rule.release();
345 PassRefPtr<StyleKeyframe> CSSParser::parseKeyframeRule(StyleSheetContents* sheet, const String& string)
347 setStyleSheet(sheet);
348 setupParser("@-webkit-keyframe-rule{ ", string, "} ");
350 return m_keyframe.release();
353 static inline bool isColorPropertyID(CSSPropertyID propertyId)
355 switch (propertyId) {
356 case CSSPropertyColor:
357 case CSSPropertyBackgroundColor:
358 case CSSPropertyBorderBottomColor:
359 case CSSPropertyBorderLeftColor:
360 case CSSPropertyBorderRightColor:
361 case CSSPropertyBorderTopColor:
362 case CSSPropertyOutlineColor:
363 case CSSPropertyTextLineThroughColor:
364 case CSSPropertyTextOverlineColor:
365 case CSSPropertyTextUnderlineColor:
366 case CSSPropertyWebkitBorderAfterColor:
367 case CSSPropertyWebkitBorderBeforeColor:
368 case CSSPropertyWebkitBorderEndColor:
369 case CSSPropertyWebkitBorderStartColor:
370 case CSSPropertyWebkitColumnRuleColor:
371 case CSSPropertyWebkitTextEmphasisColor:
372 case CSSPropertyWebkitTextFillColor:
373 case CSSPropertyWebkitTextStrokeColor:
380 static bool parseColorValue(StylePropertySet* declaration, CSSPropertyID propertyId, const String& string, bool important, CSSParserMode cssParserMode)
382 ASSERT(!string.isEmpty());
383 bool strict = isStrictParserMode(cssParserMode);
384 if (!isColorPropertyID(propertyId))
386 CSSParserString cssString;
387 cssString.characters = const_cast<UChar*>(string.characters());
388 cssString.length = string.length();
389 int valueID = cssValueKeywordID(cssString);
390 bool validPrimitive = false;
391 if (valueID == CSSValueWebkitText)
392 validPrimitive = true;
393 else if (valueID == CSSValueCurrentcolor)
394 validPrimitive = true;
395 else if ((valueID >= CSSValueAqua && valueID <= CSSValueWindowtext) || valueID == CSSValueMenu
396 || (valueID >= CSSValueWebkitFocusRingColor && valueID < CSSValueWebkitText && !strict)) {
397 validPrimitive = true;
400 if (validPrimitive) {
401 RefPtr<CSSValue> value = cssValuePool().createIdentifierValue(valueID);
402 declaration->addParsedProperty(CSSProperty(propertyId, value.release(), important));
406 if (!CSSParser::fastParseColor(color, string, strict && string[0] != '#'))
408 RefPtr<CSSValue> value = cssValuePool().createColorValue(color);
409 declaration->addParsedProperty(CSSProperty(propertyId, value.release(), important));
413 static inline bool isSimpleLengthPropertyID(CSSPropertyID propertyId, bool& acceptsNegativeNumbers)
415 switch (propertyId) {
416 case CSSPropertyFontSize:
417 case CSSPropertyHeight:
418 case CSSPropertyWidth:
419 case CSSPropertyMinHeight:
420 case CSSPropertyMinWidth:
421 case CSSPropertyPaddingBottom:
422 case CSSPropertyPaddingLeft:
423 case CSSPropertyPaddingRight:
424 case CSSPropertyPaddingTop:
425 case CSSPropertyWebkitLogicalWidth:
426 case CSSPropertyWebkitLogicalHeight:
427 case CSSPropertyWebkitMinLogicalWidth:
428 case CSSPropertyWebkitMinLogicalHeight:
429 case CSSPropertyWebkitPaddingAfter:
430 case CSSPropertyWebkitPaddingBefore:
431 case CSSPropertyWebkitPaddingEnd:
432 case CSSPropertyWebkitPaddingStart:
433 acceptsNegativeNumbers = false;
435 #if ENABLE(CSS_EXCLUSIONS)
436 case CSSPropertyWebkitWrapMargin:
437 case CSSPropertyWebkitWrapPadding:
438 acceptsNegativeNumbers = false;
439 return RuntimeEnabledFeatures::cssExclusionsEnabled();
441 case CSSPropertyBottom:
442 case CSSPropertyLeft:
443 case CSSPropertyMarginBottom:
444 case CSSPropertyMarginLeft:
445 case CSSPropertyMarginRight:
446 case CSSPropertyMarginTop:
447 case CSSPropertyRight:
448 case CSSPropertyTextIndent:
450 case CSSPropertyWebkitMarginAfter:
451 case CSSPropertyWebkitMarginBefore:
452 case CSSPropertyWebkitMarginEnd:
453 case CSSPropertyWebkitMarginStart:
454 acceptsNegativeNumbers = true;
461 template <typename CharType>
462 static inline bool parseSimpleLength(const CharType* characters, unsigned& length, CSSPrimitiveValue::UnitTypes& unit, double& number)
464 if (length > 2 && (characters[length - 2] | 0x20) == 'p' && (characters[length - 1] | 0x20) == 'x') {
466 unit = CSSPrimitiveValue::CSS_PX;
467 } else if (length > 1 && characters[length - 1] == '%') {
469 unit = CSSPrimitiveValue::CSS_PERCENTAGE;
472 // We rely on charactersToDouble for validation as well. The function
473 // will set "ok" to "false" if the entire passed-in character range does
474 // not represent a double.
476 number = charactersToDouble(characters, length, &ok);
480 static bool parseSimpleLengthValue(StylePropertySet* declaration, CSSPropertyID propertyId, const String& string, bool important, CSSParserMode cssParserMode)
482 ASSERT(!string.isEmpty());
483 bool acceptsNegativeNumbers;
484 if (!isSimpleLengthPropertyID(propertyId, acceptsNegativeNumbers))
487 unsigned length = string.length();
489 CSSPrimitiveValue::UnitTypes unit = CSSPrimitiveValue::CSS_NUMBER;
491 if (string.is8Bit()) {
492 if (!parseSimpleLength(string.characters8(), length, unit, number))
495 if (!parseSimpleLength(string.characters16(), length, unit, number))
499 if (unit == CSSPrimitiveValue::CSS_NUMBER) {
500 if (number && isStrictParserMode(cssParserMode))
502 unit = CSSPrimitiveValue::CSS_PX;
504 if (number < 0 && !acceptsNegativeNumbers)
507 RefPtr<CSSValue> value = cssValuePool().createValue(number, unit);
508 declaration->addParsedProperty(CSSProperty(propertyId, value.release(), important));
512 static inline bool isValidKeywordPropertyAndValue(CSSPropertyID propertyId, int valueID, const CSSParserContext& parserContext)
517 switch (propertyId) {
518 case CSSPropertyBorderCollapse: // collapse | separate | inherit
519 if (valueID == CSSValueCollapse || valueID == CSSValueSeparate)
522 case CSSPropertyBorderTopStyle: // <border-style> | inherit
523 case CSSPropertyBorderRightStyle: // Defined as: none | hidden | dotted | dashed |
524 case CSSPropertyBorderBottomStyle: // solid | double | groove | ridge | inset | outset
525 case CSSPropertyBorderLeftStyle:
526 case CSSPropertyWebkitBorderAfterStyle:
527 case CSSPropertyWebkitBorderBeforeStyle:
528 case CSSPropertyWebkitBorderEndStyle:
529 case CSSPropertyWebkitBorderStartStyle:
530 case CSSPropertyWebkitColumnRuleStyle:
531 if (valueID >= CSSValueNone && valueID <= CSSValueDouble)
534 case CSSPropertyBoxSizing:
535 if (valueID == CSSValueBorderBox || valueID == CSSValueContentBox)
538 case CSSPropertyCaptionSide: // top | bottom | left | right | inherit
539 if (valueID == CSSValueLeft || valueID == CSSValueRight || valueID == CSSValueTop || valueID == CSSValueBottom)
542 case CSSPropertyClear: // none | left | right | both | inherit
543 if (valueID == CSSValueNone || valueID == CSSValueLeft || valueID == CSSValueRight || valueID == CSSValueBoth)
546 case CSSPropertyDirection: // ltr | rtl | inherit
547 if (valueID == CSSValueLtr || valueID == CSSValueRtl)
550 case CSSPropertyDisplay:
551 // inline | block | list-item | run-in | inline-block | table |
552 // inline-table | table-row-group | table-header-group | table-footer-group | table-row |
553 // table-column-group | table-column | table-cell | table-caption | -webkit-box | -webkit-inline-box | none | inherit
554 // -webkit-flex | -webkit-inline-flex | -webkit-grid | -webkit-inline-grid
555 if ((valueID >= CSSValueInline && valueID <= CSSValueWebkitInlineBox) || valueID == CSSValueNone)
557 #if ENABLE(CSS3_FLEXBOX)
558 if (valueID == CSSValueWebkitFlex || valueID == CSSValueWebkitInlineFlex)
561 if (parserContext.isCSSGridLayoutEnabled && (valueID == CSSValueWebkitGrid || valueID == CSSValueWebkitInlineGrid))
565 case CSSPropertyEmptyCells: // show | hide | inherit
566 if (valueID == CSSValueShow || valueID == CSSValueHide)
569 case CSSPropertyFloat: // left | right | none | center (for buggy CSS, maps to none)
570 if (valueID == CSSValueLeft || valueID == CSSValueRight || valueID == CSSValueNone || valueID == CSSValueCenter)
573 case CSSPropertyFontStyle: // normal | italic | oblique | inherit
574 if (valueID == CSSValueNormal || valueID == CSSValueItalic || valueID == CSSValueOblique)
577 case CSSPropertyImageRendering: // auto | optimizeContrast
578 if (valueID == CSSValueAuto || valueID == CSSValueWebkitOptimizeContrast)
581 case CSSPropertyListStylePosition: // inside | outside | inherit
582 if (valueID == CSSValueInside || valueID == CSSValueOutside)
585 case CSSPropertyListStyleType:
586 // See section CSS_PROP_LIST_STYLE_TYPE of file CSSValueKeywords.in
587 // for the list of supported list-style-types.
588 if ((valueID >= CSSValueDisc && valueID <= CSSValueKatakanaIroha) || valueID == CSSValueNone)
591 case CSSPropertyOutlineStyle: // (<border-style> except hidden) | auto | inherit
592 if (valueID == CSSValueAuto || valueID == CSSValueNone || (valueID >= CSSValueInset && valueID <= CSSValueDouble))
595 case CSSPropertyOverflowWrap: // normal | break-word
596 case CSSPropertyWordWrap:
597 if (valueID == CSSValueNormal || valueID == CSSValueBreakWord)
600 case CSSPropertyOverflowX:
601 case CSSPropertyOverflowY: // visible | hidden | scroll | auto | marquee | overlay | inherit
602 if (valueID == CSSValueVisible || valueID == CSSValueHidden || valueID == CSSValueScroll || valueID == CSSValueAuto || valueID == CSSValueOverlay || valueID == CSSValueWebkitMarquee)
605 case CSSPropertyPageBreakAfter: // auto | always | avoid | left | right | inherit
606 case CSSPropertyPageBreakBefore:
607 case CSSPropertyWebkitColumnBreakAfter:
608 case CSSPropertyWebkitColumnBreakBefore:
609 if (valueID == CSSValueAuto || valueID == CSSValueAlways || valueID == CSSValueAvoid || valueID == CSSValueLeft || valueID == CSSValueRight)
612 case CSSPropertyPageBreakInside: // avoid | auto | inherit
613 case CSSPropertyWebkitColumnBreakInside:
614 if (valueID == CSSValueAuto || valueID == CSSValueAvoid)
617 case CSSPropertyPointerEvents:
618 // none | visiblePainted | visibleFill | visibleStroke | visible |
619 // painted | fill | stroke | auto | all | inherit
620 if (valueID == CSSValueVisible || valueID == CSSValueNone || valueID == CSSValueAll || valueID == CSSValueAuto || (valueID >= CSSValueVisiblepainted && valueID <= CSSValueStroke))
623 case CSSPropertyPosition: // static | relative | absolute | fixed | sticky | inherit
624 if (valueID == CSSValueStatic || valueID == CSSValueRelative || valueID == CSSValueAbsolute || valueID == CSSValueFixed
625 #if ENABLE(CSS_STICKY_POSITION)
626 || valueID == CSSValueWebkitSticky
631 case CSSPropertyResize: // none | both | horizontal | vertical | auto
632 if (valueID == CSSValueNone || valueID == CSSValueBoth || valueID == CSSValueHorizontal || valueID == CSSValueVertical || valueID == CSSValueAuto)
635 case CSSPropertySpeak: // none | normal | spell-out | digits | literal-punctuation | no-punctuation | inherit
636 if (valueID == CSSValueNone || valueID == CSSValueNormal || valueID == CSSValueSpellOut || valueID == CSSValueDigits || valueID == CSSValueLiteralPunctuation || valueID == CSSValueNoPunctuation)
639 case CSSPropertyTableLayout: // auto | fixed | inherit
640 if (valueID == CSSValueAuto || valueID == CSSValueFixed)
643 case CSSPropertyTextLineThroughMode:
644 case CSSPropertyTextOverlineMode:
645 case CSSPropertyTextUnderlineMode:
646 if (valueID == CSSValueContinuous || valueID == CSSValueSkipWhiteSpace)
649 case CSSPropertyTextLineThroughStyle:
650 case CSSPropertyTextOverlineStyle:
651 case CSSPropertyTextUnderlineStyle:
652 if (valueID == CSSValueNone || valueID == CSSValueSolid || valueID == CSSValueDouble || valueID == CSSValueDashed || valueID == CSSValueDotDash || valueID == CSSValueDotDotDash || valueID == CSSValueWave)
655 case CSSPropertyTextOverflow: // clip | ellipsis
656 if (valueID == CSSValueClip || valueID == CSSValueEllipsis)
659 case CSSPropertyTextRendering: // auto | optimizeSpeed | optimizeLegibility | geometricPrecision
660 if (valueID == CSSValueAuto || valueID == CSSValueOptimizespeed || valueID == CSSValueOptimizelegibility || valueID == CSSValueGeometricprecision)
663 case CSSPropertyTextTransform: // capitalize | uppercase | lowercase | none | inherit
664 if ((valueID >= CSSValueCapitalize && valueID <= CSSValueLowercase) || valueID == CSSValueNone)
667 case CSSPropertyVisibility: // visible | hidden | collapse | inherit
668 if (valueID == CSSValueVisible || valueID == CSSValueHidden || valueID == CSSValueCollapse)
671 case CSSPropertyWebkitAppearance:
672 if ((valueID >= CSSValueCheckbox && valueID <= CSSValueTextarea) || valueID == CSSValueNone)
675 case CSSPropertyWebkitBackfaceVisibility:
676 if (valueID == CSSValueVisible || valueID == CSSValueHidden)
679 case CSSPropertyWebkitBorderFit:
680 if (valueID == CSSValueBorder || valueID == CSSValueLines)
683 case CSSPropertyWebkitBoxAlign:
684 if (valueID == CSSValueStretch || valueID == CSSValueStart || valueID == CSSValueEnd || valueID == CSSValueCenter || valueID == CSSValueBaseline)
687 #if ENABLE(CSS_BOX_DECORATION_BREAK)
688 case CSSPropertyWebkitBoxDecorationBreak:
689 if (valueID == CSSValueClone || valueID == CSSValueSlice)
693 case CSSPropertyWebkitBoxDirection:
694 if (valueID == CSSValueNormal || valueID == CSSValueReverse)
697 case CSSPropertyWebkitBoxLines:
698 if (valueID == CSSValueSingle || valueID == CSSValueMultiple)
701 case CSSPropertyWebkitBoxOrient:
702 if (valueID == CSSValueHorizontal || valueID == CSSValueVertical || valueID == CSSValueInlineAxis || valueID == CSSValueBlockAxis)
705 case CSSPropertyWebkitBoxPack:
706 if (valueID == CSSValueStart || valueID == CSSValueEnd || valueID == CSSValueCenter || valueID == CSSValueJustify)
709 case CSSPropertyWebkitColorCorrection:
710 if (valueID == CSSValueSrgb || valueID == CSSValueDefault)
713 #if ENABLE(CSS3_FLEXBOX)
714 case CSSPropertyWebkitAlignContent:
715 if (valueID == CSSValueFlexStart || valueID == CSSValueFlexEnd || valueID == CSSValueCenter || valueID == CSSValueSpaceBetween || valueID == CSSValueSpaceAround || valueID == CSSValueStretch)
718 case CSSPropertyWebkitAlignItems:
719 if (valueID == CSSValueFlexStart || valueID == CSSValueFlexEnd || valueID == CSSValueCenter || valueID == CSSValueBaseline || valueID == CSSValueStretch)
722 case CSSPropertyWebkitAlignSelf:
723 if (valueID == CSSValueAuto || valueID == CSSValueFlexStart || valueID == CSSValueFlexEnd || valueID == CSSValueCenter || valueID == CSSValueBaseline || valueID == CSSValueStretch)
726 case CSSPropertyWebkitFlexDirection:
727 if (valueID == CSSValueRow || valueID == CSSValueRowReverse || valueID == CSSValueColumn || valueID == CSSValueColumnReverse)
730 case CSSPropertyWebkitFlexWrap:
731 if (valueID == CSSValueNone || valueID == CSSValueWrap || valueID == CSSValueWrapReverse)
734 case CSSPropertyWebkitJustifyContent:
735 if (valueID == CSSValueFlexStart || valueID == CSSValueFlexEnd || valueID == CSSValueCenter || valueID == CSSValueSpaceBetween || valueID == CSSValueSpaceAround)
739 case CSSPropertyWebkitFontKerning:
740 if (valueID == CSSValueAuto || valueID == CSSValueNormal || valueID == CSSValueNone)
743 case CSSPropertyWebkitFontSmoothing:
744 if (valueID == CSSValueAuto || valueID == CSSValueNone || valueID == CSSValueAntialiased || valueID == CSSValueSubpixelAntialiased)
747 case CSSPropertyWebkitHyphens:
748 if (valueID == CSSValueNone || valueID == CSSValueManual || valueID == CSSValueAuto)
751 case CSSPropertyWebkitLineAlign:
752 if (valueID == CSSValueNone || valueID == CSSValueEdges)
755 case CSSPropertyWebkitLineBreak: // normal | after-white-space
756 if (valueID == CSSValueNormal || valueID == CSSValueAfterWhiteSpace)
759 case CSSPropertyWebkitLineSnap:
760 if (valueID == CSSValueNone || valueID == CSSValueBaseline || valueID == CSSValueContain)
763 case CSSPropertyWebkitMarginAfterCollapse:
764 case CSSPropertyWebkitMarginBeforeCollapse:
765 case CSSPropertyWebkitMarginBottomCollapse:
766 case CSSPropertyWebkitMarginTopCollapse:
767 if (valueID == CSSValueCollapse || valueID == CSSValueSeparate || valueID == CSSValueDiscard)
770 case CSSPropertyWebkitMarqueeDirection:
771 if (valueID == CSSValueForwards || valueID == CSSValueBackwards || valueID == CSSValueAhead || valueID == CSSValueReverse || valueID == CSSValueLeft || valueID == CSSValueRight || valueID == CSSValueDown
772 || valueID == CSSValueUp || valueID == CSSValueAuto)
775 case CSSPropertyWebkitMarqueeStyle:
776 if (valueID == CSSValueNone || valueID == CSSValueSlide || valueID == CSSValueScroll || valueID == CSSValueAlternate)
779 case CSSPropertyWebkitNbspMode: // normal | space
780 if (valueID == CSSValueNormal || valueID == CSSValueSpace)
783 #if ENABLE(OVERFLOW_SCROLLING)
784 case CSSPropertyWebkitOverflowScrolling:
785 if (valueID == CSSValueAuto || valueID == CSSValueTouch)
789 case CSSPropertyWebkitPrintColorAdjust:
790 if (valueID == CSSValueExact || valueID == CSSValueEconomy)
793 #if ENABLE(CSS_REGIONS)
794 case CSSPropertyWebkitRegionBreakAfter:
795 case CSSPropertyWebkitRegionBreakBefore:
796 if (parserContext.isCSSRegionsEnabled && (valueID == CSSValueAuto || valueID == CSSValueAlways || valueID == CSSValueAvoid || valueID == CSSValueLeft || valueID == CSSValueRight))
799 case CSSPropertyWebkitRegionBreakInside:
800 if (parserContext.isCSSRegionsEnabled && (valueID == CSSValueAuto || valueID == CSSValueAvoid))
803 case CSSPropertyWebkitRegionOverflow:
804 if (parserContext.isCSSRegionsEnabled && (valueID == CSSValueAuto || valueID == CSSValueBreak))
808 case CSSPropertyWebkitRtlOrdering:
809 if (valueID == CSSValueLogical || valueID == CSSValueVisual)
812 case CSSPropertyWebkitTextCombine:
813 if (valueID == CSSValueNone || valueID == CSSValueHorizontal)
816 case CSSPropertyWebkitTextEmphasisPosition:
817 if (valueID == CSSValueOver || valueID == CSSValueUnder)
820 case CSSPropertyWebkitTextSecurity:
821 // disc | circle | square | none | inherit
822 if (valueID == CSSValueDisc || valueID == CSSValueCircle || valueID == CSSValueSquare || valueID == CSSValueNone)
825 case CSSPropertyWebkitTextSizeAdjust:
826 if (valueID == CSSValueAuto || valueID == CSSValueNone)
829 case CSSPropertyWebkitTransformStyle:
830 if (valueID == CSSValueFlat || valueID == CSSValuePreserve3d)
833 case CSSPropertyWebkitUserDrag: // auto | none | element
834 if (valueID == CSSValueAuto || valueID == CSSValueNone || valueID == CSSValueElement)
837 case CSSPropertyWebkitUserModify: // read-only | read-write
838 if (valueID == CSSValueReadOnly || valueID == CSSValueReadWrite || valueID == CSSValueReadWritePlaintextOnly)
841 case CSSPropertyWebkitUserSelect: // auto | none | text
842 if (valueID == CSSValueAuto || valueID == CSSValueNone || valueID == CSSValueText)
845 #if ENABLE(CSS_EXCLUSIONS)
846 case CSSPropertyWebkitWrapFlow:
847 if (!RuntimeEnabledFeatures::cssExclusionsEnabled())
849 if (valueID == CSSValueAuto || valueID == CSSValueBoth || valueID == CSSValueStart || valueID == CSSValueEnd || valueID == CSSValueMaximum || valueID == CSSValueClear)
852 case CSSPropertyWebkitWrapThrough:
853 if (!RuntimeEnabledFeatures::cssExclusionsEnabled())
855 if (valueID == CSSValueWrap || valueID == CSSValueNone)
859 case CSSPropertyWebkitWritingMode:
860 if (valueID >= CSSValueHorizontalTb && valueID <= CSSValueHorizontalBt)
863 case CSSPropertyWhiteSpace: // normal | pre | nowrap | inherit
864 if (valueID == CSSValueNormal || valueID == CSSValuePre || valueID == CSSValuePreWrap || valueID == CSSValuePreLine || valueID == CSSValueNowrap)
867 case CSSPropertyWordBreak: // normal | break-all | break-word (this is a custom extension)
868 if (valueID == CSSValueNormal || valueID == CSSValueBreakAll || valueID == CSSValueBreakWord)
872 ASSERT_NOT_REACHED();
878 static inline bool isKeywordPropertyID(CSSPropertyID propertyId)
880 switch (propertyId) {
881 case CSSPropertyBorderBottomStyle:
882 case CSSPropertyBorderCollapse:
883 case CSSPropertyBorderLeftStyle:
884 case CSSPropertyBorderRightStyle:
885 case CSSPropertyBorderTopStyle:
886 case CSSPropertyBoxSizing:
887 case CSSPropertyCaptionSide:
888 case CSSPropertyClear:
889 case CSSPropertyDirection:
890 case CSSPropertyDisplay:
891 case CSSPropertyEmptyCells:
892 case CSSPropertyFloat:
893 case CSSPropertyFontStyle:
894 case CSSPropertyImageRendering:
895 case CSSPropertyListStylePosition:
896 case CSSPropertyListStyleType:
897 case CSSPropertyOutlineStyle:
898 case CSSPropertyOverflowWrap:
899 case CSSPropertyOverflowX:
900 case CSSPropertyOverflowY:
901 case CSSPropertyPageBreakAfter:
902 case CSSPropertyPageBreakBefore:
903 case CSSPropertyPageBreakInside:
904 case CSSPropertyPointerEvents:
905 case CSSPropertyPosition:
906 case CSSPropertyResize:
907 case CSSPropertySpeak:
908 case CSSPropertyTableLayout:
909 case CSSPropertyTextLineThroughMode:
910 case CSSPropertyTextLineThroughStyle:
911 case CSSPropertyTextOverflow:
912 case CSSPropertyTextOverlineMode:
913 case CSSPropertyTextOverlineStyle:
914 case CSSPropertyTextRendering:
915 case CSSPropertyTextTransform:
916 case CSSPropertyTextUnderlineMode:
917 case CSSPropertyTextUnderlineStyle:
918 case CSSPropertyVisibility:
919 case CSSPropertyWebkitAppearance:
920 case CSSPropertyWebkitBackfaceVisibility:
921 case CSSPropertyWebkitBorderAfterStyle:
922 case CSSPropertyWebkitBorderBeforeStyle:
923 case CSSPropertyWebkitBorderEndStyle:
924 case CSSPropertyWebkitBorderFit:
925 case CSSPropertyWebkitBorderStartStyle:
926 case CSSPropertyWebkitBoxAlign:
927 #if ENABLE(CSS_BOX_DECORATION_BREAK)
928 case CSSPropertyWebkitBoxDecorationBreak:
930 case CSSPropertyWebkitBoxDirection:
931 case CSSPropertyWebkitBoxLines:
932 case CSSPropertyWebkitBoxOrient:
933 case CSSPropertyWebkitBoxPack:
934 case CSSPropertyWebkitColorCorrection:
935 case CSSPropertyWebkitColumnBreakAfter:
936 case CSSPropertyWebkitColumnBreakBefore:
937 case CSSPropertyWebkitColumnBreakInside:
938 case CSSPropertyWebkitColumnRuleStyle:
939 #if ENABLE(CSS3_FLEXBOX)
940 case CSSPropertyWebkitAlignContent:
941 case CSSPropertyWebkitAlignItems:
942 case CSSPropertyWebkitAlignSelf:
943 case CSSPropertyWebkitFlexDirection:
944 case CSSPropertyWebkitFlexWrap:
945 case CSSPropertyWebkitJustifyContent:
947 case CSSPropertyWebkitFontKerning:
948 case CSSPropertyWebkitFontSmoothing:
949 case CSSPropertyWebkitHyphens:
950 case CSSPropertyWebkitLineAlign:
951 case CSSPropertyWebkitLineBreak:
952 case CSSPropertyWebkitLineSnap:
953 case CSSPropertyWebkitMarginAfterCollapse:
954 case CSSPropertyWebkitMarginBeforeCollapse:
955 case CSSPropertyWebkitMarginBottomCollapse:
956 case CSSPropertyWebkitMarginTopCollapse:
957 case CSSPropertyWebkitMarqueeDirection:
958 case CSSPropertyWebkitMarqueeStyle:
959 case CSSPropertyWebkitNbspMode:
960 #if ENABLE(OVERFLOW_SCROLLING)
961 case CSSPropertyWebkitOverflowScrolling:
963 case CSSPropertyWebkitPrintColorAdjust:
964 #if ENABLE(CSS_REGIONS)
965 case CSSPropertyWebkitRegionBreakAfter:
966 case CSSPropertyWebkitRegionBreakBefore:
967 case CSSPropertyWebkitRegionBreakInside:
968 case CSSPropertyWebkitRegionOverflow:
970 case CSSPropertyWebkitRtlOrdering:
971 case CSSPropertyWebkitTextCombine:
972 case CSSPropertyWebkitTextEmphasisPosition:
973 case CSSPropertyWebkitTextSecurity:
974 case CSSPropertyWebkitTextSizeAdjust:
975 case CSSPropertyWebkitTransformStyle:
976 case CSSPropertyWebkitUserDrag:
977 case CSSPropertyWebkitUserModify:
978 case CSSPropertyWebkitUserSelect:
979 #if ENABLE(CSS_EXCLUSIONS)
980 case CSSPropertyWebkitWrapFlow:
981 case CSSPropertyWebkitWrapThrough:
983 case CSSPropertyWebkitWritingMode:
984 case CSSPropertyWhiteSpace:
985 case CSSPropertyWordBreak:
986 case CSSPropertyWordWrap:
993 static bool parseKeywordValue(StylePropertySet* declaration, CSSPropertyID propertyId, const String& string, bool important, const CSSParserContext& parserContext)
995 ASSERT(!string.isEmpty());
997 if (!isKeywordPropertyID(propertyId))
1000 CSSParserString cssString;
1001 cssString.characters = const_cast<UChar*>(string.characters());
1002 cssString.length = string.length();
1003 int valueID = cssValueKeywordID(cssString);
1008 RefPtr<CSSValue> value;
1009 if (valueID == CSSValueInherit)
1010 value = cssValuePool().createInheritedValue();
1011 else if (valueID == CSSValueInitial)
1012 value = cssValuePool().createExplicitInitialValue();
1013 else if (isValidKeywordPropertyAndValue(propertyId, valueID, parserContext))
1014 value = cssValuePool().createIdentifierValue(valueID);
1018 declaration->addParsedProperty(CSSProperty(propertyId, value.release(), important));
1022 template <typename CharType>
1023 static bool parseTransformArguments(WebKitCSSTransformValue* transformValue, CharType* characters, unsigned length, unsigned start, unsigned expectedCount)
1025 while (expectedCount) {
1026 size_t end = WTF::find(characters, length, expectedCount == 1 ? ')' : ',', start);
1027 if (end == notFound || (expectedCount == 1 && end != length - 1))
1029 unsigned argumentLength = end - start;
1030 CSSPrimitiveValue::UnitTypes unit = CSSPrimitiveValue::CSS_NUMBER;
1032 if (!parseSimpleLength(characters + start, argumentLength, unit, number))
1034 if (unit != CSSPrimitiveValue::CSS_PX && (number || unit != CSSPrimitiveValue::CSS_NUMBER))
1036 transformValue->append(cssValuePool().createValue(number, unit));
1043 static bool parseTransformValue(StylePropertySet* properties, CSSPropertyID propertyID, const String& string, bool important)
1045 if (propertyID != CSSPropertyWebkitTransform)
1047 static const unsigned shortestValidTransformStringLength = 12;
1048 static const unsigned likelyMultipartTransformStringLengthCutoff = 32;
1049 if (string.length() < shortestValidTransformStringLength || string.length() > likelyMultipartTransformStringLengthCutoff)
1051 if (!string.startsWith("translate", false))
1053 UChar c9 = toASCIILower(string[9]);
1054 UChar c10 = toASCIILower(string[10]);
1056 WebKitCSSTransformValue::TransformOperationType transformType;
1057 unsigned expectedArgumentCount = 1;
1058 unsigned argumentStart = 11;
1059 if (c9 == 'x' && c10 == '(')
1060 transformType = WebKitCSSTransformValue::TranslateXTransformOperation;
1061 else if (c9 == 'y' && c10 == '(')
1062 transformType = WebKitCSSTransformValue::TranslateYTransformOperation;
1063 else if (c9 == 'z' && c10 == '(')
1064 transformType = WebKitCSSTransformValue::TranslateZTransformOperation;
1065 else if (c9 == '(') {
1066 transformType = WebKitCSSTransformValue::TranslateTransformOperation;
1067 expectedArgumentCount = 2;
1069 } else if (c9 == '3' && c10 == 'd' && string[11] == '(') {
1070 transformType = WebKitCSSTransformValue::Translate3DTransformOperation;
1071 expectedArgumentCount = 3;
1076 RefPtr<WebKitCSSTransformValue> transformValue = WebKitCSSTransformValue::create(transformType);
1078 if (string.is8Bit())
1079 success = parseTransformArguments(transformValue.get(), string.characters8(), string.length(), argumentStart, expectedArgumentCount);
1081 success = parseTransformArguments(transformValue.get(), string.characters16(), string.length(), argumentStart, expectedArgumentCount);
1084 RefPtr<CSSValueList> result = CSSValueList::createSpaceSeparated();
1085 result->append(transformValue.release());
1086 properties->addParsedProperty(CSSProperty(CSSPropertyWebkitTransform, result.release(), important));
1090 PassRefPtr<CSSValueList> CSSParser::parseFontFaceValue(const AtomicString& string)
1092 if (string.isEmpty())
1094 RefPtr<StylePropertySet> dummyStyle = StylePropertySet::create();
1095 if (!parseValue(dummyStyle.get(), CSSPropertyFontFamily, string, false, CSSQuirksMode, 0))
1097 return static_pointer_cast<CSSValueList>(dummyStyle->getPropertyCSSValue(CSSPropertyFontFamily));
1100 #if ENABLE(CSS_VARIABLES)
1101 bool CSSParser::parseValue(StylePropertySet* declaration, CSSPropertyID propertyID, const String& string, bool important, Document* document)
1103 ASSERT(!string.isEmpty());
1105 CSSParserContext context(document);
1107 if (parseSimpleLengthValue(declaration, propertyID, string, important, context.mode))
1109 if (parseColorValue(declaration, propertyID, string, important, context.mode))
1111 if (parseKeywordValue(declaration, propertyID, string, important, context))
1114 CSSParser parser(context);
1115 return parser.parseValue(declaration, propertyID, string, important, static_cast<StyleSheetContents*>(0));
1119 bool CSSParser::parseValue(StylePropertySet* declaration, CSSPropertyID propertyID, const String& string, bool important, CSSParserMode cssParserMode, StyleSheetContents* contextStyleSheet)
1121 ASSERT(!string.isEmpty());
1122 if (parseSimpleLengthValue(declaration, propertyID, string, important, cssParserMode))
1124 if (parseColorValue(declaration, propertyID, string, important, cssParserMode))
1126 if (parseKeywordValue(declaration, propertyID, string, important, contextStyleSheet->parserContext()))
1128 if (parseTransformValue(declaration, propertyID, string, important))
1131 CSSParserContext context(cssParserMode);
1132 if (contextStyleSheet) {
1133 context = contextStyleSheet->parserContext();
1134 context.mode = cssParserMode;
1136 CSSParser parser(context);
1137 return parser.parseValue(declaration, propertyID, string, important, contextStyleSheet);
1140 bool CSSParser::parseValue(StylePropertySet* declaration, CSSPropertyID propertyID, const String& string, bool important, StyleSheetContents* contextStyleSheet)
1142 setStyleSheet(contextStyleSheet);
1144 setupParser("@-webkit-value{", string, "} ");
1147 m_important = important;
1154 if (m_hasFontFaceOnlyValues)
1155 deleteFontFaceOnlyValues();
1156 if (!m_parsedProperties.isEmpty()) {
1158 declaration->addParsedProperties(m_parsedProperties);
1165 // The color will only be changed when string contains a valid CSS color, so callers
1166 // can set it to a default color and ignore the boolean result.
1167 bool CSSParser::parseColor(RGBA32& color, const String& string, bool strict)
1169 // First try creating a color specified by name, rgba(), rgb() or "#" syntax.
1170 if (fastParseColor(color, string, strict))
1173 CSSParser parser(CSSStrictMode);
1175 // In case the fast-path parser didn't understand the color, try the full parser.
1176 if (!parser.parseColor(string))
1179 CSSValue* value = parser.m_parsedProperties.first().value();
1180 if (!value->isPrimitiveValue())
1183 CSSPrimitiveValue* primitiveValue = static_cast<CSSPrimitiveValue*>(value);
1184 if (!primitiveValue->isRGBColor())
1187 color = primitiveValue->getRGBA32Value();
1191 bool CSSParser::parseColor(const String& string)
1193 setupParser("@-webkit-decls{color:", string, "} ");
1197 return !m_parsedProperties.isEmpty() && m_parsedProperties.first().id() == CSSPropertyColor;
1200 bool CSSParser::parseSystemColor(RGBA32& color, const String& string, Document* document)
1202 if (!document || !document->page())
1205 CSSParserString cssColor;
1206 cssColor.characters = const_cast<UChar*>(string.characters());
1207 cssColor.length = string.length();
1208 int id = cssValueKeywordID(cssColor);
1212 color = document->page()->theme()->systemColor(id).rgb();
1216 void CSSParser::parseSelector(const String& string, CSSSelectorList& selectorList)
1218 m_selectorListForParseSelector = &selectorList;
1220 setupParser("@-webkit-selector{", string, "}");
1224 m_selectorListForParseSelector = 0;
1227 bool CSSParser::parseDeclaration(StylePropertySet* declaration, const String& string, PassRefPtr<CSSRuleSourceData> prpRuleSourceData, StyleSheetContents* contextStyleSheet)
1229 // Length of the "@-webkit-decls{" prefix.
1230 static const unsigned prefixLength = 15;
1232 setStyleSheet(contextStyleSheet);
1234 RefPtr<CSSRuleSourceData> ruleSourceData = prpRuleSourceData;
1235 if (ruleSourceData) {
1236 m_currentRuleDataStack = adoptPtr(new RuleSourceDataList());
1237 m_currentRuleDataStack->append(ruleSourceData);
1240 setupParser("@-webkit-decls{", string, "} ");
1245 if (m_hasFontFaceOnlyValues)
1246 deleteFontFaceOnlyValues();
1247 if (!m_parsedProperties.isEmpty()) {
1249 declaration->addParsedProperties(m_parsedProperties);
1253 if (ruleSourceData) {
1254 ASSERT(m_currentRuleDataStack->size() == 1);
1255 ruleSourceData->ruleBodyRange.start = 0;
1256 ruleSourceData->ruleBodyRange.end = string.length();
1257 for (size_t i = 0, size = ruleSourceData->styleSourceData->propertyData.size(); i < size; ++i) {
1258 CSSPropertySourceData& propertyData = ruleSourceData->styleSourceData->propertyData.at(i);
1259 propertyData.range.start -= prefixLength;
1260 propertyData.range.end -= prefixLength;
1263 fixUnparsedPropertyRanges(ruleSourceData.get());
1264 m_currentRuleDataStack.clear();
1270 PassOwnPtr<MediaQuery> CSSParser::parseMediaQuery(const String& string)
1272 if (string.isEmpty())
1275 ASSERT(!m_mediaQuery);
1277 // can't use { because tokenizer state switches from mediaquery to initial state when it sees { token.
1278 // instead insert one " " (which is WHITESPACE in CSSGrammar.y)
1279 setupParser("@-webkit-mediaquery ", string, "} ");
1282 return m_mediaQuery.release();
1285 #if ENABLE(CSS_VARIABLES)
1286 static inline void filterProperties(bool important, const CSSParser::ParsedPropertyVector& input, Vector<CSSProperty, 256>& output, size_t& unusedEntries, BitArray<numCSSProperties>& seenProperties, HashSet<AtomicString>& seenVariables)
1288 static inline void filterProperties(bool important, const CSSParser::ParsedPropertyVector& input, Vector<CSSProperty, 256>& output, size_t& unusedEntries, BitArray<numCSSProperties>& seenProperties)
1291 // Add properties in reverse order so that highest priority definitions are reached first. Duplicate definitions can then be ignored when found.
1292 for (int i = input.size() - 1; i >= 0; --i) {
1293 const CSSProperty& property = input[i];
1294 if (property.isImportant() != important)
1296 #if ENABLE(CSS_VARIABLES)
1297 if (property.id() == CSSPropertyVariable) {
1298 const AtomicString& name = static_cast<CSSVariableValue*>(property.value())->name();
1299 if (seenVariables.contains(name))
1301 seenVariables.add(name);
1302 output[--unusedEntries] = property;
1306 const unsigned propertyIDIndex = property.id() - firstCSSProperty;
1307 if (seenProperties.get(propertyIDIndex))
1309 seenProperties.set(propertyIDIndex);
1310 output[--unusedEntries] = property;
1314 PassRefPtr<StylePropertySet> CSSParser::createStylePropertySet()
1316 BitArray<numCSSProperties> seenProperties;
1317 size_t unusedEntries = m_parsedProperties.size();
1318 Vector<CSSProperty, 256> results(unusedEntries);
1320 // Important properties have higher priority, so add them first. Duplicate definitions can then be ignored when found.
1321 #if ENABLE(CSS_VARIABLES)
1322 HashSet<AtomicString> seenVariables;
1323 filterProperties(true, m_parsedProperties, results, unusedEntries, seenProperties, seenVariables);
1324 filterProperties(false, m_parsedProperties, results, unusedEntries, seenProperties, seenVariables);
1326 filterProperties(true, m_parsedProperties, results, unusedEntries, seenProperties);
1327 filterProperties(false, m_parsedProperties, results, unusedEntries, seenProperties);
1330 results.remove(0, unusedEntries);
1332 return StylePropertySet::createImmutable(results.data(), results.size(), m_context.mode);
1335 void CSSParser::addProperty(CSSPropertyID propId, PassRefPtr<CSSValue> value, bool important, bool implicit)
1337 m_parsedProperties.append(CSSProperty(propId, value, important, m_currentShorthand, m_implicitShorthand || implicit));
1340 void CSSParser::rollbackLastProperties(int num)
1343 ASSERT(m_parsedProperties.size() >= static_cast<unsigned>(num));
1344 m_parsedProperties.shrink(m_parsedProperties.size() - num);
1347 void CSSParser::clearProperties()
1349 m_parsedProperties.clear();
1350 m_numParsedPropertiesBeforeMarginBox = INVALID_NUM_PARSED_PROPERTIES;
1351 m_hasFontFaceOnlyValues = false;
1354 void CSSParser::setStyleSheet(StyleSheetContents* styleSheet)
1356 m_styleSheet = styleSheet;
1359 KURL CSSParser::completeURL(const CSSParserContext& context, const String& url)
1363 if (context.charset.isEmpty())
1364 return KURL(context.baseURL, url);
1365 return KURL(context.baseURL, url, context.charset);
1368 KURL CSSParser::completeURL(const String& url) const
1370 return completeURL(m_context, url);
1373 bool CSSParser::validCalculationUnit(CSSParserValue* value, Units unitflags)
1375 bool mustBeNonNegative = unitflags & FNonNeg;
1377 if (!parseCalculation(value, mustBeNonNegative ? CalculationRangeNonNegative : CalculationRangeAll))
1381 switch (m_parsedCalculation->category()) {
1383 b = (unitflags & FLength);
1386 b = (unitflags & FPercent);
1387 if (b && mustBeNonNegative && m_parsedCalculation->isNegative())
1391 b = (unitflags & FNumber);
1392 if (!b && (unitflags & FInteger) && m_parsedCalculation->isInt())
1394 if (b && mustBeNonNegative && m_parsedCalculation->isNegative())
1397 case CalcPercentLength:
1398 b = (unitflags & FPercent) && (unitflags & FLength);
1400 case CalcPercentNumber:
1401 b = (unitflags & FPercent) && (unitflags & FNumber);
1407 m_parsedCalculation.release();
1411 inline bool CSSParser::shouldAcceptUnitLessValues(CSSParserValue* value, Units unitflags, CSSParserMode cssParserMode)
1413 // Qirks mode and svg presentation attributes accept unit less values.
1414 return (unitflags & (FLength | FAngle | FTime)) && (!value->fValue || cssParserMode == CSSQuirksMode || cssParserMode == SVGAttributeMode);
1417 bool CSSParser::validUnit(CSSParserValue* value, Units unitflags, CSSParserMode cssParserMode)
1419 if (isCalculation(value))
1420 return validCalculationUnit(value, unitflags);
1423 switch (value->unit) {
1424 #if ENABLE(CSS_VARIABLES)
1425 case CSSPrimitiveValue::CSS_VARIABLE_NAME:
1426 // Variables are checked at the point they are dereferenced because unit type is not available here.
1430 case CSSPrimitiveValue::CSS_NUMBER:
1431 b = (unitflags & FNumber);
1432 if (!b && shouldAcceptUnitLessValues(value, unitflags, cssParserMode)) {
1433 value->unit = (unitflags & FLength) ? CSSPrimitiveValue::CSS_PX :
1434 ((unitflags & FAngle) ? CSSPrimitiveValue::CSS_DEG : CSSPrimitiveValue::CSS_MS);
1437 if (!b && (unitflags & FInteger) && value->isInt)
1440 case CSSPrimitiveValue::CSS_PERCENTAGE:
1441 b = (unitflags & FPercent);
1443 case CSSParserValue::Q_EMS:
1444 case CSSPrimitiveValue::CSS_EMS:
1445 case CSSPrimitiveValue::CSS_REMS:
1446 case CSSPrimitiveValue::CSS_EXS:
1447 case CSSPrimitiveValue::CSS_PX:
1448 case CSSPrimitiveValue::CSS_CM:
1449 case CSSPrimitiveValue::CSS_MM:
1450 case CSSPrimitiveValue::CSS_IN:
1451 case CSSPrimitiveValue::CSS_PT:
1452 case CSSPrimitiveValue::CSS_PC:
1453 case CSSPrimitiveValue::CSS_VW:
1454 case CSSPrimitiveValue::CSS_VH:
1455 case CSSPrimitiveValue::CSS_VMIN:
1456 b = (unitflags & FLength);
1458 #if ENABLE(TIZEN_MEDIA_QUERY)
1459 case CSSPrimitiveValue::CSS_DPCM:
1460 b = (unitflags & FLength);
1461 value->unit = CSSPrimitiveValue::CSS_DPCM;
1464 case CSSPrimitiveValue::CSS_MS:
1465 case CSSPrimitiveValue::CSS_S:
1466 b = (unitflags & FTime);
1468 case CSSPrimitiveValue::CSS_DEG:
1469 case CSSPrimitiveValue::CSS_RAD:
1470 case CSSPrimitiveValue::CSS_GRAD:
1471 case CSSPrimitiveValue::CSS_TURN:
1472 b = (unitflags & FAngle);
1474 #if ENABLE(CSS_IMAGE_RESOLUTION)
1475 case CSSPrimitiveValue::CSS_DPPX:
1476 case CSSPrimitiveValue::CSS_DPI:
1477 case CSSPrimitiveValue::CSS_DPCM:
1478 b = (unitflags & FResolution);
1481 case CSSPrimitiveValue::CSS_HZ:
1482 case CSSPrimitiveValue::CSS_KHZ:
1483 case CSSPrimitiveValue::CSS_DIMENSION:
1487 if (b && unitflags & FNonNeg && value->fValue < 0)
1492 inline PassRefPtr<CSSPrimitiveValue> CSSParser::createPrimitiveNumericValue(CSSParserValue* value)
1494 #if ENABLE(CSS_VARIABLES)
1495 if (value->unit == CSSPrimitiveValue::CSS_VARIABLE_NAME)
1496 return CSSPrimitiveValue::create(value->string, CSSPrimitiveValue::CSS_VARIABLE_NAME);
1499 if (m_parsedCalculation) {
1500 ASSERT(isCalculation(value));
1501 return CSSPrimitiveValue::create(m_parsedCalculation.release());
1504 #if ENABLE(CSS_IMAGE_RESOLUTION)
1505 ASSERT((value->unit >= CSSPrimitiveValue::CSS_NUMBER && value->unit <= CSSPrimitiveValue::CSS_KHZ)
1506 || (value->unit >= CSSPrimitiveValue::CSS_TURN && value->unit <= CSSPrimitiveValue::CSS_REMS)
1507 || (value->unit >= CSSPrimitiveValue::CSS_VW && value->unit <= CSSPrimitiveValue::CSS_VMIN)
1508 || (value->unit >= CSSPrimitiveValue::CSS_DPPX && value->unit <= CSSPrimitiveValue::CSS_DPCM));
1510 ASSERT((value->unit >= CSSPrimitiveValue::CSS_NUMBER && value->unit <= CSSPrimitiveValue::CSS_KHZ)
1511 || (value->unit >= CSSPrimitiveValue::CSS_TURN && value->unit <= CSSPrimitiveValue::CSS_REMS)
1512 || (value->unit >= CSSPrimitiveValue::CSS_VW && value->unit <= CSSPrimitiveValue::CSS_VMIN));
1514 return cssValuePool().createValue(value->fValue, static_cast<CSSPrimitiveValue::UnitTypes>(value->unit));
1517 inline PassRefPtr<CSSPrimitiveValue> CSSParser::createPrimitiveStringValue(CSSParserValue* value)
1519 ASSERT(value->unit == CSSPrimitiveValue::CSS_STRING || value->unit == CSSPrimitiveValue::CSS_IDENT);
1520 return cssValuePool().createValue(value->string, CSSPrimitiveValue::CSS_STRING);
1523 static int unitFromString(CSSParserValue* value)
1525 if (value->unit != CSSPrimitiveValue::CSS_IDENT || value->id)
1528 if (equal(value->string, "em"))
1529 return CSSPrimitiveValue::CSS_EMS;
1530 if (equal(value->string, "rem"))
1531 return CSSPrimitiveValue::CSS_REMS;
1532 if (equal(value->string, "ex"))
1533 return CSSPrimitiveValue::CSS_EXS;
1534 if (equal(value->string, "px"))
1535 return CSSPrimitiveValue::CSS_PX;
1536 if (equal(value->string, "cm"))
1537 return CSSPrimitiveValue::CSS_CM;
1538 if (equal(value->string, "mm"))
1539 return CSSPrimitiveValue::CSS_MM;
1540 if (equal(value->string, "in"))
1541 return CSSPrimitiveValue::CSS_IN;
1542 if (equal(value->string, "pt"))
1543 return CSSPrimitiveValue::CSS_PT;
1544 if (equal(value->string, "pc"))
1545 return CSSPrimitiveValue::CSS_PC;
1546 if (equal(value->string, "deg"))
1547 return CSSPrimitiveValue::CSS_DEG;
1548 if (equal(value->string, "rad"))
1549 return CSSPrimitiveValue::CSS_RAD;
1550 if (equal(value->string, "grad"))
1551 return CSSPrimitiveValue::CSS_GRAD;
1552 if (equal(value->string, "turn"))
1553 return CSSPrimitiveValue::CSS_TURN;
1554 if (equal(value->string, "ms"))
1555 return CSSPrimitiveValue::CSS_MS;
1556 if (equal(value->string, "s"))
1557 return CSSPrimitiveValue::CSS_S;
1558 if (equal(value->string, "Hz"))
1559 return CSSPrimitiveValue::CSS_HZ;
1560 if (equal(value->string, "kHz"))
1561 return CSSPrimitiveValue::CSS_KHZ;
1562 if (equal(value->string, "vw"))
1563 return CSSPrimitiveValue::CSS_VW;
1564 if (equal(value->string, "vh"))
1565 return CSSPrimitiveValue::CSS_VH;
1566 if (equal(value->string, "vmin"))
1567 return CSSPrimitiveValue::CSS_VMIN;
1568 #if ENABLE(CSS_IMAGE_RESOLUTION)
1569 if (equal(value->string, "dppx"))
1570 return CSSPrimitiveValue::CSS_DPPX;
1571 if (equal(value->string, "dpi"))
1572 return CSSPrimitiveValue::CSS_DPI;
1573 if (equal(value->string, "dpcm"))
1574 return CSSPrimitiveValue::CSS_DPCM;
1580 static inline bool isComma(CSSParserValue* value)
1582 return value && value->unit == CSSParserValue::Operator && value->iValue == ',';
1585 bool CSSParser::validWidth(CSSParserValue* value)
1588 if (id == CSSValueIntrinsic || id == CSSValueMinIntrinsic || id == CSSValueWebkitMinContent || id == CSSValueWebkitMaxContent || id == CSSValueWebkitFillAvailable || id == CSSValueWebkitFitContent)
1590 return !id && validUnit(value, FLength | FPercent | FNonNeg);
1593 // FIXME: Combine this with validWidth when we support fit-content, et al, for heights.
1594 bool CSSParser::validHeight(CSSParserValue* value)
1597 if (id == CSSValueIntrinsic || id == CSSValueMinIntrinsic)
1599 return !id && validUnit(value, FLength | FPercent | FNonNeg);
1602 void CSSParser::checkForOrphanedUnits()
1604 if (inStrictMode() || inShorthand())
1607 // The purpose of this code is to implement the WinIE quirk that allows unit types to be separated from their numeric values
1608 // by whitespace, so e.g., width: 20 px instead of width:20px. This is invalid CSS, so we don't do this in strict mode.
1609 CSSParserValue* numericVal = 0;
1610 unsigned size = m_valueList->size();
1611 for (unsigned i = 0; i < size; i++) {
1612 CSSParserValue* value = m_valueList->valueAt(i);
1615 // Change the unit type of the numeric val to match.
1616 int unit = unitFromString(value);
1618 numericVal->unit = unit;
1621 // Now delete the bogus unit value.
1622 m_valueList->deleteValueAt(i);
1623 i--; // We're safe even though |i| is unsigned, since we only hit this code if we had a previous numeric value (so |i| is always > 0 here).
1629 numericVal = (value->unit == CSSPrimitiveValue::CSS_NUMBER) ? value : 0;
1633 inline PassRefPtr<CSSPrimitiveValue> CSSParser::parseValidPrimitive(int identifier, CSSParserValue* value)
1636 return cssValuePool().createIdentifierValue(identifier);
1637 if (value->unit == CSSPrimitiveValue::CSS_STRING)
1638 return createPrimitiveStringValue(value);
1639 if (value->unit >= CSSPrimitiveValue::CSS_NUMBER && value->unit <= CSSPrimitiveValue::CSS_KHZ)
1640 return createPrimitiveNumericValue(value);
1641 if (value->unit >= CSSPrimitiveValue::CSS_TURN && value->unit <= CSSPrimitiveValue::CSS_REMS)
1642 return createPrimitiveNumericValue(value);
1643 if (value->unit >= CSSPrimitiveValue::CSS_VW && value->unit <= CSSPrimitiveValue::CSS_VMIN)
1644 return createPrimitiveNumericValue(value);
1645 #if ENABLE(CSS_IMAGE_RESOLUTION)
1646 if (value->unit >= CSSPrimitiveValue::CSS_DPPX && value->unit <= CSSPrimitiveValue::CSS_DPCM)
1647 return createPrimitiveNumericValue(value);
1649 if (value->unit >= CSSParserValue::Q_EMS)
1650 return CSSPrimitiveValue::createAllowingMarginQuirk(value->fValue, CSSPrimitiveValue::CSS_EMS);
1651 if (isCalculation(value))
1652 return CSSPrimitiveValue::create(m_parsedCalculation.release());
1657 bool CSSParser::parseValue(CSSPropertyID propId, bool important)
1662 CSSParserValue* value = m_valueList->current();
1667 // Note: m_parsedCalculation is used to pass the calc value to validUnit and then cleared at the end of this function.
1668 // FIXME: This is to avoid having to pass parsedCalc to all validUnit callers.
1669 ASSERT(!m_parsedCalculation);
1673 // In quirks mode, we will look for units that have been incorrectly separated from the number they belong to
1674 // by a space. We go ahead and associate the unit with the number even though it is invalid CSS.
1675 checkForOrphanedUnits();
1677 int num = inShorthand() ? 1 : m_valueList->size();
1679 if (id == CSSValueInherit) {
1682 addProperty(propId, cssValuePool().createInheritedValue(), important);
1685 else if (id == CSSValueInitial) {
1688 addProperty(propId, cssValuePool().createExplicitInitialValue(), important);
1692 #if ENABLE(CSS_VARIABLES)
1693 if (!id && value->unit == CSSPrimitiveValue::CSS_VARIABLE_NAME && num == 1) {
1694 addProperty(propId, CSSPrimitiveValue::create(value->string, CSSPrimitiveValue::CSS_VARIABLE_NAME), important);
1695 m_valueList->next();
1698 ASSERT(propId != CSSPropertyVariable);
1701 if (isKeywordPropertyID(propId)) {
1702 if (!isValidKeywordPropertyAndValue(propId, id, m_context))
1704 if (m_valueList->next() && !inShorthand())
1706 addProperty(propId, cssValuePool().createIdentifierValue(id), important);
1710 bool validPrimitive = false;
1711 RefPtr<CSSValue> parsedValue;
1714 case CSSPropertySize: // <length>{1,2} | auto | [ <page-size> || [ portrait | landscape] ]
1715 return parseSize(propId, important);
1717 case CSSPropertyQuotes: // [<string> <string>]+ | none | inherit
1719 validPrimitive = true;
1721 return parseQuotes(propId, important);
1723 case CSSPropertyUnicodeBidi: // normal | embed | (bidi-override || isolate) | plaintext | inherit
1724 if (id == CSSValueNormal
1725 || id == CSSValueEmbed
1726 || id == CSSValueWebkitPlaintext)
1727 validPrimitive = true;
1729 RefPtr<CSSValueList> list = CSSValueList::createSpaceSeparated();
1730 bool isValid = true;
1731 while (isValid && value) {
1732 switch (value->id) {
1733 case CSSValueBidiOverride:
1734 case CSSValueWebkitIsolate:
1735 list->append(cssValuePool().createIdentifierValue(value->id));
1740 value = m_valueList->next();
1742 if (list->length() && isValid) {
1743 parsedValue = list.release();
1744 m_valueList->next();
1749 case CSSPropertyContent: // [ <string> | <uri> | <counter> | attr(X) | open-quote |
1750 // close-quote | no-open-quote | no-close-quote ]+ | inherit
1751 return parseContent(propId, important);
1753 case CSSPropertyClip: // <shape> | auto | inherit
1754 if (id == CSSValueAuto)
1755 validPrimitive = true;
1756 else if (value->unit == CSSParserValue::Function)
1757 return parseClipShape(propId, important);
1760 /* Start of supported CSS properties with validation. This is needed for parseShorthand to work
1761 * correctly and allows optimization in WebCore::applyRule(..)
1763 case CSSPropertyOverflow: {
1764 ShorthandScope scope(this, propId);
1765 if (num != 1 || !parseValue(CSSPropertyOverflowX, important))
1767 CSSValue* value = m_parsedProperties.last().value();
1768 addProperty(CSSPropertyOverflowY, value, important);
1772 case CSSPropertyTextAlign:
1773 // left | right | center | justify | -webkit-left | -webkit-right | -webkit-center | -webkit-match-parent
1774 // | start | end | <string> | inherit | -webkit-auto (converted to start)
1775 if ((id >= CSSValueWebkitAuto && id <= CSSValueWebkitMatchParent) || id == CSSValueStart || id == CSSValueEnd
1776 || value->unit == CSSPrimitiveValue::CSS_STRING)
1777 validPrimitive = true;
1780 case CSSPropertyFontWeight: { // normal | bold | bolder | lighter | 100 | 200 | 300 | 400 | 500 | 600 | 700 | 800 | 900 | inherit
1781 if (m_valueList->size() != 1)
1783 return parseFontWeight(important);
1785 case CSSPropertyBorderSpacing: {
1787 ShorthandScope scope(this, CSSPropertyBorderSpacing);
1788 if (!parseValue(CSSPropertyWebkitBorderHorizontalSpacing, important))
1790 CSSValue* value = m_parsedProperties.last().value();
1791 addProperty(CSSPropertyWebkitBorderVerticalSpacing, value, important);
1794 else if (num == 2) {
1795 ShorthandScope scope(this, CSSPropertyBorderSpacing);
1796 if (!parseValue(CSSPropertyWebkitBorderHorizontalSpacing, important) || !parseValue(CSSPropertyWebkitBorderVerticalSpacing, important))
1802 case CSSPropertyWebkitBorderHorizontalSpacing:
1803 case CSSPropertyWebkitBorderVerticalSpacing:
1804 validPrimitive = validUnit(value, FLength | FNonNeg);
1806 case CSSPropertyOutlineColor: // <color> | invert | inherit
1807 // Outline color has "invert" as additional keyword.
1808 // Also, we want to allow the special focus color even in strict parsing mode.
1809 if (id == CSSValueInvert || id == CSSValueWebkitFocusRingColor) {
1810 validPrimitive = true;
1814 case CSSPropertyBackgroundColor: // <color> | inherit
1815 case CSSPropertyBorderTopColor: // <color> | inherit
1816 case CSSPropertyBorderRightColor:
1817 case CSSPropertyBorderBottomColor:
1818 case CSSPropertyBorderLeftColor:
1819 case CSSPropertyWebkitBorderStartColor:
1820 case CSSPropertyWebkitBorderEndColor:
1821 case CSSPropertyWebkitBorderBeforeColor:
1822 case CSSPropertyWebkitBorderAfterColor:
1823 case CSSPropertyColor: // <color> | inherit
1824 case CSSPropertyTextLineThroughColor: // CSS3 text decoration colors
1825 case CSSPropertyTextUnderlineColor:
1826 case CSSPropertyTextOverlineColor:
1827 case CSSPropertyWebkitColumnRuleColor:
1828 case CSSPropertyWebkitTextEmphasisColor:
1829 case CSSPropertyWebkitTextFillColor:
1830 case CSSPropertyWebkitTextStrokeColor:
1831 if (id == CSSValueWebkitText)
1832 validPrimitive = true; // Always allow this, even when strict parsing is on,
1833 // since we use this in our UA sheets.
1834 else if (id == CSSValueCurrentcolor)
1835 validPrimitive = true;
1836 else if ((id >= CSSValueAqua && id <= CSSValueWindowtext) || id == CSSValueMenu ||
1837 (id >= CSSValueWebkitFocusRingColor && id < CSSValueWebkitText && inQuirksMode())) {
1838 validPrimitive = true;
1840 parsedValue = parseColor();
1842 m_valueList->next();
1846 #if ENABLE(TIZEN_CSS3_TEXT)
1847 case CSSPropertyWebkitTextAlignLast:
1848 // auto | start | end | left | right | center | justify
1849 if ((id >= CSSValueLeft && id <= CSSValueJustify) || id == CSSValueStart || id == CSSValueEnd || id == CSSValueAuto)
1850 validPrimitive = true;
1852 #endif // TIZEN_CSS3_TEXT
1854 case CSSPropertyCursor: {
1855 // [<uri>,]* [ auto | crosshair | default | pointer | progress | move | e-resize | ne-resize |
1856 // nw-resize | n-resize | se-resize | sw-resize | s-resize | w-resize | ew-resize |
1857 // ns-resize | nesw-resize | nwse-resize | col-resize | row-resize | text | wait | help |
1858 // vertical-text | cell | context-menu | alias | copy | no-drop | not-allowed | -webkit-zoom-in
1859 // -webkit-zoom-out | all-scroll | -webkit-grab | -webkit-grabbing ] ] | inherit
1860 RefPtr<CSSValueList> list;
1861 while (value && value->unit == CSSPrimitiveValue::CSS_URI) {
1863 list = CSSValueList::createCommaSeparated();
1864 String uri = value->string;
1866 value = m_valueList->next();
1867 while (value && value->unit == CSSPrimitiveValue::CSS_NUMBER) {
1868 coords.append(int(value->fValue));
1869 value = m_valueList->next();
1871 IntPoint hotSpot(-1, -1);
1872 int nrcoords = coords.size();
1873 if (nrcoords > 0 && nrcoords != 2)
1876 hotSpot = IntPoint(coords[0], coords[1]);
1879 list->append(CSSCursorImageValue::create(completeURL(uri), hotSpot));
1881 if ((inStrictMode() && !value) || (value && !(value->unit == CSSParserValue::Operator && value->iValue == ',')))
1883 value = m_valueList->next(); // comma
1886 if (!value) { // no value after url list (MSIE 5 compatibility)
1887 if (list->length() != 1)
1889 } else if (inQuirksMode() && value->id == CSSValueHand) // MSIE 5 compatibility :/
1890 list->append(cssValuePool().createIdentifierValue(CSSValuePointer));
1891 else if ((value->id >= CSSValueAuto && value->id <= CSSValueWebkitGrabbing) || value->id == CSSValueCopy || value->id == CSSValueNone)
1892 list->append(cssValuePool().createIdentifierValue(value->id));
1893 m_valueList->next();
1894 parsedValue = list.release();
1898 if (inQuirksMode() && value->id == CSSValueHand) { // MSIE 5 compatibility :/
1899 id = CSSValuePointer;
1900 validPrimitive = true;
1901 } else if ((value->id >= CSSValueAuto && value->id <= CSSValueWebkitGrabbing) || value->id == CSSValueCopy || value->id == CSSValueNone)
1902 validPrimitive = true;
1904 ASSERT_NOT_REACHED();
1910 case CSSPropertyBackgroundAttachment:
1911 case CSSPropertyBackgroundClip:
1912 case CSSPropertyWebkitBackgroundClip:
1913 case CSSPropertyWebkitBackgroundComposite:
1914 case CSSPropertyBackgroundImage:
1915 case CSSPropertyBackgroundOrigin:
1916 case CSSPropertyWebkitBackgroundOrigin:
1917 case CSSPropertyBackgroundPosition:
1918 case CSSPropertyBackgroundPositionX:
1919 case CSSPropertyBackgroundPositionY:
1920 case CSSPropertyBackgroundSize:
1921 case CSSPropertyWebkitBackgroundSize:
1922 case CSSPropertyBackgroundRepeat:
1923 case CSSPropertyBackgroundRepeatX:
1924 case CSSPropertyBackgroundRepeatY:
1925 case CSSPropertyWebkitMaskAttachment:
1926 case CSSPropertyWebkitMaskClip:
1927 case CSSPropertyWebkitMaskComposite:
1928 case CSSPropertyWebkitMaskImage:
1929 case CSSPropertyWebkitMaskOrigin:
1930 case CSSPropertyWebkitMaskPosition:
1931 case CSSPropertyWebkitMaskPositionX:
1932 case CSSPropertyWebkitMaskPositionY:
1933 case CSSPropertyWebkitMaskSize:
1934 case CSSPropertyWebkitMaskRepeat:
1935 case CSSPropertyWebkitMaskRepeatX:
1936 case CSSPropertyWebkitMaskRepeatY: {
1937 RefPtr<CSSValue> val1;
1938 RefPtr<CSSValue> val2;
1939 CSSPropertyID propId1, propId2;
1940 bool result = false;
1941 if (parseFillProperty(propId, propId1, propId2, val1, val2)) {
1942 OwnPtr<ShorthandScope> shorthandScope;
1943 if (propId == CSSPropertyBackgroundPosition ||
1944 propId == CSSPropertyBackgroundRepeat ||
1945 propId == CSSPropertyWebkitMaskPosition ||
1946 propId == CSSPropertyWebkitMaskRepeat) {
1947 shorthandScope = adoptPtr(new ShorthandScope(this, propId));
1949 addProperty(propId1, val1.release(), important);
1951 addProperty(propId2, val2.release(), important);
1954 m_implicitShorthand = false;
1957 case CSSPropertyListStyleImage: // <uri> | none | inherit
1958 case CSSPropertyBorderImageSource:
1959 case CSSPropertyWebkitMaskBoxImageSource:
1960 if (id == CSSValueNone) {
1961 parsedValue = cssValuePool().createIdentifierValue(CSSValueNone);
1962 m_valueList->next();
1963 } else if (value->unit == CSSPrimitiveValue::CSS_URI) {
1964 parsedValue = CSSImageValue::create(completeURL(value->string));
1965 m_valueList->next();
1966 } else if (isGeneratedImageValue(value)) {
1967 if (parseGeneratedImage(m_valueList.get(), parsedValue))
1968 m_valueList->next();
1972 #if ENABLE(CSS_IMAGE_SET)
1973 else if (value->unit == CSSParserValue::Function && equalIgnoringCase(value->function->name, "-webkit-image-set(")) {
1974 parsedValue = parseImageSet(m_valueList.get());
1977 m_valueList->next();
1982 case CSSPropertyWebkitTextStrokeWidth:
1983 case CSSPropertyOutlineWidth: // <border-width> | inherit
1984 case CSSPropertyBorderTopWidth: //// <border-width> | inherit
1985 case CSSPropertyBorderRightWidth: // Which is defined as
1986 case CSSPropertyBorderBottomWidth: // thin | medium | thick | <length>
1987 case CSSPropertyBorderLeftWidth:
1988 case CSSPropertyWebkitBorderStartWidth:
1989 case CSSPropertyWebkitBorderEndWidth:
1990 case CSSPropertyWebkitBorderBeforeWidth:
1991 case CSSPropertyWebkitBorderAfterWidth:
1992 case CSSPropertyWebkitColumnRuleWidth:
1993 if (id == CSSValueThin || id == CSSValueMedium || id == CSSValueThick)
1994 validPrimitive = true;
1996 validPrimitive = validUnit(value, FLength | FNonNeg);
1999 case CSSPropertyLetterSpacing: // normal | <length> | inherit
2000 case CSSPropertyWordSpacing: // normal | <length> | inherit
2001 if (id == CSSValueNormal)
2002 validPrimitive = true;
2004 validPrimitive = validUnit(value, FLength);
2007 case CSSPropertyTextIndent: // <length> | <percentage> | inherit
2008 validPrimitive = (!id && validUnit(value, FLength | FPercent));
2011 case CSSPropertyPaddingTop: //// <padding-width> | inherit
2012 case CSSPropertyPaddingRight: // Which is defined as
2013 case CSSPropertyPaddingBottom: // <length> | <percentage>
2014 case CSSPropertyPaddingLeft: ////
2015 case CSSPropertyWebkitPaddingStart:
2016 case CSSPropertyWebkitPaddingEnd:
2017 case CSSPropertyWebkitPaddingBefore:
2018 case CSSPropertyWebkitPaddingAfter:
2019 validPrimitive = (!id && validUnit(value, FLength | FPercent | FNonNeg));
2022 case CSSPropertyMaxWidth:
2023 case CSSPropertyWebkitMaxLogicalWidth:
2024 validPrimitive = (id == CSSValueNone || validWidth(value));
2027 case CSSPropertyMinWidth:
2028 case CSSPropertyWebkitMinLogicalWidth:
2029 case CSSPropertyWidth:
2030 case CSSPropertyWebkitLogicalWidth:
2031 validPrimitive = (id == CSSValueAuto || validWidth(value));
2034 case CSSPropertyMaxHeight:
2035 case CSSPropertyWebkitMaxLogicalHeight:
2036 validPrimitive = (id == CSSValueNone || validHeight(value));
2039 case CSSPropertyMinHeight:
2040 case CSSPropertyWebkitMinLogicalHeight:
2041 case CSSPropertyHeight:
2042 case CSSPropertyWebkitLogicalHeight:
2043 validPrimitive = (id == CSSValueAuto || validHeight(value));
2046 case CSSPropertyFontSize:
2047 return parseFontSize(important);
2049 case CSSPropertyFontVariant: // normal | small-caps | inherit
2050 return parseFontVariant(important);
2052 case CSSPropertyVerticalAlign:
2053 // baseline | sub | super | top | text-top | middle | bottom | text-bottom |
2054 // <percentage> | <length> | inherit
2056 if (id >= CSSValueBaseline && id <= CSSValueWebkitBaselineMiddle)
2057 validPrimitive = true;
2059 validPrimitive = (!id && validUnit(value, FLength | FPercent));
2062 case CSSPropertyBottom: // <length> | <percentage> | auto | inherit
2063 case CSSPropertyLeft: // <length> | <percentage> | auto | inherit
2064 case CSSPropertyRight: // <length> | <percentage> | auto | inherit
2065 case CSSPropertyTop: // <length> | <percentage> | auto | inherit
2066 case CSSPropertyMarginTop: //// <margin-width> | inherit
2067 case CSSPropertyMarginRight: // Which is defined as
2068 case CSSPropertyMarginBottom: // <length> | <percentage> | auto | inherit
2069 case CSSPropertyMarginLeft: ////
2070 case CSSPropertyWebkitMarginStart:
2071 case CSSPropertyWebkitMarginEnd:
2072 case CSSPropertyWebkitMarginBefore:
2073 case CSSPropertyWebkitMarginAfter:
2074 if (id == CSSValueAuto)
2075 validPrimitive = true;
2077 validPrimitive = (!id && validUnit(value, FLength | FPercent));
2080 case CSSPropertyZIndex: // auto | <integer> | inherit
2081 if (id == CSSValueAuto) {
2082 validPrimitive = true;
2086 case CSSPropertyOrphans: // <integer> | inherit
2087 case CSSPropertyWidows: // <integer> | inherit
2088 // ### not supported later on
2089 validPrimitive = (!id && validUnit(value, FInteger, CSSQuirksMode));
2092 case CSSPropertyLineHeight:
2093 return parseLineHeight(important);
2094 case CSSPropertyCounterIncrement: // [ <identifier> <integer>? ]+ | none | inherit
2095 if (id != CSSValueNone)
2096 return parseCounter(propId, 1, important);
2097 validPrimitive = true;
2099 case CSSPropertyCounterReset: // [ <identifier> <integer>? ]+ | none | inherit
2100 if (id != CSSValueNone)
2101 return parseCounter(propId, 0, important);
2102 validPrimitive = true;
2104 case CSSPropertyFontFamily:
2105 // [[ <family-name> | <generic-family> ],]* [<family-name> | <generic-family>] | inherit
2107 parsedValue = parseFontFamily();
2111 case CSSPropertyTextDecoration:
2112 case CSSPropertyWebkitTextDecorationsInEffect:
2113 // none | [ underline || overline || line-through || blink ] | inherit
2114 if (id == CSSValueNone) {
2115 validPrimitive = true;
2117 RefPtr<CSSValueList> list = CSSValueList::createSpaceSeparated();
2118 bool isValid = true;
2119 while (isValid && value) {
2120 switch (value->id) {
2123 case CSSValueUnderline:
2124 case CSSValueOverline:
2125 case CSSValueLineThrough:
2126 list->append(cssValuePool().createIdentifierValue(value->id));
2131 value = m_valueList->next();
2133 if (list->length() && isValid) {
2134 parsedValue = list.release();
2135 m_valueList->next();
2140 case CSSPropertyZoom: // normal | reset | document | <number> | <percentage> | inherit
2141 if (id == CSSValueNormal || id == CSSValueReset || id == CSSValueDocument)
2142 validPrimitive = true;
2144 validPrimitive = (!id && validUnit(value, FNumber | FPercent | FNonNeg, CSSStrictMode));
2147 case CSSPropertySrc: // Only used within @font-face, so cannot use inherit | initial or be !important. This is a list of urls or local references.
2148 return parseFontFaceSrc();
2150 case CSSPropertyUnicodeRange:
2151 return parseFontFaceUnicodeRange();
2153 /* CSS3 properties */
2155 case CSSPropertyBorderImage: {
2156 RefPtr<CSSValue> result;
2157 return parseBorderImage(propId, result, important);
2159 case CSSPropertyWebkitBorderImage:
2160 case CSSPropertyWebkitMaskBoxImage: {
2161 RefPtr<CSSValue> result;
2162 if (parseBorderImage(propId, result)) {
2163 addProperty(propId, result, important);
2168 case CSSPropertyBorderImageOutset:
2169 case CSSPropertyWebkitMaskBoxImageOutset: {
2170 RefPtr<CSSPrimitiveValue> result;
2171 if (parseBorderImageOutset(result)) {
2172 addProperty(propId, result, important);
2177 case CSSPropertyBorderImageRepeat:
2178 case CSSPropertyWebkitMaskBoxImageRepeat: {
2179 RefPtr<CSSValue> result;
2180 if (parseBorderImageRepeat(result)) {
2181 addProperty(propId, result, important);
2186 case CSSPropertyBorderImageSlice:
2187 case CSSPropertyWebkitMaskBoxImageSlice: {
2188 RefPtr<CSSBorderImageSliceValue> result;
2189 if (parseBorderImageSlice(propId, result)) {
2190 addProperty(propId, result, important);
2195 case CSSPropertyBorderImageWidth:
2196 case CSSPropertyWebkitMaskBoxImageWidth: {
2197 RefPtr<CSSPrimitiveValue> result;
2198 if (parseBorderImageWidth(result)) {
2199 addProperty(propId, result, important);
2204 case CSSPropertyBorderTopRightRadius:
2205 case CSSPropertyBorderTopLeftRadius:
2206 case CSSPropertyBorderBottomLeftRadius:
2207 case CSSPropertyBorderBottomRightRadius: {
2208 if (num != 1 && num != 2)
2210 validPrimitive = validUnit(value, FLength | FPercent | FNonNeg);
2211 if (!validPrimitive)
2213 RefPtr<CSSPrimitiveValue> parsedValue1 = createPrimitiveNumericValue(value);
2214 RefPtr<CSSPrimitiveValue> parsedValue2;
2216 value = m_valueList->next();
2217 validPrimitive = validUnit(value, FLength | FPercent | FNonNeg);
2218 if (!validPrimitive)
2220 parsedValue2 = createPrimitiveNumericValue(value);
2222 parsedValue2 = parsedValue1;
2224 RefPtr<Pair> pair = Pair::create(parsedValue1.release(), parsedValue2.release());
2225 RefPtr<CSSPrimitiveValue> val = cssValuePool().createValue(pair.release());
2226 addProperty(propId, val.release(), important);
2229 case CSSPropertyTabSize:
2230 validPrimitive = validUnit(value, FInteger | FNonNeg);
2232 case CSSPropertyWebkitAspectRatio:
2233 return parseAspectRatio(important);
2234 case CSSPropertyBorderRadius:
2235 case CSSPropertyWebkitBorderRadius:
2236 return parseBorderRadius(propId, important);
2237 case CSSPropertyOutlineOffset:
2238 validPrimitive = validUnit(value, FLength | FPercent);
2240 case CSSPropertyTextShadow: // CSS2 property, dropped in CSS2.1, back in CSS3, so treat as CSS3
2241 case CSSPropertyBoxShadow:
2242 case CSSPropertyWebkitBoxShadow:
2243 if (id == CSSValueNone)
2244 validPrimitive = true;
2246 RefPtr<CSSValueList> shadowValueList = parseShadow(m_valueList.get(), propId);
2247 if (shadowValueList) {
2248 addProperty(propId, shadowValueList.release(), important);
2249 m_valueList->next();
2255 case CSSPropertyWebkitBoxReflect:
2256 if (id == CSSValueNone)
2257 validPrimitive = true;
2259 return parseReflect(propId, important);
2261 case CSSPropertyOpacity:
2262 validPrimitive = validUnit(value, FNumber);
2264 case CSSPropertyWebkitBoxFlex:
2265 validPrimitive = validUnit(value, FNumber);
2267 case CSSPropertyWebkitBoxFlexGroup:
2268 validPrimitive = validUnit(value, FInteger | FNonNeg, CSSStrictMode);
2270 case CSSPropertyWebkitBoxOrdinalGroup:
2271 validPrimitive = validUnit(value, FInteger | FNonNeg, CSSStrictMode) && value->fValue;
2273 #if ENABLE(CSS_FILTERS)
2274 case CSSPropertyWebkitFilter:
2275 if (id == CSSValueNone)
2276 validPrimitive = true;
2278 RefPtr<CSSValue> val = parseFilter();
2280 addProperty(propId, val, important);
2287 #if ENABLE(CSS3_FLEXBOX)
2288 case CSSPropertyWebkitFlex: {
2289 ShorthandScope scope(this, propId);
2290 if (id == CSSValueNone) {
2291 addProperty(CSSPropertyWebkitFlexGrow, cssValuePool().createValue(0, CSSPrimitiveValue::CSS_NUMBER), important);
2292 addProperty(CSSPropertyWebkitFlexShrink, cssValuePool().createValue(0, CSSPrimitiveValue::CSS_NUMBER), important);
2293 addProperty(CSSPropertyWebkitFlexBasis, cssValuePool().createIdentifierValue(CSSValueAuto), important);
2296 return parseFlex(m_valueList.get(), important);
2298 case CSSPropertyWebkitFlexBasis:
2299 // FIXME: Support intrinsic dimensions too.
2300 if (id == CSSValueAuto)
2301 validPrimitive = true;
2303 validPrimitive = (!id && validUnit(value, FLength | FPercent | FNonNeg));
2305 case CSSPropertyWebkitFlexGrow:
2306 case CSSPropertyWebkitFlexShrink:
2307 validPrimitive = validUnit(value, FNumber | FNonNeg);
2309 case CSSPropertyWebkitOrder:
2310 validPrimitive = validUnit(value, FNumber);
2313 case CSSPropertyWebkitMarquee:
2314 return parseShorthand(propId, webkitMarqueeShorthand(), important);
2315 case CSSPropertyWebkitMarqueeIncrement:
2316 if (id == CSSValueSmall || id == CSSValueLarge || id == CSSValueMedium)
2317 validPrimitive = true;
2319 validPrimitive = validUnit(value, FLength | FPercent);
2321 case CSSPropertyWebkitMarqueeRepetition:
2322 if (id == CSSValueInfinite)
2323 validPrimitive = true;
2325 validPrimitive = validUnit(value, FInteger | FNonNeg);
2327 case CSSPropertyWebkitMarqueeSpeed:
2328 if (id == CSSValueNormal || id == CSSValueSlow || id == CSSValueFast)
2329 validPrimitive = true;
2331 validPrimitive = validUnit(value, FTime | FInteger | FNonNeg);
2333 #if ENABLE(CSS_REGIONS)
2334 case CSSPropertyWebkitFlowInto:
2335 if (!cssRegionsEnabled())
2337 return parseFlowThread(propId, important);
2338 case CSSPropertyWebkitFlowFrom:
2339 if (!cssRegionsEnabled())
2341 return parseRegionThread(propId, important);
2343 case CSSPropertyWebkitTransform:
2344 if (id == CSSValueNone)
2345 validPrimitive = true;
2347 PassRefPtr<CSSValue> val = parseTransform();
2349 addProperty(propId, val, important);
2355 case CSSPropertyWebkitTransformOrigin:
2356 case CSSPropertyWebkitTransformOriginX:
2357 case CSSPropertyWebkitTransformOriginY:
2358 case CSSPropertyWebkitTransformOriginZ: {
2359 RefPtr<CSSValue> val1;
2360 RefPtr<CSSValue> val2;
2361 RefPtr<CSSValue> val3;
2362 CSSPropertyID propId1, propId2, propId3;
2363 if (parseTransformOrigin(propId, propId1, propId2, propId3, val1, val2, val3)) {
2364 addProperty(propId1, val1.release(), important);
2366 addProperty(propId2, val2.release(), important);
2368 addProperty(propId3, val3.release(), important);
2373 case CSSPropertyWebkitPerspective:
2374 if (id == CSSValueNone)
2375 validPrimitive = true;
2377 // Accepting valueless numbers is a quirk of the -webkit prefixed version of the property.
2378 if (validUnit(value, FNumber | FLength | FNonNeg)) {
2379 RefPtr<CSSValue> val = createPrimitiveNumericValue(value);
2381 addProperty(propId, val.release(), important);
2388 case CSSPropertyWebkitPerspectiveOrigin:
2389 case CSSPropertyWebkitPerspectiveOriginX:
2390 case CSSPropertyWebkitPerspectiveOriginY: {
2391 RefPtr<CSSValue> val1;
2392 RefPtr<CSSValue> val2;
2393 CSSPropertyID propId1, propId2;
2394 if (parsePerspectiveOrigin(propId, propId1, propId2, val1, val2)) {
2395 addProperty(propId1, val1.release(), important);
2397 addProperty(propId2, val2.release(), important);
2402 case CSSPropertyWebkitAnimationDelay:
2403 case CSSPropertyWebkitAnimationDirection:
2404 case CSSPropertyWebkitAnimationDuration:
2405 case CSSPropertyWebkitAnimationFillMode:
2406 case CSSPropertyWebkitAnimationName:
2407 case CSSPropertyWebkitAnimationPlayState:
2408 case CSSPropertyWebkitAnimationIterationCount:
2409 case CSSPropertyWebkitAnimationTimingFunction:
2410 case CSSPropertyWebkitTransitionDelay:
2411 case CSSPropertyWebkitTransitionDuration:
2412 case CSSPropertyWebkitTransitionTimingFunction:
2413 case CSSPropertyWebkitTransitionProperty: {
2414 RefPtr<CSSValue> val;
2415 if (parseAnimationProperty(propId, val)) {
2416 addProperty(propId, val.release(), important);
2422 case CSSPropertyWebkitGridColumns:
2423 case CSSPropertyWebkitGridRows:
2424 if (!cssGridLayoutEnabled())
2426 return parseGridTrackList(propId, important);
2428 case CSSPropertyWebkitGridColumn:
2429 case CSSPropertyWebkitGridRow:
2430 if (!cssGridLayoutEnabled())
2432 validPrimitive = id == CSSValueAuto || validUnit(value, FInteger);
2435 case CSSPropertyWebkitMarginCollapse: {
2437 ShorthandScope scope(this, CSSPropertyWebkitMarginCollapse);
2438 if (!parseValue(webkitMarginCollapseShorthand().properties()[0], important))
2440 CSSValue* value = m_parsedProperties.last().value();
2441 addProperty(webkitMarginCollapseShorthand().properties()[1], value, important);
2444 else if (num == 2) {
2445 ShorthandScope scope(this, CSSPropertyWebkitMarginCollapse);
2446 if (!parseValue(webkitMarginCollapseShorthand().properties()[0], important) || !parseValue(webkitMarginCollapseShorthand().properties()[1], important))
2452 case CSSPropertyTextLineThroughWidth:
2453 case CSSPropertyTextOverlineWidth:
2454 case CSSPropertyTextUnderlineWidth:
2455 if (id == CSSValueAuto || id == CSSValueNormal || id == CSSValueThin ||
2456 id == CSSValueMedium || id == CSSValueThick)
2457 validPrimitive = true;
2459 validPrimitive = !id && validUnit(value, FNumber | FLength | FPercent);
2461 case CSSPropertyWebkitColumnCount:
2462 if (id == CSSValueAuto)
2463 validPrimitive = true;
2465 validPrimitive = !id && validUnit(value, FInteger | FNonNeg, CSSQuirksMode);
2467 case CSSPropertyWebkitColumnGap: // normal | <length>
2468 if (id == CSSValueNormal)
2469 validPrimitive = true;
2471 validPrimitive = validUnit(value, FLength | FNonNeg);
2473 case CSSPropertyWebkitColumnAxis:
2474 if (id == CSSValueHorizontal || id == CSSValueVertical || id == CSSValueAuto)
2475 validPrimitive = true;
2477 case CSSPropertyWebkitColumnProgression:
2478 if (id == CSSValueNormal || id == CSSValueReverse)
2479 validPrimitive = true;
2481 case CSSPropertyWebkitColumnSpan: // none | all | 1 (will be dropped in the unprefixed property)
2482 if (id == CSSValueAll || id == CSSValueNone)
2483 validPrimitive = true;
2485 validPrimitive = validUnit(value, FNumber | FNonNeg) && value->fValue == 1;
2487 case CSSPropertyWebkitColumnWidth: // auto | <length>
2488 if (id == CSSValueAuto)
2489 validPrimitive = true;
2490 else // Always parse this property in strict mode, since it would be ambiguous otherwise when used in the 'columns' shorthand property.
2491 validPrimitive = validUnit(value, FLength, CSSStrictMode);
2493 // End of CSS3 properties
2495 // Apple specific properties. These will never be standardized and are purely to
2496 // support custom WebKit-based Apple applications.
2497 case CSSPropertyWebkitLineClamp:
2498 // When specifying number of lines, don't allow 0 as a valid value
2499 // When specifying either type of unit, require non-negative integers
2500 validPrimitive = (!id && (value->unit == CSSPrimitiveValue::CSS_PERCENTAGE || value->fValue) && validUnit(value, FInteger | FPercent | FNonNeg, CSSQuirksMode));
2503 case CSSPropertyWebkitFontSizeDelta: // <length>
2504 validPrimitive = validUnit(value, FLength);
2507 case CSSPropertyWebkitHighlight:
2508 if (id == CSSValueNone || value->unit == CSSPrimitiveValue::CSS_STRING)
2509 validPrimitive = true;
2512 case CSSPropertyWebkitHyphenateCharacter:
2513 if (id == CSSValueAuto || value->unit == CSSPrimitiveValue::CSS_STRING)
2514 validPrimitive = true;
2517 case CSSPropertyWebkitHyphenateLimitBefore:
2518 case CSSPropertyWebkitHyphenateLimitAfter:
2519 if (id == CSSValueAuto || validUnit(value, FInteger | FNonNeg, CSSStrictMode))
2520 validPrimitive = true;
2523 case CSSPropertyWebkitHyphenateLimitLines:
2524 if (id == CSSValueNoLimit || validUnit(value, FInteger | FNonNeg, CSSStrictMode))
2525 validPrimitive = true;
2528 case CSSPropertyWebkitLineGrid:
2529 if (id == CSSValueNone)
2530 validPrimitive = true;
2531 else if (value->unit == CSSPrimitiveValue::CSS_IDENT) {
2532 String lineGridValue = String(value->string);
2533 if (!lineGridValue.isEmpty()) {
2534 addProperty(propId, cssValuePool().createValue(lineGridValue, CSSPrimitiveValue::CSS_STRING), important);
2539 case CSSPropertyWebkitLocale:
2540 if (id == CSSValueAuto || value->unit == CSSPrimitiveValue::CSS_STRING)
2541 validPrimitive = true;
2544 #if ENABLE(DASHBOARD_SUPPORT)
2545 case CSSPropertyWebkitDashboardRegion: // <dashboard-region> | <dashboard-region>
2546 if (value->unit == CSSParserValue::Function || id == CSSValueNone)
2547 return parseDashboardRegions(propId, important);
2550 // End Apple-specific properties
2552 #if ENABLE(TOUCH_EVENTS)
2553 case CSSPropertyWebkitTapHighlightColor:
2554 if ((id >= CSSValueAqua && id <= CSSValueWindowtext) || id == CSSValueMenu
2555 || (id >= CSSValueWebkitFocusRingColor && id < CSSValueWebkitText && inQuirksMode())) {
2556 validPrimitive = true;
2558 parsedValue = parseColor();
2560 m_valueList->next();
2565 /* shorthand properties */
2566 case CSSPropertyBackground: {
2567 // Position must come before color in this array because a plain old "0" is a legal color
2568 // in quirks mode but it's usually the X coordinate of a position.
2569 const CSSPropertyID properties[] = { CSSPropertyBackgroundImage, CSSPropertyBackgroundRepeat,
2570 CSSPropertyBackgroundAttachment, CSSPropertyBackgroundPosition, CSSPropertyBackgroundOrigin,
2571 CSSPropertyBackgroundClip, CSSPropertyBackgroundColor, CSSPropertyBackgroundSize };
2572 return parseFillShorthand(propId, properties, WTF_ARRAY_LENGTH(properties), important);
2574 case CSSPropertyWebkitMask: {
2575 const CSSPropertyID properties[] = { CSSPropertyWebkitMaskImage, CSSPropertyWebkitMaskRepeat,
2576 CSSPropertyWebkitMaskAttachment, CSSPropertyWebkitMaskPosition,
2577 CSSPropertyWebkitMaskOrigin, CSSPropertyWebkitMaskClip };
2578 return parseFillShorthand(propId, properties, 6, important);
2580 case CSSPropertyBorder:
2581 // [ 'border-width' || 'border-style' || <color> ] | inherit
2583 if (parseShorthand(propId, borderAbridgedShorthand(), important)) {
2584 // The CSS3 Borders and Backgrounds specification says that border also resets border-image. It's as
2585 // though a value of none was specified for the image.
2586 addProperty(CSSPropertyBorderImage, cssValuePool().createImplicitInitialValue(), important);
2591 case CSSPropertyBorderTop:
2592 // [ 'border-top-width' || 'border-style' || <color> ] | inherit
2593 return parseShorthand(propId, borderTopShorthand(), important);
2594 case CSSPropertyBorderRight:
2595 // [ 'border-right-width' || 'border-style' || <color> ] | inherit
2596 return parseShorthand(propId, borderRightShorthand(), important);
2597 case CSSPropertyBorderBottom:
2598 // [ 'border-bottom-width' || 'border-style' || <color> ] | inherit
2599 return parseShorthand(propId, borderBottomShorthand(), important);
2600 case CSSPropertyBorderLeft:
2601 // [ 'border-left-width' || 'border-style' || <color> ] | inherit
2602 return parseShorthand(propId, borderLeftShorthand(), important);
2603 case CSSPropertyWebkitBorderStart:
2604 return parseShorthand(propId, webkitBorderStartShorthand(), important);
2605 case CSSPropertyWebkitBorderEnd:
2606 return parseShorthand(propId, webkitBorderEndShorthand(), important);
2607 case CSSPropertyWebkitBorderBefore:
2608 return parseShorthand(propId, webkitBorderBeforeShorthand(), important);
2609 case CSSPropertyWebkitBorderAfter:
2610 return parseShorthand(propId, webkitBorderAfterShorthand(), important);
2611 case CSSPropertyOutline:
2612 // [ 'outline-color' || 'outline-style' || 'outline-width' ] | inherit
2613 return parseShorthand(propId, outlineShorthand(), important);
2614 case CSSPropertyBorderColor:
2615 // <color>{1,4} | inherit
2616 return parse4Values(propId, borderColorShorthand().properties(), important);
2617 case CSSPropertyBorderWidth:
2618 // <border-width>{1,4} | inherit
2619 return parse4Values(propId, borderWidthShorthand().properties(), important);
2620 case CSSPropertyBorderStyle:
2621 // <border-style>{1,4} | inherit
2622 return parse4Values(propId, borderStyleShorthand().properties(), important);
2623 case CSSPropertyMargin:
2624 // <margin-width>{1,4} | inherit
2625 return parse4Values(propId, marginShorthand().properties(), important);
2626 case CSSPropertyPadding:
2627 // <padding-width>{1,4} | inherit
2628 return parse4Values(propId, paddingShorthand().properties(), important);
2629 #if ENABLE(CSS3_FLEXBOX)
2630 case CSSPropertyWebkitFlexFlow:
2631 return parseShorthand(propId, webkitFlexFlowShorthand(), important);
2633 case CSSPropertyFont:
2634 // [ [ 'font-style' || 'font-variant' || 'font-weight' ]? 'font-size' [ / 'line-height' ]?
2635 // 'font-family' ] | caption | icon | menu | message-box | small-caption | status-bar | inherit
2636 if (id >= CSSValueCaption && id <= CSSValueStatusBar)
2637 validPrimitive = true;
2639 return parseFont(important);
2641 case CSSPropertyListStyle:
2642 return parseShorthand(propId, listStyleShorthand(), important);
2643 case CSSPropertyWebkitColumns:
2644 return parseShorthand(propId, webkitColumnsShorthand(), important);
2645 case CSSPropertyWebkitColumnRule:
2646 return parseShorthand(propId, webkitColumnRuleShorthand(), important);
2647 case CSSPropertyWebkitTextStroke:
2648 return parseShorthand(propId, webkitTextStrokeShorthand(), important);
2649 case CSSPropertyWebkitAnimation:
2650 return parseAnimationShorthand(important);
2651 case CSSPropertyWebkitTransition:
2652 return parseTransitionShorthand(important);
2653 case CSSPropertyInvalid:
2655 case CSSPropertyPage:
2656 return parsePage(propId, important);
2657 case CSSPropertyFontStretch:
2658 case CSSPropertyTextLineThrough:
2659 case CSSPropertyTextOverline:
2660 case CSSPropertyTextUnderline:
2662 // CSS Text Layout Module Level 3: Vertical writing support
2663 case CSSPropertyWebkitTextEmphasis:
2664 return parseShorthand(propId, webkitTextEmphasisShorthand(), important);
2666 case CSSPropertyWebkitTextEmphasisStyle:
2667 return parseTextEmphasisStyle(important);
2669 case CSSPropertyWebkitTextOrientation:
2670 // FIXME: For now just support upright and vertical-right.
2671 if (id == CSSValueVerticalRight || id == CSSValueUpright)
2672 validPrimitive = true;
2675 case CSSPropertyWebkitLineBoxContain:
2676 if (id == CSSValueNone)
2677 validPrimitive = true;
2679 return parseLineBoxContain(important);
2681 case CSSPropertyWebkitFontFeatureSettings:
2682 if (id == CSSValueNormal)
2683 validPrimitive = true;
2685 return parseFontFeatureSettings(important);
2688 case CSSPropertyWebkitFontVariantLigatures:
2689 if (id == CSSValueNormal)
2690 validPrimitive = true;
2692 return parseFontVariantLigatures(important);
2694 case CSSPropertyWebkitClipPath:
2695 if (id == CSSValueNone)
2696 validPrimitive = true;
2697 else if (value->unit == CSSParserValue::Function)
2698 return parseBasicShape(propId, important);
2700 #if ENABLE(CSS_EXCLUSIONS)
2701 case CSSPropertyWebkitShapeInside:
2702 case CSSPropertyWebkitShapeOutside:
2703 if (!RuntimeEnabledFeatures::cssExclusionsEnabled())
2705 if (id == CSSValueAuto)
2706 validPrimitive = true;
2707 else if (value->unit == CSSParserValue::Function)
2708 return parseBasicShape(propId, important);
2710 case CSSPropertyWebkitWrapMargin:
2711 case CSSPropertyWebkitWrapPadding:
2712 validPrimitive = (RuntimeEnabledFeatures::cssExclusionsEnabled() && !id && validUnit(value, FLength | FNonNeg));
2714 case CSSPropertyWebkitWrap:
2715 return RuntimeEnabledFeatures::cssExclusionsEnabled() && parseShorthand(propId, webkitWrapShorthand(), important);
2717 #if ENABLE(CSS_IMAGE_ORIENTATION)
2718 case CSSPropertyImageOrientation:
2719 validPrimitive = !id && validUnit(value, FAngle);
2722 #if ENABLE(CSS_IMAGE_RESOLUTION)
2723 case CSSPropertyImageResolution:
2724 parsedValue = parseImageResolution(m_valueList.get());
2727 m_valueList->next();
2730 case CSSPropertyBorderBottomStyle:
2731 case CSSPropertyBorderCollapse:
2732 case CSSPropertyBorderLeftStyle:
2733 case CSSPropertyBorderRightStyle:
2734 case CSSPropertyBorderTopStyle:
2735 case CSSPropertyBoxSizing:
2736 case CSSPropertyCaptionSide:
2737 case CSSPropertyClear:
2738 case CSSPropertyDirection:
2739 case CSSPropertyDisplay:
2740 case CSSPropertyEmptyCells:
2741 case CSSPropertyFloat:
2742 case CSSPropertyFontStyle:
2743 case CSSPropertyImageRendering:
2744 case CSSPropertyListStylePosition:
2745 case CSSPropertyListStyleType:
2746 case CSSPropertyOutlineStyle:
2747 case CSSPropertyOverflowWrap:
2748 case CSSPropertyOverflowX:
2749 case CSSPropertyOverflowY:
2750 case CSSPropertyPageBreakAfter:
2751 case CSSPropertyPageBreakBefore:
2752 case CSSPropertyPageBreakInside:
2753 case CSSPropertyPointerEvents:
2754 case CSSPropertyPosition:
2755 case CSSPropertyResize:
2756 case CSSPropertySpeak:
2757 case CSSPropertyTableLayout:
2758 case CSSPropertyTextLineThroughMode:
2759 case CSSPropertyTextLineThroughStyle:
2760 case CSSPropertyTextOverflow:
2761 case CSSPropertyTextOverlineMode:
2762 case CSSPropertyTextOverlineStyle:
2763 case CSSPropertyTextRendering:
2764 case CSSPropertyTextTransform:
2765 case CSSPropertyTextUnderlineMode:
2766 case CSSPropertyTextUnderlineStyle:
2767 #if ENABLE(CSS_VARIABLES)
2768 case CSSPropertyVariable:
2770 case CSSPropertyVisibility:
2771 case CSSPropertyWebkitAppearance:
2772 case CSSPropertyWebkitBackfaceVisibility:
2773 case CSSPropertyWebkitBorderAfterStyle:
2774 case CSSPropertyWebkitBorderBeforeStyle:
2775 case CSSPropertyWebkitBorderEndStyle:
2776 case CSSPropertyWebkitBorderFit:
2777 case CSSPropertyWebkitBorderStartStyle:
2778 case CSSPropertyWebkitBoxAlign:
2779 #if ENABLE(CSS_BOX_DECORATION_BREAK)
2780 case CSSPropertyWebkitBoxDecorationBreak:
2782 case CSSPropertyWebkitBoxDirection:
2783 case CSSPropertyWebkitBoxLines:
2784 case CSSPropertyWebkitBoxOrient:
2785 case CSSPropertyWebkitBoxPack:
2786 case CSSPropertyWebkitColorCorrection:
2787 case CSSPropertyWebkitColumnBreakAfter:
2788 case CSSPropertyWebkitColumnBreakBefore:
2789 case CSSPropertyWebkitColumnBreakInside:
2790 case CSSPropertyWebkitColumnRuleStyle:
2791 #if ENABLE(CSS3_FLEXBOX)
2792 case CSSPropertyWebkitAlignContent:
2793 case CSSPropertyWebkitAlignItems:
2794 case CSSPropertyWebkitAlignSelf:
2795 case CSSPropertyWebkitFlexDirection:
2796 case CSSPropertyWebkitFlexWrap:
2797 case CSSPropertyWebkitJustifyContent:
2799 case CSSPropertyWebkitFontKerning:
2800 case CSSPropertyWebkitFontSmoothing:
2801 case CSSPropertyWebkitHyphens:
2802 case CSSPropertyWebkitLineAlign:
2803 case CSSPropertyWebkitLineBreak:
2804 case CSSPropertyWebkitLineSnap:
2805 case CSSPropertyWebkitMarginAfterCollapse:
2806 case CSSPropertyWebkitMarginBeforeCollapse:
2807 case CSSPropertyWebkitMarginBottomCollapse:
2808 case CSSPropertyWebkitMarginTopCollapse:
2809 case CSSPropertyWebkitMarqueeDirection:
2810 case CSSPropertyWebkitMarqueeStyle:
2811 case CSSPropertyWebkitNbspMode:
2812 #if ENABLE(OVERFLOW_SCROLLING)
2813 case CSSPropertyWebkitOverflowScrolling:
2815 case CSSPropertyWebkitPrintColorAdjust:
2816 #if ENABLE(CSS_REGIONS)
2817 case CSSPropertyWebkitRegionBreakAfter:
2818 case CSSPropertyWebkitRegionBreakBefore:
2819 case CSSPropertyWebkitRegionBreakInside:
2820 case CSSPropertyWebkitRegionOverflow:
2822 case CSSPropertyWebkitRtlOrdering:
2823 case CSSPropertyWebkitTextCombine:
2824 case CSSPropertyWebkitTextEmphasisPosition:
2825 case CSSPropertyWebkitTextSecurity:
2826 case CSSPropertyWebkitTextSizeAdjust:
2827 case CSSPropertyWebkitTransformStyle:
2828 case CSSPropertyWebkitUserDrag:
2829 case CSSPropertyWebkitUserModify:
2830 case CSSPropertyWebkitUserSelect:
2831 #if ENABLE(CSS_EXCLUSIONS)
2832 case CSSPropertyWebkitWrapFlow:
2833 case CSSPropertyWebkitWrapThrough:
2835 case CSSPropertyWebkitWritingMode:
2836 case CSSPropertyWhiteSpace:
2837 case CSSPropertyWordBreak:
2838 case CSSPropertyWordWrap:
2839 // These properties should be handled before in isValidKeywordPropertyAndValue().
2840 ASSERT_NOT_REACHED();
2844 return parseSVGValue(propId, important);
2848 if (validPrimitive) {
2849 parsedValue = parseValidPrimitive(id, value);
2850 m_valueList->next();
2852 ASSERT(!m_parsedCalculation);
2854 if (!m_valueList->current() || inShorthand()) {
2855 addProperty(propId, parsedValue.release(), important);
2862 void CSSParser::addFillValue(RefPtr<CSSValue>& lval, PassRefPtr<CSSValue> rval)
2865 if (lval->isValueList())
2866 static_cast<CSSValueList*>(lval.get())->append(rval);
2868 PassRefPtr<CSSValue> oldlVal(lval.release());
2869 PassRefPtr<CSSValueList> list = CSSValueList::createCommaSeparated();
2870 list->append(oldlVal);
2879 static bool parseBackgroundClip(CSSParserValue* parserValue, RefPtr<CSSValue>& cssValue)
2881 if (parserValue->id == CSSValueBorderBox || parserValue->id == CSSValuePaddingBox
2882 || parserValue->id == CSSValueContentBox || parserValue->id == CSSValueWebkitText) {
2883 cssValue = cssValuePool().createIdentifierValue(parserValue->id);
2889 const int cMaxFillProperties = 9;
2891 bool CSSParser::parseFillShorthand(CSSPropertyID propId, const CSSPropertyID* properties, int numProperties, bool important)
2893 ASSERT(numProperties <= cMaxFillProperties);
2894 if (numProperties > cMaxFillProperties)
2897 ShorthandScope scope(this, propId);
2899 bool parsedProperty[cMaxFillProperties] = { false };
2900 RefPtr<CSSValue> values[cMaxFillProperties];
2901 RefPtr<CSSValue> clipValue;
2902 RefPtr<CSSValue> positionYValue;
2903 RefPtr<CSSValue> repeatYValue;
2904 bool foundClip = false;
2906 bool foundBackgroundPositionCSSProperty = false;
2908 while (m_valueList->current()) {
2909 CSSParserValue* val = m_valueList->current();
2910 if (val->unit == CSSParserValue::Operator && val->iValue == ',') {
2911 // We hit the end. Fill in all remaining values with the initial value.
2912 m_valueList->next();
2913 for (i = 0; i < numProperties; ++i) {
2914 if (properties[i] == CSSPropertyBackgroundColor && parsedProperty[i])
2915 // Color is not allowed except as the last item in a list for backgrounds.
2916 // Reject the entire property.
2919 if (!parsedProperty[i] && properties[i] != CSSPropertyBackgroundColor) {
2920 addFillValue(values[i], cssValuePool().createImplicitInitialValue());
2921 if (properties[i] == CSSPropertyBackgroundPosition || properties[i] == CSSPropertyWebkitMaskPosition)
2922 addFillValue(positionYValue, cssValuePool().createImplicitInitialValue());
2923 if (properties[i] == CSSPropertyBackgroundRepeat || properties[i] == CSSPropertyWebkitMaskRepeat)
2924 addFillValue(repeatYValue, cssValuePool().createImplicitInitialValue());
2925 if ((properties[i] == CSSPropertyBackgroundOrigin || properties[i] == CSSPropertyWebkitMaskOrigin) && !parsedProperty[i]) {
2926 // If background-origin wasn't present, then reset background-clip also.
2927 addFillValue(clipValue, cssValuePool().createImplicitInitialValue());
2930 parsedProperty[i] = false;
2932 if (!m_valueList->current())
2936 bool backgroundSizeCSSPropertyExpected = false;
2937 if ((val->unit == CSSParserValue::Operator && val->iValue == '/') && foundBackgroundPositionCSSProperty) {
2938 backgroundSizeCSSPropertyExpected = true;
2939 m_valueList->next();
2942 foundBackgroundPositionCSSProperty = false;
2944 for (i = 0; !found && i < numProperties; ++i) {
2946 if (backgroundSizeCSSPropertyExpected && properties[i] != CSSPropertyBackgroundSize)
2948 if (!backgroundSizeCSSPropertyExpected && properties[i] == CSSPropertyBackgroundSize)
2951 if (!parsedProperty[i]) {
2952 RefPtr<CSSValue> val1;
2953 RefPtr<CSSValue> val2;
2954 CSSPropertyID propId1, propId2;
2955 CSSParserValue* parserValue = m_valueList->current();
2956 if (parseFillProperty(properties[i], propId1, propId2, val1, val2)) {
2957 parsedProperty[i] = found = true;
2958 addFillValue(values[i], val1.release());
2959 if (properties[i] == CSSPropertyBackgroundPosition || properties[i] == CSSPropertyWebkitMaskPosition)
2960 addFillValue(positionYValue, val2.release());
2961 if (properties[i] == CSSPropertyBackgroundRepeat || properties[i] == CSSPropertyWebkitMaskRepeat)
2962 addFillValue(repeatYValue, val2.release());
2963 if (properties[i] == CSSPropertyBackgroundOrigin || properties[i] == CSSPropertyWebkitMaskOrigin) {
2964 // Reparse the value as a clip, and see if we succeed.
2965 if (parseBackgroundClip(parserValue, val1))
2966 addFillValue(clipValue, val1.release()); // The property parsed successfully.
2968 addFillValue(clipValue, cssValuePool().createImplicitInitialValue()); // Some value was used for origin that is not supported by clip. Just reset clip instead.
2970 if (properties[i] == CSSPropertyBackgroundClip || properties[i] == CSSPropertyWebkitMaskClip) {
2972 addFillValue(clipValue, val1.release());
2975 if (properties[i] == CSSPropertyBackgroundPosition)
2976 foundBackgroundPositionCSSProperty = true;
2981 // if we didn't find at least one match, this is an
2982 // invalid shorthand and we have to ignore it
2987 // Now add all of the properties we found.
2988 for (i = 0; i < numProperties; i++) {
2989 // Fill in any remaining properties with the initial value.
2990 if (!parsedProperty[i]) {
2991 addFillValue(values[i], cssValuePool().createImplicitInitialValue());
2992 if (properties[i] == CSSPropertyBackgroundPosition || properties[i] == CSSPropertyWebkitMaskPosition)
2993 addFillValue(positionYValue, cssValuePool().createImplicitInitialValue());
2994 if (properties[i] == CSSPropertyBackgroundRepeat || properties[i] == CSSPropertyWebkitMaskRepeat)
2995 addFillValue(repeatYValue, cssValuePool().createImplicitInitialValue());
2996 if ((properties[i] == CSSPropertyBackgroundOrigin || properties[i] == CSSPropertyWebkitMaskOrigin)) {
2997 // If background-origin wasn't present, then reset background-clip also.
2998 addFillValue(clipValue, cssValuePool().createImplicitInitialValue());
3001 if (properties[i] == CSSPropertyBackgroundPosition) {
3002 addProperty(CSSPropertyBackgroundPositionX, values[i].release(), important);
3003 // it's OK to call positionYValue.release() since we only see CSSPropertyBackgroundPosition once
3004 addProperty(CSSPropertyBackgroundPositionY, positionYValue.release(), important);
3005 } else if (properties[i] == CSSPropertyWebkitMaskPosition) {
3006 addProperty(CSSPropertyWebkitMaskPositionX, values[i].release(), important);
3007 // it's OK to call positionYValue.release() since we only see CSSPropertyWebkitMaskPosition once
3008 addProperty(CSSPropertyWebkitMaskPositionY, positionYValue.release(), important);
3009 } else if (properties[i] == CSSPropertyBackgroundRepeat) {
3010 addProperty(CSSPropertyBackgroundRepeatX, values[i].release(), important);
3011 // it's OK to call repeatYValue.release() since we only see CSSPropertyBackgroundPosition once
3012 addProperty(CSSPropertyBackgroundRepeatY, repeatYValue.release(), important);
3013 } else if (properties[i] == CSSPropertyWebkitMaskRepeat) {
3014 addProperty(CSSPropertyWebkitMaskRepeatX, values[i].release(), important);
3015 // it's OK to call repeatYValue.release() since we only see CSSPropertyBackgroundPosition once
3016 addProperty(CSSPropertyWebkitMaskRepeatY, repeatYValue.release(), important);
3017 } else if ((properties[i] == CSSPropertyBackgroundClip || properties[i] == CSSPropertyWebkitMaskClip) && !foundClip)
3018 // Value is already set while updating origin
3020 #if ENABLE(TIZEN_NOT_INITIAIZE_BACKGROUND_SIZE_IN_SHORTHAND_WORKAROUND)
3021 else if (properties[i] == CSSPropertyBackgroundSize && !parsedProperty[i])
3025 addProperty(properties[i], values[i].release(), important);
3027 // Add in clip values when we hit the corresponding origin property.
3028 if (properties[i] == CSSPropertyBackgroundOrigin && !foundClip)
3029 addProperty(CSSPropertyBackgroundClip, clipValue.release(), important);
3030 else if (properties[i] == CSSPropertyWebkitMaskOrigin && !foundClip)
3031 addProperty(CSSPropertyWebkitMaskClip, clipValue.release(), important);
3037 #if ENABLE(CSS_VARIABLES)
3038 bool CSSParser::cssVariablesEnabled() const
3040 return m_context.isCSSVariablesEnabled;
3043 void CSSParser::storeVariableDeclaration(const CSSParserString& name, PassOwnPtr<CSSParserValueList> value, bool important)
3045 ASSERT(name.length > 12);
3046 AtomicString variableName = String(name.characters + 12, name.length - 12);
3048 StringBuilder builder;
3049 for (unsigned i = 0, size = value->size(); i < size; i++) {
3051 builder.append(' ');
3052 RefPtr<CSSValue> cssValue = value->valueAt(i)->createCSSValue();
3055 builder.append(cssValue->cssText());
3057 addProperty(CSSPropertyVariable, CSSVariableValue::create(variableName, builder.toString()), important, false);
3061 void CSSParser::addAnimationValue(RefPtr<CSSValue>& lval, PassRefPtr<CSSValue> rval)
3064 if (lval->isValueList())
3065 static_cast<CSSValueList*>(lval.get())->append(rval);
3067 PassRefPtr<CSSValue> oldVal(lval.release());
3068 PassRefPtr<CSSValueList> list = CSSValueList::createCommaSeparated();
3069 list->append(oldVal);
3078 bool CSSParser::parseAnimationShorthand(bool important)
3080 // When we parse the animation shorthand we need to look for animation-name
3081 // last because otherwise it might match against the keywords for fill mode,
3082 // timing functions and infinite iteration. This means that animation names
3083 // that are the same as keywords (e.g. 'forwards') won't always match in the
3084 // shorthand. In that case they should be using longhands (or reconsidering
3085 // their approach). This is covered by the animations spec bug:
3086 // https://www.w3.org/Bugs/Public/show_bug.cgi?id=14790
3087 // And in the spec (editor's draft) at:
3088 // http://dev.w3.org/csswg/css3-animations/#animation-shorthand-property
3090 static const CSSPropertyID animationProperties[] = {
3091 CSSPropertyWebkitAnimationDuration,
3092 CSSPropertyWebkitAnimationTimingFunction,
3093 CSSPropertyWebkitAnimationDelay,
3094 CSSPropertyWebkitAnimationIterationCount,
3095 CSSPropertyWebkitAnimationDirection,
3096 CSSPropertyWebkitAnimationFillMode,
3097 CSSPropertyWebkitAnimationName
3099 const unsigned numProperties = 7;
3101 // The list of properties in the shorthand should be the same
3102 // length as the list we have here, even though they are
3103 // a different order.
3104 ASSERT(numProperties == webkitAnimationShorthand().length());
3106 ShorthandScope scope(this, CSSPropertyWebkitAnimation);
3108 bool parsedProperty[numProperties] = { false };
3109 RefPtr<CSSValue> values[numProperties];
3112 while (m_valueList->current()) {
3113 CSSParserValue* val = m_valueList->current();
3114 if (val->unit == CSSParserValue::Operator && val->iValue == ',') {
3115 // We hit the end. Fill in all remaining values with the initial value.
3116 m_valueList->next();
3117 for (i = 0; i < numProperties; ++i) {
3118 if (!parsedProperty[i])
3119 addAnimationValue(values[i], cssValuePool().createImplicitInitialValue());
3120 parsedProperty[i] = false;
3122 if (!m_valueList->current())
3127 for (i = 0; i < numProperties; ++i) {
3128 if (!parsedProperty[i]) {
3129 RefPtr<CSSValue> val;
3130 if (parseAnimationProperty(animationProperties[i], val)) {
3131 parsedProperty[i] = found = true;
3132 addAnimationValue(values[i], val.release());
3138 // if we didn't find at least one match, this is an
3139 // invalid shorthand and we have to ignore it
3144 for (i = 0; i < numProperties; ++i) {
3145 // If we didn't find the property, set an intial value.
3146 if (!parsedProperty[i])
3147 addAnimationValue(values[i], cssValuePool().createImplicitInitialValue());
3149 addProperty(animationProperties[i], values[i].release(), important);
3155 bool CSSParser::parseTransitionShorthand(bool important)
3157 const unsigned numProperties = webkitTransitionShorthand().length();
3159 ShorthandScope scope(this, CSSPropertyWebkitTransition);
3161 bool parsedProperty[] = { false, false, false, false };
3162 RefPtr<CSSValue> values[4];
3165 while (m_valueList->current()) {
3166 CSSParserValue* val = m_valueList->current();
3167 if (val->unit == CSSParserValue::Operator && val->iValue == ',') {
3168 // We hit the end. Fill in all remaining values with the initial value.
3169 m_valueList->next();
3170 for (i = 0; i < numProperties; ++i) {
3171 if (!parsedProperty[i])
3172 addAnimationValue(values[i], cssValuePool().createImplicitInitialValue());
3173 parsedProperty[i] = false;
3175 if (!m_valueList->current())
3180 for (i = 0; !found && i < numProperties; ++i) {
3181 if (!parsedProperty[i]) {
3182 RefPtr<CSSValue> val;
3183 if (parseAnimationProperty(webkitTransitionShorthand().properties()[i], val)) {
3184 parsedProperty[i] = found = true;
3185 addAnimationValue(values[i], val.release());
3190 // if we didn't find at least one match, this is an
3191 // invalid shorthand and we have to ignore it
3196 // Fill in any remaining properties with the initial value.
3197 for (i = 0; i < numProperties; ++i) {
3198 if (!parsedProperty[i])
3199 addAnimationValue(values[i], cssValuePool().createImplicitInitialValue());
3202 // Now add all of the properties we found.
3203 for (i = 0; i < numProperties; i++)
3204 addProperty(webkitTransitionShorthand().properties()[i], values[i].release(), important);
3209 bool CSSParser::parseShorthand(CSSPropertyID propId, const StylePropertyShorthand& shorthand, bool important)
3211 // We try to match as many properties as possible
3212 // We set up an array of booleans to mark which property has been found,
3213 // and we try to search for properties until it makes no longer any sense.
3214 ShorthandScope scope(this, propId);
3217 unsigned propertiesParsed = 0;
3218 bool propertyFound[6]= { false, false, false, false, false, false }; // 6 is enough size.
3220 while (m_valueList->current()) {
3222 for (unsigned propIndex = 0; !found && propIndex < shorthand.length(); ++propIndex) {
3223 if (!propertyFound[propIndex] && parseValue(shorthand.properties()[propIndex], important)) {
3224 propertyFound[propIndex] = found = true;
3229 // if we didn't find at least one match, this is an
3230 // invalid shorthand and we have to ignore it
3235 if (propertiesParsed == shorthand.length())
3238 // Fill in any remaining properties with the initial value.
3239 ImplicitScope implicitScope(this, PropertyImplicit);
3240 const StylePropertyShorthand* const* const propertiesForInitialization = shorthand.propertiesForInitialization();
3241 for (unsigned i = 0; i < shorthand.length(); ++i) {
3242 if (propertyFound[i])
3245 if (propertiesForInitialization) {
3246 const StylePropertyShorthand& initProperties = *(propertiesForInitialization[i]);
3247 for (unsigned propIndex = 0; propIndex < initProperties.length(); ++propIndex)
3248 addProperty(initProperties.properties()[propIndex], cssValuePool().createImplicitInitialValue(), important);
3250 addProperty(shorthand.properties()[i], cssValuePool().createImplicitInitialValue(), important);
3256 bool CSSParser::parse4Values(CSSPropertyID propId, const CSSPropertyID *properties, bool important)
3258 /* From the CSS 2 specs, 8.3
3259 * If there is only one value, it applies to all sides. If there are two values, the top and
3260 * bottom margins are set to the first value and the right and left margins are set to the second.
3261 * If there are three values, the top is set to the first value, the left and right are set to the
3262 * second, and the bottom is set to the third. If there are four values, they apply to the top,
3263 * right, bottom, and left, respectively.
3266 int num = inShorthand() ? 1 : m_valueList->size();
3268 ShorthandScope scope(this, propId);
3270 // the order is top, right, bottom, left
3273 if (!parseValue(properties[0], important))
3275 CSSValue *value = m_parsedProperties.last().value();
3276 ImplicitScope implicitScope(this, PropertyImplicit);
3277 addProperty(properties[1], value, important);
3278 addProperty(properties[2], value, important);
3279 addProperty(properties[3], value, important);
3283 if (!parseValue(properties[0], important) || !parseValue(properties[1], important))
3285 CSSValue *value = m_parsedProperties[m_parsedProperties.size() - 2].value();
3286 ImplicitScope implicitScope(this, PropertyImplicit);
3287 addProperty(properties[2], value, important);
3288 value = m_parsedProperties[m_parsedProperties.size() - 2].value();
3289 addProperty(properties[3], value, important);
3293 if (!parseValue(properties[0], important) || !parseValue(properties[1], important) || !parseValue(properties[2], important))
3295 CSSValue *value = m_parsedProperties[m_parsedProperties.size() - 2].value();
3296 ImplicitScope implicitScope(this, PropertyImplicit);
3297 addProperty(properties[3], value, important);
3301 if (!parseValue(properties[0], important) || !parseValue(properties[1], important) ||
3302 !parseValue(properties[2], important) || !parseValue(properties[3], important))
3314 // auto | <identifier>
3315 bool CSSParser::parsePage(CSSPropertyID propId, bool important)
3317 ASSERT(propId == CSSPropertyPage);
3319 if (m_valueList->size() != 1)
3322 CSSParserValue* value = m_valueList->current();
3326 if (value->id == CSSValueAuto) {
3327 addProperty(propId, cssValuePool().createIdentifierValue(value->id), important);
3329 } else if (value->id == 0 && value->unit == CSSPrimitiveValue::CSS_IDENT) {
3330 addProperty(propId, createPrimitiveStringValue(value), important);
3336 // <length>{1,2} | auto | [ <page-size> || [ portrait | landscape] ]
3337 bool CSSParser::parseSize(CSSPropertyID propId, bool important)
3339 ASSERT(propId == CSSPropertySize);
3341 if (m_valueList->size() > 2)
3344 CSSParserValue* value = m_valueList->current();
3348 RefPtr<CSSValueList> parsedValues = CSSValueList::createSpaceSeparated();
3351 SizeParameterType paramType = parseSizeParameter(parsedValues.get(), value, None);
3352 if (paramType == None)
3355 // Second parameter, if any.
3356 value = m_valueList->next();
3358 paramType = parseSizeParameter(parsedValues.get(), value, paramType);
3359 if (paramType == None)
3363 addProperty(propId, parsedValues.release(), important);
3367 CSSParser::SizeParameterType CSSParser::parseSizeParameter(CSSValueList* parsedValues, CSSParserValue* value, SizeParameterType prevParamType)
3369 switch (value->id) {
3371 if (prevParamType == None) {
3372 parsedValues->append(cssValuePool().createIdentifierValue(value->id));
3376 case CSSValueLandscape:
3377 case CSSValuePortrait:
3378 if (prevParamType == None || prevParamType == PageSize) {
3379 parsedValues->append(cssValuePool().createIdentifierValue(value->id));
3388 case CSSValueLedger:
3390 case CSSValueLetter:
3391 if (prevParamType == None || prevParamType == Orientation) {
3392 // Normalize to Page Size then Orientation order by prepending.
3393 // This is not specified by the CSS3 Paged Media specification, but for simpler processing later (StyleResolver::applyPageSizeProperty).
3394 parsedValues->prepend(cssValuePool().createIdentifierValue(value->id));
3399 if (validUnit(value, FLength | FNonNeg) && (prevParamType == None || prevParamType == Length)) {
3400 parsedValues->append(createPrimitiveNumericValue(value));
3409 // [ <string> <string> ]+ | inherit | none
3410 // inherit and none are handled in parseValue.
3411 bool CSSParser::parseQuotes(CSSPropertyID propId, bool important)
3413 RefPtr<CSSValueList> values = CSSValueList::createCommaSeparated();
3414 while (CSSParserValue* val = m_valueList->current()) {
3415 RefPtr<CSSValue> parsedValue;
3416 if (val->unit == CSSPrimitiveValue::CSS_STRING)
3417 parsedValue = CSSPrimitiveValue::create(val->string, CSSPrimitiveValue::CSS_STRING);
3420 values->append(parsedValue.release());
3421 m_valueList->next();
3423 if (values->length()) {
3424 addProperty(propId, values.release(), important);
3425 m_valueList->next();
3431 // [ <string> | <uri> | <counter> | attr(X) | open-quote | close-quote | no-open-quote | no-close-quote ]+ | inherit
3432 // in CSS 2.1 this got somewhat reduced:
3433 // [ <string> | attr(X) | open-quote | close-quote | no-open-quote | no-close-quote ]+ | inherit
3434 bool CSSParser::parseContent(CSSPropertyID propId, bool important)
3436 RefPtr<CSSValueList> values = CSSValueList::createCommaSeparated();
3438 while (CSSParserValue* val = m_valueList->current()) {
3439 RefPtr<CSSValue> parsedValue;
3440 if (val->unit == CSSPrimitiveValue::CSS_URI) {
3442 parsedValue = CSSImageValue::create(completeURL(val->string));
3443 } else if (val->unit == CSSParserValue::Function) {
3444 // attr(X) | counter(X [,Y]) | counters(X, Y, [,Z]) | -webkit-gradient(...)
3445 CSSParserValueList* args = val->function->args.get();
3448 if (equalIgnoringCase(val->function->name, "attr(")) {
3449 parsedValue = parseAttr(args);
3452 } else if (equalIgnoringCase(val->function->name, "counter(")) {
3453 parsedValue = parseCounterContent(args, false);
3456 } else if (equalIgnoringCase(val->function->name, "counters(")) {
3457 parsedValue = parseCounterContent(args, true);
3460 #if ENABLE(CSS_IMAGE_SET)
3461 } else if (equalIgnoringCase(val->function->name, "-webkit-image-set(")) {
3462 parsedValue = parseImageSet(m_valueList.get());
3466 } else if (isGeneratedImageValue(val)) {
3467 if (!parseGeneratedImage(m_valueList.get(), parsedValue))
3471 } else if (val->unit == CSSPrimitiveValue::CSS_IDENT) {
3477 // FIXME: These are not yet implemented (http://bugs.webkit.org/show_bug.cgi?id=6503).
3481 case CSSValueOpenQuote:
3482 case CSSValueCloseQuote:
3483 case CSSValueNoOpenQuote:
3484 case CSSValueNoCloseQuote:
3486 case CSSValueNormal:
3487 parsedValue = cssValuePool().createIdentifierValue(val->id);
3489 } else if (val->unit == CSSPrimitiveValue::CSS_STRING) {
3490 parsedValue = createPrimitiveStringValue(val);
3494 values->append(parsedValue.release());
3495 m_valueList->next();
3498 if (values->length()) {
3499 addProperty(propId, values.release(), important);
3500 m_valueList->next();
3507 PassRefPtr<CSSValue> CSSParser::parseAttr(CSSParserValueList* args)
3509 if (args->size() != 1)
3512 CSSParserValue* a = args->current();
3514 if (a->unit != CSSPrimitiveValue::CSS_IDENT)
3517 String attrName = a->string;
3518 // CSS allows identifiers with "-" at the start, like "-webkit-mask-image".
3519 // But HTML attribute names can't have those characters, and we should not
3520 // even parse them inside attr().
3521 if (attrName[0] == '-')
3524 if (m_context.isHTMLDocument)
3525 attrName = attrName.lower();
3527 return cssValuePool().createValue(attrName, CSSPrimitiveValue::CSS_ATTR);
3530 PassRefPtr<CSSValue> CSSParser::parseBackgroundColor()
3532 int id = m_valueList->current()->id;
3533 if (id == CSSValueWebkitText || (id >= CSSValueAqua && id <= CSSValueWindowtext) || id == CSSValueMenu || id == CSSValueCurrentcolor ||
3534 (id >= CSSValueGrey && id < CSSValueWebkitText && inQuirksMode()))
3535 return cssValuePool().createIdentifierValue(id);
3536 return parseColor();
3539 bool CSSParser::parseFillImage(CSSParserValueList* valueList, RefPtr<CSSValue>& value)
3541 if (valueList->current()->id == CSSValueNone) {
3542 value = cssValuePool().createIdentifierValue(CSSValueNone);
3545 if (valueList->current()->unit == CSSPrimitiveValue::CSS_URI) {
3546 value = CSSImageValue::create(completeURL(valueList->current()->string));
3550 if (isGeneratedImageValue(valueList->current()))
3551 return parseGeneratedImage(valueList, value);
3553 #if ENABLE(CSS_IMAGE_SET)
3554 if (valueList->current()->unit == CSSParserValue::Function && equalIgnoringCase(valueList->current()->function->name, "-webkit-image-set(")) {
3555 value = parseImageSet(m_valueList.get());
3564 PassRefPtr<CSSValue> CSSParser::parseFillPositionX(CSSParserValueList* valueList)
3566 int id = valueList->current()->id;
3567 if (id == CSSValueLeft || id == CSSValueRight || id == CSSValueCenter) {
3569 if (id == CSSValueRight)
3571 else if (id == CSSValueCenter)
3573 return cssValuePool().createValue(percent, CSSPrimitiveValue::CSS_PERCENTAGE);
3575 if (validUnit(valueList->current(), FPercent | FLength))
3576 return createPrimitiveNumericValue(valueList->current());
3580 PassRefPtr<CSSValue> CSSParser::parseFillPositionY(CSSParserValueList* valueList)
3582 int id = valueList->current()->id;
3583 if (id == CSSValueTop || id == CSSValueBottom || id == CSSValueCenter) {
3585 if (id == CSSValueBottom)
3587 else if (id == CSSValueCenter)
3589 return cssValuePool().createValue(percent, CSSPrimitiveValue::CSS_PERCENTAGE);
3591 if (validUnit(valueList->current(), FPercent | FLength))
3592 return createPrimitiveNumericValue(valueList->current());
3596 PassRefPtr<CSSValue> CSSParser::parseFillPositionComponent(CSSParserValueList* valueList, unsigned& cumulativeFlags, FillPositionFlag& individualFlag)
3598 int id = valueList->current()->id;
3599 if (id == CSSValueLeft || id == CSSValueTop || id == CSSValueRight || id == CSSValueBottom || id == CSSValueCenter) {
3601 if (id == CSSValueLeft || id == CSSValueRight) {
3602 if (cumulativeFlags & XFillPosition)
3604 cumulativeFlags |= XFillPosition;
3605 individualFlag = XFillPosition;
3606 if (id == CSSValueRight)
3609 else if (id == CSSValueTop || id == CSSValueBottom) {
3610 if (cumulativeFlags & YFillPosition)
3612 cumulativeFlags |= YFillPosition;
3613 individualFlag = YFillPosition;
3614 if (id == CSSValueBottom)
3616 } else if (id == CSSValueCenter) {
3617 // Center is ambiguous, so we're not sure which position we've found yet, an x or a y.
3619 cumulativeFlags |= AmbiguousFillPosition;
3620 individualFlag = AmbiguousFillPosition;
3622 return cssValuePool().createValue(percent, CSSPrimitiveValue::CSS_PERCENTAGE);
3624 if (validUnit(valueList->current(), FPercent | FLength)) {
3625 if (!cumulativeFlags) {
3626 cumulativeFlags |= XFillPosition;
3627 individualFlag = XFillPosition;
3628 } else if (cumulativeFlags & (XFillPosition | AmbiguousFillPosition)) {
3629 cumulativeFlags |= YFillPosition;
3630 individualFlag = YFillPosition;
3632 if (m_parsedCalculation)
3633 m_parsedCalculation.release();
3636 return createPrimitiveNumericValue(valueList->current());
3641 void CSSParser::parseFillPosition(CSSParserValueList* valueList, RefPtr<CSSValue>& value1, RefPtr<CSSValue>& value2)
3643 CSSParserValue* value = valueList->current();
3645 // Parse the first value. We're just making sure that it is one of the valid keywords or a percentage/length.
3646 unsigned cumulativeFlags = 0;
3647 FillPositionFlag value1Flag = InvalidFillPosition;
3648 FillPositionFlag value2Flag = InvalidFillPosition;
3649 value1 = parseFillPositionComponent(valueList, cumulativeFlags, value1Flag);
3653 // It only takes one value for background-position to be correctly parsed if it was specified in a shorthand (since we
3654 // can assume that any other values belong to the rest of the shorthand). If we're not parsing a shorthand, though, the
3655 // value was explicitly specified for our property.
3656 value = valueList->next();
3658 // First check for the comma. If so, we are finished parsing this value or value pair.
3663 value2 = parseFillPositionComponent(valueList, cumulativeFlags, value2Flag);
3667 if (!inShorthand()) {
3675 // Only one value was specified. If that value was not a keyword, then it sets the x position, and the y position
3676 // is simply 50%. This is our default.
3677 // For keywords, the keyword was either an x-keyword (left/right), a y-keyword (top/bottom), or an ambiguous keyword (center).
3678 // For left/right/center, the default of 50% in the y is still correct.
3679 value2 = cssValuePool().createValue(50, CSSPrimitiveValue::CSS_PERCENTAGE);
3681 if (value1Flag == YFillPosition || value2Flag == XFillPosition)
3682 value1.swap(value2);
3685 void CSSParser::parseFillRepeat(RefPtr<CSSValue>& value1, RefPtr<CSSValue>& value2)
3687 int id = m_valueList->current()->id;
3688 if (id == CSSValueRepeatX) {
3689 m_implicitShorthand = true;
3690 value1 = cssValuePool().createIdentifierValue(CSSValueRepeat);
3691 value2 = cssValuePool().createIdentifierValue(CSSValueNoRepeat);
3692 m_valueList->next();
3695 if (id == CSSValueRepeatY) {
3696 m_implicitShorthand = true;
3697 value1 = cssValuePool().createIdentifierValue(CSSValueNoRepeat);
3698 value2 = cssValuePool().createIdentifierValue(CSSValueRepeat);
3699 m_valueList->next();
3702 if (id == CSSValueRepeat || id == CSSValueNoRepeat || id == CSSValueRound || id == CSSValueSpace)
3703 value1 = cssValuePool().createIdentifierValue(id);
3709 CSSParserValue* value = m_valueList->next();
3711 // Parse the second value if one is available
3712 if (value && !isComma(value)) {
3714 if (id == CSSValueRepeat || id == CSSValueNoRepeat || id == CSSValueRound || id == CSSValueSpace) {
3715 value2 = cssValuePool().createIdentifierValue(id);
3716 m_valueList->next();
3721 // If only one value was specified, value2 is the same as value1.
3722 m_implicitShorthand = true;
3723 value2 = cssValuePool().createIdentifierValue(static_cast<CSSPrimitiveValue*>(value1.get())->getIdent());
3726 PassRefPtr<CSSValue> CSSParser::parseFillSize(CSSPropertyID propId, bool& allowComma)
3729 CSSParserValue* value = m_valueList->current();
3731 if (value->id == CSSValueContain || value->id == CSSValueCover)
3732 return cssValuePool().createIdentifierValue(value->id);
3734 RefPtr<CSSPrimitiveValue> parsedValue1;
3736 if (value->id == CSSValueAuto)
3737 parsedValue1 = cssValuePool().createIdentifierValue(CSSValueAuto);
3739 if (!validUnit(value, FLength | FPercent))
3741 parsedValue1 = createPrimitiveNumericValue(value);
3744 RefPtr<CSSPrimitiveValue> parsedValue2;
3745 if ((value = m_valueList->next())) {
3746 if (value->unit == CSSParserValue::Operator && value->iValue == ',')
3748 else if (value->id != CSSValueAuto) {
3749 if (!validUnit(value, FLength | FPercent)) {
3752 // We need to rewind the value list, so that when it is advanced we'll end up back at this value.
3753 m_valueList->previous();
3755 parsedValue2 = createPrimitiveNumericValue(value);
3757 } else if (!parsedValue2 && propId == CSSPropertyWebkitBackgroundSize) {
3758 // For backwards compatibility we set the second value to the first if it is omitted.
3759 // We only need to do this for -webkit-background-size. It should be safe to let masks match
3760 // the real property.
3761 parsedValue2 = parsedValue1;
3765 return parsedValue1;
3766 return cssValuePool().createValue(Pair::create(parsedValue1.release(), parsedValue2.release()));
3769 bool CSSParser::parseFillProperty(CSSPropertyID propId, CSSPropertyID& propId1, CSSPropertyID& propId2,
3770 RefPtr<CSSValue>& retValue1, RefPtr<CSSValue>& retValue2)
3772 RefPtr<CSSValueList> values;
3773 RefPtr<CSSValueList> values2;
3774 CSSParserValue* val;
3775 RefPtr<CSSValue> value;
3776 RefPtr<CSSValue> value2;
3778 bool allowComma = false;
3780 retValue1 = retValue2 = 0;
3783 if (propId == CSSPropertyBackgroundPosition) {
3784 propId1 = CSSPropertyBackgroundPositionX;
3785 propId2 = CSSPropertyBackgroundPositionY;
3786 } else if (propId == CSSPropertyWebkitMaskPosition) {
3787 propId1 = CSSPropertyWebkitMaskPositionX;
3788 propId2 = CSSPropertyWebkitMaskPositionY;
3789 } else if (propId == CSSPropertyBackgroundRepeat) {
3790 propId1 = CSSPropertyBackgroundRepeatX;
3791 propId2 = CSSPropertyBackgroundRepeatY;
3792 } else if (propId == CSSPropertyWebkitMaskRepeat) {
3793 propId1 = CSSPropertyWebkitMaskRepeatX;
3794 propId2 = CSSPropertyWebkitMaskRepeatY;
3797 while ((val = m_valueList->current())) {
3798 RefPtr<CSSValue> currValue;
3799 RefPtr<CSSValue> currValue2;
3804 m_valueList->next();
3809 case CSSPropertyBackgroundColor:
3810 currValue = parseBackgroundColor();
3812 m_valueList->next();
3814 case CSSPropertyBackgroundAttachment:
3815 case CSSPropertyWebkitMaskAttachment:
3816 if (val->id == CSSValueScroll || val->id == CSSValueFixed || val->id == CSSValueLocal) {
3817 currValue = cssValuePool().createIdentifierValue(val->id);
3818 m_valueList->next();
3821 case CSSPropertyBackgroundImage:
3822 case CSSPropertyWebkitMaskImage:
3823 if (parseFillImage(m_valueList.get(), currValue))
3824 m_valueList->next();
3826 case CSSPropertyWebkitBackgroundClip:
3827 case CSSPropertyWebkitBackgroundOrigin:
3828 case CSSPropertyWebkitMaskClip:
3829 case CSSPropertyWebkitMaskOrigin:
3830 // The first three values here are deprecated and do not apply to the version of the property that has
3831 // the -webkit- prefix removed.
3832 if (val->id == CSSValueBorder || val->id == CSSValuePadding || val->id == CSSValueContent ||
3833 val->id == CSSValueBorderBox || val->id == CSSValuePaddingBox || val->id == CSSValueContentBox ||
3834 ((propId == CSSPropertyWebkitBackgroundClip || propId == CSSPropertyWebkitMaskClip) &&
3835 (val->id == CSSValueText || val->id == CSSValueWebkitText))) {
3836 currValue = cssValuePool().createIdentifierValue(val->id);
3837 m_valueList->next();
3840 case CSSPropertyBackgroundClip:
3841 if (parseBackgroundClip(val, currValue))
3842 m_valueList->next();
3844 case CSSPropertyBackgroundOrigin:
3845 if (val->id == CSSValueBorderBox || val->id == CSSValuePaddingBox || val->id == CSSValueContentBox) {
3846 currValue = cssValuePool().createIdentifierValue(val->id);
3847 m_valueList->next();
3850 case CSSPropertyBackgroundPosition:
3851 case CSSPropertyWebkitMaskPosition:
3852 parseFillPosition(m_valueList.get(), currValue, currValue2);
3853 // parseFillPosition advances the m_valueList pointer
3855 case CSSPropertyBackgroundPositionX:
3856 case CSSPropertyWebkitMaskPositionX: {
3857 currValue = parseFillPositionX(m_valueList.get());
3859 m_valueList->next();
3862 case CSSPropertyBackgroundPositionY:
3863 case CSSPropertyWebkitMaskPositionY: {
3864 currValue = parseFillPositionY(m_valueList.get());
3866 m_valueList->next();
3869 case CSSPropertyWebkitBackgroundComposite:
3870 case CSSPropertyWebkitMaskComposite:
3871 if ((val->id >= CSSValueClear && val->id <= CSSValuePlusLighter) || val->id == CSSValueHighlight) {
3872 currValue = cssValuePool().createIdentifierValue(val->id);
3873 m_valueList->next();
3876 case CSSPropertyBackgroundRepeat:
3877 case CSSPropertyWebkitMaskRepeat:
3878 parseFillRepeat(currValue, currValue2);
3879 // parseFillRepeat advances the m_valueList pointer
3881 case CSSPropertyBackgroundSize:
3882 case CSSPropertyWebkitBackgroundSize:
3883 case CSSPropertyWebkitMaskSize: {
3884 currValue = parseFillSize(propId, allowComma);
3886 m_valueList->next();
3895 if (value && !values) {
3896 values = CSSValueList::createCommaSeparated();
3897 values->append(value.release());
3900 if (value2 && !values2) {
3901 values2 = CSSValueList::createCommaSeparated();
3902 values2->append(value2.release());
3906 values->append(currValue.release());
3908 value = currValue.release();
3911 values2->append(currValue2.release());
3913 value2 = currValue2.release();
3917 // When parsing any fill shorthand property, we let it handle building up the lists for all
3923 if (values && values->length()) {
3924 retValue1 = values.release();
3925 if (values2 && values2->length())
3926 retValue2 = values2.release();
3930 retValue1 = value.release();
3931 retValue2 = value2.release();
3937 PassRefPtr<CSSValue> CSSParser::parseAnimationDelay()
3939 CSSParserValue* value = m_valueList->current();
3940 if (validUnit(value, FTime))
3941 return createPrimitiveNumericValue(value);
3945 PassRefPtr<CSSValue> CSSParser::parseAnimationDirection()
3947 CSSParserValue* value = m_valueList->current();
3948 if (value->id == CSSValueNormal || value->id == CSSValueAlternate || value->id == CSSValueReverse || value->id == CSSValueAlternateReverse)
3949 return cssValuePool().createIdentifierValue(value->id);
3953 PassRefPtr<CSSValue> CSSParser::parseAnimationDuration()
3955 CSSParserValue* value = m_valueList->current();
3956 if (validUnit(value, FTime | FNonNeg))
3957 return createPrimitiveNumericValue(value);
3961 PassRefPtr<CSSValue> CSSParser::parseAnimationFillMode()
3963 CSSParserValue* value = m_valueList->current();
3964 if (value->id == CSSValueNone || value->id == CSSValueForwards || value->id == CSSValueBackwards || value->id == CSSValueBoth)
3965 return cssValuePool().createIdentifierValue(value->id);
3969 PassRefPtr<CSSValue> CSSParser::parseAnimationIterationCount()
3971 CSSParserValue* value = m_valueList->current();
3972 if (value->id == CSSValueInfinite)
3973 return cssValuePool().createIdentifierValue(value->id);
3974 if (validUnit(value, FNumber | FNonNeg))
3975 return createPrimitiveNumericValue(value);
3979 PassRefPtr<CSSValue> CSSParser::parseAnimationName()
3981 CSSParserValue* value = m_valueList->current();
3982 if (value->unit == CSSPrimitiveValue::CSS_STRING || value->unit == CSSPrimitiveValue::CSS_IDENT) {
3983 if (value->id == CSSValueNone || (value->unit == CSSPrimitiveValue::CSS_STRING && equalIgnoringCase(value->string, "none"))) {
3984 return cssValuePool().createIdentifierValue(CSSValueNone);
3986 return createPrimitiveStringValue(value);
3992 PassRefPtr<CSSValue> CSSParser::parseAnimationPlayState()
3994 CSSParserValue* value = m_valueList->current();
3995 if (value->id == CSSValueRunning || value->id == CSSValuePaused)
3996 return cssValuePool().createIdentifierValue(value->id);
4000 PassRefPtr<CSSValue> CSSParser::parseAnimationProperty()
4002 CSSParserValue* value = m_valueList->current();
4003 if (value->unit != CSSPrimitiveValue::CSS_IDENT)
4005 int result = cssPropertyID(value->string);
4007 return cssValuePool().createIdentifierValue(result);
4008 if (equalIgnoringCase(value->string, "all"))
4009 return cssValuePool().createIdentifierValue(CSSValueAll);
4010 if (equalIgnoringCase(value->string, "none"))
4011 return cssValuePool().createIdentifierValue(CSSValueNone);
4015 bool CSSParser::parseTransformOriginShorthand(RefPtr<CSSValue>& value1, RefPtr<CSSValue>& value2, RefPtr<CSSValue>& value3)
4017 parseFillPosition(m_valueList.get(), value1, value2);
4020 if (m_valueList->current()) {
4021 if (validUnit(m_valueList->current(), FLength)) {
4022 value3 = createPrimitiveNumericValue(m_valueList->current());
4023 m_valueList->next();
4028 value3 = cssValuePool().createImplicitInitialValue();
4032 bool CSSParser::parseCubicBezierTimingFunctionValue(CSSParserValueList*& args, double& result)
4034 CSSParserValue* v = args->current();
4035 if (!validUnit(v, FNumber))
4040 // The last number in the function has no comma after it, so we're done.
4048 PassRefPtr<CSSValue> CSSParser::parseAnimationTimingFunction()
4050 CSSParserValue* value = m_valueList->current();
4051 if (value->id == CSSValueEase || value->id == CSSValueLinear || value->id == CSSValueEaseIn || value->id == CSSValueEaseOut
4052 || value->id == CSSValueEaseInOut || value->id == CSSValueStepStart || value->id == CSSValueStepEnd)
4053 return cssValuePool().createIdentifierValue(value->id);
4055 // We must be a function.
4056 if (value->unit != CSSParserValue::Function)
4059 CSSParserValueList* args = value->function->args.get();
4061 if (equalIgnoringCase(value->function->name, "steps(")) {
4062 // For steps, 1 or 2 params must be specified (comma-separated)
4063 if (!args || (args->size() != 1 && args->size() != 3))
4066 // There are two values.
4068 bool stepAtStart = false;
4070 CSSParserValue* v = args->current();
4071 if (!validUnit(v, FInteger))
4073 numSteps = clampToInteger(v->fValue);
4079 // There is a comma so we need to parse the second value
4083 if (v->id != CSSValueStart && v->id != CSSValueEnd)
4085 stepAtStart = v->id == CSSValueStart;
4088 return CSSStepsTimingFunctionValue::create(numSteps, stepAtStart);
4091 if (equalIgnoringCase(value->function->name, "cubic-bezier(")) {
4092 // For cubic bezier, 4 values must be specified.
4093 if (!args || args->size() != 7)
4096 // There are two points specified. The values must be between 0 and 1.
4097 double x1, y1, x2, y2;
4099 if (!parseCubicBezierTimingFunctionValue(args, x1))
4101 if (!parseCubicBezierTimingFunctionValue(args, y1))
4103 if (!parseCubicBezierTimingFunctionValue(args, x2))
4105 if (!parseCubicBezierTimingFunctionValue(args, y2))
4108 return CSSCubicBezierTimingFunctionValue::create(x1, y1, x2, y2);
4114 bool CSSParser::parseAnimationProperty(CSSPropertyID propId, RefPtr<CSSValue>& result)
4116 RefPtr<CSSValueList> values;
4117 CSSParserValue* val;
4118 RefPtr<CSSValue> value;
4119 bool allowComma = false;
4123 while ((val = m_valueList->current())) {
4124 RefPtr<CSSValue> currValue;
4128 m_valueList->next();
4133 case CSSPropertyWebkitAnimationDelay:
4134 case CSSPropertyWebkitTransitionDelay:
4135 currValue = parseAnimationDelay();
4137 m_valueList->next();
4139 case CSSPropertyWebkitAnimationDirection:
4140 currValue = parseAnimationDirection();
4142 m_valueList->next();
4144 case CSSPropertyWebkitAnimationDuration:
4145 case CSSPropertyWebkitTransitionDuration:
4146 currValue = parseAnimationDuration();
4148 m_valueList->next();
4150 case CSSPropertyWebkitAnimationFillMode:
4151 currValue = parseAnimationFillMode();
4153 m_valueList->next();
4155 case CSSPropertyWebkitAnimationIterationCount:
4156 currValue = parseAnimationIterationCount();
4158 m_valueList->next();
4160 case CSSPropertyWebkitAnimationName:
4161 currValue = parseAnimationName();
4163 m_valueList->next();
4165 case CSSPropertyWebkitAnimationPlayState:
4166 currValue = parseAnimationPlayState();
4168 m_valueList->next();
4170 case CSSPropertyWebkitTransitionProperty:
4171 currValue = parseAnimationProperty();
4173 m_valueList->next();
4175 case CSSPropertyWebkitAnimationTimingFunction:
4176 case CSSPropertyWebkitTransitionTimingFunction:
4177 currValue = parseAnimationTimingFunction();
4179 m_valueList->next();
4182 ASSERT_NOT_REACHED();
4189 if (value && !values) {
4190 values = CSSValueList::createCommaSeparated();
4191 values->append(value.release());
4195 values->append(currValue.release());
4197 value = currValue.release();
4202 // When parsing the 'transition' shorthand property, we let it handle building up the lists for all
4208 if (values && values->length()) {
4209 result = values.release();
4213 result = value.release();
4219 bool CSSParser::parseGridTrackList(CSSPropertyID propId, bool important)
4221 CSSParserValue* value = m_valueList->current();
4222 if (value->id == CSSValueNone) {
4223 if (m_valueList->next())
4226 addProperty(propId, cssValuePool().createIdentifierValue(value->id), important);
4230 RefPtr<CSSValueList> values = CSSValueList::createSpaceSeparated();
4232 bool valid = validUnit(value, FLength | FPercent) || value->id == CSSValueAuto;
4236 RefPtr<CSSPrimitiveValue> primitiveValue = value->id == CSSValueAuto ? cssValuePool().createIdentifierValue(CSSValueAuto) : createPrimitiveNumericValue(value);
4237 values->append(primitiveValue.release());
4238 value = m_valueList->next();
4240 addProperty(propId, values.release(), important);
4245 #if ENABLE(DASHBOARD_SUPPORT)
4247 #define DASHBOARD_REGION_NUM_PARAMETERS 6
4248 #define DASHBOARD_REGION_SHORT_NUM_PARAMETERS 2
4250 static CSSParserValue* skipCommaInDashboardRegion(CSSParserValueList *args)
4252 if (args->size() == (DASHBOARD_REGION_NUM_PARAMETERS*2-1) ||
4253 args->size() == (DASHBOARD_REGION_SHORT_NUM_PARAMETERS*2-1)) {
4254 CSSParserValue* current = args->current();
4255 if (current->unit == CSSParserValue::Operator && current->iValue == ',')
4256 return args->next();
4258 return args->current();
4261 bool CSSParser::parseDashboardRegions(CSSPropertyID propId, bool important)
4265 CSSParserValue* value = m_valueList->current();
4267 if (value->id == CSSValueNone) {
4268 if (m_valueList->next())
4270 addProperty(propId, cssValuePool().createIdentifierValue(value->id), important);
4274 RefPtr<DashboardRegion> firstRegion = DashboardRegion::create();
4275 DashboardRegion* region = 0;
4279 region = firstRegion.get();
4281 RefPtr<DashboardRegion> nextRegion = DashboardRegion::create();
4282 region->m_next = nextRegion;
4283 region = nextRegion.get();
4286 if (value->unit != CSSParserValue::Function) {
4291 // Commas count as values, so allow:
4292 // dashboard-region(label, type, t, r, b, l) or dashboard-region(label type t r b l)
4293 // dashboard-region(label, type, t, r, b, l) or dashboard-region(label type t r b l)
4295 // dashboard-region(label, type) or dashboard-region(label type)
4296 // dashboard-region(label, type) or dashboard-region(label type)
4297 CSSParserValueList* args = value->function->args.get();
4298 if (!equalIgnoringCase(value->function->name, "dashboard-region(") || !args) {
4303 int numArgs = args->size();
4304 if ((numArgs != DASHBOARD_REGION_NUM_PARAMETERS && numArgs != (DASHBOARD_REGION_NUM_PARAMETERS*2-1)) &&
4305 (numArgs != DASHBOARD_REGION_SHORT_NUM_PARAMETERS && numArgs != (DASHBOARD_REGION_SHORT_NUM_PARAMETERS*2-1))) {
4310 // First arg is a label.
4311 CSSParserValue* arg = args->current();
4312 if (arg->unit != CSSPrimitiveValue::CSS_IDENT) {
4317 region->m_label = arg->string;
4319 // Second arg is a type.
4321 arg = skipCommaInDashboardRegion(args);
4322 if (arg->unit != CSSPrimitiveValue::CSS_IDENT) {
4327 if (equalIgnoringCase(arg->string, "circle"))
4328 region->m_isCircle = true;
4329 else if (equalIgnoringCase(arg->string, "rectangle"))
4330 region->m_isRectangle = true;
4336 region->m_geometryType = arg->string;
4338 if (numArgs == DASHBOARD_REGION_SHORT_NUM_PARAMETERS || numArgs == (DASHBOARD_REGION_SHORT_NUM_PARAMETERS*2-1)) {
4339 // This originally used CSSValueInvalid by accident. It might be more logical to use something else.
4340 RefPtr<CSSPrimitiveValue> amount = cssValuePool().createIdentifierValue(CSSValueInvalid);
4342 region->setTop(amount);
4343 region->setRight(amount);
4344 region->setBottom(amount);
4345 region->setLeft(amount);
4347 // Next four arguments must be offset numbers
4349 for (i = 0; i < 4; i++) {
4351 arg = skipCommaInDashboardRegion(args);
4353 valid = arg->id == CSSValueAuto || validUnit(arg, FLength);
4357 RefPtr<CSSPrimitiveValue> amount = arg->id == CSSValueAuto ?
4358 cssValuePool().createIdentifierValue(CSSValueAuto) :
4359 createPrimitiveNumericValue(arg);
4362 region->setTop(amount);
4364 region->setRight(amount);
4366 region->setBottom(amount);
4368 region->setLeft(amount);
4375 value = m_valueList->next();
4379 addProperty(propId, cssValuePool().createValue(firstRegion.release()), important);
4384 #endif /* ENABLE(DASHBOARD_SUPPORT) */
4386 PassRefPtr<CSSValue> CSSParser::parseCounterContent(CSSParserValueList* args, bool counters)
4388 unsigned numArgs = args->size();
4389 if (counters && numArgs != 3 && numArgs != 5)
4391 if (!counters && numArgs != 1 && numArgs != 3)
4394 CSSParserValue* i = args->current();
4395 if (i->unit != CSSPrimitiveValue::CSS_IDENT)
4397 RefPtr<CSSPrimitiveValue> identifier = createPrimitiveStringValue(i);
4399 RefPtr<CSSPrimitiveValue> separator;
4401 separator = cssValuePool().createValue(String(), CSSPrimitiveValue::CSS_STRING);
4404 if (i->unit != CSSParserValue::Operator || i->iValue != ',')
4408 if (i->unit != CSSPrimitiveValue::CSS_STRING)
4411 separator = createPrimitiveStringValue(i);
4414 RefPtr<CSSPrimitiveValue> listStyle;
4416 if (!i) // Make the list style default decimal
4417 listStyle = cssValuePool().createIdentifierValue(CSSValueDecimal);
4419 if (i->unit != CSSParserValue::Operator || i->iValue != ',')
4423 if (i->unit != CSSPrimitiveValue::CSS_IDENT)
4426 int listStyleID = 0;
4427 if (i->id == CSSValueNone || (i->id >= CSSValueDisc && i->id <= CSSValueKatakanaIroha))
4428 listStyleID = i->id;
4432 listStyle = cssValuePool().createIdentifierValue(listStyleID);
4435 return cssValuePool().createValue(Counter::create(identifier.release(), listStyle.release(), separator.release()));
4438 bool CSSParser::parseClipShape(CSSPropertyID propId, bool important)
4440 CSSParserValue* value = m_valueList->current();
4441 CSSParserValueList* args = value->function->args.get();
4443 if (!equalIgnoringCase(value->function->name, "rect(") || !args)
4446 // rect(t, r, b, l) || rect(t r b l)
4447 if (args->size() != 4 && args->size() != 7)
4449 RefPtr<Rect> rect = Rect::create();
4452 CSSParserValue* a = args->current();
4454 valid = a->id == CSSValueAuto || validUnit(a, FLength);
4457 RefPtr<CSSPrimitiveValue> length = a->id == CSSValueAuto ?
4458 cssValuePool().createIdentifierValue(CSSValueAuto) :
4459 createPrimitiveNumericValue(a);
4461 rect->setTop(length);
4463 rect->setRight(length);
4465 rect->setBottom(length);
4467 rect->setLeft(length);
4469 if (a && args->size() == 7) {
4470 if (a->unit == CSSParserValue::Operator && a->iValue == ',') {
4480 addProperty(propId, cssValuePool().createValue(rect.release()), important);
4481 m_valueList->next();
4487 PassRefPtr<CSSBasicShape> CSSParser::parseBasicShapeRectangle(CSSParserValueList* args)
4491 // rect(x, y, width, height, [[rx], ry])
4492 if (args->size() != 7 && args->size() != 9 && args->size() != 11)
4495 RefPtr<CSSBasicShapeRectangle> shape = CSSBasicShapeRectangle::create();
4497 unsigned argumentNumber = 0;
4498 CSSParserValue* argument = args->current();
4500 Units unitFlags = FLength | FPercent;
4501 if (argumentNumber > 1) {
4502 // Arguments width, height, rx, and ry cannot be negative.
4503 unitFlags = unitFlags | FNonNeg;
4505 if (!validUnit(argument, unitFlags))
4508 RefPtr<CSSPrimitiveValue> length = createPrimitiveNumericValue(argument);
4509 ASSERT(argumentNumber < 6);
4510 switch (argumentNumber) {
4512 shape->setX(length);
4515 shape->setY(length);
4518 shape->setWidth(length);
4521 shape->setHeight(length);
4524 shape->setRadiusX(length);
4527 shape->setRadiusY(length);
4530 argument = args->next();
4532 if (!isComma(argument))
4535 argument = args->next();
4540 if (argumentNumber < 4)
4545 PassRefPtr<CSSBasicShape> CSSParser::parseBasicShapeCircle(CSSParserValueList* args)
4549 // circle(centerX, centerY, radius)
4550 if (args->size() != 5)
4553 RefPtr<CSSBasicShapeCircle> shape = CSSBasicShapeCircle::create();
4555 unsigned argumentNumber = 0;
4556 CSSParserValue* argument = args->current();
4558 Units unitFlags = FLength | FPercent;
4559 if (argumentNumber == 2) {
4560 // Argument radius cannot be negative.
4561 unitFlags = unitFlags | FNonNeg;
4564 if (!validUnit(argument, unitFlags))
4567 RefPtr<CSSPrimitiveValue> length = createPrimitiveNumericValue(argument);
4568 ASSERT(argumentNumber < 3);
4569 switch (argumentNumber) {
4571 shape->setCenterX(length);
4574 shape->setCenterY(length);
4577 shape->setRadius(length);
4581 argument = args->next();
4583 if (!isComma(argument))
4585 argument = args->next();
4590 if (argumentNumber < 3)
4595 PassRefPtr<CSSBasicShape> CSSParser::parseBasicShapeEllipse(CSSParserValueList* args)
4599 // ellipse(centerX, centerY, radiusX, radiusY)
4600 if (args->size() != 7)
4603 RefPtr<CSSBasicShapeEllipse> shape = CSSBasicShapeEllipse::create();
4604 unsigned argumentNumber = 0;
4605 CSSParserValue* argument = args->current();
4607 Units unitFlags = FLength | FPercent;
4608 if (argumentNumber > 1) {
4609 // Arguments radiusX and radiusY cannot be negative.
4610 unitFlags = unitFlags | FNonNeg;
4612 if (!validUnit(argument, unitFlags))
4615 RefPtr<CSSPrimitiveValue> length = createPrimitiveNumericValue(argument);
4616 ASSERT(argumentNumber < 4);
4617 switch (argumentNumber) {
4619 shape->setCenterX(length);
4622 shape->setCenterY(length);
4625 shape->setRadiusX(length);
4628 shape->setRadiusY(length);
4632 argument = args->next();
4634 if (!isComma(argument))
4636 argument = args->next();
4641 if (argumentNumber < 4)
4646 PassRefPtr<CSSBasicShape> CSSParser::parseBasicShapePolygon(CSSParserValueList* args)
4650 unsigned size = args->size();
4654 RefPtr<CSSBasicShapePolygon> shape = CSSBasicShapePolygon::create();
4656 CSSParserValue* argument = args->current();
4657 if (argument->id == CSSValueEvenodd || argument->id == CSSValueNonzero) {
4658 shape->setWindRule(argument->id == CSSValueEvenodd ? RULE_EVENODD : RULE_NONZERO);
4660 if (!isComma(args->next()))
4663 argument = args->next();
4667 // <length> <length>, ... <length> <length> -> each pair has 3 elements except the last one
4668 if (!size || (size % 3) - 2)
4671 CSSParserValue* argumentX = argument;
4673 if (!validUnit(argumentX, FLength | FPercent))
4676 CSSParserValue* argumentY = args->next();
4677 if (!argumentY || !validUnit(argumentY, FLength | FPercent))
4680 RefPtr<CSSPrimitiveValue> xLength = createPrimitiveNumericValue(argumentX);
4681 RefPtr<CSSPrimitiveValue> yLength = createPrimitiveNumericValue(argumentY);
4683 shape->appendPoint(xLength.release(), yLength.release());
4685 CSSParserValue* commaOrNull = args->next();
4688 else if (!isComma(commaOrNull))
4691 argumentX = args->next();
4697 bool CSSParser::parseBasicShape(CSSPropertyID propId, bool important)
4699 CSSParserValue* value = m_valueList->current();
4700 ASSERT(value->unit == CSSParserValue::Function);
4701 CSSParserValueList* args = value->function->args.get();
4706 RefPtr<CSSBasicShape> shape;
4707 if (equalIgnoringCase(value->function->name, "rectangle("))
4708 shape = parseBasicShapeRectangle(args);
4709 else if (equalIgnoringCase(value->function->name, "circle("))
4710 shape = parseBasicShapeCircle(args);
4711 else if (equalIgnoringCase(value->function->name, "ellipse("))
4712 shape = parseBasicShapeEllipse(args);
4713 else if (equalIgnoringCase(value->function->name, "polygon("))
4714 shape = parseBasicShapePolygon(args);
4719 addProperty(propId, cssValuePool().createValue(shape.release()), important);
4720 m_valueList->next();
4724 // [ 'font-style' || 'font-variant' || 'font-weight' ]? 'font-size' [ / 'line-height' ]? 'font-family'
4725 bool CSSParser::parseFont(bool important)
4727 // Let's check if there is an inherit or initial somewhere in the shorthand.
4728 for (unsigned i = 0; i < m_valueList->size(); ++i) {
4729 if (m_valueList->valueAt(i)->id == CSSValueInherit || m_valueList->valueAt(i)->id == CSSValueInitial)
4733 ShorthandScope scope(this, CSSPropertyFont);
4734 // Optional font-style, font-variant and font-weight.
4735 bool fontStyleParsed = false;
4736 bool fontVariantParsed = false;
4737 bool fontWeightParsed = false;
4738 CSSParserValue* value;
4739 while ((value = m_valueList->current())) {
4740 if (!fontStyleParsed && isValidKeywordPropertyAndValue(CSSPropertyFontStyle, value->id, m_context)) {
4741 addProperty(CSSPropertyFontStyle, cssValuePool().createIdentifierValue(value->id), important);
4742 fontStyleParsed = true;
4743 } else if (!fontVariantParsed && (value->id == CSSValueNormal || value->id == CSSValueSmallCaps)) {
4744 // Font variant in the shorthand is particular, it only accepts normal or small-caps.
4745 addProperty(CSSPropertyFontVariant, cssValuePool().createIdentifierValue(value->id), important);
4746 fontVariantParsed = true;
4747 } else if (!fontWeightParsed && parseFontWeight(important))
4748 fontWeightParsed = true;
4751 m_valueList->next();
4757 if (!fontStyleParsed)
4758 addProperty(CSSPropertyFontStyle, cssValuePool().createIdentifierValue(CSSValueNormal), important, true);
4759 if (!fontVariantParsed)
4760 addProperty(CSSPropertyFontVariant, cssValuePool().createIdentifierValue(CSSValueNormal), important, true);
4761 if (!fontWeightParsed)
4762 addProperty(CSSPropertyFontWeight, cssValuePool().createIdentifierValue(CSSValueNormal), important, true);
4764 // Now a font size _must_ come.
4765 // <absolute-size> | <relative-size> | <length> | <percentage> | inherit
4766 if (!parseFontSize(important))
4769 value = m_valueList->current();
4773 if (value->unit == CSSParserValue::Operator && value->iValue == '/') {
4774 // The line-height property.
4775 value = m_valueList->next();
4778 if (!parseLineHeight(important))
4781 addProperty(CSSPropertyLineHeight, cssValuePool().createIdentifierValue(CSSValueNormal), important, true);
4783 // Font family must come now.
4784 RefPtr<CSSValue> parsedFamilyValue = parseFontFamily();
4785 if (!parsedFamilyValue)
4788 addProperty(CSSPropertyFontFamily, parsedFamilyValue.release(), important);
4790 // FIXME: http://www.w3.org/TR/2011/WD-css3-fonts-20110324/#font-prop requires that
4791 // "font-stretch", "font-size-adjust", and "font-kerning" be reset to their initial values
4792 // but we don't seem to support them at the moment. They should also be added here once implemented.
4793 if (m_valueList->current())
4799 class FontFamilyValueBuilder {
4801 FontFamilyValueBuilder(CSSValueList* list)
4806 void add(const CSSParserString& string)
4808 if (!m_builder.isEmpty())
4809 m_builder.append(' ');
4810 m_builder.append(string.characters, string.length);
4815 if (m_builder.isEmpty())
4817 m_list->append(cssValuePool().createFontFamilyValue(m_builder.toString()));
4822 StringBuilder m_builder;
4823 CSSValueList* m_list;
4826 PassRefPtr<CSSValueList> CSSParser::parseFontFamily()
4828 RefPtr<CSSValueList> list = CSSValueList::createCommaSeparated();
4829 CSSParserValue* value = m_valueList->current();
4831 FontFamilyValueBuilder familyBuilder(list.get());
4832 bool inFamily = false;
4835 if (value->id == CSSValueInitial || value->id == CSSValueInherit || value->id == CSSValueDefault)
4837 CSSParserValue* nextValue = m_valueList->next();
4838 bool nextValBreaksFont = !nextValue ||
4839 (nextValue->unit == CSSParserValue::Operator && nextValue->iValue == ',');
4840 bool nextValIsFontName = nextValue &&
4841 ((nextValue->id >= CSSValueSerif && nextValue->id <= CSSValueWebkitBody) ||
4842 (nextValue->unit == CSSPrimitiveValue::CSS_STRING || nextValue->unit == CSSPrimitiveValue::CSS_IDENT));
4844 if (value->id >= CSSValueSerif && value->id <= CSSValueWebkitBody) {
4846 familyBuilder.add(value->string);
4847 else if (nextValBreaksFont || !nextValIsFontName)
4848 list->append(cssValuePool().createIdentifierValue(value->id));
4850 familyBuilder.commit();
4851 familyBuilder.add(value->string);
4854 } else if (value->unit == CSSPrimitiveValue::CSS_STRING) {
4855 // Strings never share in a family name.
4857 familyBuilder.commit();
4858 list->append(cssValuePool().createFontFamilyValue(value->string));
4859 } else if (value->unit == CSSPrimitiveValue::CSS_IDENT) {
4861 familyBuilder.add(value->string);
4862 else if (nextValBreaksFont || !nextValIsFontName)
4863 list->append(cssValuePool().createFontFamilyValue(value->string));
4865 familyBuilder.commit();
4866 familyBuilder.add(value->string);
4876 if (nextValBreaksFont) {
4877 value = m_valueList->next();
4878 familyBuilder.commit();
4881 else if (nextValIsFontName)
4886 familyBuilder.commit();
4888 if (!list->length())
4890 return list.release();
4893 bool CSSParser::parseLineHeight(bool important)
4895 CSSParserValue* value = m_valueList->current();
4897 bool validPrimitive = false;
4898 // normal | <number> | <length> | <percentage> | inherit
4899 if (id == CSSValueNormal)
4900 validPrimitive = true;
4902 validPrimitive = (!id && validUnit(value, FNumber | FLength | FPercent | FNonNeg));
4903 if (validPrimitive && (!m_valueList->next() || inShorthand()))
4904 addProperty(CSSPropertyLineHeight, parseValidPrimitive(id, value), important);
4905 return validPrimitive;
4908 bool CSSParser::parseFontSize(bool important)
4910 CSSParserValue* value = m_valueList->current();
4912 bool validPrimitive = false;
4913 // <absolute-size> | <relative-size> | <length> | <percentage> | inherit
4914 if (id >= CSSValueXxSmall && id <= CSSValueLarger)
4915 validPrimitive = true;
4917 validPrimitive = validUnit(value, FLength | FPercent | FNonNeg);
4918 if (validPrimitive && (!m_valueList->next() || inShorthand()))
4919 addProperty(CSSPropertyFontSize, parseValidPrimitive(id, value), important);
4920 return validPrimitive;
4923 bool CSSParser::parseFontVariant(bool important)
4925 RefPtr<CSSValueList> values;
4926 if (m_valueList->size() > 1)
4927 values = CSSValueList::createCommaSeparated();
4928 CSSParserValue* val;
4929 bool expectComma = false;
4930 while ((val = m_valueList->current())) {
4931 RefPtr<CSSPrimitiveValue> parsedValue;
4934 if (val->id == CSSValueNormal || val->id == CSSValueSmallCaps)
4935 parsedValue = cssValuePool().createIdentifierValue(val->id);
4936 else if (val->id == CSSValueAll && !values) {
4937 // 'all' is only allowed in @font-face and with no other values. Make a value list to
4938 // indicate that we are in the @font-face case.
4939 values = CSSValueList::createCommaSeparated();
4940 parsedValue = cssValuePool().createIdentifierValue(val->id);
4942 } else if (val->unit == CSSParserValue::Operator && val->iValue == ',') {
4943 expectComma = false;
4944 m_valueList->next();
4951 m_valueList->next();
4954 values->append(parsedValue.release());
4956 addProperty(CSSPropertyFontVariant, parsedValue.release(), important);
4961 if (values && values->length()) {
4962 m_hasFontFaceOnlyValues = true;
4963 addProperty(CSSPropertyFontVariant, values.release(), important);
4970 bool CSSParser::parseFontWeight(bool important)
4972 CSSParserValue* value = m_valueList->current();
4973 if ((value->id >= CSSValueNormal) && (value->id <= CSSValue900)) {
4974 addProperty(CSSPropertyFontWeight, cssValuePool().createIdentifierValue(value->id), important);
4977 if (validUnit(value, FInteger | FNonNeg, CSSQuirksMode)) {
4978 int weight = static_cast<int>(value->fValue);
4979 if (!(weight % 100) && weight >= 100 && weight <= 900) {
4980 addProperty(CSSPropertyFontWeight, cssValuePool().createIdentifierValue(CSSValue100 + weight / 100 - 1), important);
4987 bool CSSParser::parseFontFaceSrcURI(CSSValueList* valueList)
4989 RefPtr<CSSFontFaceSrcValue> uriValue(CSSFontFaceSrcValue::create(completeURL(m_valueList->current()->string)));
4991 CSSParserValue* value = m_valueList->next();
4993 valueList->append(uriValue.release());
4996 if (value->unit == CSSParserValue::Operator && value->iValue == ',') {
4997 m_valueList->next();
4998 valueList->append(uriValue.release());
5002 if (value->unit != CSSParserValue::Function || !equalIgnoringCase(value->function->name, "format("))
5005 // FIXME: http://www.w3.org/TR/2011/WD-css3-fonts-20111004/ says that format() contains a comma-separated list of strings,
5006 // but CSSFontFaceSrcValue stores only one format. Allowing one format for now.
5007 CSSParserValueList* args = value->function->args.get();
5008 if (!args || args->size() != 1 || (args->current()->unit != CSSPrimitiveValue::CSS_STRING && args->current()->unit != CSSPrimitiveValue::CSS_IDENT))
5010 uriValue->setFormat(args->current()->string);
5011 valueList->append(uriValue.release());
5012 value = m_valueList->next();
5013 if (value && value->unit == CSSParserValue::Operator && value->iValue == ',')
5014 m_valueList->next();
5018 bool CSSParser::parseFontFaceSrcLocal(CSSValueList* valueList)
5020 CSSParserValueList* args = m_valueList->current()->function->args.get();
5021 if (!args || !args->size())
5024 if (args->size() == 1 && args->current()->unit == CSSPrimitiveValue::CSS_STRING)
5025 valueList->append(CSSFontFaceSrcValue::createLocal(args->current()->string));
5026 else if (args->current()->unit == CSSPrimitiveValue::CSS_IDENT) {
5027 StringBuilder builder;
5028 for (CSSParserValue* localValue = args->current(); localValue; localValue = args->next()) {
5029 if (localValue->unit != CSSPrimitiveValue::CSS_IDENT)
5031 if (!builder.isEmpty())
5032 builder.append(' ');
5033 builder.append(localValue->string);
5035 valueList->append(CSSFontFaceSrcValue::createLocal(builder.toString()));
5039 if (CSSParserValue* value = m_valueList->next()) {
5040 if (value->unit == CSSParserValue::Operator && value->iValue == ',')
5041 m_valueList->next();
5046 bool CSSParser::parseFontFaceSrc()
5048 RefPtr<CSSValueList> values(CSSValueList::createCommaSeparated());
5050 while (CSSParserValue* value = m_valueList->current()) {
5051 if (value->unit == CSSPrimitiveValue::CSS_URI) {
5052 if (!parseFontFaceSrcURI(values.get()))
5054 } else if (value->unit == CSSParserValue::Function && equalIgnoringCase(value->function->name, "local(")) {
5055 if (!parseFontFaceSrcLocal(values.get()))
5060 if (!values->length())
5063 addProperty(CSSPropertySrc, values.release(), m_important);
5064 m_valueList->next();
5068 bool CSSParser::parseFontFaceUnicodeRange()
5070 RefPtr<CSSValueList> values = CSSValueList::createCommaSeparated();
5071 bool failed = false;
5072 bool operatorExpected = false;
5073 for (; m_valueList->current(); m_valueList->next(), operatorExpected = !operatorExpected) {
5074 if (operatorExpected) {
5075 if (m_valueList->current()->unit == CSSParserValue::Operator && m_valueList->current()->iValue == ',')
5080 if (m_valueList->current()->unit != CSSPrimitiveValue::CSS_UNICODE_RANGE) {
5085 String rangeString = m_valueList->current()->string;
5088 unsigned length = rangeString.length();
5096 while (i < length) {
5097 UChar c = rangeString[i];
5098 if (c == '-' || c == '?')
5101 if (c >= '0' && c <= '9')
5103 else if (c >= 'A' && c <= 'F')
5104 from += 10 + c - 'A';
5105 else if (c >= 'a' && c <= 'f')
5106 from += 10 + c - 'a';
5118 else if (rangeString[i] == '?') {
5120 while (i < length && rangeString[i] == '?') {
5127 to = from + span - 1;
5129 if (length < i + 2) {
5134 while (i < length) {
5135 UChar c = rangeString[i];
5137 if (c >= '0' && c <= '9')
5139 else if (c >= 'A' && c <= 'F')
5141 else if (c >= 'a' && c <= 'f')
5153 values->append(CSSUnicodeRangeValue::create(from, to));
5155 if (failed || !values->length())
5157 addProperty(CSSPropertyUnicodeRange, values.release(), m_important);
5161 // Returns the number of characters which form a valid double
5162 // and are terminated by the given terminator character
5163 static int checkForValidDouble(const UChar* string, const UChar* end, const char terminator)
5165 int length = end - string;
5169 bool decimalMarkSeen = false;
5170 int processedLength = 0;
5172 for (int i = 0; i < length; ++i) {
5173 if (string[i] == terminator) {
5174 processedLength = i;
5177 if (!isASCIIDigit(string[i])) {
5178 if (!decimalMarkSeen && string[i] == '.')
5179 decimalMarkSeen = true;
5185 if (decimalMarkSeen && processedLength == 1)
5188 return processedLength;
5191 // Returns the number of characters consumed for parsing a valid double
5192 // terminated by the given terminator character
5193 static int parseDouble(const UChar* string, const UChar* end, const char terminator, double& value)
5195 int length = checkForValidDouble(string, end, terminator);
5200 double localValue = 0;
5202 // The consumed characters here are guaranteed to be
5203 // ASCII digits with or without a decimal mark
5204 for (; position < length; ++position) {
5205 if (string[position] == '.')
5207 localValue = localValue * 10 + string[position] - '0';
5210 if (++position == length) {
5215 double fraction = 0;
5218 while (position < length && scale < MAX_SCALE) {
5219 fraction = fraction * 10 + string[position++] - '0';
5223 value = localValue + fraction / scale;
5227 static bool parseColorIntOrPercentage(const UChar*& string, const UChar* end, const char terminator, CSSPrimitiveValue::UnitTypes& expect, int& value)
5229 const UChar* current = string;
5230 double localValue = 0;
5231 bool negative = false;
5232 while (current != end && isHTMLSpace(*current))
5234 if (current != end && *current == '-') {
5238 if (current == end || !isASCIIDigit(*current))
5240 while (current != end && isASCIIDigit(*current)) {
5241 double newValue = localValue * 10 + *current++ - '0';
5242 if (newValue >= 255) {
5243 // Clamp values at 255.
5245 while (current != end && isASCIIDigit(*current))
5249 localValue = newValue;
5255 if (expect == CSSPrimitiveValue::CSS_NUMBER && (*current == '.' || *current == '%'))
5258 if (*current == '.') {
5259 // We already parsed the integral part, try to parse
5260 // the fraction part of the percentage value.
5261 double percentage = 0;
5262 int numCharactersParsed = parseDouble(current, end, '%', percentage);
5263 if (!numCharactersParsed)
5265 current += numCharactersParsed;
5266 if (*current != '%')
5268 localValue += percentage;
5271 if (expect == CSSPrimitiveValue::CSS_PERCENTAGE && *current != '%')
5274 if (*current == '%') {
5275 expect = CSSPrimitiveValue::CSS_PERCENTAGE;
5276 localValue = localValue / 100.0 * 256.0;
5277 // Clamp values at 255 for percentages over 100%
5278 if (localValue > 255)
5282 expect = CSSPrimitiveValue::CSS_NUMBER;
5284 while (current != end && isHTMLSpace(*current))
5286 if (current == end || *current++ != terminator)
5288 // Clamp negative values at zero.
5289 value = negative ? 0 : static_cast<int>(localValue);
5294 static inline bool isTenthAlpha(const UChar* string, const int length)
5297 if (length == 3 && string[0] == '0' && string[1] == '.' && isASCIIDigit(string[2]))
5301 if (length == 2 && string[0] == '.' && isASCIIDigit(string[1]))
5307 static inline bool parseAlphaValue(const UChar*& string, const UChar* end, const char terminator, int& value)
5309 while (string != end && isHTMLSpace(*string))
5312 bool negative = false;
5314 if (string != end && *string == '-') {
5321 int length = end - string;
5325 if (string[length - 1] != terminator || !isASCIIDigit(string[length - 2]))
5328 if (string[0] != '0' && string[0] != '1' && string[0] != '.') {
5329 if (checkForValidDouble(string, end, terminator)) {
5330 value = negative ? 0 : 255;
5337 if (length == 2 && string[0] != '.') {
5338 value = !negative && string[0] == '1' ? 255 : 0;
5343 if (isTenthAlpha(string, length - 1)) {
5344 static const int tenthAlphaValues[] = { 0, 25, 51, 76, 102, 127, 153, 179, 204, 230 };
5345 value = negative ? 0 : tenthAlphaValues[string[length - 2] - '0'];
5351 if (!parseDouble(string, end, terminator, alpha))
5353 value = negative ? 0 : static_cast<int>(alpha * nextafter(256.0, 0.0));
5358 static inline bool mightBeRGBA(const UChar* characters, unsigned length)
5362 return characters[4] == '('
5363 && isASCIIAlphaCaselessEqual(characters[0], 'r')
5364 && isASCIIAlphaCaselessEqual(characters[1], 'g')
5365 && isASCIIAlphaCaselessEqual(characters[2], 'b')
5366 && isASCIIAlphaCaselessEqual(characters[3], 'a');
5369 static inline bool mightBeRGB(const UChar* characters, unsigned length)
5373 return characters[3] == '('
5374 && isASCIIAlphaCaselessEqual(characters[0], 'r')
5375 && isASCIIAlphaCaselessEqual(characters[1], 'g')
5376 && isASCIIAlphaCaselessEqual(characters[2], 'b');
5379 bool CSSParser::fastParseColor(RGBA32& rgb, const String& name, bool strict)
5381 const UChar* characters = name.characters();
5382 unsigned length = name.length();
5383 CSSPrimitiveValue::UnitTypes expect = CSSPrimitiveValue::CSS_UNKNOWN;
5385 if (!strict && length >= 3) {
5386 if (name[0] == '#') {
5387 if (Color::parseHexColor(characters + 1, length - 1, rgb))
5390 if (Color::parseHexColor(characters, length, rgb))
5395 // Try rgba() syntax.
5396 if (mightBeRGBA(characters, length)) {
5397 const UChar* current = characters + 5;
5398 const UChar* end = characters + length;
5404 if (!parseColorIntOrPercentage(current, end, ',', expect, red))
5406 if (!parseColorIntOrPercentage(current, end, ',', expect, green))
5408 if (!parseColorIntOrPercentage(current, end, ',', expect, blue))
5410 if (!parseAlphaValue(current, end, ')', alpha))
5414 rgb = makeRGBA(red, green, blue, alpha);
5418 // Try rgb() syntax.
5419 if (mightBeRGB(characters, length)) {
5420 const UChar* current = characters + 4;
5421 const UChar* end = characters + length;
5425 if (!parseColorIntOrPercentage(current, end, ',', expect, red))
5427 if (!parseColorIntOrPercentage(current, end, ',', expect, green))
5429 if (!parseColorIntOrPercentage(current, end, ')', expect, blue))
5433 rgb = makeRGB(red, green, blue);
5437 // Try named colors.
5439 tc.setNamedColor(name);
5447 inline double CSSParser::parsedDouble(CSSParserValue *v, ReleaseParsedCalcValueCondition releaseCalc)
5449 const double result = m_parsedCalculation ? m_parsedCalculation->doubleValue() : v->fValue;
5450 if (releaseCalc == ReleaseParsedCalcValue)
5451 m_parsedCalculation.release();
5455 bool CSSParser::isCalculation(CSSParserValue* value)
5457 return (value->unit == CSSParserValue::Function)
5458 && (equalIgnoringCase(value->function->name, "-webkit-calc(")
5459 || equalIgnoringCase(value->function->name, "-webkit-min(")
5460 || equalIgnoringCase(value->function->name, "-webkit-max("));
5463 inline int CSSParser::colorIntFromValue(CSSParserValue* v)
5467 if (m_parsedCalculation)
5468 isPercent = m_parsedCalculation->category() == CalcPercent;
5470 isPercent = v->unit == CSSPrimitiveValue::CSS_PERCENTAGE;
5472 const double value = parsedDouble(v, ReleaseParsedCalcValue);
5480 return static_cast<int>(value * 256.0 / 100.0);
5486 return static_cast<int>(value);
5489 bool CSSParser::parseColorParameters(CSSParserValue* value, int* colorArray, bool parseAlpha)
5491 CSSParserValueList* args = value->function->args.get();
5492 CSSParserValue* v = args->current();
5493 Units unitType = FUnknown;
5494 // Get the first value and its type
5495 if (validUnit(v, FInteger, CSSStrictMode))
5496 unitType = FInteger;
5497 else if (validUnit(v, FPercent, CSSStrictMode))
5498 unitType = FPercent;
5502 colorArray[0] = colorIntFromValue(v);
5503 for (int i = 1; i < 3; i++) {
5505 if (v->unit != CSSParserValue::Operator && v->iValue != ',')
5508 if (!validUnit(v, unitType, CSSStrictMode))
5510 colorArray[i] = colorIntFromValue(v);
5514 if (v->unit != CSSParserValue::Operator && v->iValue != ',')
5517 if (!validUnit(v, FNumber, CSSStrictMode))
5519 const double value = parsedDouble(v, ReleaseParsedCalcValue);
5520 // Convert the floating pointer number of alpha to an integer in the range [0, 256),
5521 // with an equal distribution across all 256 values.
5522 colorArray[3] = static_cast<int>(max(0.0, min(1.0, value)) * nextafter(256.0, 0.0));
5527 // The CSS3 specification defines the format of a HSL color as
5528 // hsl(<number>, <percent>, <percent>)
5529 // and with alpha, the format is
5530 // hsla(<number>, <percent>, <percent>, <number>)
5531 // The first value, HUE, is in an angle with a value between 0 and 360
5532 bool CSSParser::parseHSLParameters(CSSParserValue* value, double* colorArray, bool parseAlpha)
5534 CSSParserValueList* args = value->function->args.get();
5535 CSSParserValue* v = args->current();
5536 // Get the first value
5537 if (!validUnit(v, FNumber, CSSStrictMode))
5539 // normalize the Hue value and change it to be between 0 and 1.0
5540 colorArray[0] = (((static_cast<int>(parsedDouble(v, ReleaseParsedCalcValue)) % 360) + 360) % 360) / 360.0;
5541 for (int i = 1; i < 3; i++) {
5543 if (v->unit != CSSParserValue::Operator && v->iValue != ',')
5546 if (!validUnit(v, FPercent, CSSStrictMode))
5548 colorArray[i] = max(0.0, min(100.0, parsedDouble(v, ReleaseParsedCalcValue))) / 100.0; // needs to be value between 0 and 1.0
5552 if (v->unit != CSSParserValue::Operator && v->iValue != ',')
5555 if (!validUnit(v, FNumber, CSSStrictMode))
5557 colorArray[3] = max(0.0, min(1.0, parsedDouble(v, ReleaseParsedCalcValue)));
5562 PassRefPtr<CSSPrimitiveValue> CSSParser::parseColor(CSSParserValue* value)
5564 RGBA32 c = Color::transparent;
5565 if (!parseColorFromValue(value ? value : m_valueList->current(), c))
5567 return cssValuePool().createColorValue(c);
5570 bool CSSParser::parseColorFromValue(CSSParserValue* value, RGBA32& c)
5572 if (inQuirksMode() && value->unit == CSSPrimitiveValue::CSS_NUMBER
5573 && value->fValue >= 0. && value->fValue < 1000000.) {
5574 String str = String::format("%06d", static_cast<int>((value->fValue+.5)));
5575 // FIXME: This should be strict parsing for SVG as well.
5576 if (!fastParseColor(c, str, inStrictMode()))
5578 } else if (value->unit == CSSPrimitiveValue::CSS_PARSER_HEXCOLOR ||
5579 value->unit == CSSPrimitiveValue::CSS_IDENT ||
5580 (inQuirksMode() && value->unit == CSSPrimitiveValue::CSS_DIMENSION)) {
5581 if (!fastParseColor(c, value->string, inStrictMode() && value->unit == CSSPrimitiveValue::CSS_IDENT))
5583 } else if (value->unit == CSSParserValue::Function &&
5584 value->function->args != 0 &&
5585 value->function->args->size() == 5 /* rgb + two commas */ &&
5586 equalIgnoringCase(value->function->name, "rgb(")) {
5588 if (!parseColorParameters(value, colorValues, false))
5590 c = makeRGB(colorValues[0], colorValues[1], colorValues[2]);
5592 if (value->unit == CSSParserValue::Function &&
5593 value->function->args != 0 &&
5594 value->function->args->size() == 7 /* rgba + three commas */ &&
5595 equalIgnoringCase(value->function->name, "rgba(")) {
5597 if (!parseColorParameters(value, colorValues, true))
5599 c = makeRGBA(colorValues[0], colorValues[1], colorValues[2], colorValues[3]);
5600 } else if (value->unit == CSSParserValue::Function &&
5601 value->function->args != 0 &&
5602 value->function->args->size() == 5 /* hsl + two commas */ &&
5603 equalIgnoringCase(value->function->name, "hsl(")) {
5604 double colorValues[3];
5605 if (!parseHSLParameters(value, colorValues, false))
5607 c = makeRGBAFromHSLA(colorValues[0], colorValues[1], colorValues[2], 1.0);
5608 } else if (value->unit == CSSParserValue::Function &&
5609 value->function->args != 0 &&
5610 value->function->args->size() == 7 /* hsla + three commas */ &&
5611 equalIgnoringCase(value->function->name, "hsla(")) {
5612 double colorValues[4];
5613 if (!parseHSLParameters(value, colorValues, true))
5615 c = makeRGBAFromHSLA(colorValues[0], colorValues[1], colorValues[2], colorValues[3]);
5623 // This class tracks parsing state for shadow values. If it goes out of scope (e.g., due to an early return)
5624 // without the allowBreak bit being set, then it will clean up all of the objects and destroy them.
5625 struct ShadowParseContext {
5626 ShadowParseContext(CSSPropertyID prop, CSSParser* parser)
5632 , allowSpread(false)
5634 , allowStyle(prop == CSSPropertyWebkitBoxShadow || prop == CSSPropertyBoxShadow)
5639 bool allowLength() { return allowX || allowY || allowBlur || allowSpread; }
5643 // Handle the ,, case gracefully by doing nothing.
5644 if (x || y || blur || spread || color || style) {
5646 values = CSSValueList::createCommaSeparated();
5648 // Construct the current shadow value and add it to the list.
5649 values->append(ShadowValue::create(x.release(), y.release(), blur.release(), spread.release(), style.release(), color.release()));
5652 // Now reset for the next shadow value.
5665 allowSpread = false;
5666 allowStyle = property == CSSPropertyWebkitBoxShadow || property == CSSPropertyBoxShadow;
5669 void commitLength(CSSParserValue* v)
5671 RefPtr<CSSPrimitiveValue> val = m_parser->createPrimitiveNumericValue(v);
5680 } else if (allowY) {
5685 allowStyle = property == CSSPropertyWebkitBoxShadow || property == CSSPropertyBoxShadow;
5687 } else if (allowBlur) {
5688 blur = val.release();
5690 allowSpread = property == CSSPropertyWebkitBoxShadow || property == CSSPropertyBoxShadow;
5691 } else if (allowSpread) {
5692 spread = val.release();
5693 allowSpread = false;
5697 void commitColor(PassRefPtr<CSSPrimitiveValue> val)
5706 allowSpread = false;
5707 allowStyle = property == CSSPropertyWebkitBoxShadow || property == CSSPropertyBoxShadow;
5711 void commitStyle(CSSParserValue* v)
5713 style = cssValuePool().createIdentifierValue(v->id);
5719 allowSpread = false;
5724 CSSPropertyID property;
5725 CSSParser* m_parser;
5727 RefPtr<CSSValueList> values;
5728 RefPtr<CSSPrimitiveValue> x;
5729 RefPtr<CSSPrimitiveValue> y;
5730 RefPtr<CSSPrimitiveValue> blur;
5731 RefPtr<CSSPrimitiveValue> spread;
5732 RefPtr<CSSPrimitiveValue> style;
5733 RefPtr<CSSPrimitiveValue> color;
5740 bool allowStyle; // inset or not.
5744 PassRefPtr<CSSValueList> CSSParser::parseShadow(CSSParserValueList* valueList, CSSPropertyID propId)
5746 ShadowParseContext context(propId, this);
5747 CSSParserValue* val;
5748 while ((val = valueList->current())) {
5749 // Check for a comma break first.
5750 if (val->unit == CSSParserValue::Operator) {
5751 if (val->iValue != ',' || !context.allowBreak)
5752 // Other operators aren't legal or we aren't done with the current shadow
5753 // value. Treat as invalid.
5756 // -webkit-svg-shadow does not support multiple values.
5757 if (propId == CSSPropertyWebkitSvgShadow)
5760 // The value is good. Commit it.
5761 context.commitValue();
5762 } else if (validUnit(val, FLength, CSSStrictMode)) {
5763 // We required a length and didn't get one. Invalid.
5764 if (!context.allowLength())
5767 // A length is allowed here. Construct the value and add it.
5768 context.commitLength(val);
5769 } else if (val->id == CSSValueInset) {
5770 if (!context.allowStyle)
5773 context.commitStyle(val);
5775 // The only other type of value that's ok is a color value.
5776 RefPtr<CSSPrimitiveValue> parsedColor;
5777 bool isColor = ((val->id >= CSSValueAqua && val->id <= CSSValueWindowtext) || val->id == CSSValueMenu
5778 || (val->id >= CSSValueWebkitFocusRingColor && val->id <= CSSValueWebkitText && inQuirksMode())
5779 || val->id == CSSValueCurrentcolor);
5781 if (!context.allowColor)
5783 parsedColor = cssValuePool().createIdentifierValue(val->id);
5787 // It's not built-in. Try to parse it as a color.
5788 parsedColor = parseColor(val);
5790 if (!parsedColor || !context.allowColor)
5791 return 0; // This value is not a color or length and is invalid or
5792 // it is a color, but a color isn't allowed at this point.
5794 context.commitColor(parsedColor.release());
5800 if (context.allowBreak) {
5801 context.commitValue();
5802 if (context.values && context.values->length())
5803 return context.values.release();
5809 bool CSSParser::parseReflect(CSSPropertyID propId, bool important)
5811 // box-reflect: <direction> <offset> <mask>
5813 // Direction comes first.
5814 CSSParserValue* val = m_valueList->current();
5815 CSSReflectionDirection direction;
5818 direction = ReflectionAbove;
5821 direction = ReflectionBelow;
5824 direction = ReflectionLeft;
5827 direction = ReflectionRight;
5833 // The offset comes next.
5834 val = m_valueList->next();
5835 RefPtr<CSSPrimitiveValue> offset;
5837 offset = cssValuePool().createValue(0, CSSPrimitiveValue::CSS_PX);
5839 if (!validUnit(val, FLength | FPercent))
5841 offset = createPrimitiveNumericValue(val);
5844 // Now for the mask.
5845 RefPtr<CSSValue> mask;
5846 val = m_valueList->next();
5848 if (!parseBorderImage(propId, mask))
5852 RefPtr<CSSReflectValue> reflectValue = CSSReflectValue::create(direction, offset.release(), mask.release());
5853 addProperty(propId, reflectValue.release(), important);
5854 m_valueList->next();
5858 #if ENABLE(CSS3_FLEXBOX)
5860 bool CSSParser::parseFlex(CSSParserValueList* args, bool important)
5862 if (!args || !args->size() || args->size() > 3)
5864 static const double unsetValue = -1;
5865 double flexGrow = unsetValue;
5866 double flexShrink = unsetValue;
5867 RefPtr<CSSPrimitiveValue> flexBasis;
5869 while (CSSParserValue* arg = args->current()) {
5870 if (validUnit(arg, FNumber | FNonNeg)) {
5871 if (flexGrow == unsetValue)
5872 flexGrow = arg->fValue;
5873 else if (flexShrink == unsetValue)
5874 flexShrink = arg->fValue;
5875 else if (!arg->fValue) {
5876 // flex only allows a basis of 0 (sans units) if flex-grow and flex-shrink values have already been set.
5877 flexBasis = cssValuePool().createValue(0, CSSPrimitiveValue::CSS_PX);
5879 // We only allow 3 numbers without units if the last value is 0. E.g., flex:1 1 1 is invalid.
5882 } else if (!flexBasis && (arg->id == CSSValueAuto || validUnit(arg, FLength | FPercent | FNonNeg)))
5883 flexBasis = parseValidPrimitive(arg->id, arg);
5885 // Not a valid arg for flex.
5891 if (flexGrow == unsetValue)
5893 if (flexShrink == unsetValue)
5896 flexBasis = cssValuePool().createValue(0, CSSPrimitiveValue::CSS_PX);
5898 addProperty(CSSPropertyWebkitFlexGrow, cssValuePool().createValue(clampToFloat(flexGrow), CSSPrimitiveValue::CSS_NUMBER), important);
5899 addProperty(CSSPropertyWebkitFlexShrink, cssValuePool().createValue(clampToFloat(flexShrink), CSSPrimitiveValue::CSS_NUMBER), important);
5900 addProperty(CSSPropertyWebkitFlexBasis, flexBasis, important);
5906 struct BorderImageParseContext {
5907 BorderImageParseContext()
5908 : m_canAdvance(false)
5909 , m_allowCommit(true)
5910 , m_allowImage(true)
5911 , m_allowImageSlice(true)
5912 , m_allowRepeat(true)
5913 , m_allowSlash(false)
5914 , m_requireWidth(false)
5915 , m_requireOutset(false)
5918 bool canAdvance() const { return m_canAdvance; }
5919 void setCanAdvance(bool canAdvance) { m_canAdvance = canAdvance; }
5921 bool allowCommit() const { return m_allowCommit; }
5922 bool allowImage() const { return m_allowImage; }
5923 bool allowImageSlice() const { return m_allowImageSlice; }
5924 bool allowRepeat() const { return m_allowRepeat; }
5925 bool allowSlash() const { return m_allowSlash; }
5927 bool requireWidth() const { return m_requireWidth; }
5928 bool requireOutset() const { return m_requireOutset; }
5930 void commitImage(PassRefPtr<CSSValue> image)
5933 m_canAdvance = true;
5934 m_allowCommit = true;
5935 m_allowImage = m_allowSlash = m_requireWidth = m_requireOutset = false;
5936 m_allowImageSlice = !m_imageSlice;
5937 m_allowRepeat = !m_repeat;
5939 void commitImageSlice(PassRefPtr<CSSBorderImageSliceValue> slice)
5941 m_imageSlice = slice;
5942 m_canAdvance = true;
5943 m_allowCommit = m_allowSlash = true;
5944 m_allowImageSlice = m_requireWidth = m_requireOutset = false;
5945 m_allowImage = !m_image;
5946 m_allowRepeat = !m_repeat;
5950 m_canAdvance = true;
5951 m_allowCommit = m_allowImage = m_allowImageSlice = m_allowRepeat = m_allowSlash = false;
5952 if (!m_borderSlice) {
5953 m_requireWidth = true;
5954 m_requireOutset = false;
5956 m_requireOutset = true;
5957 m_requireWidth = false;
5960 void commitBorderWidth(PassRefPtr<CSSPrimitiveValue> slice)
5962 m_borderSlice = slice;
5963 m_canAdvance = true;
5964 m_allowCommit = m_allowSlash = true;
5965 m_allowImageSlice = m_requireWidth = m_requireOutset = false;
5966 m_allowImage = !m_image;
5967 m_allowRepeat = !m_repeat;
5969 void commitBorderOutset(PassRefPtr<CSSPrimitiveValue> outset)
5972 m_canAdvance = true;
5973 m_allowCommit = true;
5974 m_allowImageSlice = m_allowSlash = m_requireWidth = m_requireOutset = false;
5975 m_allowImage = !m_image;
5976 m_allowRepeat = !m_repeat;
5978 void commitRepeat(PassRefPtr<CSSValue> repeat)
5981 m_canAdvance = true;
5982 m_allowCommit = true;
5983 m_allowRepeat = m_allowSlash = m_requireWidth = m_requireOutset = false;
5984 m_allowImageSlice = !m_imageSlice;
5985 m_allowImage = !m_image;
5988 PassRefPtr<CSSValue> commitWebKitBorderImage()
5990 return createBorderImageValue(m_image, m_imageSlice, m_borderSlice, m_outset, m_repeat);
5993 void commitBorderImage(CSSParser* parser, bool important)
5995 commitBorderImageProperty(CSSPropertyBorderImageSource, parser, m_image, important);
5996 commitBorderImageProperty(CSSPropertyBorderImageSlice, parser, m_imageSlice, important);
5997 commitBorderImageProperty(CSSPropertyBorderImageWidth, parser, m_borderSlice, important);
5998 commitBorderImageProperty(CSSPropertyBorderImageOutset, parser, m_outset, important);
5999 commitBorderImageProperty(CSSPropertyBorderImageRepeat, parser, m_repeat, important);
6002 void commitBorderImageProperty(CSSPropertyID propId, CSSParser* parser, PassRefPtr<CSSValue> value, bool important)
6005 parser->addProperty(propId, value, important);
6007 parser->addProperty(propId, cssValuePool().createImplicitInitialValue(), important, true);
6014 bool m_allowImageSlice;
6018 bool m_requireWidth;
6019 bool m_requireOutset;
6021 RefPtr<CSSValue> m_image;
6022 RefPtr<CSSBorderImageSliceValue> m_imageSlice;
6023 RefPtr<CSSPrimitiveValue> m_borderSlice;
6024 RefPtr<CSSPrimitiveValue> m_outset;
6026 RefPtr<CSSValue> m_repeat;
6029 bool CSSParser::parseBorderImage(CSSPropertyID propId, RefPtr<CSSValue>& result, bool important)
6031 ShorthandScope scope(this, propId);
6032 BorderImageParseContext context;
6033 while (CSSParserValue* val = m_valueList->current()) {
6034 context.setCanAdvance(false);
6036 if (!context.canAdvance() && context.allowSlash() && val->unit == CSSParserValue::Operator && val->iValue == '/')
6037 context.commitSlash();
6039 if (!context.canAdvance() && context.allowImage()) {
6040 if (val->unit == CSSPrimitiveValue::CSS_URI)
6041 context.commitImage(CSSImageValue::create(completeURL(val->string)));
6042 else if (isGeneratedImageValue(val)) {
6043 RefPtr<CSSValue> value;
6044 if (parseGeneratedImage(m_valueList.get(), value))
6045 context.commitImage(value);
6048 #if ENABLE(CSS_IMAGE_SET)
6049 } else if (val->unit == CSSParserValue::Function && equalIgnoringCase(val->function->name, "-webkit-image-set(")) {
6050 RefPtr<CSSValue> value = parseImageSet(m_valueList.get());
6052 context.commitImage(value);
6056 } else if (val->id == CSSValueNone)
6057 context.commitImage(cssValuePool().createIdentifierValue(CSSValueNone));
6060 if (!context.canAdvance() && context.allowImageSlice()) {
6061 RefPtr<CSSBorderImageSliceValue> imageSlice;
6062 if (parseBorderImageSlice(propId, imageSlice))
6063 context.commitImageSlice(imageSlice.release());
6066 if (!context.canAdvance() && context.allowRepeat()) {
6067 RefPtr<CSSValue> repeat;
6068 if (parseBorderImageRepeat(repeat))
6069 context.commitRepeat(repeat);
6072 if (!context.canAdvance() && context.requireWidth()) {
6073 RefPtr<CSSPrimitiveValue> borderSlice;
6074 if (parseBorderImageWidth(borderSlice))
6075 context.commitBorderWidth(borderSlice.release());
6078 if (!context.canAdvance() && context.requireOutset()) {
6079 RefPtr<CSSPrimitiveValue> borderOutset;
6080 if (parseBorderImageOutset(borderOutset))
6081 context.commitBorderOutset(borderOutset.release());
6084 if (!context.canAdvance())
6087 m_valueList->next();
6090 if (context.allowCommit()) {
6091 if (propId == CSSPropertyBorderImage)
6092 context.commitBorderImage(this, important);
6094 // Need to fully commit as a single value.
6095 result = context.commitWebKitBorderImage();
6102 static bool isBorderImageRepeatKeyword(int id)
6104 return id == CSSValueStretch || id == CSSValueRepeat || id == CSSValueSpace || id == CSSValueRound;
6107 bool CSSParser::parseBorderImageRepeat(RefPtr<CSSValue>& result)
6109 RefPtr<CSSPrimitiveValue> firstValue;
6110 RefPtr<CSSPrimitiveValue> secondValue;
6111 CSSParserValue* val = m_valueList->current();
6114 if (isBorderImageRepeatKeyword(val->id))
6115 firstValue = cssValuePool().createIdentifierValue(val->id);
6119 val = m_valueList->next();
6121 if (isBorderImageRepeatKeyword(val->id))
6122 secondValue = cssValuePool().createIdentifierValue(val->id);
6123 else if (!inShorthand()) {
6124 // If we're not parsing a shorthand then we are invalid.
6127 // We need to rewind the value list, so that when its advanced we'll
6128 // end up back at this value.
6129 m_valueList->previous();
6132 secondValue = firstValue;
6134 result = cssValuePool().createValue(Pair::create(firstValue, secondValue));
6138 class BorderImageSliceParseContext {
6140 BorderImageSliceParseContext(CSSParser* parser)
6142 , m_allowNumber(true)
6144 , m_allowFinalCommit(false)
6148 bool allowNumber() const { return m_allowNumber; }
6149 bool allowFill() const { return m_allowFill; }
6150 bool allowFinalCommit() const { return m_allowFinalCommit; }
6151 CSSPrimitiveValue* top() const { return m_top.get(); }
6153 void commitNumber(CSSParserValue* v)
6155 RefPtr<CSSPrimitiveValue> val = m_parser->createPrimitiveNumericValue(v);
6167 m_allowNumber = !m_left;
6168 m_allowFinalCommit = true;
6171 void commitFill() { m_fill = true; m_allowFill = false; m_allowNumber = !m_top; }
6173 PassRefPtr<CSSBorderImageSliceValue> commitBorderImageSlice()
6175 // We need to clone and repeat values for any omissions.
6189 // Now build a rect value to hold all four of our primitive values.
6190 RefPtr<Quad> quad = Quad::create();
6191 quad->setTop(m_top);
6192 quad->setRight(m_right);
6193 quad->setBottom(m_bottom);
6194 quad->setLeft(m_left);
6196 // Make our new border image value now.
6197 return CSSBorderImageSliceValue::create(cssValuePool().createValue(quad.release()), m_fill);
6201 CSSParser* m_parser;
6205 bool m_allowFinalCommit;
6207 RefPtr<CSSPrimitiveValue> m_top;
6208 RefPtr<CSSPrimitiveValue> m_right;
6209 RefPtr<CSSPrimitiveValue> m_bottom;
6210 RefPtr<CSSPrimitiveValue> m_left;
6215 bool CSSParser::parseBorderImageSlice(CSSPropertyID propId, RefPtr<CSSBorderImageSliceValue>& result)
6217 BorderImageSliceParseContext context(this);
6218 CSSParserValue* val;
6219 while ((val = m_valueList->current())) {
6220 // FIXME calc() http://webkit.org/b/16662 : calc is parsed but values are not created yet.
6221 if (context.allowNumber() && !isCalculation(val) && validUnit(val, FInteger | FNonNeg | FPercent, CSSStrictMode)) {
6222 context.commitNumber(val);
6223 } else if (context.allowFill() && val->id == CSSValueFill)
6224 context.commitFill();
6225 else if (!inShorthand()) {
6226 // If we're not parsing a shorthand then we are invalid.
6229 if (context.allowFinalCommit()) {
6230 // We're going to successfully parse, but we don't want to consume this token.
6231 m_valueList->previous();
6235 m_valueList->next();
6238 if (context.allowFinalCommit()) {
6239 // FIXME: For backwards compatibility, -webkit-border-image, -webkit-mask-box-image and -webkit-box-reflect have to do a fill by default.
6240 // FIXME: What do we do with -webkit-box-reflect and -webkit-mask-box-image? Probably just have to leave them filling...
6241 if (propId == CSSPropertyWebkitBorderImage || propId == CSSPropertyWebkitMaskBoxImage || propId == CSSPropertyWebkitBoxReflect)
6242 context.commitFill();
6244 // Need to fully commit as a single value.
6245 result = context.commitBorderImageSlice();
6252 class BorderImageQuadParseContext {
6254 BorderImageQuadParseContext(CSSParser* parser)
6256 , m_allowNumber(true)
6257 , m_allowFinalCommit(false)
6260 bool allowNumber() const { return m_allowNumber; }
6261 bool allowFinalCommit() const { return m_allowFinalCommit; }
6262 CSSPrimitiveValue* top() const { return m_top.get(); }
6264 void commitNumber(CSSParserValue* v)
6266 RefPtr<CSSPrimitiveValue> val;
6267 if (v->id == CSSValueAuto)
6268 val = cssValuePool().createIdentifierValue(v->id);
6270 val = m_parser->createPrimitiveNumericValue(v);
6283 m_allowNumber = !m_left;
6284 m_allowFinalCommit = true;
6287 void setAllowFinalCommit() { m_allowFinalCommit = true; }
6288 void setTop(PassRefPtr<CSSPrimitiveValue> val) { m_top = val; }
6290 PassRefPtr<CSSPrimitiveValue> commitBorderImageQuad()
6292 // We need to clone and repeat values for any omissions.
6306 // Now build a quad value to hold all four of our primitive values.
6307 RefPtr<Quad> quad = Quad::create();
6308 quad->setTop(m_top);
6309 quad->setRight(m_right);
6310 quad->setBottom(m_bottom);
6311 quad->setLeft(m_left);
6313 // Make our new value now.
6314 return cssValuePool().createValue(quad.release());
6318 CSSParser* m_parser;
6321 bool m_allowFinalCommit;
6323 RefPtr<CSSPrimitiveValue> m_top;
6324 RefPtr<CSSPrimitiveValue> m_right;
6325 RefPtr<CSSPrimitiveValue> m_bottom;
6326 RefPtr<CSSPrimitiveValue> m_left;
6329 bool CSSParser::parseBorderImageQuad(Units validUnits, RefPtr<CSSPrimitiveValue>& result)
6331 BorderImageQuadParseContext context(this);
6332 CSSParserValue* val;
6333 while ((val = m_valueList->current())) {
6334 if (context.allowNumber() && (validUnit(val, validUnits, CSSStrictMode) || val->id == CSSValueAuto)) {
6335 context.commitNumber(val);
6336 } else if (!inShorthand()) {
6337 // If we're not parsing a shorthand then we are invalid.
6340 if (context.allowFinalCommit())
6341 m_valueList->previous(); // The shorthand loop will advance back to this point.
6344 m_valueList->next();
6347 if (context.allowFinalCommit()) {
6348 // Need to fully commit as a single value.
6349 result = context.commitBorderImageQuad();
6355 bool CSSParser::parseBorderImageWidth(RefPtr<CSSPrimitiveValue>& result)
6357 return parseBorderImageQuad(FLength | FInteger | FNonNeg | FPercent, result);
6360 bool CSSParser::parseBorderImageOutset(RefPtr<CSSPrimitiveValue>& result)
6362 return parseBorderImageQuad(FLength | FInteger | FNonNeg, result);
6365 static void completeBorderRadii(RefPtr<CSSPrimitiveValue> radii[4])
6371 radii[1] = radii[0];
6372 radii[2] = radii[0];
6374 radii[3] = radii[1];
6377 bool CSSParser::parseBorderRadius(CSSPropertyID propId, bool important)
6379 unsigned num = m_valueList->size();
6383 ShorthandScope scope(this, propId);
6384 RefPtr<CSSPrimitiveValue> radii[2][4];
6386 unsigned indexAfterSlash = 0;
6387 for (unsigned i = 0; i < num; ++i) {
6388 CSSParserValue* value = m_valueList->valueAt(i);
6389 if (value->unit == CSSParserValue::Operator) {
6390 if (value->iValue != '/')
6393 if (!i || indexAfterSlash || i + 1 == num || num > i + 5)
6396 indexAfterSlash = i + 1;
6397 completeBorderRadii(radii[0]);
6401 if (i - indexAfterSlash >= 4)
6404 if (!validUnit(value, FLength | FPercent | FNonNeg))
6407 RefPtr<CSSPrimitiveValue> radius = createPrimitiveNumericValue(value);
6409 if (!indexAfterSlash) {
6410 radii[0][i] = radius;
6412 // Legacy syntax: -webkit-border-radius: l1 l2; is equivalent to border-radius: l1 / l2;
6413 if (num == 2 && propId == CSSPropertyWebkitBorderRadius) {
6414 indexAfterSlash = 1;
6415 completeBorderRadii(radii[0]);
6418 radii[1][i - indexAfterSlash] = radius.release();
6421 if (!indexAfterSlash) {
6422 completeBorderRadii(radii[0]);
6423 for (unsigned i = 0; i < 4; ++i)
6424 radii[1][i] = radii[0][i];
6426 completeBorderRadii(radii[1]);
6428 ImplicitScope implicitScope(this, PropertyImplicit);
6429 addProperty(CSSPropertyBorderTopLeftRadius, cssValuePool().createValue(Pair::create(radii[0][0].release(), radii[1][0].release())), important);
6430 addProperty(CSSPropertyBorderTopRightRadius, cssValuePool().createValue(Pair::create(radii[0][1].release(), radii[1][1].release())), important);
6431 addProperty(CSSPropertyBorderBottomRightRadius, cssValuePool().createValue(Pair::create(radii[0][2].release(), radii[1][2].release())), important);
6432 addProperty(CSSPropertyBorderBottomLeftRadius, cssValuePool().createValue(Pair::create(radii[0][3].release(), radii[1][3].release())), important);
6436 bool CSSParser::parseAspectRatio(bool important)
6438 unsigned num = m_valueList->size();
6439 if (num == 1 && m_valueList->valueAt(0)->id == CSSValueNone) {
6440 addProperty(CSSPropertyWebkitAspectRatio, cssValuePool().createIdentifierValue(CSSValueNone), important);
6447 CSSParserValue* lvalue = m_valueList->valueAt(0);
6448 CSSParserValue* op = m_valueList->valueAt(1);
6449 CSSParserValue* rvalue = m_valueList->valueAt(2);
6451 if (op->unit != CSSParserValue::Operator || op->iValue != '/')
6454 if (!validUnit(lvalue, FNumber | FNonNeg) || !validUnit(rvalue, FNumber | FNonNeg))
6457 if (!lvalue->fValue || !rvalue->fValue)
6460 addProperty(CSSPropertyWebkitAspectRatio, CSSAspectRatioValue::create(narrowPrecisionToFloat(lvalue->fValue), narrowPrecisionToFloat(rvalue->fValue)), important);
6465 bool CSSParser::parseCounter(CSSPropertyID propId, int defaultValue, bool important)
6467 enum { ID, VAL } state = ID;
6469 RefPtr<CSSValueList> list = CSSValueList::createCommaSeparated();
6470 RefPtr<CSSPrimitiveValue> counterName;
6473 CSSParserValue* val = m_valueList->current();
6476 if (val && val->unit == CSSPrimitiveValue::CSS_IDENT) {
6477 counterName = createPrimitiveStringValue(val);
6479 m_valueList->next();
6484 int i = defaultValue;
6485 if (val && val->unit == CSSPrimitiveValue::CSS_NUMBER) {
6486 i = clampToInteger(val->fValue);
6487 m_valueList->next();
6490 list->append(cssValuePool().createValue(Pair::create(counterName.release(),
6491 cssValuePool().createValue(i, CSSPrimitiveValue::CSS_NUMBER))));
6499 if (list->length() > 0) {
6500 addProperty(propId, list.release(), important);
6507 // This should go away once we drop support for -webkit-gradient
6508 static PassRefPtr<CSSPrimitiveValue> parseDeprecatedGradientPoint(CSSParserValue* a, bool horizontal)
6510 RefPtr<CSSPrimitiveValue> result;
6511 if (a->unit == CSSPrimitiveValue::CSS_IDENT) {
6512 if ((equalIgnoringCase(a->string, "left") && horizontal)
6513 || (equalIgnoringCase(a->string, "top") && !horizontal))
6514 result = cssValuePool().createValue(0., CSSPrimitiveValue::CSS_PERCENTAGE);
6515 else if ((equalIgnoringCase(a->string, "right") && horizontal)
6516 || (equalIgnoringCase(a->string, "bottom") && !horizontal))
6517 result = cssValuePool().createValue(100., CSSPrimitiveValue::CSS_PERCENTAGE);
6518 else if (equalIgnoringCase(a->string, "center"))
6519 result = cssValuePool().createValue(50., CSSPrimitiveValue::CSS_PERCENTAGE);
6520 } else if (a->unit == CSSPrimitiveValue::CSS_NUMBER || a->unit == CSSPrimitiveValue::CSS_PERCENTAGE)
6521 result = cssValuePool().createValue(a->fValue, static_cast<CSSPrimitiveValue::UnitTypes>(a->unit));
6525 static bool parseDeprecatedGradientColorStop(CSSParser* p, CSSParserValue* a, CSSGradientColorStop& stop)
6527 if (a->unit != CSSParserValue::Function)
6530 if (!equalIgnoringCase(a->function->name, "from(") &&
6531 !equalIgnoringCase(a->function->name, "to(") &&
6532 !equalIgnoringCase(a->function->name, "color-stop("))
6535 CSSParserValueList* args = a->function->args.get();
6539 if (equalIgnoringCase(a->function->name, "from(")
6540 || equalIgnoringCase(a->function->name, "to(")) {
6541 // The "from" and "to" stops expect 1 argument.
6542 if (args->size() != 1)
6545 if (equalIgnoringCase(a->function->name, "from("))
6546 stop.m_position = cssValuePool().createValue(0, CSSPrimitiveValue::CSS_NUMBER);
6548 stop.m_position = cssValuePool().createValue(1, CSSPrimitiveValue::CSS_NUMBER);
6550 int id = args->current()->id;
6551 if (id == CSSValueWebkitText || (id >= CSSValueAqua && id <= CSSValueWindowtext) || id == CSSValueMenu)
6552 stop.m_color = cssValuePool().createIdentifierValue(id);
6554 stop.m_color = p->parseColor(args->current());
6559 // The "color-stop" function expects 3 arguments.
6560 if (equalIgnoringCase(a->function->name, "color-stop(")) {
6561 if (args->size() != 3)
6564 CSSParserValue* stopArg = args->current();
6565 if (stopArg->unit == CSSPrimitiveValue::CSS_PERCENTAGE)
6566 stop.m_position = cssValuePool().createValue(stopArg->fValue / 100, CSSPrimitiveValue::CSS_NUMBER);
6567 else if (stopArg->unit == CSSPrimitiveValue::CSS_NUMBER)
6568 stop.m_position = cssValuePool().createValue(stopArg->fValue, CSSPrimitiveValue::CSS_NUMBER);
6572 stopArg = args->next();
6573 if (stopArg->unit != CSSParserValue::Operator || stopArg->iValue != ',')
6576 stopArg = args->next();
6577 int id = stopArg->id;
6578 if (id == CSSValueWebkitText || (id >= CSSValueAqua && id <= CSSValueWindowtext) || id == CSSValueMenu)
6579 stop.m_color = cssValuePool().createIdentifierValue(id);
6581 stop.m_color = p->parseColor(stopArg);
6589 bool CSSParser::parseDeprecatedGradient(CSSParserValueList* valueList, RefPtr<CSSValue>& gradient)
6591 // Walk the arguments.
6592 CSSParserValueList* args = valueList->current()->function->args.get();
6593 if (!args || args->size() == 0)
6596 // The first argument is the gradient type. It is an identifier.
6597 CSSGradientType gradientType;
6598 CSSParserValue* a = args->current();
6599 if (!a || a->unit != CSSPrimitiveValue::CSS_IDENT)
6601 if (equalIgnoringCase(a->string, "linear"))
6602 gradientType = CSSLinearGradient;
6603 else if (equalIgnoringCase(a->string, "radial"))
6604 gradientType = CSSRadialGradient;
6608 RefPtr<CSSGradientValue> result;
6609 switch (gradientType) {
6610 case CSSLinearGradient:
6611 result = CSSLinearGradientValue::create(NonRepeating, true);
6613 case CSSRadialGradient:
6614 result = CSSRadialGradientValue::create(NonRepeating, true);
6623 // Next comes the starting point for the gradient as an x y pair. There is no
6624 // comma between the x and the y values.
6625 // First X. It can be left, right, number or percent.
6629 RefPtr<CSSPrimitiveValue> point = parseDeprecatedGradientPoint(a, true);
6632 result->setFirstX(point.release());
6634 // First Y. It can be top, bottom, number or percent.
6638 point = parseDeprecatedGradientPoint(a, false);
6641 result->setFirstY(point.release());
6643 // Comma after the first point.
6648 // For radial gradients only, we now expect a numeric radius.
6649 if (gradientType == CSSRadialGradient) {
6651 if (!a || a->unit != CSSPrimitiveValue::CSS_NUMBER)
6653 static_cast<CSSRadialGradientValue*>(result.get())->setFirstRadius(createPrimitiveNumericValue(a));
6655 // Comma after the first radius.
6661 // Next is the ending point for the gradient as an x, y pair.
6662 // Second X. It can be left, right, number or percent.
6666 point = parseDeprecatedGradientPoint(a, true);
6669 result->setSecondX(point.release());
6671 // Second Y. It can be top, bottom, number or percent.
6675 point = parseDeprecatedGradientPoint(a, false);
6678 result->setSecondY(point.release());
6680 // For radial gradients only, we now expect the second radius.
6681 if (gradientType == CSSRadialGradient) {
6682 // Comma after the second point.
6688 if (!a || a->unit != CSSPrimitiveValue::CSS_NUMBER)
6690 static_cast<CSSRadialGradientValue*>(result.get())->setSecondRadius(createPrimitiveNumericValue(a));
6693 // We now will accept any number of stops (0 or more).
6696 // Look for the comma before the next stop.
6700 // Now examine the stop itself.
6705 // The function name needs to be one of "from", "to", or "color-stop."
6706 CSSGradientColorStop stop;
6707 if (!parseDeprecatedGradientColorStop(this, a, stop))
6709 result->addStop(stop);
6715 gradient = result.release();
6719 static PassRefPtr<CSSPrimitiveValue> valueFromSideKeyword(CSSParserValue* a, bool& isHorizontal)
6721 if (a->unit != CSSPrimitiveValue::CSS_IDENT)
6727 isHorizontal = true;
6730 case CSSValueBottom:
6731 isHorizontal = false;
6736 return cssValuePool().createIdentifierValue(a->id);
6739 static PassRefPtr<CSSPrimitiveValue> parseGradientColorOrKeyword(CSSParser* p, CSSParserValue* value)
6742 if (id == CSSValueWebkitText || (id >= CSSValueAqua && id <= CSSValueWindowtext) || id == CSSValueMenu || id == CSSValueCurrentcolor)
6743 return cssValuePool().createIdentifierValue(id);
6745 return p->parseColor(value);
6748 bool CSSParser::parseLinearGradient(CSSParserValueList* valueList, RefPtr<CSSValue>& gradient, CSSGradientRepeat repeating)
6750 RefPtr<CSSLinearGradientValue> result = CSSLinearGradientValue::create(repeating);
6752 // Walk the arguments.
6753 CSSParserValueList* args = valueList->current()->function->args.get();
6754 if (!args || !args->size())
6757 CSSParserValue* a = args->current();
6761 bool expectComma = false;
6763 if (validUnit(a, FAngle, CSSStrictMode)) {
6764 result->setAngle(createPrimitiveNumericValue(a));
6769 // Look one or two optional keywords that indicate a side or corner.
6770 RefPtr<CSSPrimitiveValue> startX, startY;
6772 RefPtr<CSSPrimitiveValue> location;
6773 bool isHorizontal = false;
6774 if ((location = valueFromSideKeyword(a, isHorizontal))) {
6780 if ((a = args->next())) {
6781 if ((location = valueFromSideKeyword(a, isHorizontal))) {
6799 if (!startX && !startY)
6800 startY = cssValuePool().createIdentifierValue(CSSValueTop);
6802 result->setFirstX(startX.release());
6803 result->setFirstY(startY.release());
6806 if (!parseGradientColorStops(args, result.get(), expectComma))
6809 Vector<CSSGradientColorStop>& stops = result->stops();
6810 if (stops.isEmpty())
6813 gradient = result.release();
6817 bool CSSParser::parseRadialGradient(CSSParserValueList* valueList, RefPtr<CSSValue>& gradient, CSSGradientRepeat repeating)
6819 RefPtr<CSSRadialGradientValue> result = CSSRadialGradientValue::create(repeating);
6821 // Walk the arguments.
6822 CSSParserValueList* args = valueList->current()->function->args.get();
6823 if (!args || !args->size())
6826 CSSParserValue* a = args->current();
6830 bool expectComma = false;
6832 // Optional background-position
6833 RefPtr<CSSValue> centerX;
6834 RefPtr<CSSValue> centerY;
6835 // parseFillPosition advances the args next pointer.
6836 parseFillPosition(args, centerX, centerY);
6837 a = args->current();
6841 if (centerX || centerY) {
6851 ASSERT(!centerX || centerX->isPrimitiveValue());
6852 ASSERT(!centerY || centerY->isPrimitiveValue());
6854 result->setFirstX(static_cast<CSSPrimitiveValue*>(centerX.get()));
6855 result->setSecondX(static_cast<CSSPrimitiveValue*>(centerX.get()));
6856 // CSS3 radial gradients always share the same start and end point.
6857 result->setFirstY(static_cast<CSSPrimitiveValue*>(centerY.get()));
6858 result->setSecondY(static_cast<CSSPrimitiveValue*>(centerY.get()));
6860 RefPtr<CSSPrimitiveValue> shapeValue;
6861 RefPtr<CSSPrimitiveValue> sizeValue;
6863 // Optional shape and/or size in any order.
6864 for (int i = 0; i < 2; ++i) {
6865 if (a->unit != CSSPrimitiveValue::CSS_IDENT)
6868 bool foundValue = false;
6870 case CSSValueCircle:
6871 case CSSValueEllipse:
6872 shapeValue = cssValuePool().createIdentifierValue(a->id);
6875 case CSSValueClosestSide:
6876 case CSSValueClosestCorner:
6877 case CSSValueFarthestSide:
6878 case CSSValueFarthestCorner:
6879 case CSSValueContain:
6881 sizeValue = cssValuePool().createIdentifierValue(a->id);
6895 result->setShape(shapeValue);
6896 result->setSizingBehavior(sizeValue);
6898 // Or, two lengths or percentages
6899 RefPtr<CSSPrimitiveValue> horizontalSize;
6900 RefPtr<CSSPrimitiveValue> verticalSize;
6902 if (!shapeValue && !sizeValue) {
6903 if (validUnit(a, FLength | FPercent)) {
6904 horizontalSize = createPrimitiveNumericValue(a);
6912 if (validUnit(a, FLength | FPercent)) {
6913 verticalSize = createPrimitiveNumericValue(a);
6922 // Must have neither or both.
6923 if (!horizontalSize != !verticalSize)
6926 result->setEndHorizontalSize(horizontalSize);
6927 result->setEndVerticalSize(verticalSize);
6929 if (!parseGradientColorStops(args, result.get(), expectComma))
6932 gradient = result.release();
6936 bool CSSParser::parseGradientColorStops(CSSParserValueList* valueList, CSSGradientValue* gradient, bool expectComma)
6938 CSSParserValue* a = valueList->current();
6940 // Now look for color stops.
6942 // Look for the comma before the next stop.
6947 a = valueList->next();
6952 // <color-stop> = <color> [ <percentage> | <length> ]?
6953 CSSGradientColorStop stop;
6954 stop.m_color = parseGradientColorOrKeyword(this, a);
6958 a = valueList->next();
6960 if (validUnit(a, FLength | FPercent)) {
6961 stop.m_position = createPrimitiveNumericValue(a);
6962 a = valueList->next();
6966 gradient->addStop(stop);
6970 // Must have 2 or more stops to be valid.
6971 return gradient->stops().size() > 1;
6974 bool CSSParser::isGeneratedImageValue(CSSParserValue* val) const
6976 if (val->unit != CSSParserValue::Function)
6979 return equalIgnoringCase(val->function->name, "-webkit-gradient(")
6980 || equalIgnoringCase(val->function->name, "-webkit-linear-gradient(")
6981 || equalIgnoringCase(val->function->name, "-webkit-repeating-linear-gradient(")
6982 || equalIgnoringCase(val->function->name, "-webkit-radial-gradient(")
6983 || equalIgnoringCase(val->function->name, "-webkit-repeating-radial-gradient(")
6984 || equalIgnoringCase(val->function->name, "-webkit-canvas(")
6985 || equalIgnoringCase(val->function->name, "-webkit-cross-fade(");
6988 bool CSSParser::parseGeneratedImage(CSSParserValueList* valueList, RefPtr<CSSValue>& value)
6990 CSSParserValue* val = valueList->current();
6992 if (val->unit != CSSParserValue::Function)
6995 if (equalIgnoringCase(val->function->name, "-webkit-gradient("))
6996 return parseDeprecatedGradient(valueList, value);
6998 if (equalIgnoringCase(val->function->name, "-webkit-linear-gradient("))
6999 return parseLinearGradient(valueList, value, NonRepeating);
7001 if (equalIgnoringCase(val->function->name, "-webkit-repeating-linear-gradient("))
7002 return parseLinearGradient(valueList, value, Repeating);
7004 if (equalIgnoringCase(val->function->name, "-webkit-radial-gradient("))
7005 return parseRadialGradient(valueList, value, NonRepeating);
7007 if (equalIgnoringCase(val->function->name, "-webkit-repeating-radial-gradient("))
7008 return parseRadialGradient(valueList, value, Repeating);
7010 if (equalIgnoringCase(val->function->name, "-webkit-canvas("))
7011 return parseCanvas(valueList, value);
7013 if (equalIgnoringCase(val->function->name, "-webkit-cross-fade("))
7014 return parseCrossfade(valueList, value);
7019 bool CSSParser::parseCrossfade(CSSParserValueList* valueList, RefPtr<CSSValue>& crossfade)
7021 RefPtr<CSSCrossfadeValue> result;
7023 // Walk the arguments.
7024 CSSParserValueList* args = valueList->current()->function->args.get();
7025 if (!args || args->size() != 5)
7027 CSSParserValue* a = args->current();
7028 RefPtr<CSSValue> fromImageValue;
7029 RefPtr<CSSValue> toImageValue;
7031 // The first argument is the "from" image. It is a fill image.
7032 if (!a || !parseFillImage(args, fromImageValue))
7041 // The second argument is the "to" image. It is a fill image.
7042 if (!a || !parseFillImage(args, toImageValue))
7051 // The third argument is the crossfade value. It is a percentage or a fractional number.
7052 RefPtr<CSSPrimitiveValue> percentage;
7056 if (a->unit == CSSPrimitiveValue::CSS_PERCENTAGE)
7057 percentage = cssValuePool().createValue(clampTo<double>(a->fValue / 100, 0, 1), CSSPrimitiveValue::CSS_NUMBER);
7058 else if (a->unit == CSSPrimitiveValue::CSS_NUMBER)
7059 percentage = cssValuePool().createValue(clampTo<double>(a->fValue, 0, 1), CSSPrimitiveValue::CSS_NUMBER);
7063 result = CSSCrossfadeValue::create(fromImageValue, toImageValue);
7064 result->setPercentage(percentage);
7071 bool CSSParser::parseCanvas(CSSParserValueList* valueList, RefPtr<CSSValue>& canvas)
7073 // Walk the arguments.
7074 CSSParserValueList* args = valueList->current()->function->args.get();
7075 if (!args || args->size() != 1)
7078 // The first argument is the canvas name. It is an identifier.
7079 CSSParserValue* value = args->current();
7080 if (!value || value->unit != CSSPrimitiveValue::CSS_IDENT)
7083 canvas = CSSCanvasValue::create(value->string);
7087 #if ENABLE(CSS_IMAGE_RESOLUTION)
7088 PassRefPtr<CSSValue> CSSParser::parseImageResolution(CSSParserValueList* valueList)
7090 RefPtr<CSSValueList> list = CSSValueList::createSpaceSeparated();
7091 bool haveResolution = false;
7092 bool haveFromImage = false;
7093 bool haveSnap = false;
7095 CSSParserValue* value = valueList->current();
7097 if (!haveFromImage && value->id == CSSValueFromImage) {
7098 list->append(cssValuePool().createIdentifierValue(value->id));
7099 haveFromImage = true;
7100 } else if (!haveSnap && value->id == CSSValueSnap) {
7101 list->append(cssValuePool().createIdentifierValue(value->id));
7103 } else if (!haveResolution && validUnit(value, FResolution | FNonNeg) && value->fValue > 0) {
7104 list->append(createPrimitiveNumericValue(value));
7105 haveResolution = true;
7108 value = m_valueList->next();
7110 if (!list->length())
7112 if (!haveFromImage && !haveResolution)
7118 #if ENABLE(CSS_IMAGE_SET)
7119 PassRefPtr<CSSValue> CSSParser::parseImageSet(CSSParserValueList* valueList)
7121 CSSParserValue* function = valueList->current();
7123 if (function->unit != CSSParserValue::Function)
7126 CSSParserValueList* functionArgs = valueList->current()->function->args.get();
7127 if (!functionArgs || !functionArgs->size() || !functionArgs->current())
7130 RefPtr<CSSImageSetValue> imageSet = CSSImageSetValue::create();
7132 CSSParserValue* arg = functionArgs->current();
7134 if (arg->unit != CSSPrimitiveValue::CSS_URI)
7137 RefPtr<CSSImageValue> image = CSSImageValue::create(completeURL(arg->string));
7138 imageSet->append(image);
7140 arg = functionArgs->next();
7141 if (!arg || arg->unit != CSSPrimitiveValue::CSS_DIMENSION)
7144 double imageScaleFactor = 0;
7145 const String& string = arg->string;
7146 const UChar* current = string.characters();
7147 const UChar* end = current + string.length();
7148 parseDouble(current, end, 'x', imageScaleFactor);
7149 if (imageScaleFactor <= 0)
7151 imageSet->append(cssValuePool().createValue(imageScaleFactor, CSSPrimitiveValue::CSS_NUMBER));
7153 // If there are no more arguments, we're done.
7154 arg = functionArgs->next();
7158 // If there are more arguments, they should be after a comma.
7162 // Skip the comma and move on to the next argument.
7163 arg = functionArgs->next();
7170 class TransformOperationInfo {
7172 TransformOperationInfo(const CSSParserString& name)
7173 : m_type(WebKitCSSTransformValue::UnknownTransformOperation)
7175 , m_allowSingleArgument(false)
7176 , m_unit(CSSParser::FUnknown)
7178 if (equalIgnoringCase(name, "scale(") || equalIgnoringCase(name, "scalex(") || equalIgnoringCase(name, "scaley(") || equalIgnoringCase(name, "scalez(")) {
7179 m_unit = CSSParser::FNumber;
7180 if (equalIgnoringCase(name, "scale("))
7181 m_type = WebKitCSSTransformValue::ScaleTransformOperation;
7182 else if (equalIgnoringCase(name, "scalex("))
7183 m_type = WebKitCSSTransformValue::ScaleXTransformOperation;
7184 else if (equalIgnoringCase(name, "scaley("))
7185 m_type = WebKitCSSTransformValue::ScaleYTransformOperation;
7187 m_type = WebKitCSSTransformValue::ScaleZTransformOperation;
7188 } else if (equalIgnoringCase(name, "scale3d(")) {
7189 m_type = WebKitCSSTransformValue::Scale3DTransformOperation;
7191 m_unit = CSSParser::FNumber;
7192 } else if (equalIgnoringCase(name, "rotate(")) {
7193 m_type = WebKitCSSTransformValue::RotateTransformOperation;
7194 m_unit = CSSParser::FAngle;
7195 } else if (equalIgnoringCase(name, "rotatex(") ||
7196 equalIgnoringCase(name, "rotatey(") ||
7197 equalIgnoringCase(name, "rotatez(")) {
7198 m_unit = CSSParser::FAngle;
7199 if (equalIgnoringCase(name, "rotatex("))
7200 m_type = WebKitCSSTransformValue::RotateXTransformOperation;
7201 else if (equalIgnoringCase(name, "rotatey("))
7202 m_type = WebKitCSSTransformValue::RotateYTransformOperation;
7204 m_type = WebKitCSSTransformValue::RotateZTransformOperation;
7205 } else if (equalIgnoringCase(name, "rotate3d(")) {
7206 m_type = WebKitCSSTransformValue::Rotate3DTransformOperation;
7208 m_unit = CSSParser::FNumber;
7209 } else if (equalIgnoringCase(name, "skew(") || equalIgnoringCase(name, "skewx(") || equalIgnoringCase(name, "skewy(")) {
7210 m_unit = CSSParser::FAngle;
7211 if (equalIgnoringCase(name, "skew("))
7212 m_type = WebKitCSSTransformValue::SkewTransformOperation;
7213 else if (equalIgnoringCase(name, "skewx("))
7214 m_type = WebKitCSSTransformValue::SkewXTransformOperation;
7216 m_type = WebKitCSSTransformValue::SkewYTransformOperation;
7217 } else if (equalIgnoringCase(name, "translate(") || equalIgnoringCase(name, "translatex(") || equalIgnoringCase(name, "translatey(") || equalIgnoringCase(name, "translatez(")) {
7218 m_unit = CSSParser::FLength | CSSParser::FPercent;
7219 if (equalIgnoringCase(name, "translate("))
7220 m_type = WebKitCSSTransformValue::TranslateTransformOperation;
7221 else if (equalIgnoringCase(name, "translatex("))
7222 m_type = WebKitCSSTransformValue::TranslateXTransformOperation;
7223 else if (equalIgnoringCase(name, "translatey("))
7224 m_type = WebKitCSSTransformValue::TranslateYTransformOperation;
7226 m_type = WebKitCSSTransformValue::TranslateZTransformOperation;
7227 } else if (equalIgnoringCase(name, "translate3d(")) {
7228 m_type = WebKitCSSTransformValue::Translate3DTransformOperation;
7230 m_unit = CSSParser::FLength | CSSParser::FPercent;
7231 } else if (equalIgnoringCase(name, "matrix(")) {
7232 m_type = WebKitCSSTransformValue::MatrixTransformOperation;
7234 m_unit = CSSParser::FNumber;
7235 } else if (equalIgnoringCase(name, "matrix3d(")) {
7236 m_type = WebKitCSSTransformValue::Matrix3DTransformOperation;
7238 m_unit = CSSParser::FNumber;
7239 } else if (equalIgnoringCase(name, "perspective(")) {
7240 m_type = WebKitCSSTransformValue::PerspectiveTransformOperation;
7241 m_unit = CSSParser::FNumber;
7244 if (equalIgnoringCase(name, "scale(") || equalIgnoringCase(name, "skew(") || equalIgnoringCase(name, "translate(")) {
7245 m_allowSingleArgument = true;
7250 WebKitCSSTransformValue::TransformOperationType type() const { return m_type; }
7251 unsigned argCount() const { return m_argCount; }
7252 CSSParser::Units unit() const { return m_unit; }
7254 bool unknown() const { return m_type == WebKitCSSTransformValue::UnknownTransformOperation; }
7255 bool hasCorrectArgCount(unsigned argCount) { return m_argCount == argCount || (m_allowSingleArgument && argCount == 1); }
7258 WebKitCSSTransformValue::TransformOperationType m_type;
7259 unsigned m_argCount;
7260 bool m_allowSingleArgument;
7261 CSSParser::Units m_unit;
7264 PassRefPtr<CSSValueList> CSSParser::parseTransform()
7269 // The transform is a list of functional primitives that specify transform operations.
7270 // We collect a list of WebKitCSSTransformValues, where each value specifies a single operation.
7271 RefPtr<CSSValueList> list = CSSValueList::createSpaceSeparated();
7272 for (CSSParserValue* value = m_valueList->current(); value; value = m_valueList->next()) {
7273 if (value->unit != CSSParserValue::Function || !value->function)
7276 // Every primitive requires at least one argument.
7277 CSSParserValueList* args = value->function->args.get();
7281 // See if the specified primitive is one we understand.
7282 TransformOperationInfo info(value->function->name);
7286 if (!info.hasCorrectArgCount(args->size()))
7289 // Create the new WebKitCSSTransformValue for this operation and add it to our list.
7290 RefPtr<WebKitCSSTransformValue> transformValue = WebKitCSSTransformValue::create(info.type());
7291 list->append(transformValue);
7294 CSSParserValue* a = args->current();
7295 unsigned argNumber = 0;
7297 CSSParser::Units unit = info.unit();
7299 if (info.type() == WebKitCSSTransformValue::Rotate3DTransformOperation && argNumber == 3) {
7300 // 4th param of rotate3d() is an angle rather than a bare number, validate it as such
7301 if (!validUnit(a, FAngle, CSSStrictMode))
7303 } else if (info.type() == WebKitCSSTransformValue::Translate3DTransformOperation && argNumber == 2) {
7304 // 3rd param of translate3d() cannot be a percentage
7305 if (!validUnit(a, FLength, CSSStrictMode))
7307 } else if (info.type() == WebKitCSSTransformValue::TranslateZTransformOperation && argNumber == 0) {
7308 // 1st param of translateZ() cannot be a percentage
7309 if (!validUnit(a, FLength, CSSStrictMode))
7311 } else if (info.type() == WebKitCSSTransformValue::PerspectiveTransformOperation && argNumber == 0) {
7312 // 1st param of perspective() must be a non-negative number (deprecated) or length.
7313 if (!validUnit(a, FNumber | FLength | FNonNeg, CSSStrictMode))
7315 } else if (!validUnit(a, unit, CSSStrictMode))
7318 // Add the value to the current transform operation.
7319 transformValue->append(createPrimitiveNumericValue(a));
7324 if (a->unit != CSSParserValue::Operator || a->iValue != ',')
7332 return list.release();
7335 #if ENABLE(CSS_FILTERS)
7337 static void filterInfoForName(const CSSParserString& name, WebKitCSSFilterValue::FilterOperationType& filterType, unsigned& maximumArgumentCount)
7339 if (equalIgnoringCase(name, "grayscale("))
7340 filterType = WebKitCSSFilterValue::GrayscaleFilterOperation;
7341 else if (equalIgnoringCase(name, "sepia("))
7342 filterType = WebKitCSSFilterValue::SepiaFilterOperation;
7343 else if (equalIgnoringCase(name, "saturate("))
7344 filterType = WebKitCSSFilterValue::SaturateFilterOperation;
7345 else if (equalIgnoringCase(name, "hue-rotate("))
7346 filterType = WebKitCSSFilterValue::HueRotateFilterOperation;
7347 else if (equalIgnoringCase(name, "invert("))
7348 filterType = WebKitCSSFilterValue::InvertFilterOperation;
7349 else if (equalIgnoringCase(name, "opacity("))
7350 filterType = WebKitCSSFilterValue::OpacityFilterOperation;
7351 else if (equalIgnoringCase(name, "brightness("))
7352 filterType = WebKitCSSFilterValue::BrightnessFilterOperation;
7353 else if (equalIgnoringCase(name, "contrast("))
7354 filterType = WebKitCSSFilterValue::ContrastFilterOperation;
7355 else if (equalIgnoringCase(name, "blur("))
7356 filterType = WebKitCSSFilterValue::BlurFilterOperation;
7357 else if (equalIgnoringCase(name, "drop-shadow(")) {
7358 filterType = WebKitCSSFilterValue::DropShadowFilterOperation;
7359 maximumArgumentCount = 4; // x-offset, y-offset, blur-radius, color -- spread and inset style not allowed.
7361 #if ENABLE(CSS_SHADERS)
7362 else if (equalIgnoringCase(name, "custom("))
7363 filterType = WebKitCSSFilterValue::CustomFilterOperation;
7367 #if ENABLE(CSS_SHADERS)
7368 static bool acceptCommaOperator(CSSParserValueList* argsList)
7370 if (CSSParserValue* arg = argsList->current()) {
7378 PassRefPtr<WebKitCSSFilterValue> CSSParser::parseCustomFilter(CSSParserValue* value)
7380 CSSParserValueList* argsList = value->function->args.get();
7384 RefPtr<WebKitCSSFilterValue> filterValue = WebKitCSSFilterValue::create(WebKitCSSFilterValue::CustomFilterOperation);
7386 // Custom filter syntax:
7388 // vertexShader: <uri> | none
7389 // fragmentShader: <uri> | none
7391 // box: filter-box | border-box | padding-box | content-box
7392 // vertexMesh: +<integer>{1,2}[wsp<box>][wsp'detached']
7394 // param-value: true|false[wsp+true|false]{0-3} |
7395 // <number>[wsp+<number>]{0-3} |
7399 // array: 'array('<number>[wsp<number>]*')'
7400 // css-3d-transform: <transform-function>;[<transform-function>]*
7401 // transform: <css-3d-transform> | <mat>
7402 // mat: 'mat2('<number>(,<number>){3}')' |
7403 // 'mat3('<number>(,<number>){8}')' |
7404 // 'mat4('<number>(,<number>){15}')' )
7405 // param-def: <param-name>wsp<param-value>
7406 // param-name: <ident>
7407 // params: [<param-def>[,<param-def>*]]
7409 // custom(<vertex-shader>[wsp<fragment-shader>][,<vertex-mesh>][,<params>])
7411 // 1. Parse the shader URLs: <vertex-shader>[wsp<fragment-shader>]
7412 RefPtr<CSSValueList> shadersList = CSSValueList::createSpaceSeparated();
7413 bool hadAtLeastOneCustomShader = false;
7414 CSSParserValue* arg;
7415 while ((arg = argsList->current())) {
7416 RefPtr<CSSValue> value;
7417 if (arg->id == CSSValueNone)
7418 value = cssValuePool().createIdentifierValue(CSSValueNone);
7419 else if (arg->unit == CSSPrimitiveValue::CSS_URI) {
7420 KURL shaderURL = completeURL(arg->string);
7421 value = WebKitCSSShaderValue::create(shaderURL.string());
7422 hadAtLeastOneCustomShader = true;
7426 shadersList->append(value.release());
7430 if (!shadersList->length() || !hadAtLeastOneCustomShader || shadersList->length() > 2 || !acceptCommaOperator(argsList))
7433 filterValue->append(shadersList.release());
7435 // 2. Parse the mesh size <vertex-mesh>
7436 RefPtr<CSSValueList> meshSizeList = CSSValueList::createSpaceSeparated();
7438 while ((arg = argsList->current())) {
7439 if (!validUnit(arg, FInteger | FNonNeg, CSSStrictMode))
7441 int integerValue = clampToInteger(arg->fValue);
7442 // According to the specification we can only accept positive non-zero values.
7443 if (integerValue < 1)
7445 meshSizeList->append(cssValuePool().createValue(integerValue, CSSPrimitiveValue::CSS_NUMBER));
7449 if (meshSizeList->length() > 2)
7452 if ((arg = argsList->current()) && (arg->id == CSSValueBorderBox || arg->id == CSSValuePaddingBox
7453 || arg->id == CSSValueContentBox || arg->id == CSSValueFilterBox)) {
7454 meshSizeList->append(cssValuePool().createIdentifierValue(arg->id));
7458 if ((arg = argsList->current()) && arg->id == CSSValueDetached) {
7459 meshSizeList->append(cssValuePool().createIdentifierValue(arg->id));
7463 if (meshSizeList->length()) {
7464 if (!acceptCommaOperator(argsList))
7466 filterValue->append(meshSizeList.release());
7469 // 3. Parser the parameters.
7470 RefPtr<CSSValueList> paramList = CSSValueList::createCommaSeparated();
7472 while ((arg = argsList->current())) {
7473 if (arg->id || arg->unit != CSSPrimitiveValue::CSS_IDENT)
7476 RefPtr<CSSValueList> parameter = CSSValueList::createSpaceSeparated();
7477 parameter->append(createPrimitiveStringValue(arg));
7480 if (!(arg = argsList->current()))
7483 // TODO: Implement other parameters types parsing.
7484 // textures: https://bugs.webkit.org/show_bug.cgi?id=71442
7485 // 3d-transforms: https://bugs.webkit.org/show_bug.cgi?id=71443
7486 // mat2, mat3, mat4: https://bugs.webkit.org/show_bug.cgi?id=71444
7487 RefPtr<CSSValueList> paramValueList = CSSValueList::createSpaceSeparated();
7488 while ((arg = argsList->current())) {
7489 // If we hit a comma it means we finished this parameter's values.
7492 if (!validUnit(arg, FNumber, CSSStrictMode))
7494 paramValueList->append(cssValuePool().createValue(arg->fValue, CSSPrimitiveValue::CSS_NUMBER));
7497 if (!paramValueList->length() || paramValueList->length() > 4)
7499 parameter->append(paramValueList.release());
7500 paramList->append(parameter.release());
7501 if (!acceptCommaOperator(argsList))
7505 if (paramList->length())
7506 filterValue->append(paramList.release());
7512 PassRefPtr<WebKitCSSFilterValue> CSSParser::parseBuiltinFilterArguments(CSSParserValueList* args, WebKitCSSFilterValue::FilterOperationType filterType)
7514 RefPtr<WebKitCSSFilterValue> filterValue = WebKitCSSFilterValue::create(filterType);
7517 switch (filterType) {
7518 case WebKitCSSFilterValue::GrayscaleFilterOperation:
7519 case WebKitCSSFilterValue::SepiaFilterOperation:
7520 case WebKitCSSFilterValue::SaturateFilterOperation:
7521 case WebKitCSSFilterValue::InvertFilterOperation:
7522 case WebKitCSSFilterValue::OpacityFilterOperation:
7523 case WebKitCSSFilterValue::ContrastFilterOperation: {
7524 // One optional argument, 0-1 or 0%-100%, if missing use 100%.
7525 if (args->size() > 1)
7529 CSSParserValue* value = args->current();
7530 if (!validUnit(value, FNumber | FPercent | FNonNeg, CSSStrictMode))
7533 double amount = value->fValue;
7535 // Saturate and Contrast allow values over 100%.
7536 if (filterType != WebKitCSSFilterValue::SaturateFilterOperation
7537 && filterType != WebKitCSSFilterValue::ContrastFilterOperation) {
7538 double maxAllowed = value->unit == CSSPrimitiveValue::CSS_PERCENTAGE ? 100.0 : 1.0;
7539 if (amount > maxAllowed)
7543 filterValue->append(cssValuePool().createValue(amount, static_cast<CSSPrimitiveValue::UnitTypes>(value->unit)));
7547 case WebKitCSSFilterValue::BrightnessFilterOperation: {
7548 // One optional argument, -1 to +1 or -100% to +100%, if missing use 0,
7549 if (args->size() > 1)
7553 CSSParserValue* value = args->current();
7554 if (!validUnit(value, FNumber | FPercent, CSSStrictMode))
7557 double amount = value->fValue;
7558 double minAllowed = value->unit == CSSPrimitiveValue::CSS_PERCENTAGE ? -100.0 : -1.0;
7559 double maxAllowed = value->unit == CSSPrimitiveValue::CSS_PERCENTAGE ? 100.0 : 1.0;
7560 if (amount < minAllowed || amount > maxAllowed)
7563 filterValue->append(cssValuePool().createValue(amount, static_cast<CSSPrimitiveValue::UnitTypes>(value->unit)));
7567 case WebKitCSSFilterValue::HueRotateFilterOperation: {
7568 // hue-rotate() takes one optional angle.
7569 if (args->size() > 1)
7573 CSSParserValue* argument = args->current();
7574 if (!validUnit(argument, FAngle, CSSStrictMode))
7577 filterValue->append(createPrimitiveNumericValue(argument));
7581 case WebKitCSSFilterValue::BlurFilterOperation: {
7582 // Blur takes a single length. Zero parameters are allowed.
7583 if (args->size() > 1)
7587 CSSParserValue* argument = args->current();
7588 if (!validUnit(argument, FLength | FNonNeg, CSSStrictMode))
7591 filterValue->append(createPrimitiveNumericValue(argument));
7595 case WebKitCSSFilterValue::DropShadowFilterOperation: {
7596 // drop-shadow() takes a single shadow.
7597 RefPtr<CSSValueList> shadowValueList = parseShadow(args, CSSPropertyWebkitFilter);
7598 if (!shadowValueList || shadowValueList->length() != 1)
7601 filterValue->append((shadowValueList.release())->itemWithoutBoundsCheck(0));
7605 ASSERT_NOT_REACHED();
7607 return filterValue.release();
7610 PassRefPtr<CSSValueList> CSSParser::parseFilter()
7615 // The filter is a list of functional primitives that specify individual operations.
7616 RefPtr<CSSValueList> list = CSSValueList::createSpaceSeparated();
7617 for (CSSParserValue* value = m_valueList->current(); value; value = m_valueList->next()) {
7618 if (value->unit != CSSPrimitiveValue::CSS_URI && (value->unit != CSSParserValue::Function || !value->function))
7621 WebKitCSSFilterValue::FilterOperationType filterType = WebKitCSSFilterValue::UnknownFilterOperation;
7623 // See if the specified primitive is one we understand.
7624 if (value->unit == CSSPrimitiveValue::CSS_URI) {
7626 RefPtr<WebKitCSSFilterValue> referenceFilterValue = WebKitCSSFilterValue::create(WebKitCSSFilterValue::ReferenceFilterOperation);
7627 list->append(referenceFilterValue);
7628 referenceFilterValue->append(WebKitCSSSVGDocumentValue::create(value->string));
7631 const CSSParserString name = value->function->name;
7632 unsigned maximumArgumentCount = 1;
7634 filterInfoForName(name, filterType, maximumArgumentCount);
7636 if (filterType == WebKitCSSFilterValue::UnknownFilterOperation)
7639 #if ENABLE(CSS_SHADERS)
7640 if (filterType == WebKitCSSFilterValue::CustomFilterOperation) {
7641 // Make sure parsing fails if custom filters are disabled.
7642 if (!m_context.isCSSCustomFilterEnabled)
7645 RefPtr<WebKitCSSFilterValue> filterValue = parseCustomFilter(value);
7648 list->append(filterValue.release());
7652 CSSParserValueList* args = value->function->args.get();
7656 RefPtr<WebKitCSSFilterValue> filterValue = parseBuiltinFilterArguments(args, filterType);
7660 list->append(filterValue);
7664 return list.release();
7668 #if ENABLE(CSS_REGIONS)
7669 static bool validFlowName(const String& flowName)
7671 return !(equalIgnoringCase(flowName, "auto")
7672 || equalIgnoringCase(flowName, "default")
7673 || equalIgnoringCase(flowName, "inherit")
7674 || equalIgnoringCase(flowName, "initial")
7675 || equalIgnoringCase(flowName, "none"));
7679 bool CSSParser::cssRegionsEnabled() const
7681 return m_context.isCSSRegionsEnabled;
7684 bool CSSParser::cssGridLayoutEnabled() const
7686 return m_context.isCSSGridLayoutEnabled;
7689 #if ENABLE(CSS_REGIONS)
7690 bool CSSParser::parseFlowThread(const String& flowName)
7692 setupParser("@-webkit-decls{-webkit-flow-into:", flowName, "}");
7697 return ((m_parsedProperties.size() == 1) && (m_parsedProperties.first().id() == CSSPropertyWebkitFlowInto));
7701 bool CSSParser::parseFlowThread(CSSPropertyID propId, bool important)
7703 ASSERT(propId == CSSPropertyWebkitFlowInto);
7704 ASSERT(cssRegionsEnabled());
7706 if (m_valueList->size() != 1)
7709 CSSParserValue* value = m_valueList->current();
7713 if (value->unit != CSSPrimitiveValue::CSS_IDENT)
7716 if (value->id == CSSValueNone) {
7717 addProperty(propId, cssValuePool().createIdentifierValue(value->id), important);
7721 String inputProperty = String(value->string);
7722 if (!inputProperty.isEmpty()) {
7723 if (!validFlowName(inputProperty))
7725 addProperty(propId, cssValuePool().createValue(inputProperty, CSSPrimitiveValue::CSS_STRING), important);
7727 addProperty(propId, cssValuePool().createIdentifierValue(CSSValueNone), important);
7732 // -webkit-flow-from: none | <ident>
7733 bool CSSParser::parseRegionThread(CSSPropertyID propId, bool important)
7735 ASSERT(propId == CSSPropertyWebkitFlowFrom);
7736 ASSERT(cssRegionsEnabled());
7738 if (m_valueList->size() != 1)
7741 CSSParserValue* value = m_valueList->current();
7745 if (value->unit != CSSPrimitiveValue::CSS_IDENT)
7748 if (value->id == CSSValueNone)
7749 addProperty(propId, cssValuePool().createIdentifierValue(value->id), important);
7751 String inputProperty = String(value->string);
7752 if (!inputProperty.isEmpty()) {
7753 if (!validFlowName(inputProperty))
7755 addProperty(propId, cssValuePool().createValue(inputProperty, CSSPrimitiveValue::CSS_STRING), important);
7757 addProperty(propId, cssValuePool().createIdentifierValue(CSSValueNone), important);
7764 bool CSSParser::parseTransformOrigin(CSSPropertyID propId, CSSPropertyID& propId1, CSSPropertyID& propId2, CSSPropertyID& propId3, RefPtr<CSSValue>& value, RefPtr<CSSValue>& value2, RefPtr<CSSValue>& value3)
7769 if (propId == CSSPropertyWebkitTransformOrigin) {
7770 propId1 = CSSPropertyWebkitTransformOriginX;
7771 propId2 = CSSPropertyWebkitTransformOriginY;
7772 propId3 = CSSPropertyWebkitTransformOriginZ;
7776 case CSSPropertyWebkitTransformOrigin:
7777 if (!parseTransformOriginShorthand(value, value2, value3))
7779 // parseTransformOriginShorthand advances the m_valueList pointer
7781 case CSSPropertyWebkitTransformOriginX: {
7782 value = parseFillPositionX(m_valueList.get());
7784 m_valueList->next();
7787 case CSSPropertyWebkitTransformOriginY: {
7788 value = parseFillPositionY(m_valueList.get());
7790 m_valueList->next();
7793 case CSSPropertyWebkitTransformOriginZ: {
7794 if (validUnit(m_valueList->current(), FLength))
7795 value = createPrimitiveNumericValue(m_valueList->current());
7797 m_valueList->next();
7801 ASSERT_NOT_REACHED();
7808 bool CSSParser::parsePerspectiveOrigin(CSSPropertyID propId, CSSPropertyID& propId1, CSSPropertyID& propId2, RefPtr<CSSValue>& value, RefPtr<CSSValue>& value2)
7812 if (propId == CSSPropertyWebkitPerspectiveOrigin) {
7813 propId1 = CSSPropertyWebkitPerspectiveOriginX;
7814 propId2 = CSSPropertyWebkitPerspectiveOriginY;
7818 case CSSPropertyWebkitPerspectiveOrigin:
7819 if (m_valueList->size() > 2)
7821 parseFillPosition(m_valueList.get(), value, value2);
7823 case CSSPropertyWebkitPerspectiveOriginX: {
7824 value = parseFillPositionX(m_valueList.get());
7826 m_valueList->next();
7829 case CSSPropertyWebkitPerspectiveOriginY: {
7830 value = parseFillPositionY(m_valueList.get());
7832 m_valueList->next();
7836 ASSERT_NOT_REACHED();
7843 bool CSSParser::parseTextEmphasisStyle(bool important)
7845 unsigned valueListSize = m_valueList->size();
7847 RefPtr<CSSPrimitiveValue> fill;
7848 RefPtr<CSSPrimitiveValue> shape;
7850 for (CSSParserValue* value = m_valueList->current(); value; value = m_valueList->next()) {
7851 if (value->unit == CSSPrimitiveValue::CSS_STRING) {
7852 if (fill || shape || (valueListSize != 1 && !inShorthand()))
7854 addProperty(CSSPropertyWebkitTextEmphasisStyle, createPrimitiveStringValue(value), important);
7855 m_valueList->next();
7859 if (value->id == CSSValueNone) {
7860 if (fill || shape || (valueListSize != 1 && !inShorthand()))
7862 addProperty(CSSPropertyWebkitTextEmphasisStyle, cssValuePool().createIdentifierValue(CSSValueNone), important);
7863 m_valueList->next();
7867 if (value->id == CSSValueOpen || value->id == CSSValueFilled) {
7870 fill = cssValuePool().createIdentifierValue(value->id);
7871 } else if (value->id == CSSValueDot || value->id == CSSValueCircle || value->id == CSSValueDoubleCircle || value->id == CSSValueTriangle || value->id == CSSValueSesame) {
7874 shape = cssValuePool().createIdentifierValue(value->id);
7875 } else if (!inShorthand())
7881 if (fill && shape) {
7882 RefPtr<CSSValueList> parsedValues = CSSValueList::createSpaceSeparated();
7883 parsedValues->append(fill.release());
7884 parsedValues->append(shape.release());
7885 addProperty(CSSPropertyWebkitTextEmphasisStyle, parsedValues.release(), important);
7889 addProperty(CSSPropertyWebkitTextEmphasisStyle, fill.release(), important);
7893 addProperty(CSSPropertyWebkitTextEmphasisStyle, shape.release(), important);
7900 bool CSSParser::parseLineBoxContain(bool important)
7902 LineBoxContain lineBoxContain = LineBoxContainNone;
7904 for (CSSParserValue* value = m_valueList->current(); value; value = m_valueList->next()) {
7905 if (value->id == CSSValueBlock) {
7906 if (lineBoxContain & LineBoxContainBlock)
7908 lineBoxContain |= LineBoxContainBlock;
7909 } else if (value->id == CSSValueInline) {
7910 if (lineBoxContain & LineBoxContainInline)
7912 lineBoxContain |= LineBoxContainInline;
7913 } else if (value->id == CSSValueFont) {
7914 if (lineBoxContain & LineBoxContainFont)
7916 lineBoxContain |= LineBoxContainFont;
7917 } else if (value->id == CSSValueGlyphs) {
7918 if (lineBoxContain & LineBoxContainGlyphs)
7920 lineBoxContain |= LineBoxContainGlyphs;
7921 } else if (value->id == CSSValueReplaced) {
7922 if (lineBoxContain & LineBoxContainReplaced)
7924 lineBoxContain |= LineBoxContainReplaced;
7925 } else if (value->id == CSSValueInlineBox) {
7926 if (lineBoxContain & LineBoxContainInlineBox)
7928 lineBoxContain |= LineBoxContainInlineBox;
7933 if (!lineBoxContain)
7936 addProperty(CSSPropertyWebkitLineBoxContain, CSSLineBoxContainValue::create(lineBoxContain), important);
7940 bool CSSParser::parseFontFeatureTag(CSSValueList* settings)
7942 // Feature tag name consists of 4-letter characters.
7943 static const int tagNameLength = 4;
7945 CSSParserValue* value = m_valueList->current();
7946 // Feature tag name comes first
7947 if (value->unit != CSSPrimitiveValue::CSS_STRING)
7949 if (value->string.length != tagNameLength)
7951 for (int i = 0; i < tagNameLength; ++i) {
7952 // Limits the range of characters to 0x20-0x7E, following the tag name rules defiend in the OpenType specification.
7953 UChar character = value->string.characters[i];
7954 if (character < 0x20 || character > 0x7E)
7958 String tag = value->string;
7960 // Feature tag values could follow: <integer> | on | off
7961 value = m_valueList->next();
7963 if (value->unit == CSSPrimitiveValue::CSS_NUMBER && value->isInt && value->fValue >= 0) {
7964 tagValue = clampToInteger(value->fValue);
7967 m_valueList->next();
7968 } else if (value->id == CSSValueOn || value->id == CSSValueOff) {
7969 tagValue = value->id == CSSValueOn;
7970 m_valueList->next();
7973 settings->append(FontFeatureValue::create(tag, tagValue));
7977 bool CSSParser::parseFontFeatureSettings(bool important)
7979 if (m_valueList->size() == 1 && m_valueList->current()->id == CSSValueNormal) {
7980 RefPtr<CSSPrimitiveValue> normalValue = cssValuePool().createIdentifierValue(CSSValueNormal);
7981 m_valueList->next();
7982 addProperty(CSSPropertyWebkitFontFeatureSettings, normalValue.release(), important);
7986 RefPtr<CSSValueList> settings = CSSValueList::createCommaSeparated();
7987 for (CSSParserValue* value = m_valueList->current(); value; value = m_valueList->next()) {
7988 if (!parseFontFeatureTag(settings.get()))
7991 // If the list isn't parsed fully, the current value should be comma.
7992 value = m_valueList->current();
7993 if (value && !isComma(value))
7996 if (settings->length()) {
7997 addProperty(CSSPropertyWebkitFontFeatureSettings, settings.release(), important);
8003 bool CSSParser::parseFontVariantLigatures(bool important)
8005 RefPtr<CSSValueList> ligatureValues = CSSValueList::createSpaceSeparated();
8006 bool sawCommonLigaturesValue = false;
8007 bool sawDiscretionaryLigaturesValue = false;
8008 bool sawHistoricalLigaturesValue = false;
8010 for (CSSParserValue* value = m_valueList->current(); value; value = m_valueList->next()) {
8011 if (value->unit != CSSPrimitiveValue::CSS_IDENT)
8014 switch (value->id) {
8015 case CSSValueNoCommonLigatures:
8016 case CSSValueCommonLigatures:
8017 if (sawCommonLigaturesValue)
8019 sawCommonLigaturesValue = true;
8020 ligatureValues->append(cssValuePool().createIdentifierValue(value->id));
8022 case CSSValueNoDiscretionaryLigatures:
8023 case CSSValueDiscretionaryLigatures:
8024 if (sawDiscretionaryLigaturesValue)
8026 sawDiscretionaryLigaturesValue = true;
8027 ligatureValues->append(cssValuePool().createIdentifierValue(value->id));
8029 case CSSValueNoHistoricalLigatures:
8030 case CSSValueHistoricalLigatures:
8031 if (sawHistoricalLigaturesValue)
8033 sawHistoricalLigaturesValue = true;
8034 ligatureValues->append(cssValuePool().createIdentifierValue(value->id));
8041 if (!ligatureValues->length())
8044 addProperty(CSSPropertyWebkitFontVariantLigatures, ligatureValues.release(), important);
8048 bool CSSParser::parseCalculation(CSSParserValue* value, CalculationPermittedValueRange range)
8050 ASSERT(isCalculation(value));
8052 CSSParserValueList* args = value->function->args.get();
8053 if (!args || !args->size())
8056 ASSERT(!m_parsedCalculation);
8057 m_parsedCalculation = CSSCalcValue::create(value->function->name, args, range);
8059 if (!m_parsedCalculation)
8067 #include "CSSGrammar.h"
8069 enum CharacterType {
8070 // Types for the main switch.
8072 // The first 4 types must be grouped together, as they
8073 // represent the allowed chars in an identifier.
8075 CharacterIdentifierStart,
8081 CharacterWhiteSpace,
8082 CharacterEndMediaQuery,
8083 CharacterEndNthChild,
8085 CharacterExclamationMark,
8096 CharacterVerticalBar,
8101 static const CharacterType typesOfASCIICharacters[128] = {
8102 /* 0 - Null */ CharacterNull,
8103 /* 1 - Start of Heading */ CharacterOther,
8104 /* 2 - Start of Text */ CharacterOther,
8105 /* 3 - End of Text */ CharacterOther,
8106 /* 4 - End of Transm. */ CharacterOther,
8107 /* 5 - Enquiry */ CharacterOther,
8108 /* 6 - Acknowledgment */ CharacterOther,
8109 /* 7 - Bell */ CharacterOther,
8110 /* 8 - Back Space */ CharacterOther,
8111 /* 9 - Horizontal Tab */ CharacterWhiteSpace,
8112 /* 10 - Line Feed */ CharacterWhiteSpace,
8113 /* 11 - Vertical Tab */ CharacterOther,
8114 /* 12 - Form Feed */ CharacterWhiteSpace,
8115 /* 13 - Carriage Return */ CharacterWhiteSpace,
8116 /* 14 - Shift Out */ CharacterOther,
8117 /* 15 - Shift In */ CharacterOther,
8118 /* 16 - Data Line Escape */ CharacterOther,
8119 /* 17 - Device Control 1 */ CharacterOther,
8120 /* 18 - Device Control 2 */ CharacterOther,
8121 /* 19 - Device Control 3 */ CharacterOther,
8122 /* 20 - Device Control 4 */ CharacterOther,
8123 /* 21 - Negative Ack. */ CharacterOther,
8124 /* 22 - Synchronous Idle */ CharacterOther,
8125 /* 23 - End of Transmit */ CharacterOther,
8126 /* 24 - Cancel */ CharacterOther,
8127 /* 25 - End of Medium */ CharacterOther,
8128 /* 26 - Substitute */ CharacterOther,
8129 /* 27 - Escape */ CharacterOther,
8130 /* 28 - File Separator */ CharacterOther,
8131 /* 29 - Group Separator */ CharacterOther,
8132 /* 30 - Record Separator */ CharacterOther,
8133 /* 31 - Unit Separator */ CharacterOther,
8134 /* 32 - Space */ CharacterWhiteSpace,
8135 /* 33 - ! */ CharacterExclamationMark,
8136 /* 34 - " */ CharacterQuote,
8137 /* 35 - # */ CharacterHashmark,
8138 /* 36 - $ */ CharacterDollar,
8139 /* 37 - % */ CharacterOther,
8140 /* 38 - & */ CharacterOther,
8141 /* 39 - ' */ CharacterQuote,
8142 /* 40 - ( */ CharacterOther,
8143 /* 41 - ) */ CharacterEndNthChild,
8144 /* 42 - * */ CharacterAsterisk,
8145 /* 43 - + */ CharacterPlus,
8146 /* 44 - , */ CharacterOther,
8147 /* 45 - - */ CharacterDash,
8148 /* 46 - . */ CharacterDot,
8149 /* 47 - / */ CharacterSlash,
8150 /* 48 - 0 */ CharacterNumber,
8151 /* 49 - 1 */ CharacterNumber,
8152 /* 50 - 2 */ CharacterNumber,
8153 /* 51 - 3 */ CharacterNumber,
8154 /* 52 - 4 */ CharacterNumber,
8155 /* 53 - 5 */ CharacterNumber,
8156 /* 54 - 6 */ CharacterNumber,
8157 /* 55 - 7 */ CharacterNumber,
8158 /* 56 - 8 */ CharacterNumber,
8159 /* 57 - 9 */ CharacterNumber,
8160 /* 58 - : */ CharacterOther,
8161 /* 59 - ; */ CharacterEndMediaQuery,
8162 /* 60 - < */ CharacterLess,
8163 /* 61 - = */ CharacterOther,
8164 /* 62 - > */ CharacterOther,
8165 /* 63 - ? */ CharacterOther,
8166 /* 64 - @ */ CharacterAt,
8167 /* 65 - A */ CharacterIdentifierStart,
8168 /* 66 - B */ CharacterIdentifierStart,
8169 /* 67 - C */ CharacterIdentifierStart,
8170 /* 68 - D */ CharacterIdentifierStart,
8171 /* 69 - E */ CharacterIdentifierStart,
8172 /* 70 - F */ CharacterIdentifierStart,
8173 /* 71 - G */ CharacterIdentifierStart,
8174 /* 72 - H */ CharacterIdentifierStart,
8175 /* 73 - I */ CharacterIdentifierStart,
8176 /* 74 - J */ CharacterIdentifierStart,
8177 /* 75 - K */ CharacterIdentifierStart,
8178 /* 76 - L */ CharacterIdentifierStart,
8179 /* 77 - M */ CharacterIdentifierStart,
8180 /* 78 - N */ CharacterIdentifierStart,
8181 /* 79 - O */ CharacterIdentifierStart,
8182 /* 80 - P */ CharacterIdentifierStart,
8183 /* 81 - Q */ CharacterIdentifierStart,
8184 /* 82 - R */ CharacterIdentifierStart,
8185 /* 83 - S */ CharacterIdentifierStart,
8186 /* 84 - T */ CharacterIdentifierStart,
8187 /* 85 - U */ CharacterCaselessU,
8188 /* 86 - V */ CharacterIdentifierStart,
8189 /* 87 - W */ CharacterIdentifierStart,
8190 /* 88 - X */ CharacterIdentifierStart,
8191 /* 89 - Y */ CharacterIdentifierStart,
8192 /* 90 - Z */ CharacterIdentifierStart,
8193 /* 91 - [ */ CharacterOther,
8194 /* 92 - \ */ CharacterBackSlash,
8195 /* 93 - ] */ CharacterOther,
8196 /* 94 - ^ */ CharacterXor,
8197 /* 95 - _ */ CharacterIdentifierStart,
8198 /* 96 - ` */ CharacterOther,
8199 /* 97 - a */ CharacterIdentifierStart,
8200 /* 98 - b */ CharacterIdentifierStart,
8201 /* 99 - c */ CharacterIdentifierStart,
8202 /* 100 - d */ CharacterIdentifierStart,
8203 /* 101 - e */ CharacterIdentifierStart,
8204 /* 102 - f */ CharacterIdentifierStart,
8205 /* 103 - g */ CharacterIdentifierStart,
8206 /* 104 - h */ CharacterIdentifierStart,
8207 /* 105 - i */ CharacterIdentifierStart,
8208 /* 106 - j */ CharacterIdentifierStart,
8209 /* 107 - k */ CharacterIdentifierStart,
8210 /* 108 - l */ CharacterIdentifierStart,
8211 /* 109 - m */ CharacterIdentifierStart,
8212 /* 110 - n */ CharacterIdentifierStart,
8213 /* 111 - o */ CharacterIdentifierStart,
8214 /* 112 - p */ CharacterIdentifierStart,
8215 /* 113 - q */ CharacterIdentifierStart,
8216 /* 114 - r */ CharacterIdentifierStart,
8217 /* 115 - s */ CharacterIdentifierStart,
8218 /* 116 - t */ CharacterIdentifierStart,
8219 /* 117 - u */ CharacterCaselessU,
8220 /* 118 - v */ CharacterIdentifierStart,
8221 /* 119 - w */ CharacterIdentifierStart,
8222 /* 120 - x */ CharacterIdentifierStart,
8223 /* 121 - y */ CharacterIdentifierStart,
8224 /* 122 - z */ CharacterIdentifierStart,
8225 /* 123 - { */ CharacterEndMediaQuery,
8226 /* 124 - | */ CharacterVerticalBar,
8227 /* 125 - } */ CharacterOther,
8228 /* 126 - ~ */ CharacterTilde,
8229 /* 127 - Delete */ CharacterOther,
8232 // Utility functions for the CSS tokenizer.
8234 static inline bool isCSSLetter(UChar character)
8236 return character >= 128 || typesOfASCIICharacters[character] <= CharacterDash;
8239 static inline bool isCSSEscape(UChar character)
8241 return character >= ' ' && character != 127;
8244 static inline bool isURILetter(UChar character)
8246 return (character >= '*' && character != 127) || (character >= '#' && character <= '&') || character == '!';
8249 static inline bool isIdentifierStartAfterDash(UChar* currentCharacter)
8251 return isASCIIAlpha(currentCharacter[0]) || currentCharacter[0] == '_' || currentCharacter[0] >= 128
8252 || (currentCharacter[0] == '\\' && isCSSEscape(currentCharacter[1]));
8255 static inline bool isEqualToCSSIdentifier(UChar* cssString, const char* constantString)
8257 // Compare an UChar memory data with a zero terminated string.
8259 // The input must be part of an identifier if constantChar or constString
8260 // contains '-'. Otherwise toASCIILowerUnchecked('\r') would be equal to '-'.
8261 ASSERT((*constantString >= 'a' && *constantString <= 'z') || *constantString == '-');
8262 ASSERT(*constantString != '-' || isCSSLetter(*cssString));
8263 if (toASCIILowerUnchecked(*cssString++) != (*constantString++))
8265 } while (*constantString);
8269 static UChar* checkAndSkipEscape(UChar* currentCharacter)
8271 // Returns with 0, if escape check is failed. Otherwise
8272 // it returns with the following character.
8273 ASSERT(*currentCharacter == '\\');
8276 if (!isCSSEscape(*currentCharacter))
8279 if (isASCIIHexDigit(*currentCharacter)) {
8284 } while (isASCIIHexDigit(*currentCharacter) && --length);
8286 // Optional space after the escape sequence.
8287 if (isHTMLSpace(*currentCharacter))
8289 return currentCharacter;
8291 return currentCharacter + 1;
8294 static inline UChar* skipWhiteSpace(UChar* currentCharacter)
8296 while (isHTMLSpace(*currentCharacter))
8298 return currentCharacter;
8301 // Main CSS tokenizer functions.
8303 inline bool CSSParser::isIdentifierStart()
8305 // Check whether an identifier is started.
8306 return isIdentifierStartAfterDash((*m_currentCharacter != '-') ? m_currentCharacter : m_currentCharacter + 1);
8309 inline UChar* CSSParser::checkAndSkipString(UChar* currentCharacter, UChar quote)
8311 // Returns with 0, if string check is failed. Otherwise
8312 // it returns with the following character. This is necessary
8313 // since we cannot revert escape sequences, thus strings
8314 // must be validated before parsing.
8316 if (UNLIKELY(*currentCharacter == quote)) {
8317 // String parsing is successful.
8318 return currentCharacter + 1;
8320 if (UNLIKELY(!*currentCharacter)) {
8321 // String parsing is successful up to end of input.
8322 return currentCharacter;
8324 if (UNLIKELY(*currentCharacter <= '\r' && (*currentCharacter == '\n' || (*currentCharacter | 0x1) == '\r'))) {
8325 // String parsing is failed for character '\n', '\f' or '\r'.
8329 if (LIKELY(currentCharacter[0] != '\\'))
8331 else if (currentCharacter[1] == '\n' || currentCharacter[1] == '\f')
8332 currentCharacter += 2;
8333 else if (currentCharacter[1] == '\r')
8334 currentCharacter += currentCharacter[2] == '\n' ? 3 : 2;
8336 currentCharacter = checkAndSkipEscape(currentCharacter);
8337 if (!currentCharacter)
8343 void CSSParser::parseEscape(UChar*& result)
8345 ASSERT(*m_currentCharacter == '\\' && isCSSEscape(m_currentCharacter[1]));
8347 ++m_currentCharacter;
8348 if (isASCIIHexDigit(*m_currentCharacter)) {
8349 unsigned unicode = 0;
8353 unicode = (unicode << 4) + toASCIIHexValue(*m_currentCharacter++);
8354 } while (--length && isASCIIHexDigit(*m_currentCharacter));
8356 // Characters above 0x10ffff are not handled.
8357 if (unicode > 0x10ffff)
8360 // Optional space after the escape sequence.
8361 if (isHTMLSpace(*m_currentCharacter))
8362 ++m_currentCharacter;
8364 // Replace unicode with a surrogate pairs when it is bigger than 0xffff
8365 if (U16_LENGTH(unicode) == 2) {
8366 *result++ = U16_LEAD(unicode);
8367 *result = U16_TRAIL(unicode);
8371 *result = *m_currentCharacter++;
8375 inline void CSSParser::parseIdentifier(UChar*& result, bool& hasEscape)
8377 // If a valid identifier start is found, we can safely
8378 // parse the identifier until the next invalid character.
8379 ASSERT(isIdentifierStart());
8382 if (LIKELY(*m_currentCharacter != '\\'))
8383 *result++ = *m_currentCharacter++;
8386 parseEscape(result);
8388 } while (isCSSLetter(m_currentCharacter[0]) || (m_currentCharacter[0] == '\\' && isCSSEscape(m_currentCharacter[1])));
8391 inline void CSSParser::parseString(UChar*& result, UChar quote)
8394 if (UNLIKELY(*m_currentCharacter == quote)) {
8395 // String parsing is done.
8396 ++m_currentCharacter;
8399 if (UNLIKELY(!*m_currentCharacter)) {
8400 // String parsing is done, but don't advance pointer if at the end of input.
8403 ASSERT(*m_currentCharacter > '\r' || (*m_currentCharacter < '\n' && *m_currentCharacter) || *m_currentCharacter == '\v');
8405 if (LIKELY(m_currentCharacter[0] != '\\'))
8406 *result++ = *m_currentCharacter++;
8407 else if (m_currentCharacter[1] == '\n' || m_currentCharacter[1] == '\f')
8408 m_currentCharacter += 2;
8409 else if (m_currentCharacter[1] == '\r')
8410 m_currentCharacter += m_currentCharacter[2] == '\n' ? 3 : 2;
8412 parseEscape(result);
8416 inline void CSSParser::parseURI(UChar*& start, UChar*& result)
8418 UChar* uriStart = skipWhiteSpace(m_currentCharacter);
8420 if (*uriStart == '"' || *uriStart == '\'') {
8421 UChar quote = *uriStart;
8424 UChar* stringEnd = checkAndSkipString(uriStart, quote);
8427 stringEnd = skipWhiteSpace(stringEnd);
8428 if (*stringEnd != ')')
8431 start = result = m_currentCharacter = uriStart;
8432 parseString(result, quote);
8434 m_currentCharacter = stringEnd + 1;
8437 UChar* stringEnd = uriStart;
8439 while (isURILetter(*stringEnd)) {
8440 if (*stringEnd != '\\')
8443 stringEnd = checkAndSkipEscape(stringEnd);
8449 stringEnd = skipWhiteSpace(stringEnd);
8450 if (*stringEnd != ')')
8453 start = result = m_currentCharacter = uriStart;
8454 while (isURILetter(*m_currentCharacter)) {
8455 if (LIKELY(*m_currentCharacter != '\\'))
8456 *result++ = *m_currentCharacter++;
8458 parseEscape(result);
8461 m_currentCharacter = stringEnd + 1;
8466 inline bool CSSParser::parseUnicodeRange()
8468 UChar* currentCharacter = m_currentCharacter + 1;
8470 ASSERT(*m_currentCharacter == '+');
8472 while (isASCIIHexDigit(*currentCharacter) && length) {
8477 if (length && *currentCharacter == '?') {
8478 // At most 5 hex digit followed by a question mark.
8482 } while (*currentCharacter == '?' && length);
8483 m_currentCharacter = currentCharacter;
8488 // At least one hex digit.
8489 if (currentCharacter[0] == '-' && isASCIIHexDigit(currentCharacter[1])) {
8490 // Followed by a dash and a hex digit.
8495 } while (--length && isASCIIHexDigit(*currentCharacter));
8497 m_currentCharacter = currentCharacter;
8503 bool CSSParser::parseNthChild()
8505 UChar* currentCharacter = m_currentCharacter;
8507 while (isASCIIDigit(*currentCharacter))
8509 if (isASCIIAlphaCaselessEqual(*currentCharacter, 'n')) {
8510 m_currentCharacter = currentCharacter + 1;
8516 bool CSSParser::parseNthChildExtra()
8518 UChar* currentCharacter = skipWhiteSpace(m_currentCharacter);
8519 if (*currentCharacter != '+' && *currentCharacter != '-')
8522 currentCharacter = skipWhiteSpace(currentCharacter + 1);
8523 if (!isASCIIDigit(*currentCharacter))
8528 } while (isASCIIDigit(*currentCharacter));
8530 m_currentCharacter = currentCharacter;
8534 inline void CSSParser::detectFunctionTypeToken(int length)
8537 UChar* name = m_tokenStart;
8541 if (isASCIIAlphaCaselessEqual(name[0], 'n') && isASCIIAlphaCaselessEqual(name[1], 'o') && isASCIIAlphaCaselessEqual(name[2], 't'))
8542 m_token = NOTFUNCTION;
8543 else if (isASCIIAlphaCaselessEqual(name[0], 'u') && isASCIIAlphaCaselessEqual(name[1], 'r') && isASCIIAlphaCaselessEqual(name[2], 'l'))
8548 if (isEqualToCSSIdentifier(name, "nth-child"))
8549 m_parsingMode = NthChildMode;
8553 if (isEqualToCSSIdentifier(name, "nth-of-type"))
8554 m_parsingMode = NthChildMode;
8558 if (isEqualToCSSIdentifier(name, "nth-last-child"))
8559 m_parsingMode = NthChildMode;
8563 if (isEqualToCSSIdentifier(name, "nth-last-of-type"))
8564 m_parsingMode = NthChildMode;
8569 inline void CSSParser::detectMediaQueryToken(int length)
8571 ASSERT(m_parsingMode == MediaQueryMode);
8572 UChar* name = m_tokenStart;
8575 if (isASCIIAlphaCaselessEqual(name[0], 'a') && isASCIIAlphaCaselessEqual(name[1], 'n') && isASCIIAlphaCaselessEqual(name[2], 'd'))
8576 m_token = MEDIA_AND;
8577 else if (isASCIIAlphaCaselessEqual(name[0], 'n') && isASCIIAlphaCaselessEqual(name[1], 'o') && isASCIIAlphaCaselessEqual(name[2], 't'))
8578 m_token = MEDIA_NOT;
8579 } else if (length == 4) {
8580 if (isASCIIAlphaCaselessEqual(name[0], 'o') && isASCIIAlphaCaselessEqual(name[1], 'n')
8581 && isASCIIAlphaCaselessEqual(name[2], 'l') && isASCIIAlphaCaselessEqual(name[3], 'y'))
8582 m_token = MEDIA_ONLY;
8586 inline void CSSParser::detectNumberToken(UChar* type, int length)
8590 switch (toASCIILowerUnchecked(type[0])) {
8592 if (length == 2 && isASCIIAlphaCaselessEqual(type[1], 'm'))
8597 if (length == 3 && isASCIIAlphaCaselessEqual(type[1], 'e') && isASCIIAlphaCaselessEqual(type[2], 'g'))
8599 #if ENABLE(CSS_IMAGE_RESOLUTION)
8600 else if (length > 2 && isASCIIAlphaCaselessEqual(type[1], 'p')) {
8602 // There is a discussion about the name of this unit on www-style.
8603 // Keep this compile time guard in place until that is resolved.
8604 // http://lists.w3.org/Archives/Public/www-style/2012May/0915.html
8605 if (isASCIIAlphaCaselessEqual(type[2], 'p') && isASCIIAlphaCaselessEqual(type[3], 'x'))
8607 else if (isASCIIAlphaCaselessEqual(type[2], 'c') && isASCIIAlphaCaselessEqual(type[3], 'm'))
8609 } else if (length == 3 && isASCIIAlphaCaselessEqual(type[2], 'i'))
8617 if (isASCIIAlphaCaselessEqual(type[1], 'm'))
8619 else if (isASCIIAlphaCaselessEqual(type[1], 'x'))
8625 if (length == 4 && isASCIIAlphaCaselessEqual(type[1], 'r')
8626 && isASCIIAlphaCaselessEqual(type[2], 'a') && isASCIIAlphaCaselessEqual(type[3], 'd'))
8631 if (length == 2 && isASCIIAlphaCaselessEqual(type[1], 'z'))
8636 if (length == 2 && isASCIIAlphaCaselessEqual(type[1], 'n'))
8641 if (length == 3 && isASCIIAlphaCaselessEqual(type[1], 'h') && isASCIIAlphaCaselessEqual(type[2], 'z'))
8647 if (isASCIIAlphaCaselessEqual(type[1], 'm'))
8649 else if (isASCIIAlphaCaselessEqual(type[1], 's'))
8656 if (isASCIIAlphaCaselessEqual(type[1], 'x'))
8658 else if (isASCIIAlphaCaselessEqual(type[1], 't'))
8660 else if (isASCIIAlphaCaselessEqual(type[1], 'c'))
8667 if (isASCIIAlphaCaselessEqual(type[1], 'a') && isASCIIAlphaCaselessEqual(type[2], 'd'))
8669 else if (isASCIIAlphaCaselessEqual(type[1], 'e') && isASCIIAlphaCaselessEqual(type[2], 'm'))
8680 if (length == 4 && isASCIIAlphaCaselessEqual(type[1], 'u')
8681 && isASCIIAlphaCaselessEqual(type[2], 'r') && isASCIIAlphaCaselessEqual(type[3], 'n'))
8686 if (isASCIIAlphaCaselessEqual(type[1], 'w'))
8688 else if (isASCIIAlphaCaselessEqual(type[1], 'h'))
8690 } else if (length == 4 && isASCIIAlphaCaselessEqual(type[1], 'm')
8691 && isASCIIAlphaCaselessEqual(type[2], 'i') && isASCIIAlphaCaselessEqual(type[3], 'n'))
8696 if (type[0] == '_' && length == 5 && type[1] == '_' && isASCIIAlphaCaselessEqual(type[2], 'q')
8697 && isASCIIAlphaCaselessEqual(type[3], 'e') && isASCIIAlphaCaselessEqual(type[4], 'm'))
8703 inline void CSSParser::detectDashToken(int length)
8705 UChar* name = m_tokenStart;
8708 if (isASCIIAlphaCaselessEqual(name[10], 'y') && isEqualToCSSIdentifier(name + 1, "webkit-an"))
8709 m_token = ANYFUNCTION;
8710 else if (isASCIIAlphaCaselessEqual(name[10], 'n') && isEqualToCSSIdentifier(name + 1, "webkit-mi"))
8711 m_token = MINFUNCTION;
8712 else if (isASCIIAlphaCaselessEqual(name[10], 'x') && isEqualToCSSIdentifier(name + 1, "webkit-ma"))
8713 m_token = MAXFUNCTION;
8714 #if ENABLE(CSS_VARIABLES)
8715 else if (cssVariablesEnabled() && isASCIIAlphaCaselessEqual(name[10], 'r') && isEqualToCSSIdentifier(name + 1, "webkit-va"))
8716 m_token = VARFUNCTION;
8718 } else if (length == 12 && isEqualToCSSIdentifier(name + 1, "webkit-calc"))
8719 m_token = CALCFUNCTION;
8722 inline void CSSParser::detectAtToken(int length, bool hasEscape)
8724 UChar* name = m_tokenStart;
8725 ASSERT(name[0] == '@' && length >= 2);
8727 // charset, font-face, import, media, namespace, page,
8728 // -webkit-keyframes, and -webkit-mediaquery are not affected by hasEscape.
8729 switch (toASCIILowerUnchecked(name[1])) {
8736 if (isEqualToCSSIdentifier(name + 2, "ottom-left"))
8737 m_token = BOTTOMLEFT_SYM;
8741 if (isEqualToCSSIdentifier(name + 2, "ottom-right"))
8742 m_token = BOTTOMRIGHT_SYM;
8746 if (isEqualToCSSIdentifier(name + 2, "ottom-center"))
8747 m_token = BOTTOMCENTER_SYM;
8751 if (isEqualToCSSIdentifier(name + 2, "ottom-left-corner"))
8752 m_token = BOTTOMLEFTCORNER_SYM;
8756 if (isEqualToCSSIdentifier(name + 2, "ottom-right-corner"))
8757 m_token = BOTTOMRIGHTCORNER_SYM;
8763 if (length == 8 && isEqualToCSSIdentifier(name + 2, "harset"))
8764 m_token = CHARSET_SYM;
8768 if (length == 10 && isEqualToCSSIdentifier(name + 2, "ont-face"))
8769 m_token = FONT_FACE_SYM;
8773 if (length == 7 && isEqualToCSSIdentifier(name + 2, "mport")) {
8774 m_parsingMode = MediaQueryMode;
8775 m_token = IMPORT_SYM;
8779 #if ENABLE(TIZEN_CSS_ALIASES)
8781 if (length == 10 && isEqualToCSSIdentifier(name + 2, "eyframes"))
8782 m_token = WEBKIT_KEYFRAMES_SYM;
8783 else if (!hasEscape && isEqualToCSSIdentifier(name + 2, "webkit-keyframe-rule"))
8784 m_token = WEBKIT_KEYFRAME_RULE_SYM;
8793 if (isEqualToCSSIdentifier(name + 2, "eft-top"))
8794 m_token = LEFTTOP_SYM;
8795 } else if (length == 12) {
8796 // Checking the last character first could further reduce the possibile cases.
8797 if (isASCIIAlphaCaselessEqual(name[11], 'e') && isEqualToCSSIdentifier(name + 2, "eft-middl"))
8798 m_token = LEFTMIDDLE_SYM;
8799 else if (isASCIIAlphaCaselessEqual(name[11], 'm') && isEqualToCSSIdentifier(name + 2, "eft-botto"))
8800 m_token = LEFTBOTTOM_SYM;
8805 if (length == 6 && isEqualToCSSIdentifier(name + 2, "edia")) {
8806 m_parsingMode = MediaQueryMode;
8807 m_token = MEDIA_SYM;
8812 if (length == 10 && isEqualToCSSIdentifier(name + 2, "amespace"))
8813 m_token = NAMESPACE_SYM;
8817 if (length == 5 && isEqualToCSSIdentifier(name + 2, "age"))
8826 if (isEqualToCSSIdentifier(name + 2, "ight-top"))
8827 m_token = RIGHTTOP_SYM;
8828 } else if (length == 13) {
8829 // Checking the last character first could further reduce the possibile cases.
8830 if (isASCIIAlphaCaselessEqual(name[12], 'e') && isEqualToCSSIdentifier(name + 2, "ight-middl"))
8831 m_token = RIGHTMIDDLE_SYM;
8832 else if (isASCIIAlphaCaselessEqual(name[12], 'm') && isEqualToCSSIdentifier(name + 2, "ight-botto"))
8833 m_token = RIGHTBOTTOM_SYM;
8843 if (isEqualToCSSIdentifier(name + 2, "op-left"))
8844 m_token = TOPLEFT_SYM;
8848 if (isEqualToCSSIdentifier(name + 2, "op-right"))
8849 m_token = TOPRIGHT_SYM;
8853 if (isEqualToCSSIdentifier(name + 2, "op-center"))
8854 m_token = TOPCENTER_SYM;
8858 if (isEqualToCSSIdentifier(name + 2, "op-left-corner"))
8859 m_token = TOPLEFTCORNER_SYM;
8863 if (isEqualToCSSIdentifier(name + 2, "op-right-corner"))
8864 m_token = TOPRIGHTCORNER_SYM;
8872 if (!hasEscape && isEqualToCSSIdentifier(name + 2, "webkit-rule"))
8873 m_token = WEBKIT_RULE_SYM;
8880 // Checking the last character first could further reduce the possibile cases.
8881 if (isASCIIAlphaCaselessEqual(name[13], 's') && isEqualToCSSIdentifier(name + 2, "webkit-decl"))
8882 m_token = WEBKIT_DECLS_SYM;
8883 else if (isASCIIAlphaCaselessEqual(name[13], 'e') && isEqualToCSSIdentifier(name + 2, "webkit-valu"))
8884 m_token = WEBKIT_VALUE_SYM;
8888 #if ENABLE(CSS_REGIONS)
8889 if (!hasEscape && isEqualToCSSIdentifier(name + 2, "webkit-region"))
8890 m_token = WEBKIT_REGION_RULE_SYM;
8895 if (!hasEscape && isEqualToCSSIdentifier(name + 2, "webkit-selector"))
8896 m_token = WEBKIT_SELECTOR_SYM;
8900 if (isEqualToCSSIdentifier(name + 2, "webkit-keyframes"))
8901 m_token = WEBKIT_KEYFRAMES_SYM;
8905 if (isEqualToCSSIdentifier(name + 2, "webkit-mediaquery")) {
8906 m_parsingMode = MediaQueryMode;
8907 m_token = WEBKIT_MEDIAQUERY_SYM;
8912 if (!hasEscape && isEqualToCSSIdentifier(name + 2, "webkit-keyframe-rule"))
8913 m_token = WEBKIT_KEYFRAME_RULE_SYM;
8919 int CSSParser::lex(void* yylvalWithoutType)
8921 YYSTYPE* yylval = static_cast<YYSTYPE*>(yylvalWithoutType);
8922 // Write pointer for the next character.
8926 // The input buffer is terminated by a \0 character, so
8927 // it is safe to read one character ahead of a known non-null.
8930 // In debug we check with an ASSERT that the length is > 0 for string types.
8931 yylval->string.characters = 0;
8932 yylval->string.length = 0;
8935 restartAfterComment:
8936 m_tokenStart = result = m_currentCharacter;
8937 m_token = *m_currentCharacter;
8938 ++m_currentCharacter;
8940 switch ((m_token <= 127) ? typesOfASCIICharacters[m_token] : CharacterIdentifierStart) {
8941 case CharacterCaselessU:
8942 if (UNLIKELY(*m_currentCharacter == '+'))
8943 if (parseUnicodeRange()) {
8944 m_token = UNICODERANGE;
8945 yylval->string.characters = m_tokenStart;
8946 yylval->string.length = m_currentCharacter - m_tokenStart;
8949 // Fall through to CharacterIdentifierStart.
8951 case CharacterIdentifierStart:
8952 --m_currentCharacter;
8953 parseIdentifier(result, hasEscape);
8956 yylval->string.characters = m_tokenStart;
8957 yylval->string.length = result - m_tokenStart;
8959 if (UNLIKELY(*m_currentCharacter == '(')) {
8962 detectFunctionTypeToken(result - m_tokenStart);
8963 ++m_currentCharacter;
8965 ++yylval->string.length;
8967 if (token() == URI) {
8969 // Check whether it is really an URI.
8970 parseURI(yylval->string.characters, result);
8971 yylval->string.length = result - yylval->string.characters;
8973 } else if (UNLIKELY(m_parsingMode != NormalMode) && !hasEscape) {
8974 if (m_parsingMode == MediaQueryMode)
8975 detectMediaQueryToken(result - m_tokenStart);
8976 else if (m_parsingMode == NthChildMode && isASCIIAlphaCaselessEqual(m_tokenStart[0], 'n')) {
8977 if (result - m_tokenStart == 1) {
8978 // String "n" is IDENT but "n+1" is NTH.
8979 if (parseNthChildExtra()) {
8981 yylval->string.length = m_currentCharacter - m_tokenStart;
8983 } else if (result - m_tokenStart >= 2 && m_tokenStart[1] == '-') {
8984 // String "n-" is IDENT but "n-1" is NTH.
8985 // Set m_currentCharacter to '-' to continue parsing.
8986 UChar* nextCharacter = result;
8987 m_currentCharacter = m_tokenStart + 1;
8988 if (parseNthChildExtra()) {
8990 yylval->string.length = m_currentCharacter - m_tokenStart;
8992 // Revert the change to m_currentCharacter if unsuccessful.
8993 m_currentCharacter = nextCharacter;
9000 if (!isASCIIDigit(m_currentCharacter[0]))
9002 // Fall through to CharacterNumber.
9004 case CharacterNumber: {
9005 bool dotSeen = (m_token == '.');
9008 if (!isASCIIDigit(m_currentCharacter[0])) {
9009 // Only one dot is allowed for a number,
9010 // and it must be followed by a digit.
9011 if (m_currentCharacter[0] != '.' || dotSeen || !isASCIIDigit(m_currentCharacter[1]))
9015 ++m_currentCharacter;
9018 if (UNLIKELY(m_parsingMode == NthChildMode) && !dotSeen && isASCIIAlphaCaselessEqual(*m_currentCharacter, 'n')) {
9019 // "[0-9]+n" is always an NthChild.
9020 ++m_currentCharacter;
9021 parseNthChildExtra();
9023 yylval->string.characters = m_tokenStart;
9024 yylval->string.length = m_currentCharacter - m_tokenStart;
9029 // Use SVG parser for numbers on SVG presentation attributes.
9030 if (m_context.mode == SVGAttributeMode) {
9031 // We need to take care of units like 'em' or 'ex'.
9032 UChar* currentCharacter = m_currentCharacter;
9033 if (isASCIIAlphaCaselessEqual(*currentCharacter, 'e')) {
9034 ASSERT(currentCharacter - m_tokenStart > 0);
9036 if (*currentCharacter == '-' || *currentCharacter == '+' || isASCIIDigit(*currentCharacter)) {
9038 while (isASCIIDigit(*currentCharacter))
9040 // Use FLOATTOKEN if the string contains exponents.
9042 m_currentCharacter = currentCharacter;
9045 if (!parseSVGNumber(m_tokenStart, currentCharacter - m_tokenStart, yylval->number))
9049 yylval->number = charactersToDouble(m_tokenStart, m_currentCharacter - m_tokenStart);
9051 // Type of the function.
9052 if (isIdentifierStart()) {
9053 UChar* type = m_currentCharacter;
9054 result = m_currentCharacter;
9056 parseIdentifier(result, hasEscape);
9057 if (*m_currentCharacter == '+') {
9058 // Any identifier followed by a '+' sign is an invalid dimension.
9059 ++m_currentCharacter;
9060 m_token = INVALIDDIMEN;
9064 detectNumberToken(type, m_currentCharacter - type);
9066 if (m_token == DIMEN) {
9067 // The decoded number is overwritten, but this is intentional.
9068 yylval->string.characters = m_tokenStart;
9069 yylval->string.length = m_currentCharacter - m_tokenStart;
9072 } else if (*m_currentCharacter == '%') {
9073 // Although the CSS grammar says {num}% we follow
9074 // webkit at the moment which uses {num}%+.
9076 ++m_currentCharacter;
9077 } while (*m_currentCharacter == '%');
9078 m_token = PERCENTAGE;
9080 m_token = dotSeen ? FLOATTOKEN : INTEGER;
9085 if (isIdentifierStartAfterDash(m_currentCharacter)) {
9086 --m_currentCharacter;
9087 parseIdentifier(result, hasEscape);
9090 #if ENABLE(CSS_VARIABLES)
9091 if (cssVariablesEnabled() && isEqualToCSSIdentifier(m_tokenStart + 1, "webkit-var") && m_tokenStart[11] == '-' && isIdentifierStartAfterDash(m_tokenStart + 12))
9092 m_token = VAR_DEFINITION;
9095 if (*m_currentCharacter == '(') {
9098 detectDashToken(result - m_tokenStart);
9099 ++m_currentCharacter;
9101 } else if (UNLIKELY(m_parsingMode == NthChildMode) && !hasEscape && isASCIIAlphaCaselessEqual(m_tokenStart[1], 'n')) {
9102 if (result - m_tokenStart == 2) {
9103 // String "-n" is IDENT but "-n+1" is NTH.
9104 if (parseNthChildExtra()) {
9106 result = m_currentCharacter;
9108 } else if (result - m_tokenStart >= 3 && m_tokenStart[2] == '-') {
9109 // String "-n-" is IDENT but "-n-1" is NTH.
9110 // Set m_currentCharacter to second '-' of '-n-' to continue parsing.
9111 UChar* nextCharacter = result;
9112 m_currentCharacter = m_tokenStart + 2;
9113 if (parseNthChildExtra()) {
9115 result = m_currentCharacter;
9117 // Revert the change to m_currentCharacter if unsuccessful.
9118 m_currentCharacter = nextCharacter;
9122 yylval->string.characters = m_tokenStart;
9123 yylval->string.length = result - m_tokenStart;
9124 } else if (m_currentCharacter[0] == '-' && m_currentCharacter[1] == '>') {
9125 m_currentCharacter += 2;
9127 } else if (UNLIKELY(m_parsingMode == NthChildMode)) {
9128 // "-[0-9]+n" is always an NthChild.
9129 if (parseNthChild()) {
9130 parseNthChildExtra();
9132 yylval->string.characters = m_tokenStart;
9133 yylval->string.length = m_currentCharacter - m_tokenStart;
9138 case CharacterOther:
9139 // m_token is simply the current character.
9143 // Do not advance pointer at the end of input.
9144 --m_currentCharacter;
9147 case CharacterWhiteSpace:
9148 m_token = WHITESPACE;
9149 // Might start with a '\n'.
9150 --m_currentCharacter;
9152 if (*m_currentCharacter == '\n')
9154 ++m_currentCharacter;
9155 } while (*m_currentCharacter <= ' ' && (typesOfASCIICharacters[*m_currentCharacter] == CharacterWhiteSpace));
9158 case CharacterEndMediaQuery:
9159 if (m_parsingMode == MediaQueryMode)
9160 m_parsingMode = NormalMode;
9163 case CharacterEndNthChild:
9164 if (m_parsingMode == NthChildMode)
9165 m_parsingMode = NormalMode;
9168 case CharacterQuote:
9169 if (checkAndSkipString(m_currentCharacter, m_token)) {
9171 parseString(result, m_token);
9173 yylval->string.characters = m_tokenStart + 1;
9174 yylval->string.length = result - (m_tokenStart + 1);
9178 case CharacterExclamationMark: {
9179 UChar* start = skipWhiteSpace(m_currentCharacter);
9180 if (isEqualToCSSIdentifier(start, "important")) {
9181 m_token = IMPORTANT_SYM;
9182 m_currentCharacter = start + 9;
9187 case CharacterHashmark: {
9188 UChar* start = m_currentCharacter;
9189 result = m_currentCharacter;
9191 if (isASCIIDigit(*m_currentCharacter)) {
9192 // This must be a valid hex number token.
9194 ++m_currentCharacter;
9195 } while (isASCIIHexDigit(*m_currentCharacter));
9197 yylval->string.characters = start;
9198 yylval->string.length = m_currentCharacter - start;
9199 } else if (isIdentifierStart()) {
9201 parseIdentifier(result, hasEscape);
9203 // Check whether the identifier is also a valid hex number.
9204 UChar* current = start;
9207 if (!isASCIIHexDigit(*current)) {
9212 } while (current < result);
9214 yylval->string.characters = start;
9215 yylval->string.length = result - start;
9220 case CharacterSlash:
9221 // Ignore comments. They are not even considered as white spaces.
9222 if (*m_currentCharacter == '*') {
9223 ++m_currentCharacter;
9224 while (m_currentCharacter[0] != '*' || m_currentCharacter[1] != '/') {
9225 if (*m_currentCharacter == '\n')
9227 if (*m_currentCharacter == '\0') {
9228 // Unterminated comments are simply ignored.
9229 m_currentCharacter -= 2;
9232 ++m_currentCharacter;
9234 m_currentCharacter += 2;
9235 goto restartAfterComment;
9239 case CharacterDollar:
9240 if (*m_currentCharacter == '=') {
9241 ++m_currentCharacter;
9246 case CharacterAsterisk:
9247 if (*m_currentCharacter == '=') {
9248 ++m_currentCharacter;
9254 if (UNLIKELY(m_parsingMode == NthChildMode)) {
9255 // Simplest case. "+[0-9]*n" is always NthChild.
9256 if (parseNthChild()) {
9257 parseNthChildExtra();
9259 yylval->string.characters = m_tokenStart;
9260 yylval->string.length = m_currentCharacter - m_tokenStart;
9266 if (m_currentCharacter[0] == '!' && m_currentCharacter[1] == '-' && m_currentCharacter[2] == '-') {
9267 m_currentCharacter += 3;
9273 if (isIdentifierStart()) {
9274 m_token = ATKEYWORD;
9276 parseIdentifier(result, hasEscape);
9277 detectAtToken(result - m_tokenStart, hasEscape);
9281 case CharacterBackSlash:
9282 if (isCSSEscape(*m_currentCharacter)) {
9283 --m_currentCharacter;
9284 parseIdentifier(result, hasEscape);
9286 yylval->string.characters = m_tokenStart;
9287 yylval->string.length = result - m_tokenStart;
9292 if (*m_currentCharacter == '=') {
9293 ++m_currentCharacter;
9294 m_token = BEGINSWITH;
9298 case CharacterVerticalBar:
9299 if (*m_currentCharacter == '=') {
9300 ++m_currentCharacter;
9301 m_token = DASHMATCH;
9305 case CharacterTilde:
9306 if (*m_currentCharacter == '=') {
9307 ++m_currentCharacter;
9313 ASSERT_NOT_REACHED();
9320 ASSERT(yylval->string.characters == m_tokenStart + 1);
9333 ASSERT(yylval->string.characters == m_tokenStart && yylval->string.length > 0);
9337 ASSERT(yylval->string.characters && yylval->string.characters != m_tokenStart);
9342 ASSERT(yylval->string.characters == m_tokenStart + 1 && yylval->string.length > 0);
9345 #if ENABLE(TIZEN_MEDIA_QUERY)
9346 //FIXME : Upversion - Must reviewd by Gyuyoung Kim
9357 CSSParserSelector* CSSParser::createFloatingSelector()
9359 CSSParserSelector* selector = new CSSParserSelector;
9360 m_floatingSelectors.add(selector);
9364 PassOwnPtr<CSSParserSelector> CSSParser::sinkFloatingSelector(CSSParserSelector* selector)
9367 ASSERT(m_floatingSelectors.contains(selector));
9368 m_floatingSelectors.remove(selector);
9370 return adoptPtr(selector);
9373 Vector<OwnPtr<CSSParserSelector> >* CSSParser::createFloatingSelectorVector()
9375 Vector<OwnPtr<CSSParserSelector> >* selectorVector = new Vector<OwnPtr<CSSParserSelector> >;
9376 m_floatingSelectorVectors.add(selectorVector);
9377 return selectorVector;
9380 PassOwnPtr<Vector<OwnPtr<CSSParserSelector> > > CSSParser::sinkFloatingSelectorVector(Vector<OwnPtr<CSSParserSelector> >* selectorVector)
9382 if (selectorVector) {
9383 ASSERT(m_floatingSelectorVectors.contains(selectorVector));
9384 m_floatingSelectorVectors.remove(selectorVector);
9386 return adoptPtr(selectorVector);
9389 CSSParserValueList* CSSParser::createFloatingValueList()
9391 CSSParserValueList* list = new CSSParserValueList;
9392 m_floatingValueLists.add(list);
9396 PassOwnPtr<CSSParserValueList> CSSParser::sinkFloatingValueList(CSSParserValueList* list)
9399 ASSERT(m_floatingValueLists.contains(list));
9400 m_floatingValueLists.remove(list);
9402 return adoptPtr(list);
9405 CSSParserFunction* CSSParser::createFloatingFunction()
9407 CSSParserFunction* function = new CSSParserFunction;
9408 m_floatingFunctions.add(function);
9412 PassOwnPtr<CSSParserFunction> CSSParser::sinkFloatingFunction(CSSParserFunction* function)
9415 ASSERT(m_floatingFunctions.contains(function));
9416 m_floatingFunctions.remove(function);
9418 return adoptPtr(function);
9421 CSSParserValue& CSSParser::sinkFloatingValue(CSSParserValue& value)
9423 if (value.unit == CSSParserValue::Function) {
9424 ASSERT(m_floatingFunctions.contains(value.function));
9425 m_floatingFunctions.remove(value.function);
9430 MediaQueryExp* CSSParser::createFloatingMediaQueryExp(const AtomicString& mediaFeature, CSSParserValueList* values)
9432 m_floatingMediaQueryExp = MediaQueryExp::create(mediaFeature, values);
9433 return m_floatingMediaQueryExp.get();
9436 PassOwnPtr<MediaQueryExp> CSSParser::sinkFloatingMediaQueryExp(MediaQueryExp* expression)
9438 ASSERT_UNUSED(expression, expression == m_floatingMediaQueryExp);
9439 return m_floatingMediaQueryExp.release();
9442 Vector<OwnPtr<MediaQueryExp> >* CSSParser::createFloatingMediaQueryExpList()
9444 m_floatingMediaQueryExpList = adoptPtr(new Vector<OwnPtr<MediaQueryExp> >);
9445 return m_floatingMediaQueryExpList.get();
9448 PassOwnPtr<Vector<OwnPtr<MediaQueryExp> > > CSSParser::sinkFloatingMediaQueryExpList(Vector<OwnPtr<MediaQueryExp> >* list)
9450 ASSERT_UNUSED(list, list == m_floatingMediaQueryExpList);
9451 return m_floatingMediaQueryExpList.release();
9454 MediaQuery* CSSParser::createFloatingMediaQuery(MediaQuery::Restrictor restrictor, const String& mediaType, PassOwnPtr<Vector<OwnPtr<MediaQueryExp> > > expressions)
9456 m_floatingMediaQuery = adoptPtr(new MediaQuery(restrictor, mediaType, expressions));
9457 return m_floatingMediaQuery.get();
9460 MediaQuery* CSSParser::createFloatingMediaQuery(PassOwnPtr<Vector<OwnPtr<MediaQueryExp> > > expressions)
9462 return createFloatingMediaQuery(MediaQuery::None, "all", expressions);
9465 PassOwnPtr<MediaQuery> CSSParser::sinkFloatingMediaQuery(MediaQuery* query)
9467 ASSERT_UNUSED(query, query == m_floatingMediaQuery);
9468 return m_floatingMediaQuery.release();
9471 Vector<RefPtr<StyleKeyframe> >* CSSParser::createFloatingKeyframeVector()
9473 m_floatingKeyframeVector = adoptPtr(new Vector<RefPtr<StyleKeyframe> >());
9474 return m_floatingKeyframeVector.get();
9477 PassOwnPtr<Vector<RefPtr<StyleKeyframe> > > CSSParser::sinkFloatingKeyframeVector(Vector<RefPtr<StyleKeyframe> >* keyframeVector)
9479 ASSERT_UNUSED(keyframeVector, m_floatingKeyframeVector == keyframeVector);
9480 return m_floatingKeyframeVector.release();
9483 MediaQuerySet* CSSParser::createMediaQuerySet()
9485 RefPtr<MediaQuerySet> queries = MediaQuerySet::create();
9486 MediaQuerySet* result = queries.get();
9487 m_parsedMediaQuerySets.append(queries.release());
9491 StyleRuleBase* CSSParser::createImportRule(const CSSParserString& url, MediaQuerySet* media)
9493 if (!media || !m_allowImportRules)
9495 RefPtr<StyleRuleImport> rule = StyleRuleImport::create(url, media);
9496 StyleRuleImport* result = rule.get();
9497 m_parsedRules.append(rule.release());
9498 processAndAddNewRuleToSourceTreeIfNeeded();
9502 StyleRuleBase* CSSParser::createMediaRule(MediaQuerySet* media, RuleList* rules)
9504 m_allowImportRules = m_allowNamespaceDeclarations = false;
9505 RefPtr<StyleRuleMedia> rule;
9507 rule = StyleRuleMedia::create(media ? media : MediaQuerySet::create(), *rules);
9509 RuleList emptyRules;
9510 rule = StyleRuleMedia::create(media ? media : MediaQuerySet::create(), emptyRules);
9512 StyleRuleMedia* result = rule.get();
9513 m_parsedRules.append(rule.release());
9514 processAndAddNewRuleToSourceTreeIfNeeded();
9518 CSSParser::RuleList* CSSParser::createRuleList()
9520 OwnPtr<RuleList> list = adoptPtr(new RuleList);
9521 RuleList* listPtr = list.get();
9523 m_parsedRuleLists.append(list.release());
9527 void CSSParser::processAndAddNewRuleToSourceTreeIfNeeded()
9529 if (!isExtractingSourceData())
9532 RefPtr<CSSRuleSourceData> rule = popRuleData();
9533 fixUnparsedPropertyRanges(rule.get());
9534 addNewRuleToSourceTree(rule.release());
9537 void CSSParser::addNewRuleToSourceTree(PassRefPtr<CSSRuleSourceData> rule)
9539 // Precondition: (isExtractingSourceData()).
9540 if (!m_ruleSourceDataResult)
9542 if (m_currentRuleDataStack->isEmpty())
9543 m_ruleSourceDataResult->append(rule);
9545 m_currentRuleDataStack->last()->childRules.append(rule);
9548 PassRefPtr<CSSRuleSourceData> CSSParser::popRuleData()
9550 if (!m_ruleSourceDataResult)
9553 ASSERT(!m_currentRuleDataStack->isEmpty());
9554 RefPtr<CSSRuleSourceData> data = m_currentRuleDataStack->last();
9555 m_currentRuleDataStack->removeLast();
9556 return data.release();
9559 StyleRuleKeyframes* CSSParser::createKeyframesRule(const String& name, PassOwnPtr<Vector<RefPtr<StyleKeyframe> > > popKeyframes)
9561 OwnPtr<Vector<RefPtr<StyleKeyframe> > > keyframes = popKeyframes;
9562 m_allowImportRules = m_allowNamespaceDeclarations = false;
9563 RefPtr<StyleRuleKeyframes> rule = StyleRuleKeyframes::create();
9564 for (size_t i = 0; i < keyframes->size(); ++i)
9565 rule->parserAppendKeyframe(keyframes->at(i));
9566 rule->setName(name);
9567 StyleRuleKeyframes* rulePtr = rule.get();
9568 m_parsedRules.append(rule.release());
9569 processAndAddNewRuleToSourceTreeIfNeeded();
9573 StyleRuleBase* CSSParser::createStyleRule(Vector<OwnPtr<CSSParserSelector> >* selectors)
9575 StyleRule* result = 0;
9577 m_allowImportRules = m_allowNamespaceDeclarations = false;
9578 RefPtr<StyleRule> rule = StyleRule::create(m_lastSelectorLineNumber);
9579 rule->parserAdoptSelectorVector(*selectors);
9580 if (m_hasFontFaceOnlyValues)
9581 deleteFontFaceOnlyValues();
9582 rule->setProperties(createStylePropertySet());
9583 result = rule.get();
9584 m_parsedRules.append(rule.release());
9585 processAndAddNewRuleToSourceTreeIfNeeded();
9592 StyleRuleBase* CSSParser::createFontFaceRule()
9594 m_allowImportRules = m_allowNamespaceDeclarations = false;
9595 for (unsigned i = 0; i < m_parsedProperties.size(); ++i) {
9596 CSSProperty& property = m_parsedProperties[i];
9597 if (property.id() == CSSPropertyFontVariant && property.value()->isPrimitiveValue())
9598 property.wrapValueInCommaSeparatedList();
9599 else if (property.id() == CSSPropertyFontFamily && (!property.value()->isValueList() || static_cast<CSSValueList*>(property.value())->length() != 1)) {
9600 // Unlike font-family property, font-family descriptor in @font-face rule
9601 // has to be a value list with exactly one family name. It cannot have a
9602 // have 'initial' value and cannot 'inherit' from parent.
9603 // See http://dev.w3.org/csswg/css3-fonts/#font-family-desc
9608 RefPtr<StyleRuleFontFace> rule = StyleRuleFontFace::create();
9609 rule->setProperties(createStylePropertySet());
9611 StyleRuleFontFace* result = rule.get();
9612 m_parsedRules.append(rule.release());
9613 processAndAddNewRuleToSourceTreeIfNeeded();
9617 void CSSParser::addNamespace(const AtomicString& prefix, const AtomicString& uri)
9619 if (!m_styleSheet || !m_allowNamespaceDeclarations)
9621 m_allowImportRules = false;
9622 m_styleSheet->parserAddNamespace(prefix, uri);
9623 if (prefix.isEmpty() && !uri.isNull())
9624 m_defaultNamespace = uri;
9627 QualifiedName CSSParser::determineNameInNamespace(const AtomicString& prefix, const AtomicString& localName)
9630 return QualifiedName(prefix, localName, m_defaultNamespace);
9631 return QualifiedName(prefix, localName, m_styleSheet->determineNamespace(prefix));
9634 void CSSParser::updateSpecifiersWithElementName(const AtomicString& namespacePrefix, const AtomicString& elementName, CSSParserSelector* specifiers)
9636 AtomicString determinedNamespace = namespacePrefix != nullAtom && m_styleSheet ? m_styleSheet->determineNamespace(namespacePrefix) : m_defaultNamespace;
9637 QualifiedName tag = QualifiedName(namespacePrefix, elementName, determinedNamespace);
9638 if (!specifiers->isUnknownPseudoElement()) {
9639 specifiers->setTag(tag);
9643 CSSParserSelector* lastShadowDescendant = specifiers;
9644 CSSParserSelector* history = specifiers;
9645 while (history->tagHistory()) {
9646 history = history->tagHistory();
9647 if (history->isUnknownPseudoElement() || history->hasShadowDescendant())
9648 lastShadowDescendant = history;
9651 if (lastShadowDescendant->tagHistory()) {
9652 lastShadowDescendant->tagHistory()->setTag(tag);
9656 // For shadow-ID pseudo-elements to be correctly matched, the ShadowDescendant combinator has to be used.
9657 // We therefore create a new Selector with that combinator here in any case, even if matching any (host) element in any namespace (i.e. '*').
9658 OwnPtr<CSSParserSelector> elementNameSelector = adoptPtr(new CSSParserSelector);
9659 elementNameSelector->setTag(tag);
9660 lastShadowDescendant->setTagHistory(elementNameSelector.release());
9661 lastShadowDescendant->setRelation(CSSSelector::ShadowDescendant);
9664 CSSParserSelector* CSSParser::updateSpecifiers(CSSParserSelector* specifiers, CSSParserSelector* newSpecifier)
9666 if (newSpecifier->isUnknownPseudoElement()) {
9667 // Unknown pseudo element always goes at the top of selector chain.
9668 newSpecifier->appendTagHistory(CSSSelector::ShadowDescendant, sinkFloatingSelector(specifiers));
9669 return newSpecifier;
9671 if (specifiers->isUnknownPseudoElement()) {
9672 // Specifiers for unknown pseudo element go right behind it in the chain.
9673 specifiers->insertTagHistory(CSSSelector::SubSelector, sinkFloatingSelector(newSpecifier), CSSSelector::ShadowDescendant);
9676 specifiers->appendTagHistory(CSSSelector::SubSelector, sinkFloatingSelector(newSpecifier));
9680 StyleRuleBase* CSSParser::createPageRule(PassOwnPtr<CSSParserSelector> pageSelector)
9682 // FIXME: Margin at-rules are ignored.
9683 m_allowImportRules = m_allowNamespaceDeclarations = false;
9684 StyleRulePage* pageRule = 0;
9686 RefPtr<StyleRulePage> rule = StyleRulePage::create();
9687 Vector<OwnPtr<CSSParserSelector> > selectorVector;
9688 selectorVector.append(pageSelector);
9689 rule->parserAdoptSelectorVector(selectorVector);
9690 rule->setProperties(createStylePropertySet());
9691 pageRule = rule.get();
9692 m_parsedRules.append(rule.release());
9693 processAndAddNewRuleToSourceTreeIfNeeded();
9699 void CSSParser::setReusableRegionSelectorVector(Vector<OwnPtr<CSSParserSelector> >* selectors)
9702 m_reusableRegionSelectorVector.swap(*selectors);
9705 StyleRuleBase* CSSParser::createRegionRule(Vector<OwnPtr<CSSParserSelector> >* regionSelector, RuleList* rules)
9707 if (!cssRegionsEnabled() || !regionSelector || !rules)
9710 m_allowImportRules = m_allowNamespaceDeclarations = false;
9712 RefPtr<StyleRuleRegion> regionRule = StyleRuleRegion::create(regionSelector, *rules);
9714 StyleRuleRegion* result = regionRule.get();
9715 m_parsedRules.append(regionRule.release());
9716 if (isExtractingSourceData())
9717 addNewRuleToSourceTree(CSSRuleSourceData::createUnknown());
9722 StyleRuleBase* CSSParser::createMarginAtRule(CSSSelector::MarginBoxType /* marginBox */)
9724 // FIXME: Implement margin at-rule here, using:
9725 // - marginBox: margin box
9726 // - m_parsedProperties: properties at [m_numParsedPropertiesBeforeMarginBox, m_parsedProperties.size()] are for this at-rule.
9727 // Don't forget to also update the action for page symbol in CSSGrammar.y such that margin at-rule data is cleared if page_selector is invalid.
9729 endDeclarationsForMarginBox();
9730 return 0; // until this method is implemented.
9733 void CSSParser::startDeclarationsForMarginBox()
9735 m_numParsedPropertiesBeforeMarginBox = m_parsedProperties.size();
9738 void CSSParser::endDeclarationsForMarginBox()
9740 rollbackLastProperties(m_parsedProperties.size() - m_numParsedPropertiesBeforeMarginBox);
9741 m_numParsedPropertiesBeforeMarginBox = INVALID_NUM_PARSED_PROPERTIES;
9744 void CSSParser::deleteFontFaceOnlyValues()
9746 ASSERT(m_hasFontFaceOnlyValues);
9747 for (unsigned i = 0; i < m_parsedProperties.size();) {
9748 CSSProperty& property = m_parsedProperties[i];
9749 if (property.id() == CSSPropertyFontVariant && property.value()->isValueList()) {
9750 m_parsedProperties.remove(i);
9757 StyleKeyframe* CSSParser::createKeyframe(CSSParserValueList* keys)
9759 // Create a key string from the passed keys
9761 for (unsigned i = 0; i < keys->size(); ++i) {
9762 float key = static_cast<float>(keys->valueAt(i)->fValue);
9765 keyString += String::number(key);
9769 RefPtr<StyleKeyframe> keyframe = StyleKeyframe::create();
9770 keyframe->setKeyText(keyString);
9771 keyframe->setProperties(createStylePropertySet());
9775 StyleKeyframe* keyframePtr = keyframe.get();
9776 m_parsedKeyframes.append(keyframe.release());
9780 void CSSParser::invalidBlockHit()
9782 if (m_styleSheet && !m_hadSyntacticallyValidCSSRule)
9783 m_styleSheet->setHasSyntacticallyValidCSSHeader(false);
9786 void CSSParser::updateLastSelectorLineAndPosition()
9788 m_lastSelectorLineNumber = m_lineNumber;
9789 markRuleBodyStart();
9792 void CSSParser::updateLastMediaLine(MediaQuerySet* media)
9794 media->setLastLine(m_lineNumber);
9797 void CSSParser::fixUnparsedPropertyRanges(CSSRuleSourceData* ruleData)
9799 if (!ruleData->styleSourceData)
9801 Vector<CSSPropertySourceData>& propertyData = ruleData->styleSourceData->propertyData;
9802 unsigned size = propertyData.size();
9806 unsigned styleStart = ruleData->ruleBodyRange.start;
9807 const UChar* characters = m_dataStart.get() + m_parsedTextPrefixLength;
9808 CSSPropertySourceData* nextData = &(propertyData.at(0));
9809 for (unsigned i = 0; i < size; ++i) {
9810 CSSPropertySourceData* currentData = nextData;
9811 nextData = i < size - 1 ? &(propertyData.at(i + 1)) : 0;
9813 if (currentData->parsedOk)
9815 if (currentData->range.end > 0 && characters[styleStart + currentData->range.end - 1] == ';')
9818 unsigned propertyEndInStyleSheet;
9820 propertyEndInStyleSheet = ruleData->ruleBodyRange.end - 1;
9822 propertyEndInStyleSheet = styleStart + nextData->range.start - 1;
9824 while (isHTMLSpace(characters[propertyEndInStyleSheet]))
9825 --propertyEndInStyleSheet;
9827 // propertyEndInStyleSheet points at the last property text character.
9828 unsigned newPropertyEnd = propertyEndInStyleSheet - styleStart + 1; // Exclusive of the last property text character.
9829 if (currentData->range.end != newPropertyEnd) {
9830 currentData->range.end = newPropertyEnd;
9831 unsigned valueStartInStyleSheet = styleStart + currentData->range.start + currentData->name.length();
9832 while (valueStartInStyleSheet < propertyEndInStyleSheet && characters[valueStartInStyleSheet] != ':')
9833 ++valueStartInStyleSheet;
9834 if (valueStartInStyleSheet < propertyEndInStyleSheet)
9835 ++valueStartInStyleSheet; // Shift past the ':'.
9836 while (valueStartInStyleSheet < propertyEndInStyleSheet && isHTMLSpace(characters[valueStartInStyleSheet]))
9837 ++valueStartInStyleSheet;
9838 // Need to exclude the trailing ';' from the property value.
9839 currentData->value = String(characters + valueStartInStyleSheet, propertyEndInStyleSheet - valueStartInStyleSheet + (characters[propertyEndInStyleSheet] == ';' ? 0 : 1));
9844 void CSSParser::markRuleHeaderStart(CSSRuleSourceData::Type ruleType)
9846 if (!isExtractingSourceData())
9848 RefPtr<CSSRuleSourceData> data = CSSRuleSourceData::create(ruleType);
9849 data->ruleHeaderRange.start = m_tokenStart - m_dataStart.get();
9850 m_currentRuleDataStack->append(data.release());
9853 void CSSParser::markRuleHeaderEnd()
9855 if (!isExtractingSourceData())
9857 ASSERT(!m_currentRuleDataStack->isEmpty());
9858 UChar* listEnd = m_tokenStart;
9859 while (listEnd > m_dataStart.get() + 1) {
9860 if (isHTMLSpace(*(listEnd - 1)))
9865 m_currentRuleDataStack->last()->ruleHeaderRange.end = listEnd - m_dataStart.get();
9868 void CSSParser::markRuleBodyStart()
9870 if (!isExtractingSourceData())
9872 unsigned offset = m_tokenStart - m_dataStart.get();
9873 if (*m_tokenStart == '{')
9874 ++offset; // Skip the rule body opening brace.
9875 ASSERT(!m_currentRuleDataStack->isEmpty());
9876 m_currentRuleDataStack->last()->ruleBodyRange.start = offset;
9879 void CSSParser::markRuleBodyEnd()
9881 // Precondition: (!isExtractingSourceData())
9882 unsigned offset = m_tokenStart - m_dataStart.get();
9883 ASSERT(!m_currentRuleDataStack->isEmpty());
9884 m_currentRuleDataStack->last()->ruleBodyRange.end = offset;
9887 void CSSParser::markPropertyStart()
9889 if (!isExtractingSourceData())
9891 if (m_currentRuleDataStack->isEmpty() || !m_currentRuleDataStack->last()->styleSourceData)
9894 m_propertyRange.start = m_tokenStart - m_dataStart.get();
9897 void CSSParser::markPropertyEnd(bool isImportantFound, bool isPropertyParsed)
9899 if (!isExtractingSourceData())
9901 if (m_currentRuleDataStack->isEmpty() || !m_currentRuleDataStack->last()->styleSourceData)
9904 unsigned offset = m_tokenStart - m_dataStart.get();
9905 if (*m_tokenStart == ';') // Include semicolon into the property text.
9907 m_propertyRange.end = offset;
9908 if (m_propertyRange.start != UINT_MAX && !m_currentRuleDataStack->isEmpty()) {
9909 // This stuff is only executed when the style data retrieval is requested by client.
9910 const unsigned start = m_propertyRange.start;
9911 const unsigned end = m_propertyRange.end;
9912 ASSERT(start < end);
9913 String propertyString = String(m_dataStart.get() + start, end - start).stripWhiteSpace();
9914 if (propertyString.endsWith(';'))
9915 propertyString = propertyString.left(propertyString.length() - 1);
9916 size_t colonIndex = propertyString.find(':');
9917 ASSERT(colonIndex != notFound);
9919 String name = propertyString.left(colonIndex).stripWhiteSpace();
9920 String value = propertyString.substring(colonIndex + 1, propertyString.length()).stripWhiteSpace();
9921 // The property range is relative to the declaration start offset.
9922 SourceRange& topRuleBodyRange = m_currentRuleDataStack->last()->ruleBodyRange;
9923 m_currentRuleDataStack->last()->styleSourceData->propertyData.append(
9924 CSSPropertySourceData(name, value, isImportantFound, isPropertyParsed, SourceRange(start - topRuleBodyRange.start, end - topRuleBodyRange.start)));
9926 resetPropertyRange();
9929 static CSSPropertyID cssPropertyID(const UChar* propertyName, unsigned length)
9932 return CSSPropertyInvalid;
9933 if (length > maxCSSPropertyNameLength)
9934 return CSSPropertyInvalid;
9936 char buffer[maxCSSPropertyNameLength + 1 + 1]; // 1 to turn "apple"/"khtml" into "webkit", 1 for null character
9938 for (unsigned i = 0; i != length; ++i) {
9939 UChar c = propertyName[i];
9940 if (c == 0 || c >= 0x7F)
9941 return CSSPropertyInvalid; // illegal character
9942 buffer[i] = toASCIILower(c);
9944 buffer[length] = '\0';
9946 const char* name = buffer;
9947 if (buffer[0] == '-') {
9948 #if ENABLE(LEGACY_CSS_VENDOR_PREFIXES)
9949 // If the prefix is -apple- or -khtml-, change it to -webkit-.
9950 // This makes the string one character longer.
9951 if (hasPrefix(buffer, length, "-apple-") || hasPrefix(buffer, length, "-khtml-")) {
9952 memmove(buffer + 7, buffer + 6, length + 1 - 6);
9953 memcpy(buffer, "-webkit", 7);
9958 cssPropertyNameIOSAliasing(buffer, name, length);
9962 const Property* hashTableEntry = findProperty(name, length);
9963 return hashTableEntry ? static_cast<CSSPropertyID>(hashTableEntry->id) : CSSPropertyInvalid;
9966 CSSPropertyID cssPropertyID(const String& string)
9968 return cssPropertyID(string.characters(), string.length());
9971 CSSPropertyID cssPropertyID(const CSSParserString& string)
9973 return cssPropertyID(string.characters, string.length);
9977 void cssPropertyNameIOSAliasing(const char* propertyName, const char*& propertyNameAlias, unsigned& newLength)
9979 if (!strcmp(propertyName, "-webkit-hyphenate-locale")) {
9980 // Worked in iOS 4.2.
9981 static const char* const webkitLocale = "-webkit-locale";
9982 propertyNameAlias = webkitLocale;
9983 newLength = strlen(webkitLocale);
9988 int cssValueKeywordID(const CSSParserString& string)
9990 unsigned length = string.length;
9993 if (length > maxCSSValueKeywordLength)
9996 char buffer[maxCSSValueKeywordLength + 1 + 1]; // 1 to turn "apple"/"khtml" into "webkit", 1 for null character
9998 for (unsigned i = 0; i != length; ++i) {
9999 UChar c = string.characters[i];
10000 if (c == 0 || c >= 0x7F)
10001 return 0; // illegal character
10002 buffer[i] = WTF::toASCIILower(c);
10004 buffer[length] = '\0';
10006 if (buffer[0] == '-') {
10007 // If the prefix is -apple- or -khtml-, change it to -webkit-.
10008 // This makes the string one character longer.
10009 if (hasPrefix(buffer, length, "-apple-") || hasPrefix(buffer, length, "-khtml-")) {
10010 memmove(buffer + 7, buffer + 6, length + 1 - 6);
10011 memcpy(buffer, "-webkit", 7);
10016 const Value* hashTableEntry = findValue(buffer, length);
10017 return hashTableEntry ? hashTableEntry->id : 0;
10020 // "ident" from the CSS tokenizer, minus backslash-escape sequences
10021 static bool isCSSTokenizerIdentifier(const String& string)
10023 const UChar* p = string.characters();
10024 const UChar* end = p + string.length();
10027 if (p != end && p[0] == '-')
10031 if (p == end || !(p[0] == '_' || p[0] >= 128 || isASCIIAlpha(p[0])))
10036 for (; p != end; ++p) {
10037 if (!(p[0] == '_' || p[0] == '-' || p[0] >= 128 || isASCIIAlphanumeric(p[0])))
10044 // "url" from the CSS tokenizer, minus backslash-escape sequences
10045 static bool isCSSTokenizerURL(const String& string)
10047 const UChar* p = string.characters();
10048 const UChar* end = p + string.length();
10050 for (; p != end; ++p) {
10072 // We use single quotes for now because markup.cpp uses double quotes.
10073 String quoteCSSString(const String& string)
10075 // This function expands each character to at most 3 characters ('\u0010' -> '\' '1' '0') as well as adds
10076 // 2 quote characters (before and after). Make sure the resulting size (3 * length + 2) will not overflow unsigned.
10077 if (string.length() >= (std::numeric_limits<unsigned>::max() / 3) - 2)
10080 // For efficiency, we first pre-calculate the length of the quoted string, then we build the actual one.
10081 // Please see below for the actual logic.
10082 unsigned quotedStringSize = 2; // Two quotes surrounding the entire string.
10083 bool afterEscape = false;
10084 for (unsigned i = 0; i < string.length(); ++i) {
10085 UChar ch = string[i];
10086 if (ch == '\\' || ch == '\'') {
10087 quotedStringSize += 2;
10088 afterEscape = false;
10089 } else if (ch < 0x20 || ch == 0x7F) {
10090 quotedStringSize += 2 + (ch >= 0x10);
10091 afterEscape = true;
10093 quotedStringSize += 1 + (afterEscape && (isASCIIHexDigit(ch) || ch == ' '));
10094 afterEscape = false;
10098 StringBuffer<UChar> buffer(quotedStringSize);
10099 unsigned index = 0;
10100 buffer[index++] = '\'';
10101 afterEscape = false;
10102 for (unsigned i = 0; i < string.length(); ++i) {
10103 UChar ch = string[i];
10104 if (ch == '\\' || ch == '\'') {
10105 buffer[index++] = '\\';
10106 buffer[index++] = ch;
10107 afterEscape = false;
10108 } else if (ch < 0x20 || ch == 0x7F) { // Control characters.
10109 buffer[index++] = '\\';
10110 placeByteAsHexCompressIfPossible(ch, buffer, index, Lowercase);
10111 afterEscape = true;
10113 // Space character may be required to separate backslash-escape sequence and normal characters.
10114 if (afterEscape && (isASCIIHexDigit(ch) || ch == ' '))
10115 buffer[index++] = ' ';
10116 buffer[index++] = ch;
10117 afterEscape = false;
10120 buffer[index++] = '\'';
10122 ASSERT(quotedStringSize == index);
10123 return String::adopt(buffer);
10126 String quoteCSSStringIfNeeded(const String& string)
10128 return isCSSTokenizerIdentifier(string) ? string : quoteCSSString(string);
10131 String quoteCSSURLIfNeeded(const String& string)
10133 return isCSSTokenizerURL(string) ? string : quoteCSSString(string);
10136 bool isValidNthToken(const CSSParserString& token)
10138 // The tokenizer checks for the construct of an+b.
10139 // However, since the {ident} rule precedes the {nth} rule, some of those
10140 // tokens are identified as string literal. Furthermore we need to accept
10141 // "odd" and "even" which does not match to an+b.
10142 return equalIgnoringCase(token, "odd") || equalIgnoringCase(token, "even")
10143 || equalIgnoringCase(token, "n") || equalIgnoringCase(token, "-n");