1/*
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.
9 * Copyright (C) 2012 Intel Corporation. All rights reserved.
10 *
11 * This library is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU Library General Public
13 * License as published by the Free Software Foundation; either
14 * version 2 of the License, or (at your option) any later version.
15 *
16 * This library is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
19 * Library General Public License for more details.
20 *
21 * You should have received a copy of the GNU Library General Public License
22 * along with this library; see the file COPYING.LIB.  If not, write to
23 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
24 * Boston, MA 02110-1301, USA.
25 */
26
27#include "config.h"
28#include "core/css/parser/BisonCSSParser.h"
29
30#include "core/CSSValueKeywords.h"
31#include "core/MediaTypeNames.h"
32#include "core/StylePropertyShorthand.h"
33#include "core/css/CSSAspectRatioValue.h"
34#include "core/css/CSSBasicShapes.h"
35#include "core/css/CSSBorderImage.h"
36#include "core/css/CSSCanvasValue.h"
37#include "core/css/CSSCrossfadeValue.h"
38#include "core/css/CSSCursorImageValue.h"
39#include "core/css/CSSFontFaceSrcValue.h"
40#include "core/css/CSSFontFeatureValue.h"
41#include "core/css/CSSFunctionValue.h"
42#include "core/css/CSSGradientValue.h"
43#include "core/css/CSSGridLineNamesValue.h"
44#include "core/css/CSSGridTemplateAreasValue.h"
45#include "core/css/CSSImageSetValue.h"
46#include "core/css/CSSImageValue.h"
47#include "core/css/CSSInheritedValue.h"
48#include "core/css/CSSInitialValue.h"
49#include "core/css/CSSKeyframeRule.h"
50#include "core/css/CSSKeyframesRule.h"
51#include "core/css/CSSLineBoxContainValue.h"
52#include "core/css/CSSPrimitiveValue.h"
53#include "core/css/CSSPropertySourceData.h"
54#include "core/css/CSSReflectValue.h"
55#include "core/css/CSSSelector.h"
56#include "core/css/CSSShadowValue.h"
57#include "core/css/CSSStyleSheet.h"
58#include "core/css/CSSTimingFunctionValue.h"
59#include "core/css/CSSTransformValue.h"
60#include "core/css/CSSUnicodeRangeValue.h"
61#include "core/css/CSSValueList.h"
62#include "core/css/CSSValuePool.h"
63#include "core/css/Counter.h"
64#include "core/css/HashTools.h"
65#include "core/css/MediaList.h"
66#include "core/css/MediaQueryExp.h"
67#include "core/css/Pair.h"
68#include "core/css/Rect.h"
69#include "core/css/StylePropertySet.h"
70#include "core/css/StyleRule.h"
71#include "core/css/StyleRuleImport.h"
72#include "core/css/StyleSheetContents.h"
73#include "core/css/parser/CSSParserIdioms.h"
74#include "core/dom/Document.h"
75#include "core/frame/FrameConsole.h"
76#include "core/frame/FrameHost.h"
77#include "core/frame/Settings.h"
78#include "core/frame/UseCounter.h"
79#include "core/html/parser/HTMLParserIdioms.h"
80#include "core/inspector/ConsoleMessage.h"
81#include "core/inspector/InspectorInstrumentation.h"
82#include "core/rendering/RenderTheme.h"
83#include "platform/FloatConversion.h"
84#include "platform/RuntimeEnabledFeatures.h"
85#include "wtf/BitArray.h"
86#include "wtf/HexNumber.h"
87#include "wtf/text/StringBuffer.h"
88#include "wtf/text/StringBuilder.h"
89#include "wtf/text/StringImpl.h"
90#include "wtf/text/TextEncoding.h"
91#include <limits.h>
92
93#define YYDEBUG 0
94
95#if YYDEBUG > 0
96extern int cssyydebug;
97#endif
98
99int cssyyparse(blink::BisonCSSParser*);
100
101using namespace WTF;
102
103namespace blink {
104
105static const unsigned INVALID_NUM_PARSED_PROPERTIES = UINT_MAX;
106
107BisonCSSParser::BisonCSSParser(const CSSParserContext& context)
108    : m_context(context)
109    , m_important(false)
110    , m_id(CSSPropertyInvalid)
111    , m_styleSheet(nullptr)
112    , m_supportsCondition(false)
113    , m_selectorListForParseSelector(0)
114    , m_numParsedPropertiesBeforeMarginBox(INVALID_NUM_PARSED_PROPERTIES)
115    , m_hadSyntacticallyValidCSSRule(false)
116    , m_logErrors(false)
117    , m_ignoreErrors(false)
118    , m_defaultNamespace(starAtom)
119    , m_observer(0)
120    , m_source(0)
121    , m_ruleHeaderType(CSSRuleSourceData::UNKNOWN_RULE)
122    , m_allowImportRules(true)
123    , m_allowNamespaceDeclarations(true)
124    , m_inViewport(false)
125    , m_tokenizer(*this)
126{
127#if YYDEBUG > 0
128    cssyydebug = 1;
129#endif
130}
131
132BisonCSSParser::~BisonCSSParser()
133{
134    clearProperties();
135
136    deleteAllValues(m_floatingSelectors);
137    deleteAllValues(m_floatingSelectorVectors);
138    deleteAllValues(m_floatingValueLists);
139    deleteAllValues(m_floatingFunctions);
140}
141
142void BisonCSSParser::setupParser(const char* prefix, unsigned prefixLength, const String& string, const char* suffix, unsigned suffixLength)
143{
144    m_tokenizer.setupTokenizer(prefix, prefixLength, string, suffix, suffixLength);
145    m_ruleHasHeader = true;
146}
147
148void BisonCSSParser::parseSheet(StyleSheetContents* sheet, const String& string, const TextPosition& startPosition, CSSParserObserver* observer, bool logErrors)
149{
150    setStyleSheet(sheet);
151    m_defaultNamespace = starAtom; // Reset the default namespace.
152    TemporaryChange<CSSParserObserver*> scopedObsever(m_observer, observer);
153    m_logErrors = logErrors && sheet->singleOwnerDocument() && !sheet->baseURL().isEmpty() && sheet->singleOwnerDocument()->frameHost();
154    m_ignoreErrors = false;
155    m_tokenizer.m_lineNumber = 0;
156    m_startPosition = startPosition;
157    m_source = &string;
158    m_tokenizer.m_internal = false;
159    setupParser("", string, "");
160    cssyyparse(this);
161    sheet->shrinkToFit();
162    m_source = 0;
163    m_rule = nullptr;
164    m_lineEndings.clear();
165    m_ignoreErrors = false;
166    m_logErrors = false;
167    m_tokenizer.m_internal = true;
168}
169
170PassRefPtrWillBeRawPtr<StyleRuleBase> BisonCSSParser::parseRule(StyleSheetContents* sheet, const String& string)
171{
172    setStyleSheet(sheet);
173    m_allowNamespaceDeclarations = false;
174    setupParser("@-internal-rule ", string, "");
175    cssyyparse(this);
176    return m_rule.release();
177}
178
179PassRefPtrWillBeRawPtr<StyleKeyframe> BisonCSSParser::parseKeyframeRule(StyleSheetContents* sheet, const String& string)
180{
181    setStyleSheet(sheet);
182    setupParser("@-internal-keyframe-rule ", string, "");
183    cssyyparse(this);
184    return m_keyframe.release();
185}
186
187PassOwnPtr<Vector<double> > BisonCSSParser::parseKeyframeKeyList(const String& string)
188{
189    setupParser("@-internal-keyframe-key-list ", string, "");
190    cssyyparse(this);
191    ASSERT(m_valueList);
192    return StyleKeyframe::createKeyList(m_valueList.get());
193}
194
195bool BisonCSSParser::parseSupportsCondition(const String& string)
196{
197    m_supportsCondition = false;
198    setupParser("@-internal-supports-condition ", string, "");
199    cssyyparse(this);
200    return m_supportsCondition;
201}
202
203static inline bool isColorPropertyID(CSSPropertyID propertyId)
204{
205    switch (propertyId) {
206    case CSSPropertyColor:
207    case CSSPropertyBackgroundColor:
208    case CSSPropertyBorderBottomColor:
209    case CSSPropertyBorderLeftColor:
210    case CSSPropertyBorderRightColor:
211    case CSSPropertyBorderTopColor:
212    case CSSPropertyOutlineColor:
213    case CSSPropertyWebkitBorderAfterColor:
214    case CSSPropertyWebkitBorderBeforeColor:
215    case CSSPropertyWebkitBorderEndColor:
216    case CSSPropertyWebkitBorderStartColor:
217    case CSSPropertyWebkitColumnRuleColor:
218    case CSSPropertyWebkitTextEmphasisColor:
219    case CSSPropertyWebkitTextFillColor:
220    case CSSPropertyWebkitTextStrokeColor:
221    case CSSPropertyTextDecorationColor:
222        return true;
223    default:
224        return false;
225    }
226}
227
228static bool parseColorValue(MutableStylePropertySet* declaration, CSSPropertyID propertyId, const String& string, bool important, CSSParserMode cssParserMode)
229{
230    ASSERT(!string.isEmpty());
231    bool quirksMode = isQuirksModeBehavior(cssParserMode);
232    if (!isColorPropertyID(propertyId))
233        return false;
234    CSSParserString cssString;
235    cssString.init(string);
236    CSSValueID valueID = cssValueKeywordID(cssString);
237    bool validPrimitive = false;
238    if (valueID == CSSValueWebkitText) {
239        validPrimitive = true;
240    } else if (valueID == CSSValueCurrentcolor) {
241        validPrimitive = true;
242    } else if ((valueID >= CSSValueAqua && valueID <= CSSValueWindowtext) || valueID == CSSValueMenu
243        || (quirksMode && valueID >= CSSValueWebkitFocusRingColor && valueID < CSSValueWebkitText)) {
244        validPrimitive = true;
245    }
246
247    if (validPrimitive) {
248        RefPtrWillBeRawPtr<CSSValue> value = cssValuePool().createIdentifierValue(valueID);
249        declaration->addParsedProperty(CSSProperty(propertyId, value.release(), important));
250        return true;
251    }
252    RGBA32 color;
253    if (!CSSPropertyParser::fastParseColor(color, string, !quirksMode && string[0] != '#'))
254        return false;
255    RefPtrWillBeRawPtr<CSSValue> value = cssValuePool().createColorValue(color);
256    declaration->addParsedProperty(CSSProperty(propertyId, value.release(), important));
257    return true;
258}
259
260static inline bool isSimpleLengthPropertyID(CSSPropertyID propertyId, bool& acceptsNegativeNumbers)
261{
262    switch (propertyId) {
263    case CSSPropertyFontSize:
264    case CSSPropertyHeight:
265    case CSSPropertyWidth:
266    case CSSPropertyMinHeight:
267    case CSSPropertyMinWidth:
268    case CSSPropertyPaddingBottom:
269    case CSSPropertyPaddingLeft:
270    case CSSPropertyPaddingRight:
271    case CSSPropertyPaddingTop:
272    case CSSPropertyWebkitLogicalWidth:
273    case CSSPropertyWebkitLogicalHeight:
274    case CSSPropertyWebkitMinLogicalWidth:
275    case CSSPropertyWebkitMinLogicalHeight:
276    case CSSPropertyWebkitPaddingAfter:
277    case CSSPropertyWebkitPaddingBefore:
278    case CSSPropertyWebkitPaddingEnd:
279    case CSSPropertyWebkitPaddingStart:
280        acceptsNegativeNumbers = false;
281        return true;
282    case CSSPropertyShapeMargin:
283        acceptsNegativeNumbers = false;
284        return true;
285    case CSSPropertyBottom:
286    case CSSPropertyLeft:
287    case CSSPropertyMarginBottom:
288    case CSSPropertyMarginLeft:
289    case CSSPropertyMarginRight:
290    case CSSPropertyMarginTop:
291    case CSSPropertyRight:
292    case CSSPropertyTop:
293    case CSSPropertyWebkitMarginAfter:
294    case CSSPropertyWebkitMarginBefore:
295    case CSSPropertyWebkitMarginEnd:
296    case CSSPropertyWebkitMarginStart:
297        acceptsNegativeNumbers = true;
298        return true;
299    default:
300        return false;
301    }
302}
303
304template <typename CharacterType>
305static inline bool parseSimpleLength(const CharacterType* characters, unsigned length, CSSPrimitiveValue::UnitType& unit, double& number)
306{
307    if (length > 2 && (characters[length - 2] | 0x20) == 'p' && (characters[length - 1] | 0x20) == 'x') {
308        length -= 2;
309        unit = CSSPrimitiveValue::CSS_PX;
310    } else if (length > 1 && characters[length - 1] == '%') {
311        length -= 1;
312        unit = CSSPrimitiveValue::CSS_PERCENTAGE;
313    }
314
315    // We rely on charactersToDouble for validation as well. The function
316    // will set "ok" to "false" if the entire passed-in character range does
317    // not represent a double.
318    bool ok;
319    number = charactersToDouble(characters, length, &ok);
320    return ok;
321}
322
323static bool parseSimpleLengthValue(MutableStylePropertySet* declaration, CSSPropertyID propertyId, const String& string, bool important, CSSParserMode cssParserMode)
324{
325    ASSERT(!string.isEmpty());
326    bool acceptsNegativeNumbers = false;
327
328    // In @viewport, width and height are shorthands, not simple length values.
329    if (isCSSViewportParsingEnabledForMode(cssParserMode) || !isSimpleLengthPropertyID(propertyId, acceptsNegativeNumbers))
330        return false;
331
332    unsigned length = string.length();
333    double number;
334    CSSPrimitiveValue::UnitType unit = CSSPrimitiveValue::CSS_NUMBER;
335
336    if (string.is8Bit()) {
337        if (!parseSimpleLength(string.characters8(), length, unit, number))
338            return false;
339    } else {
340        if (!parseSimpleLength(string.characters16(), length, unit, number))
341            return false;
342    }
343
344    if (unit == CSSPrimitiveValue::CSS_NUMBER) {
345        bool quirksMode = isQuirksModeBehavior(cssParserMode);
346        if (number && !quirksMode)
347            return false;
348        unit = CSSPrimitiveValue::CSS_PX;
349    }
350    if (number < 0 && !acceptsNegativeNumbers)
351        return false;
352
353    RefPtrWillBeRawPtr<CSSValue> value = cssValuePool().createValue(number, unit);
354    declaration->addParsedProperty(CSSProperty(propertyId, value.release(), important));
355    return true;
356}
357
358bool isValidKeywordPropertyAndValue(CSSPropertyID propertyId, CSSValueID valueID, const CSSParserContext& parserContext)
359{
360    if (valueID == CSSValueInvalid)
361        return false;
362
363    switch (propertyId) {
364    case CSSPropertyAll:
365        return valueID == CSSValueUnset;
366    case CSSPropertyBackgroundRepeatX: // repeat | no-repeat
367    case CSSPropertyBackgroundRepeatY: // repeat | no-repeat
368        return valueID == CSSValueRepeat || valueID == CSSValueNoRepeat;
369    case CSSPropertyBorderCollapse: // collapse | separate
370        return valueID == CSSValueCollapse || valueID == CSSValueSeparate;
371    case CSSPropertyBorderTopStyle: // <border-style>
372    case CSSPropertyBorderRightStyle: // Defined as: none | hidden | dotted | dashed |
373    case CSSPropertyBorderBottomStyle: // solid | double | groove | ridge | inset | outset
374    case CSSPropertyBorderLeftStyle:
375    case CSSPropertyWebkitBorderAfterStyle:
376    case CSSPropertyWebkitBorderBeforeStyle:
377    case CSSPropertyWebkitBorderEndStyle:
378    case CSSPropertyWebkitBorderStartStyle:
379    case CSSPropertyWebkitColumnRuleStyle:
380        return valueID >= CSSValueNone && valueID <= CSSValueDouble;
381    case CSSPropertyBoxSizing:
382        return valueID == CSSValueBorderBox || valueID == CSSValueContentBox;
383    case CSSPropertyCaptionSide: // top | bottom | left | right
384        return valueID == CSSValueLeft || valueID == CSSValueRight || valueID == CSSValueTop || valueID == CSSValueBottom;
385    case CSSPropertyClear: // none | left | right | both
386        return valueID == CSSValueNone || valueID == CSSValueLeft || valueID == CSSValueRight || valueID == CSSValueBoth;
387    case CSSPropertyDirection: // ltr | rtl
388        return valueID == CSSValueLtr || valueID == CSSValueRtl;
389    case CSSPropertyDisplay:
390        // inline | block | list-item | inline-block | table |
391        // inline-table | table-row-group | table-header-group | table-footer-group | table-row |
392        // table-column-group | table-column | table-cell | table-caption | -webkit-box | -webkit-inline-box | none
393        // flex | inline-flex | -webkit-flex | -webkit-inline-flex | grid | inline-grid
394        return (valueID >= CSSValueInline && valueID <= CSSValueInlineFlex) || valueID == CSSValueWebkitFlex || valueID == CSSValueWebkitInlineFlex || valueID == CSSValueNone
395            || (RuntimeEnabledFeatures::cssGridLayoutEnabled() && (valueID == CSSValueGrid || valueID == CSSValueInlineGrid));
396    case CSSPropertyEmptyCells: // show | hide
397        return valueID == CSSValueShow || valueID == CSSValueHide;
398    case CSSPropertyFloat: // left | right | none | center (for buggy CSS, maps to none)
399        return valueID == CSSValueLeft || valueID == CSSValueRight || valueID == CSSValueNone || valueID == CSSValueCenter;
400    case CSSPropertyFontStyle: // normal | italic | oblique
401        return valueID == CSSValueNormal || valueID == CSSValueItalic || valueID == CSSValueOblique;
402    case CSSPropertyFontStretch: // normal | ultra-condensed | extra-condensed | condensed | semi-condensed | semi-expanded | expanded | extra-expanded | ultra-expanded
403        return valueID == CSSValueNormal || (valueID >= CSSValueUltraCondensed && valueID <= CSSValueUltraExpanded);
404    case CSSPropertyImageRendering: // auto | optimizeContrast | pixelated
405        return valueID == CSSValueAuto || valueID == CSSValueWebkitOptimizeContrast || (RuntimeEnabledFeatures::imageRenderingPixelatedEnabled() && valueID == CSSValuePixelated);
406    case CSSPropertyIsolation: // auto | isolate
407        ASSERT(RuntimeEnabledFeatures::cssCompositingEnabled());
408        return valueID == CSSValueAuto || valueID == CSSValueIsolate;
409    case CSSPropertyListStylePosition: // inside | outside
410        return valueID == CSSValueInside || valueID == CSSValueOutside;
411    case CSSPropertyListStyleType:
412        // See section CSS_PROP_LIST_STYLE_TYPE of file CSSValueKeywords.in
413        // for the list of supported list-style-types.
414        return (valueID >= CSSValueDisc && valueID <= CSSValueKatakanaIroha) || valueID == CSSValueNone;
415    case CSSPropertyObjectFit:
416        return valueID == CSSValueFill || valueID == CSSValueContain || valueID == CSSValueCover || valueID == CSSValueNone || valueID == CSSValueScaleDown;
417    case CSSPropertyOutlineStyle: // (<border-style> except hidden) | auto
418        return valueID == CSSValueAuto || valueID == CSSValueNone || (valueID >= CSSValueInset && valueID <= CSSValueDouble);
419    case CSSPropertyOverflowWrap: // normal | break-word
420    case CSSPropertyWordWrap:
421        return valueID == CSSValueNormal || valueID == CSSValueBreakWord;
422    case CSSPropertyOverflowX: // visible | hidden | scroll | auto | overlay
423        return valueID == CSSValueVisible || valueID == CSSValueHidden || valueID == CSSValueScroll || valueID == CSSValueAuto || valueID == CSSValueOverlay;
424    case CSSPropertyOverflowY: // visible | hidden | scroll | auto | overlay | -webkit-paged-x | -webkit-paged-y
425        return valueID == CSSValueVisible || valueID == CSSValueHidden || valueID == CSSValueScroll || valueID == CSSValueAuto || valueID == CSSValueOverlay || valueID == CSSValueWebkitPagedX || valueID == CSSValueWebkitPagedY;
426    case CSSPropertyPageBreakAfter: // auto | always | avoid | left | right
427    case CSSPropertyPageBreakBefore:
428    case CSSPropertyWebkitColumnBreakAfter:
429    case CSSPropertyWebkitColumnBreakBefore:
430        return valueID == CSSValueAuto || valueID == CSSValueAlways || valueID == CSSValueAvoid || valueID == CSSValueLeft || valueID == CSSValueRight;
431    case CSSPropertyPageBreakInside: // avoid | auto
432    case CSSPropertyWebkitColumnBreakInside:
433        return valueID == CSSValueAuto || valueID == CSSValueAvoid;
434    case CSSPropertyPointerEvents:
435        // none | visiblePainted | visibleFill | visibleStroke | visible |
436        // painted | fill | stroke | auto | all | bounding-box
437        return valueID == CSSValueVisible || valueID == CSSValueNone || valueID == CSSValueAll || valueID == CSSValueAuto || (valueID >= CSSValueVisiblepainted && valueID <= CSSValueBoundingBox);
438    case CSSPropertyPosition: // static | relative | absolute | fixed
439        return valueID == CSSValueStatic || valueID == CSSValueRelative || valueID == CSSValueAbsolute || valueID == CSSValueFixed;
440    case CSSPropertyResize: // none | both | horizontal | vertical | auto
441        return valueID == CSSValueNone || valueID == CSSValueBoth || valueID == CSSValueHorizontal || valueID == CSSValueVertical || valueID == CSSValueAuto;
442    case CSSPropertyScrollBehavior: // instant | smooth
443        ASSERT(RuntimeEnabledFeatures::cssomSmoothScrollEnabled());
444        return valueID == CSSValueInstant || valueID == CSSValueSmooth;
445    case CSSPropertySpeak: // none | normal | spell-out | digits | literal-punctuation | no-punctuation
446        return valueID == CSSValueNone || valueID == CSSValueNormal || valueID == CSSValueSpellOut || valueID == CSSValueDigits || valueID == CSSValueLiteralPunctuation || valueID == CSSValueNoPunctuation;
447    case CSSPropertyTableLayout: // auto | fixed
448        return valueID == CSSValueAuto || valueID == CSSValueFixed;
449    case CSSPropertyTextAlignLast:
450        // auto | start | end | left | right | center | justify
451        ASSERT(RuntimeEnabledFeatures::css3TextEnabled());
452        return (valueID >= CSSValueLeft && valueID <= CSSValueJustify) || valueID == CSSValueStart || valueID == CSSValueEnd || valueID == CSSValueAuto;
453    case CSSPropertyTextDecorationStyle:
454        // solid | double | dotted | dashed | wavy
455        ASSERT(RuntimeEnabledFeatures::css3TextDecorationsEnabled());
456        return valueID == CSSValueSolid || valueID == CSSValueDouble || valueID == CSSValueDotted || valueID == CSSValueDashed || valueID == CSSValueWavy;
457    case CSSPropertyTextJustify:
458        // auto | none | inter-word | distribute
459        ASSERT(RuntimeEnabledFeatures::css3TextEnabled());
460        return valueID == CSSValueInterWord || valueID == CSSValueDistribute || valueID == CSSValueAuto || valueID == CSSValueNone;
461    case CSSPropertyTextOverflow: // clip | ellipsis
462        return valueID == CSSValueClip || valueID == CSSValueEllipsis;
463    case CSSPropertyTextRendering: // auto | optimizeSpeed | optimizeLegibility | geometricPrecision
464        return valueID == CSSValueAuto || valueID == CSSValueOptimizespeed || valueID == CSSValueOptimizelegibility || valueID == CSSValueGeometricprecision;
465    case CSSPropertyTextTransform: // capitalize | uppercase | lowercase | none
466        return (valueID >= CSSValueCapitalize && valueID <= CSSValueLowercase) || valueID == CSSValueNone;
467    case CSSPropertyUnicodeBidi:
468        return valueID == CSSValueNormal || valueID == CSSValueEmbed
469            || valueID == CSSValueBidiOverride || valueID == CSSValueWebkitIsolate
470            || valueID == CSSValueWebkitIsolateOverride || valueID == CSSValueWebkitPlaintext;
471    case CSSPropertyTouchActionDelay: // none | script
472        ASSERT(RuntimeEnabledFeatures::cssTouchActionDelayEnabled());
473        return valueID == CSSValueScript || valueID == CSSValueNone;
474    case CSSPropertyVisibility: // visible | hidden | collapse
475        return valueID == CSSValueVisible || valueID == CSSValueHidden || valueID == CSSValueCollapse;
476    case CSSPropertyWebkitAppearance:
477        return (valueID >= CSSValueCheckbox && valueID <= CSSValueTextarea) || valueID == CSSValueNone;
478    case CSSPropertyBackfaceVisibility:
479    case CSSPropertyWebkitBackfaceVisibility:
480        return valueID == CSSValueVisible || valueID == CSSValueHidden;
481    case CSSPropertyMixBlendMode:
482        ASSERT(RuntimeEnabledFeatures::cssCompositingEnabled());
483        return valueID == CSSValueNormal || valueID == CSSValueMultiply || valueID == CSSValueScreen || valueID == CSSValueOverlay
484            || valueID == CSSValueDarken || valueID == CSSValueLighten || valueID == CSSValueColorDodge || valueID == CSSValueColorBurn
485            || valueID == CSSValueHardLight || valueID == CSSValueSoftLight || valueID == CSSValueDifference || valueID == CSSValueExclusion
486            || valueID == CSSValueHue || valueID == CSSValueSaturation || valueID == CSSValueColor || valueID == CSSValueLuminosity;
487    case CSSPropertyWebkitBorderFit:
488        return valueID == CSSValueBorder || valueID == CSSValueLines;
489    case CSSPropertyWebkitBoxAlign:
490        return valueID == CSSValueStretch || valueID == CSSValueStart || valueID == CSSValueEnd || valueID == CSSValueCenter || valueID == CSSValueBaseline;
491    case CSSPropertyWebkitBoxDecorationBreak:
492        return valueID == CSSValueClone || valueID == CSSValueSlice;
493    case CSSPropertyWebkitBoxDirection:
494        return valueID == CSSValueNormal || valueID == CSSValueReverse;
495    case CSSPropertyWebkitBoxLines:
496        return valueID == CSSValueSingle || valueID == CSSValueMultiple;
497    case CSSPropertyWebkitBoxOrient:
498        return valueID == CSSValueHorizontal || valueID == CSSValueVertical || valueID == CSSValueInlineAxis || valueID == CSSValueBlockAxis;
499    case CSSPropertyWebkitBoxPack:
500        return valueID == CSSValueStart || valueID == CSSValueEnd || valueID == CSSValueCenter || valueID == CSSValueJustify;
501    case CSSPropertyColumnFill:
502        ASSERT(RuntimeEnabledFeatures::regionBasedColumnsEnabled());
503        return valueID == CSSValueAuto || valueID == CSSValueBalance;
504    case CSSPropertyAlignContent:
505        // FIXME: Per CSS alignment, this property should accept an optional <overflow-position>. We should share this parsing code with 'justify-self'.
506        return valueID == CSSValueFlexStart || valueID == CSSValueFlexEnd || valueID == CSSValueCenter || valueID == CSSValueSpaceBetween || valueID == CSSValueSpaceAround || valueID == CSSValueStretch;
507    case CSSPropertyAlignItems:
508        // FIXME: Per CSS alignment, this property should accept the same arguments as 'justify-self' so we should share its parsing code.
509        return valueID == CSSValueFlexStart || valueID == CSSValueFlexEnd || valueID == CSSValueCenter || valueID == CSSValueBaseline || valueID == CSSValueStretch;
510    case CSSPropertyAlignSelf:
511        // FIXME: Per CSS alignment, this property should accept the same arguments as 'justify-self' so we should share its parsing code.
512        return valueID == CSSValueAuto || valueID == CSSValueFlexStart || valueID == CSSValueFlexEnd || valueID == CSSValueCenter || valueID == CSSValueBaseline || valueID == CSSValueStretch;
513    case CSSPropertyFlexDirection:
514        return valueID == CSSValueRow || valueID == CSSValueRowReverse || valueID == CSSValueColumn || valueID == CSSValueColumnReverse;
515    case CSSPropertyFlexWrap:
516        return valueID == CSSValueNowrap || valueID == CSSValueWrap || valueID == CSSValueWrapReverse;
517    case CSSPropertyJustifyContent:
518        // FIXME: Per CSS alignment, this property should accept an optional <overflow-position>. We should share this parsing code with 'justify-self'.
519        return valueID == CSSValueFlexStart || valueID == CSSValueFlexEnd || valueID == CSSValueCenter || valueID == CSSValueSpaceBetween || valueID == CSSValueSpaceAround;
520    case CSSPropertyFontKerning:
521        return valueID == CSSValueAuto || valueID == CSSValueNormal || valueID == CSSValueNone;
522    case CSSPropertyWebkitFontSmoothing:
523        return valueID == CSSValueAuto || valueID == CSSValueNone || valueID == CSSValueAntialiased || valueID == CSSValueSubpixelAntialiased;
524    case CSSPropertyWebkitLineBreak: // auto | loose | normal | strict | after-white-space
525        return valueID == CSSValueAuto || valueID == CSSValueLoose || valueID == CSSValueNormal || valueID == CSSValueStrict || valueID == CSSValueAfterWhiteSpace;
526    case CSSPropertyWebkitMarginAfterCollapse:
527    case CSSPropertyWebkitMarginBeforeCollapse:
528    case CSSPropertyWebkitMarginBottomCollapse:
529    case CSSPropertyWebkitMarginTopCollapse:
530        return valueID == CSSValueCollapse || valueID == CSSValueSeparate || valueID == CSSValueDiscard;
531    case CSSPropertyInternalMarqueeDirection:
532        return valueID == CSSValueForwards || valueID == CSSValueBackwards || valueID == CSSValueAhead || valueID == CSSValueReverse || valueID == CSSValueLeft || valueID == CSSValueRight || valueID == CSSValueDown
533            || valueID == CSSValueUp || valueID == CSSValueAuto;
534    case CSSPropertyInternalMarqueeStyle:
535        return valueID == CSSValueNone || valueID == CSSValueSlide || valueID == CSSValueScroll || valueID == CSSValueAlternate;
536    case CSSPropertyWebkitPrintColorAdjust:
537        return valueID == CSSValueExact || valueID == CSSValueEconomy;
538    case CSSPropertyWebkitRtlOrdering:
539        return valueID == CSSValueLogical || valueID == CSSValueVisual;
540    case CSSPropertyWebkitRubyPosition:
541        return valueID == CSSValueBefore || valueID == CSSValueAfter;
542    case CSSPropertyWebkitTextCombine:
543        return valueID == CSSValueNone || valueID == CSSValueHorizontal;
544    case CSSPropertyWebkitTextEmphasisPosition:
545        return valueID == CSSValueOver || valueID == CSSValueUnder;
546    case CSSPropertyWebkitTextSecurity: // disc | circle | square | none
547        return valueID == CSSValueDisc || valueID == CSSValueCircle || valueID == CSSValueSquare || valueID == CSSValueNone;
548    case CSSPropertyTransformStyle:
549    case CSSPropertyWebkitTransformStyle:
550        return valueID == CSSValueFlat || valueID == CSSValuePreserve3d;
551    case CSSPropertyWebkitUserDrag: // auto | none | element
552        return valueID == CSSValueAuto || valueID == CSSValueNone || valueID == CSSValueElement;
553    case CSSPropertyWebkitUserModify: // read-only | read-write
554        return valueID == CSSValueReadOnly || valueID == CSSValueReadWrite || valueID == CSSValueReadWritePlaintextOnly;
555    case CSSPropertyWebkitUserSelect: // auto | none | text | all
556        return valueID == CSSValueAuto || valueID == CSSValueNone || valueID == CSSValueText || valueID == CSSValueAll;
557    case CSSPropertyWebkitWritingMode:
558        return valueID >= CSSValueHorizontalTb && valueID <= CSSValueHorizontalBt;
559    case CSSPropertyWhiteSpace: // normal | pre | nowrap
560        return valueID == CSSValueNormal || valueID == CSSValuePre || valueID == CSSValuePreWrap || valueID == CSSValuePreLine || valueID == CSSValueNowrap;
561    case CSSPropertyWordBreak: // normal | break-all | break-word (this is a custom extension)
562        return valueID == CSSValueNormal || valueID == CSSValueBreakAll || valueID == CSSValueBreakWord;
563    default:
564        ASSERT_NOT_REACHED();
565        return false;
566    }
567    return false;
568}
569
570bool isKeywordPropertyID(CSSPropertyID propertyId)
571{
572    switch (propertyId) {
573    case CSSPropertyAll:
574    case CSSPropertyMixBlendMode:
575    case CSSPropertyIsolation:
576    case CSSPropertyBackgroundRepeatX:
577    case CSSPropertyBackgroundRepeatY:
578    case CSSPropertyBorderBottomStyle:
579    case CSSPropertyBorderCollapse:
580    case CSSPropertyBorderLeftStyle:
581    case CSSPropertyBorderRightStyle:
582    case CSSPropertyBorderTopStyle:
583    case CSSPropertyBoxSizing:
584    case CSSPropertyCaptionSide:
585    case CSSPropertyClear:
586    case CSSPropertyDirection:
587    case CSSPropertyDisplay:
588    case CSSPropertyEmptyCells:
589    case CSSPropertyFloat:
590    case CSSPropertyFontStyle:
591    case CSSPropertyFontStretch:
592    case CSSPropertyImageRendering:
593    case CSSPropertyListStylePosition:
594    case CSSPropertyListStyleType:
595    case CSSPropertyObjectFit:
596    case CSSPropertyOutlineStyle:
597    case CSSPropertyOverflowWrap:
598    case CSSPropertyOverflowX:
599    case CSSPropertyOverflowY:
600    case CSSPropertyPageBreakAfter:
601    case CSSPropertyPageBreakBefore:
602    case CSSPropertyPageBreakInside:
603    case CSSPropertyPointerEvents:
604    case CSSPropertyPosition:
605    case CSSPropertyResize:
606    case CSSPropertyScrollBehavior:
607    case CSSPropertySpeak:
608    case CSSPropertyTableLayout:
609    case CSSPropertyTextAlignLast:
610    case CSSPropertyTextDecorationStyle:
611    case CSSPropertyTextJustify:
612    case CSSPropertyTextOverflow:
613    case CSSPropertyTextRendering:
614    case CSSPropertyTextTransform:
615    case CSSPropertyTouchActionDelay:
616    case CSSPropertyUnicodeBidi:
617    case CSSPropertyVisibility:
618    case CSSPropertyWebkitAppearance:
619    case CSSPropertyBackfaceVisibility:
620    case CSSPropertyWebkitBackfaceVisibility:
621    case CSSPropertyWebkitBorderAfterStyle:
622    case CSSPropertyWebkitBorderBeforeStyle:
623    case CSSPropertyWebkitBorderEndStyle:
624    case CSSPropertyWebkitBorderFit:
625    case CSSPropertyWebkitBorderStartStyle:
626    case CSSPropertyWebkitBoxAlign:
627    case CSSPropertyWebkitBoxDecorationBreak:
628    case CSSPropertyWebkitBoxDirection:
629    case CSSPropertyWebkitBoxLines:
630    case CSSPropertyWebkitBoxOrient:
631    case CSSPropertyWebkitBoxPack:
632    case CSSPropertyWebkitColumnBreakAfter:
633    case CSSPropertyWebkitColumnBreakBefore:
634    case CSSPropertyWebkitColumnBreakInside:
635    case CSSPropertyColumnFill:
636    case CSSPropertyWebkitColumnRuleStyle:
637    case CSSPropertyAlignContent:
638    case CSSPropertyFlexDirection:
639    case CSSPropertyFlexWrap:
640    case CSSPropertyJustifyContent:
641    case CSSPropertyFontKerning:
642    case CSSPropertyWebkitFontSmoothing:
643    case CSSPropertyWebkitLineBreak:
644    case CSSPropertyWebkitMarginAfterCollapse:
645    case CSSPropertyWebkitMarginBeforeCollapse:
646    case CSSPropertyWebkitMarginBottomCollapse:
647    case CSSPropertyWebkitMarginTopCollapse:
648    case CSSPropertyInternalMarqueeDirection:
649    case CSSPropertyInternalMarqueeStyle:
650    case CSSPropertyWebkitPrintColorAdjust:
651    case CSSPropertyWebkitRtlOrdering:
652    case CSSPropertyWebkitRubyPosition:
653    case CSSPropertyWebkitTextCombine:
654    case CSSPropertyWebkitTextEmphasisPosition:
655    case CSSPropertyWebkitTextSecurity:
656    case CSSPropertyTransformStyle:
657    case CSSPropertyWebkitTransformStyle:
658    case CSSPropertyWebkitUserDrag:
659    case CSSPropertyWebkitUserModify:
660    case CSSPropertyWebkitUserSelect:
661    case CSSPropertyWebkitWritingMode:
662    case CSSPropertyWhiteSpace:
663    case CSSPropertyWordBreak:
664    case CSSPropertyWordWrap:
665        return true;
666    case CSSPropertyAlignItems:
667    case CSSPropertyAlignSelf:
668        return !RuntimeEnabledFeatures::cssGridLayoutEnabled();
669    default:
670        return false;
671    }
672}
673
674static bool parseKeywordValue(MutableStylePropertySet* declaration, CSSPropertyID propertyId, const String& string, bool important, const CSSParserContext& parserContext)
675{
676    ASSERT(!string.isEmpty());
677
678    if (!isKeywordPropertyID(propertyId)) {
679        // All properties accept the values of "initial" and "inherit".
680        String lowerCaseString = string.lower();
681        if (lowerCaseString != "initial" && lowerCaseString != "inherit")
682            return false;
683
684        // Parse initial/inherit shorthands using the BisonCSSParser.
685        if (shorthandForProperty(propertyId).length())
686            return false;
687    }
688
689    CSSParserString cssString;
690    cssString.init(string);
691    CSSValueID valueID = cssValueKeywordID(cssString);
692
693    if (!valueID)
694        return false;
695
696    RefPtrWillBeRawPtr<CSSValue> value = nullptr;
697    if (valueID == CSSValueInherit)
698        value = cssValuePool().createInheritedValue();
699    else if (valueID == CSSValueInitial)
700        value = cssValuePool().createExplicitInitialValue();
701    else if (isValidKeywordPropertyAndValue(propertyId, valueID, parserContext))
702        value = cssValuePool().createIdentifierValue(valueID);
703    else
704        return false;
705
706    declaration->addParsedProperty(CSSProperty(propertyId, value.release(), important));
707    return true;
708}
709
710template <typename CharType>
711static bool parseTransformTranslateArguments(CharType*& pos, CharType* end, unsigned expectedCount, CSSTransformValue* transformValue)
712{
713    while (expectedCount) {
714        size_t delimiter = WTF::find(pos, end - pos, expectedCount == 1 ? ')' : ',');
715        if (delimiter == kNotFound)
716            return false;
717        unsigned argumentLength = static_cast<unsigned>(delimiter);
718        CSSPrimitiveValue::UnitType unit = CSSPrimitiveValue::CSS_NUMBER;
719        double number;
720        if (!parseSimpleLength(pos, argumentLength, unit, number))
721            return false;
722        if (unit != CSSPrimitiveValue::CSS_PX && (number || unit != CSSPrimitiveValue::CSS_NUMBER))
723            return false;
724        transformValue->append(cssValuePool().createValue(number, CSSPrimitiveValue::CSS_PX));
725        pos += argumentLength + 1;
726        --expectedCount;
727    }
728    return true;
729}
730
731template <typename CharType>
732static bool parseTransformNumberArguments(CharType*& pos, CharType* end, unsigned expectedCount, CSSTransformValue* transformValue)
733{
734    while (expectedCount) {
735        size_t delimiter = WTF::find(pos, end - pos, expectedCount == 1 ? ')' : ',');
736        if (delimiter == kNotFound)
737            return false;
738        unsigned argumentLength = static_cast<unsigned>(delimiter);
739        bool ok;
740        double number = charactersToDouble(pos, argumentLength, &ok);
741        if (!ok)
742            return false;
743        transformValue->append(cssValuePool().createValue(number, CSSPrimitiveValue::CSS_NUMBER));
744        pos += argumentLength + 1;
745        --expectedCount;
746    }
747    return true;
748}
749
750template <typename CharType>
751static PassRefPtrWillBeRawPtr<CSSTransformValue> parseSimpleTransformValue(CharType*& pos, CharType* end)
752{
753    static const int shortestValidTransformStringLength = 12;
754
755    if (end - pos < shortestValidTransformStringLength)
756        return nullptr;
757
758    const bool isTranslate = toASCIILower(pos[0]) == 't'
759        && toASCIILower(pos[1]) == 'r'
760        && toASCIILower(pos[2]) == 'a'
761        && toASCIILower(pos[3]) == 'n'
762        && toASCIILower(pos[4]) == 's'
763        && toASCIILower(pos[5]) == 'l'
764        && toASCIILower(pos[6]) == 'a'
765        && toASCIILower(pos[7]) == 't'
766        && toASCIILower(pos[8]) == 'e';
767
768    if (isTranslate) {
769        CSSTransformValue::TransformOperationType transformType;
770        unsigned expectedArgumentCount = 1;
771        unsigned argumentStart = 11;
772        CharType c9 = toASCIILower(pos[9]);
773        if (c9 == 'x' && pos[10] == '(') {
774            transformType = CSSTransformValue::TranslateXTransformOperation;
775        } else if (c9 == 'y' && pos[10] == '(') {
776            transformType = CSSTransformValue::TranslateYTransformOperation;
777        } else if (c9 == 'z' && pos[10] == '(') {
778            transformType = CSSTransformValue::TranslateZTransformOperation;
779        } else if (c9 == '(') {
780            transformType = CSSTransformValue::TranslateTransformOperation;
781            expectedArgumentCount = 2;
782            argumentStart = 10;
783        } else if (c9 == '3' && toASCIILower(pos[10]) == 'd' && pos[11] == '(') {
784            transformType = CSSTransformValue::Translate3DTransformOperation;
785            expectedArgumentCount = 3;
786            argumentStart = 12;
787        } else {
788            return nullptr;
789        }
790        pos += argumentStart;
791        RefPtrWillBeRawPtr<CSSTransformValue> transformValue = CSSTransformValue::create(transformType);
792        if (!parseTransformTranslateArguments(pos, end, expectedArgumentCount, transformValue.get()))
793            return nullptr;
794        return transformValue.release();
795    }
796
797    const bool isMatrix3d = toASCIILower(pos[0]) == 'm'
798        && toASCIILower(pos[1]) == 'a'
799        && toASCIILower(pos[2]) == 't'
800        && toASCIILower(pos[3]) == 'r'
801        && toASCIILower(pos[4]) == 'i'
802        && toASCIILower(pos[5]) == 'x'
803        && pos[6] == '3'
804        && toASCIILower(pos[7]) == 'd'
805        && pos[8] == '(';
806
807    if (isMatrix3d) {
808        pos += 9;
809        RefPtrWillBeRawPtr<CSSTransformValue> transformValue = CSSTransformValue::create(CSSTransformValue::Matrix3DTransformOperation);
810        if (!parseTransformNumberArguments(pos, end, 16, transformValue.get()))
811            return nullptr;
812        return transformValue.release();
813    }
814
815    const bool isScale3d = toASCIILower(pos[0]) == 's'
816        && toASCIILower(pos[1]) == 'c'
817        && toASCIILower(pos[2]) == 'a'
818        && toASCIILower(pos[3]) == 'l'
819        && toASCIILower(pos[4]) == 'e'
820        && pos[5] == '3'
821        && toASCIILower(pos[6]) == 'd'
822        && pos[7] == '(';
823
824    if (isScale3d) {
825        pos += 8;
826        RefPtrWillBeRawPtr<CSSTransformValue> transformValue = CSSTransformValue::create(CSSTransformValue::Scale3DTransformOperation);
827        if (!parseTransformNumberArguments(pos, end, 3, transformValue.get()))
828            return nullptr;
829        return transformValue.release();
830    }
831
832    return nullptr;
833}
834
835template <typename CharType>
836static PassRefPtrWillBeRawPtr<CSSValueList> parseSimpleTransformList(CharType*& pos, CharType* end)
837{
838    RefPtrWillBeRawPtr<CSSValueList> transformList = nullptr;
839    while (pos < end) {
840        while (pos < end && isCSSSpace(*pos))
841            ++pos;
842        RefPtrWillBeRawPtr<CSSTransformValue> transformValue = parseSimpleTransformValue(pos, end);
843        if (!transformValue)
844            return nullptr;
845        if (!transformList)
846            transformList = CSSValueList::createSpaceSeparated();
847        transformList->append(transformValue.release());
848        if (pos < end) {
849            if (isCSSSpace(*pos))
850                return nullptr;
851        }
852    }
853    return transformList.release();
854}
855
856static bool parseSimpleTransform(MutableStylePropertySet* properties, CSSPropertyID propertyID, const String& string, bool important)
857{
858    if (propertyID != CSSPropertyTransform && propertyID != CSSPropertyWebkitTransform)
859        return false;
860    if (string.isEmpty())
861        return false;
862    RefPtrWillBeRawPtr<CSSValueList> transformList = nullptr;
863    if (string.is8Bit()) {
864        const LChar* pos = string.characters8();
865        const LChar* end = pos + string.length();
866        transformList = parseSimpleTransformList(pos, end);
867        if (!transformList)
868            return false;
869    } else {
870        const UChar* pos = string.characters16();
871        const UChar* end = pos + string.length();
872        transformList = parseSimpleTransformList(pos, end);
873        if (!transformList)
874            return false;
875    }
876    properties->addParsedProperty(CSSProperty(propertyID, transformList.release(), important));
877    return true;
878}
879
880bool BisonCSSParser::parseValue(MutableStylePropertySet* declaration, CSSPropertyID propertyID, const String& string, bool important, const CSSParserContext& context)
881{
882    ASSERT(!string.isEmpty());
883
884    if (parseSimpleLengthValue(declaration, propertyID, string, important, context.mode()))
885        return true;
886    if (parseColorValue(declaration, propertyID, string, important, context.mode()))
887        return true;
888    if (parseKeywordValue(declaration, propertyID, string, important, context))
889        return true;
890
891    BisonCSSParser parser(context);
892    return parser.parseValue(declaration, propertyID, string, important, static_cast<StyleSheetContents*>(0));
893}
894
895bool BisonCSSParser::parseValue(MutableStylePropertySet* declaration, CSSPropertyID propertyID, const String& string, bool important, CSSParserMode cssParserMode, StyleSheetContents* contextStyleSheet)
896{
897    ASSERT(!string.isEmpty());
898    if (parseSimpleLengthValue(declaration, propertyID, string, important, cssParserMode))
899        return true;
900    if (parseColorValue(declaration, propertyID, string, important, cssParserMode))
901        return true;
902
903    CSSParserContext context(cssParserMode, 0);
904    if (contextStyleSheet) {
905        context = contextStyleSheet->parserContext();
906        context.setMode(cssParserMode);
907    }
908
909    if (parseKeywordValue(declaration, propertyID, string, important, context))
910        return true;
911    if (parseSimpleTransform(declaration, propertyID, string, important))
912        return true;
913
914    BisonCSSParser parser(context);
915    return parser.parseValue(declaration, propertyID, string, important, contextStyleSheet);
916}
917
918bool BisonCSSParser::parseValue(MutableStylePropertySet* declaration, CSSPropertyID propertyID, const String& string, bool important, StyleSheetContents* contextStyleSheet)
919{
920    if (m_context.useCounter())
921        m_context.useCounter()->count(m_context, propertyID);
922
923    setStyleSheet(contextStyleSheet);
924
925    setupParser("@-internal-value ", string, "");
926
927    m_id = propertyID;
928    m_important = important;
929
930    {
931        StyleDeclarationScope scope(this, declaration);
932        cssyyparse(this);
933    }
934
935    m_rule = nullptr;
936    m_id = CSSPropertyInvalid;
937
938    bool ok = false;
939    if (!m_parsedProperties.isEmpty()) {
940        ok = true;
941        declaration->addParsedProperties(m_parsedProperties);
942        clearProperties();
943    }
944
945    return ok;
946}
947
948// The color will only be changed when string contains a valid CSS color, so callers
949// can set it to a default color and ignore the boolean result.
950bool BisonCSSParser::parseColor(RGBA32& color, const String& string, bool strict)
951{
952    // First try creating a color specified by name, rgba(), rgb() or "#" syntax.
953    if (CSSPropertyParser::fastParseColor(color, string, strict))
954        return true;
955
956    BisonCSSParser parser(strictCSSParserContext());
957
958    // In case the fast-path parser didn't understand the color, try the full parser.
959    if (!parser.parseColor(string))
960        return false;
961
962    CSSValue* value = parser.m_parsedProperties.first().value();
963    if (!value->isPrimitiveValue())
964        return false;
965
966    CSSPrimitiveValue* primitiveValue = toCSSPrimitiveValue(value);
967    if (!primitiveValue->isRGBColor())
968        return false;
969
970    color = primitiveValue->getRGBA32Value();
971    return true;
972}
973
974StyleColor BisonCSSParser::colorFromRGBColorString(const String& colorString)
975{
976    // FIXME: Rework css parser so it is more SVG aware.
977    RGBA32 color;
978    if (parseColor(color, colorString.stripWhiteSpace()))
979        return StyleColor(color);
980    // FIXME: This branch catches the string currentColor, but we should error if we have an illegal color value.
981    return StyleColor::currentColor();
982}
983
984bool BisonCSSParser::parseColor(const String& string)
985{
986    setupParser("@-internal-decls color:", string, "");
987    cssyyparse(this);
988    m_rule = nullptr;
989
990    return !m_parsedProperties.isEmpty() && m_parsedProperties.first().id() == CSSPropertyColor;
991}
992
993bool BisonCSSParser::parseSystemColor(RGBA32& color, const String& string)
994{
995    CSSParserString cssColor;
996    cssColor.init(string);
997    CSSValueID id = cssValueKeywordID(cssColor);
998    if (!CSSPropertyParser::isSystemColor(id))
999        return false;
1000
1001    Color parsedColor = RenderTheme::theme().systemColor(id);
1002    color = parsedColor.rgb();
1003    return true;
1004}
1005
1006void BisonCSSParser::parseSelector(const String& string, CSSSelectorList& selectorList)
1007{
1008    m_selectorListForParseSelector = &selectorList;
1009
1010    setupParser("@-internal-selector ", string, "");
1011
1012    cssyyparse(this);
1013
1014    m_selectorListForParseSelector = 0;
1015}
1016
1017PassRefPtrWillBeRawPtr<ImmutableStylePropertySet> BisonCSSParser::parseInlineStyleDeclaration(const String& string, Element* element)
1018{
1019    Document& document = element->document();
1020    CSSParserContext context = CSSParserContext(document.elementSheet().contents()->parserContext(), UseCounter::getFrom(&document));
1021    context.setMode((element->isHTMLElement() && !document.inQuirksMode()) ? HTMLStandardMode : HTMLQuirksMode);
1022    return BisonCSSParser(context).parseDeclaration(string, document.elementSheet().contents());
1023}
1024
1025PassRefPtrWillBeRawPtr<ImmutableStylePropertySet> BisonCSSParser::parseDeclaration(const String& string, StyleSheetContents* contextStyleSheet)
1026{
1027    setStyleSheet(contextStyleSheet);
1028
1029    setupParser("@-internal-decls ", string, "");
1030    cssyyparse(this);
1031    m_rule = nullptr;
1032
1033    RefPtrWillBeRawPtr<ImmutableStylePropertySet> style = createStylePropertySet();
1034    clearProperties();
1035    return style.release();
1036}
1037
1038
1039bool BisonCSSParser::parseDeclaration(MutableStylePropertySet* declaration, const String& string, CSSParserObserver* observer, StyleSheetContents* contextStyleSheet)
1040{
1041    setStyleSheet(contextStyleSheet);
1042
1043    TemporaryChange<CSSParserObserver*> scopedObsever(m_observer, observer);
1044
1045    setupParser("@-internal-decls ", string, "");
1046    if (m_observer) {
1047        m_observer->startRuleHeader(CSSRuleSourceData::STYLE_RULE, 0);
1048        m_observer->endRuleHeader(1);
1049        m_observer->startRuleBody(0);
1050    }
1051
1052    {
1053        StyleDeclarationScope scope(this, declaration);
1054        cssyyparse(this);
1055    }
1056
1057    m_rule = nullptr;
1058
1059    bool ok = false;
1060    if (!m_parsedProperties.isEmpty()) {
1061        ok = true;
1062        declaration->addParsedProperties(m_parsedProperties);
1063        clearProperties();
1064    }
1065
1066    if (m_observer)
1067        m_observer->endRuleBody(string.length(), false);
1068
1069    return ok;
1070}
1071
1072bool BisonCSSParser::parseAttributeMatchType(CSSSelector::AttributeMatchType& matchType, const String& string)
1073{
1074    if (!RuntimeEnabledFeatures::cssAttributeCaseSensitivityEnabled() && !isUASheetBehavior(m_context.mode()))
1075        return false;
1076    if (string == "i") {
1077        matchType = CSSSelector::CaseInsensitive;
1078        return true;
1079    }
1080    return false;
1081}
1082
1083static inline void filterProperties(bool important, const WillBeHeapVector<CSSProperty, 256>& input, WillBeHeapVector<CSSProperty, 256>& output, size_t& unusedEntries, BitArray<numCSSProperties>& seenProperties)
1084{
1085    // Add properties in reverse order so that highest priority definitions are reached first. Duplicate definitions can then be ignored when found.
1086    for (int i = input.size() - 1; i >= 0; --i) {
1087        const CSSProperty& property = input[i];
1088        if (property.isImportant() != important)
1089            continue;
1090        const unsigned propertyIDIndex = property.id() - firstCSSProperty;
1091        if (seenProperties.get(propertyIDIndex))
1092            continue;
1093        seenProperties.set(propertyIDIndex);
1094        output[--unusedEntries] = property;
1095    }
1096}
1097
1098PassRefPtrWillBeRawPtr<ImmutableStylePropertySet> BisonCSSParser::createStylePropertySet()
1099{
1100    BitArray<numCSSProperties> seenProperties;
1101    size_t unusedEntries = m_parsedProperties.size();
1102    WillBeHeapVector<CSSProperty, 256> results(unusedEntries);
1103
1104    // Important properties have higher priority, so add them first. Duplicate definitions can then be ignored when found.
1105    filterProperties(true, m_parsedProperties, results, unusedEntries, seenProperties);
1106    filterProperties(false, m_parsedProperties, results, unusedEntries, seenProperties);
1107    if (unusedEntries)
1108        results.remove(0, unusedEntries);
1109
1110    CSSParserMode mode = inViewport() ? CSSViewportRuleMode : m_context.mode();
1111
1112    return ImmutableStylePropertySet::create(results.data(), results.size(), mode);
1113}
1114
1115void BisonCSSParser::rollbackLastProperties(int num)
1116{
1117    ASSERT(num >= 0);
1118    ASSERT(m_parsedProperties.size() >= static_cast<unsigned>(num));
1119    m_parsedProperties.shrink(m_parsedProperties.size() - num);
1120}
1121
1122void BisonCSSParser::clearProperties()
1123{
1124    m_parsedProperties.clear();
1125    m_numParsedPropertiesBeforeMarginBox = INVALID_NUM_PARSED_PROPERTIES;
1126}
1127
1128void BisonCSSParser::setCurrentProperty(CSSPropertyID propId)
1129{
1130    m_id = propId;
1131}
1132
1133bool BisonCSSParser::parseValue(CSSPropertyID propId, bool important)
1134{
1135    return CSSPropertyParser::parseValue(propId, important, m_valueList.get(), m_context, m_inViewport, m_parsedProperties, m_ruleHeaderType);
1136}
1137
1138
1139class TransformOperationInfo {
1140public:
1141    TransformOperationInfo(const CSSParserString& name)
1142        : m_type(CSSTransformValue::UnknownTransformOperation)
1143        , m_argCount(1)
1144        , m_allowSingleArgument(false)
1145        , m_unit(CSSPropertyParser::FUnknown)
1146    {
1147        const UChar* characters;
1148        unsigned nameLength = name.length();
1149
1150        const unsigned longestNameLength = 11;
1151        UChar characterBuffer[longestNameLength];
1152        if (name.is8Bit()) {
1153            unsigned length = std::min(longestNameLength, nameLength);
1154            const LChar* characters8 = name.characters8();
1155            for (unsigned i = 0; i < length; ++i)
1156                characterBuffer[i] = characters8[i];
1157            characters = characterBuffer;
1158        } else
1159            characters = name.characters16();
1160
1161        SWITCH(characters, nameLength) {
1162            CASE("skew") {
1163                m_unit = CSSPropertyParser::FAngle;
1164                m_type = CSSTransformValue::SkewTransformOperation;
1165                m_allowSingleArgument = true;
1166                m_argCount = 3;
1167            }
1168            CASE("scale") {
1169                m_unit = CSSPropertyParser::FNumber;
1170                m_type = CSSTransformValue::ScaleTransformOperation;
1171                m_allowSingleArgument = true;
1172                m_argCount = 3;
1173            }
1174            CASE("skewx") {
1175                m_unit = CSSPropertyParser::FAngle;
1176                m_type = CSSTransformValue::SkewXTransformOperation;
1177            }
1178            CASE("skewy") {
1179                m_unit = CSSPropertyParser::FAngle;
1180                m_type = CSSTransformValue::SkewYTransformOperation;
1181            }
1182            CASE("matrix") {
1183                m_unit = CSSPropertyParser::FNumber;
1184                m_type = CSSTransformValue::MatrixTransformOperation;
1185                m_argCount = 11;
1186            }
1187            CASE("rotate") {
1188                m_unit = CSSPropertyParser::FAngle;
1189                m_type = CSSTransformValue::RotateTransformOperation;
1190            }
1191            CASE("scalex") {
1192                m_unit = CSSPropertyParser::FNumber;
1193                m_type = CSSTransformValue::ScaleXTransformOperation;
1194            }
1195            CASE("scaley") {
1196                m_unit = CSSPropertyParser::FNumber;
1197                m_type = CSSTransformValue::ScaleYTransformOperation;
1198            }
1199            CASE("scalez") {
1200                m_unit = CSSPropertyParser::FNumber;
1201                m_type = CSSTransformValue::ScaleZTransformOperation;
1202            }
1203            CASE("scale3d") {
1204                m_unit = CSSPropertyParser::FNumber;
1205                m_type = CSSTransformValue::Scale3DTransformOperation;
1206                m_argCount = 5;
1207            }
1208            CASE("rotatex") {
1209                m_unit = CSSPropertyParser::FAngle;
1210                m_type = CSSTransformValue::RotateXTransformOperation;
1211            }
1212            CASE("rotatey") {
1213                m_unit = CSSPropertyParser::FAngle;
1214                m_type = CSSTransformValue::RotateYTransformOperation;
1215            }
1216            CASE("rotatez") {
1217                m_unit = CSSPropertyParser::FAngle;
1218                m_type = CSSTransformValue::RotateZTransformOperation;
1219            }
1220            CASE("matrix3d") {
1221                m_unit = CSSPropertyParser::FNumber;
1222                m_type = CSSTransformValue::Matrix3DTransformOperation;
1223                m_argCount = 31;
1224            }
1225            CASE("rotate3d") {
1226                m_unit = CSSPropertyParser::FNumber;
1227                m_type = CSSTransformValue::Rotate3DTransformOperation;
1228                m_argCount = 7;
1229            }
1230            CASE("translate") {
1231                m_unit = CSSPropertyParser::FLength | CSSPropertyParser::FPercent;
1232                m_type = CSSTransformValue::TranslateTransformOperation;
1233                m_allowSingleArgument = true;
1234                m_argCount = 3;
1235            }
1236            CASE("translatex") {
1237                m_unit = CSSPropertyParser::FLength | CSSPropertyParser::FPercent;
1238                m_type = CSSTransformValue::TranslateXTransformOperation;
1239            }
1240            CASE("translatey") {
1241                m_unit = CSSPropertyParser::FLength | CSSPropertyParser::FPercent;
1242                m_type = CSSTransformValue::TranslateYTransformOperation;
1243            }
1244            CASE("translatez") {
1245                m_unit = CSSPropertyParser::FLength | CSSPropertyParser::FPercent;
1246                m_type = CSSTransformValue::TranslateZTransformOperation;
1247            }
1248            CASE("perspective") {
1249                m_unit = CSSPropertyParser::FNumber;
1250                m_type = CSSTransformValue::PerspectiveTransformOperation;
1251            }
1252            CASE("translate3d") {
1253                m_unit = CSSPropertyParser::FLength | CSSPropertyParser::FPercent;
1254                m_type = CSSTransformValue::Translate3DTransformOperation;
1255                m_argCount = 5;
1256            }
1257        }
1258    }
1259
1260    CSSTransformValue::TransformOperationType type() const { return m_type; }
1261    unsigned argCount() const { return m_argCount; }
1262    CSSPropertyParser::Units unit() const { return m_unit; }
1263
1264    bool unknown() const { return m_type == CSSTransformValue::UnknownTransformOperation; }
1265    bool hasCorrectArgCount(unsigned argCount) { return m_argCount == argCount || (m_allowSingleArgument && argCount == 1); }
1266
1267private:
1268    CSSTransformValue::TransformOperationType m_type;
1269    unsigned m_argCount;
1270    bool m_allowSingleArgument;
1271    CSSPropertyParser::Units m_unit;
1272};
1273
1274PassRefPtrWillBeRawPtr<CSSValueList> CSSPropertyParser::parseTransform(CSSPropertyID propId)
1275{
1276    if (!m_valueList)
1277        return nullptr;
1278
1279    RefPtrWillBeRawPtr<CSSValueList> list = CSSValueList::createSpaceSeparated();
1280    for (CSSParserValue* value = m_valueList->current(); value; value = m_valueList->next()) {
1281        RefPtrWillBeRawPtr<CSSValue> parsedTransformValue = parseTransformValue(propId, value);
1282        if (!parsedTransformValue)
1283            return nullptr;
1284
1285        list->append(parsedTransformValue.release());
1286    }
1287
1288    return list.release();
1289}
1290
1291PassRefPtrWillBeRawPtr<CSSValue> CSSPropertyParser::parseTransformValue(CSSPropertyID propId, CSSParserValue *value)
1292{
1293    if (value->unit != CSSParserValue::Function || !value->function)
1294        return nullptr;
1295
1296    // Every primitive requires at least one argument.
1297    CSSParserValueList* args = value->function->args.get();
1298    if (!args)
1299        return nullptr;
1300
1301    // See if the specified primitive is one we understand.
1302    TransformOperationInfo info(value->function->name);
1303    if (info.unknown())
1304        return nullptr;
1305
1306    if (!info.hasCorrectArgCount(args->size()))
1307        return nullptr;
1308
1309    // The transform is a list of functional primitives that specify transform operations.
1310    // We collect a list of CSSTransformValues, where each value specifies a single operation.
1311
1312    // Create the new CSSTransformValue for this operation and add it to our list.
1313    RefPtrWillBeRawPtr<CSSTransformValue> transformValue = CSSTransformValue::create(info.type());
1314
1315    // Snag our values.
1316    CSSParserValue* a = args->current();
1317    unsigned argNumber = 0;
1318    while (a) {
1319        CSSPropertyParser::Units unit = info.unit();
1320
1321        if (info.type() == CSSTransformValue::Rotate3DTransformOperation && argNumber == 3) {
1322            // 4th param of rotate3d() is an angle rather than a bare number, validate it as such
1323            if (!validUnit(a, FAngle, HTMLStandardMode))
1324                return nullptr;
1325        } else if (info.type() == CSSTransformValue::Translate3DTransformOperation && argNumber == 2) {
1326            // 3rd param of translate3d() cannot be a percentage
1327            if (!validUnit(a, FLength, HTMLStandardMode))
1328                return nullptr;
1329        } else if (info.type() == CSSTransformValue::TranslateZTransformOperation && !argNumber) {
1330            // 1st param of translateZ() cannot be a percentage
1331            if (!validUnit(a, FLength, HTMLStandardMode))
1332                return nullptr;
1333        } else if (info.type() == CSSTransformValue::PerspectiveTransformOperation && !argNumber) {
1334            // 1st param of perspective() must be a non-negative number (deprecated) or length.
1335            if ((propId == CSSPropertyWebkitTransform && !validUnit(a, FNumber | FLength | FNonNeg, HTMLStandardMode))
1336                || (propId == CSSPropertyTransform && !validUnit(a, FLength | FNonNeg, HTMLStandardMode)))
1337                return nullptr;
1338        } else if (!validUnit(a, unit, HTMLStandardMode)) {
1339            return nullptr;
1340        }
1341
1342        // Add the value to the current transform operation.
1343        transformValue->append(createPrimitiveNumericValue(a));
1344
1345        a = args->next();
1346        if (!a)
1347            break;
1348        if (a->unit != CSSParserValue::Operator || a->iValue != ',')
1349            return nullptr;
1350        a = args->next();
1351
1352        argNumber++;
1353    }
1354
1355    return transformValue.release();
1356}
1357
1358void BisonCSSParser::ensureLineEndings()
1359{
1360    if (!m_lineEndings)
1361        m_lineEndings = lineEndings(*m_source);
1362}
1363
1364CSSParserSelector* BisonCSSParser::createFloatingSelectorWithTagName(const QualifiedName& tagQName)
1365{
1366    CSSParserSelector* selector = new CSSParserSelector(tagQName);
1367    m_floatingSelectors.append(selector);
1368    return selector;
1369}
1370
1371CSSParserSelector* BisonCSSParser::createFloatingSelector()
1372{
1373    CSSParserSelector* selector = new CSSParserSelector;
1374    m_floatingSelectors.append(selector);
1375    return selector;
1376}
1377
1378PassOwnPtr<CSSParserSelector> BisonCSSParser::sinkFloatingSelector(CSSParserSelector* selector)
1379{
1380    if (selector) {
1381        size_t index = m_floatingSelectors.reverseFind(selector);
1382        ASSERT(index != kNotFound);
1383        m_floatingSelectors.remove(index);
1384    }
1385    return adoptPtr(selector);
1386}
1387
1388Vector<OwnPtr<CSSParserSelector> >* BisonCSSParser::createFloatingSelectorVector()
1389{
1390    Vector<OwnPtr<CSSParserSelector> >* selectorVector = new Vector<OwnPtr<CSSParserSelector> >;
1391    m_floatingSelectorVectors.append(selectorVector);
1392    return selectorVector;
1393}
1394
1395PassOwnPtr<Vector<OwnPtr<CSSParserSelector> > > BisonCSSParser::sinkFloatingSelectorVector(Vector<OwnPtr<CSSParserSelector> >* selectorVector)
1396{
1397    if (selectorVector) {
1398        size_t index = m_floatingSelectorVectors.reverseFind(selectorVector);
1399        ASSERT(index != kNotFound);
1400        m_floatingSelectorVectors.remove(index);
1401    }
1402    return adoptPtr(selectorVector);
1403}
1404
1405CSSParserValueList* BisonCSSParser::createFloatingValueList()
1406{
1407    CSSParserValueList* list = new CSSParserValueList;
1408    m_floatingValueLists.append(list);
1409    return list;
1410}
1411
1412PassOwnPtr<CSSParserValueList> BisonCSSParser::sinkFloatingValueList(CSSParserValueList* list)
1413{
1414    if (list) {
1415        size_t index = m_floatingValueLists.reverseFind(list);
1416        ASSERT(index != kNotFound);
1417        m_floatingValueLists.remove(index);
1418    }
1419    return adoptPtr(list);
1420}
1421
1422CSSParserFunction* BisonCSSParser::createFloatingFunction()
1423{
1424    CSSParserFunction* function = new CSSParserFunction;
1425    m_floatingFunctions.append(function);
1426    return function;
1427}
1428
1429CSSParserFunction* BisonCSSParser::createFloatingFunction(const CSSParserString& name, PassOwnPtr<CSSParserValueList> args)
1430{
1431    CSSParserFunction* function = createFloatingFunction();
1432    function->name = name;
1433    function->args = args;
1434    return function;
1435}
1436
1437PassOwnPtr<CSSParserFunction> BisonCSSParser::sinkFloatingFunction(CSSParserFunction* function)
1438{
1439    if (function) {
1440        size_t index = m_floatingFunctions.reverseFind(function);
1441        ASSERT(index != kNotFound);
1442        m_floatingFunctions.remove(index);
1443    }
1444    return adoptPtr(function);
1445}
1446
1447CSSParserValue& BisonCSSParser::sinkFloatingValue(CSSParserValue& value)
1448{
1449    if (value.unit == CSSParserValue::Function) {
1450        size_t index = m_floatingFunctions.reverseFind(value.function);
1451        ASSERT(index != kNotFound);
1452        m_floatingFunctions.remove(index);
1453    }
1454    return value;
1455}
1456
1457MediaQueryExp* BisonCSSParser::createFloatingMediaQueryExp(const AtomicString& mediaFeature, CSSParserValueList* values)
1458{
1459    m_floatingMediaQueryExp = MediaQueryExp::createIfValid(mediaFeature, values);
1460    return m_floatingMediaQueryExp.get();
1461}
1462
1463PassOwnPtrWillBeRawPtr<MediaQueryExp> BisonCSSParser::sinkFloatingMediaQueryExp(MediaQueryExp* expression)
1464{
1465    ASSERT_UNUSED(expression, expression == m_floatingMediaQueryExp);
1466    return m_floatingMediaQueryExp.release();
1467}
1468
1469WillBeHeapVector<OwnPtrWillBeMember<MediaQueryExp> >* BisonCSSParser::createFloatingMediaQueryExpList()
1470{
1471    m_floatingMediaQueryExpList = adoptPtrWillBeNoop(new WillBeHeapVector<OwnPtrWillBeMember<MediaQueryExp> >);
1472    return m_floatingMediaQueryExpList.get();
1473}
1474
1475PassOwnPtrWillBeRawPtr<WillBeHeapVector<OwnPtrWillBeMember<MediaQueryExp> > > BisonCSSParser::sinkFloatingMediaQueryExpList(WillBeHeapVector<OwnPtrWillBeMember<MediaQueryExp> >* list)
1476{
1477    ASSERT_UNUSED(list, list == m_floatingMediaQueryExpList);
1478    return m_floatingMediaQueryExpList.release();
1479}
1480
1481MediaQuery* BisonCSSParser::createFloatingMediaQuery(MediaQuery::Restrictor restrictor, const AtomicString& mediaType, PassOwnPtrWillBeRawPtr<WillBeHeapVector<OwnPtrWillBeMember<MediaQueryExp> > > expressions)
1482{
1483    m_floatingMediaQuery = adoptPtrWillBeNoop(new MediaQuery(restrictor, mediaType, expressions));
1484    return m_floatingMediaQuery.get();
1485}
1486
1487MediaQuery* BisonCSSParser::createFloatingMediaQuery(PassOwnPtrWillBeRawPtr<WillBeHeapVector<OwnPtrWillBeMember<MediaQueryExp> > > expressions)
1488{
1489    return createFloatingMediaQuery(MediaQuery::None, MediaTypeNames::all, expressions);
1490}
1491
1492MediaQuery* BisonCSSParser::createFloatingNotAllQuery()
1493{
1494    return createFloatingMediaQuery(MediaQuery::Not, MediaTypeNames::all, sinkFloatingMediaQueryExpList(createFloatingMediaQueryExpList()));
1495}
1496
1497PassOwnPtrWillBeRawPtr<MediaQuery> BisonCSSParser::sinkFloatingMediaQuery(MediaQuery* query)
1498{
1499    ASSERT_UNUSED(query, query == m_floatingMediaQuery);
1500    return m_floatingMediaQuery.release();
1501}
1502
1503WillBeHeapVector<RefPtrWillBeMember<StyleKeyframe> >* BisonCSSParser::createFloatingKeyframeVector()
1504{
1505    m_floatingKeyframeVector = adoptPtrWillBeNoop(new WillBeHeapVector<RefPtrWillBeMember<StyleKeyframe> >());
1506    return m_floatingKeyframeVector.get();
1507}
1508
1509PassOwnPtrWillBeRawPtr<WillBeHeapVector<RefPtrWillBeMember<StyleKeyframe> > > BisonCSSParser::sinkFloatingKeyframeVector(WillBeHeapVector<RefPtrWillBeMember<StyleKeyframe> >* keyframeVector)
1510{
1511    ASSERT_UNUSED(keyframeVector, m_floatingKeyframeVector == keyframeVector);
1512    return m_floatingKeyframeVector.release();
1513}
1514
1515MediaQuerySet* BisonCSSParser::createMediaQuerySet()
1516{
1517    RefPtrWillBeRawPtr<MediaQuerySet> queries = MediaQuerySet::create();
1518    MediaQuerySet* result = queries.get();
1519    m_parsedMediaQuerySets.append(queries.release());
1520    return result;
1521}
1522
1523StyleRuleBase* BisonCSSParser::createImportRule(const CSSParserString& url, MediaQuerySet* media)
1524{
1525    if (!media || !m_allowImportRules)
1526        return 0;
1527    RefPtrWillBeRawPtr<StyleRuleImport> rule = StyleRuleImport::create(url, media);
1528    StyleRuleImport* result = rule.get();
1529    m_parsedRules.append(rule.release());
1530    return result;
1531}
1532
1533StyleRuleBase* BisonCSSParser::createMediaRule(MediaQuerySet* media, RuleList* rules)
1534{
1535    m_allowImportRules = m_allowNamespaceDeclarations = false;
1536    RefPtrWillBeRawPtr<StyleRuleMedia> rule = nullptr;
1537    if (rules) {
1538        rule = StyleRuleMedia::create(media ? media : MediaQuerySet::create().get(), *rules);
1539    } else {
1540        RuleList emptyRules;
1541        rule = StyleRuleMedia::create(media ? media : MediaQuerySet::create().get(), emptyRules);
1542    }
1543    StyleRuleMedia* result = rule.get();
1544    m_parsedRules.append(rule.release());
1545    return result;
1546}
1547
1548StyleRuleBase* BisonCSSParser::createSupportsRule(bool conditionIsSupported, RuleList* rules)
1549{
1550    m_allowImportRules = m_allowNamespaceDeclarations = false;
1551
1552    RefPtrWillBeRawPtr<CSSRuleSourceData> data = popSupportsRuleData();
1553    RefPtrWillBeRawPtr<StyleRuleSupports> rule = nullptr;
1554    String conditionText;
1555    unsigned conditionOffset = data->ruleHeaderRange.start + 9;
1556    unsigned conditionLength = data->ruleHeaderRange.length() - 9;
1557
1558    if (m_tokenizer.is8BitSource())
1559        conditionText = String(m_tokenizer.m_dataStart8.get() + conditionOffset, conditionLength).stripWhiteSpace();
1560    else
1561        conditionText = String(m_tokenizer.m_dataStart16.get() + conditionOffset, conditionLength).stripWhiteSpace();
1562
1563    if (rules) {
1564        rule = StyleRuleSupports::create(conditionText, conditionIsSupported, *rules);
1565    } else {
1566        RuleList emptyRules;
1567        rule = StyleRuleSupports::create(conditionText, conditionIsSupported, emptyRules);
1568    }
1569
1570    StyleRuleSupports* result = rule.get();
1571    m_parsedRules.append(rule.release());
1572
1573    return result;
1574}
1575
1576void BisonCSSParser::markSupportsRuleHeaderStart()
1577{
1578    if (!m_supportsRuleDataStack)
1579        m_supportsRuleDataStack = adoptPtrWillBeNoop(new RuleSourceDataList());
1580
1581    RefPtrWillBeRawPtr<CSSRuleSourceData> data = CSSRuleSourceData::create(CSSRuleSourceData::SUPPORTS_RULE);
1582    data->ruleHeaderRange.start = m_tokenizer.tokenStartOffset();
1583    m_supportsRuleDataStack->append(data);
1584}
1585
1586void BisonCSSParser::markSupportsRuleHeaderEnd()
1587{
1588    ASSERT(m_supportsRuleDataStack && !m_supportsRuleDataStack->isEmpty());
1589
1590    if (m_tokenizer.is8BitSource())
1591        m_supportsRuleDataStack->last()->ruleHeaderRange.end = m_tokenizer.tokenStart<LChar>() - m_tokenizer.m_dataStart8.get();
1592    else
1593        m_supportsRuleDataStack->last()->ruleHeaderRange.end = m_tokenizer.tokenStart<UChar>() - m_tokenizer.m_dataStart16.get();
1594}
1595
1596PassRefPtrWillBeRawPtr<CSSRuleSourceData> BisonCSSParser::popSupportsRuleData()
1597{
1598    ASSERT(m_supportsRuleDataStack && !m_supportsRuleDataStack->isEmpty());
1599    RefPtrWillBeRawPtr<CSSRuleSourceData> data = m_supportsRuleDataStack->last();
1600    m_supportsRuleDataStack->removeLast();
1601    return data.release();
1602}
1603
1604BisonCSSParser::RuleList* BisonCSSParser::createRuleList()
1605{
1606    OwnPtrWillBeRawPtr<RuleList> list = adoptPtrWillBeNoop(new RuleList);
1607    RuleList* listPtr = list.get();
1608
1609    m_parsedRuleLists.append(list.release());
1610    return listPtr;
1611}
1612
1613BisonCSSParser::RuleList* BisonCSSParser::appendRule(RuleList* ruleList, StyleRuleBase* rule)
1614{
1615    if (rule) {
1616        if (!ruleList)
1617            ruleList = createRuleList();
1618        ruleList->append(rule);
1619    }
1620    return ruleList;
1621}
1622
1623template <typename CharacterType>
1624ALWAYS_INLINE static void makeLower(const CharacterType* input, CharacterType* output, unsigned length)
1625{
1626    // FIXME: If we need Unicode lowercasing here, then we probably want the real kind
1627    // that can potentially change the length of the string rather than the character
1628    // by character kind. If we don't need Unicode lowercasing, it would be good to
1629    // simplify this function.
1630
1631    if (charactersAreAllASCII(input, length)) {
1632        // Fast case for all-ASCII.
1633        for (unsigned i = 0; i < length; i++)
1634            output[i] = toASCIILower(input[i]);
1635    } else {
1636        for (unsigned i = 0; i < length; i++)
1637            output[i] = Unicode::toLower(input[i]);
1638    }
1639}
1640
1641void BisonCSSParser::tokenToLowerCase(CSSParserString& token)
1642{
1643    // Since it's our internal token, we know that we created it out
1644    // of our writable work buffers. Therefore the const_cast is just
1645    // ugly and not a potential crash.
1646    size_t length = token.length();
1647    if (token.is8Bit()) {
1648        makeLower(token.characters8(), const_cast<LChar*>(token.characters8()), length);
1649    } else {
1650        makeLower(token.characters16(), const_cast<UChar*>(token.characters16()), length);
1651    }
1652}
1653
1654void BisonCSSParser::endInvalidRuleHeader()
1655{
1656    if (m_ruleHeaderType == CSSRuleSourceData::UNKNOWN_RULE)
1657        return;
1658
1659    CSSParserLocation location;
1660    location.lineNumber = m_tokenizer.m_lineNumber;
1661    location.offset = m_ruleHeaderStartOffset;
1662    if (m_tokenizer.is8BitSource())
1663        location.token.init(m_tokenizer.m_dataStart8.get() + m_ruleHeaderStartOffset, 0);
1664    else
1665        location.token.init(m_tokenizer.m_dataStart16.get() + m_ruleHeaderStartOffset, 0);
1666
1667    reportError(location, m_ruleHeaderType == CSSRuleSourceData::STYLE_RULE ? InvalidSelectorCSSError : InvalidRuleCSSError);
1668
1669    endRuleHeader();
1670}
1671
1672void BisonCSSParser::reportError(const CSSParserLocation&, CSSParserError)
1673{
1674    // FIXME: error reporting temporatily disabled.
1675}
1676
1677bool BisonCSSParser::isLoggingErrors()
1678{
1679    return m_logErrors && !m_ignoreErrors;
1680}
1681
1682void BisonCSSParser::logError(const String& message, const CSSParserLocation& location)
1683{
1684    unsigned lineNumberInStyleSheet;
1685    unsigned columnNumber = 0;
1686    if (InspectorInstrumentation::hasFrontends()) {
1687        ensureLineEndings();
1688        TextPosition tokenPosition = TextPosition::fromOffsetAndLineEndings(location.offset, *m_lineEndings);
1689        lineNumberInStyleSheet = tokenPosition.m_line.zeroBasedInt();
1690        columnNumber = (lineNumberInStyleSheet ? 0 : m_startPosition.m_column.zeroBasedInt()) + tokenPosition.m_column.zeroBasedInt();
1691    } else {
1692        lineNumberInStyleSheet = location.lineNumber;
1693    }
1694    FrameConsole& console = m_styleSheet->singleOwnerDocument()->frame()->console();
1695    console.addMessage(ConsoleMessage::create(CSSMessageSource, WarningMessageLevel, message, m_styleSheet->baseURL().string(), lineNumberInStyleSheet + m_startPosition.m_line.zeroBasedInt() + 1, columnNumber + 1));
1696}
1697
1698StyleRuleKeyframes* BisonCSSParser::createKeyframesRule(const String& name, PassOwnPtrWillBeRawPtr<WillBeHeapVector<RefPtrWillBeMember<StyleKeyframe> > > popKeyframes, bool isPrefixed)
1699{
1700    OwnPtrWillBeRawPtr<WillBeHeapVector<RefPtrWillBeMember<StyleKeyframe> > > keyframes = popKeyframes;
1701    m_allowImportRules = m_allowNamespaceDeclarations = false;
1702    RefPtrWillBeRawPtr<StyleRuleKeyframes> rule = StyleRuleKeyframes::create();
1703    for (size_t i = 0; i < keyframes->size(); ++i)
1704        rule->parserAppendKeyframe(keyframes->at(i));
1705    rule->setName(name);
1706    rule->setVendorPrefixed(isPrefixed);
1707    StyleRuleKeyframes* rulePtr = rule.get();
1708    m_parsedRules.append(rule.release());
1709    return rulePtr;
1710}
1711
1712static void recordSelectorStats(const CSSParserContext& context, const CSSSelectorList& selectorList)
1713{
1714    if (!context.useCounter())
1715        return;
1716
1717    for (const CSSSelector* selector = selectorList.first(); selector; selector = CSSSelectorList::next(*selector)) {
1718        for (const CSSSelector* current = selector; current ; current = current->tagHistory()) {
1719            UseCounter::Feature feature = UseCounter::NumberOfFeatures;
1720            switch (current->pseudoType()) {
1721            case CSSSelector::PseudoUnresolved:
1722                feature = UseCounter::CSSSelectorPseudoUnresolved;
1723                break;
1724            case CSSSelector::PseudoShadow:
1725                feature = UseCounter::CSSSelectorPseudoShadow;
1726                break;
1727            case CSSSelector::PseudoContent:
1728                feature = UseCounter::CSSSelectorPseudoContent;
1729                break;
1730            case CSSSelector::PseudoHost:
1731                feature = UseCounter::CSSSelectorPseudoHost;
1732                break;
1733            case CSSSelector::PseudoHostContext:
1734                feature = UseCounter::CSSSelectorPseudoHostContext;
1735                break;
1736            default:
1737                break;
1738            }
1739            if (feature != UseCounter::NumberOfFeatures)
1740                context.useCounter()->count(feature);
1741            if (current->relation() == CSSSelector::ShadowDeep)
1742                context.useCounter()->count(UseCounter::CSSDeepCombinator);
1743            if (current->selectorList())
1744                recordSelectorStats(context, *current->selectorList());
1745        }
1746    }
1747}
1748
1749StyleRuleBase* BisonCSSParser::createStyleRule(Vector<OwnPtr<CSSParserSelector> >* selectors)
1750{
1751    StyleRule* result = 0;
1752    if (selectors) {
1753        m_allowImportRules = m_allowNamespaceDeclarations = false;
1754        RefPtrWillBeRawPtr<StyleRule> rule = StyleRule::create();
1755        rule->parserAdoptSelectorVector(*selectors);
1756        rule->setProperties(createStylePropertySet());
1757        result = rule.get();
1758        m_parsedRules.append(rule.release());
1759        recordSelectorStats(m_context, result->selectorList());
1760    }
1761    clearProperties();
1762    return result;
1763}
1764
1765StyleRuleBase* BisonCSSParser::createFontFaceRule()
1766{
1767    m_allowImportRules = m_allowNamespaceDeclarations = false;
1768    for (unsigned i = 0; i < m_parsedProperties.size(); ++i) {
1769        CSSProperty& property = m_parsedProperties[i];
1770        if (property.id() == CSSPropertyFontVariant && property.value()->isPrimitiveValue())
1771            property.wrapValueInCommaSeparatedList();
1772        else if (property.id() == CSSPropertyFontFamily && (!property.value()->isValueList() || toCSSValueList(property.value())->length() != 1)) {
1773            // Unlike font-family property, font-family descriptor in @font-face rule
1774            // has to be a value list with exactly one family name. It cannot have a
1775            // have 'initial' value and cannot 'inherit' from parent.
1776            // See http://dev.w3.org/csswg/css3-fonts/#font-family-desc
1777            clearProperties();
1778            return 0;
1779        }
1780    }
1781    RefPtrWillBeRawPtr<StyleRuleFontFace> rule = StyleRuleFontFace::create();
1782    rule->setProperties(createStylePropertySet());
1783    clearProperties();
1784    StyleRuleFontFace* result = rule.get();
1785    m_parsedRules.append(rule.release());
1786    if (m_styleSheet)
1787        m_styleSheet->setHasFontFaceRule(true);
1788    return result;
1789}
1790
1791void BisonCSSParser::addNamespace(const AtomicString& prefix, const AtomicString& uri)
1792{
1793    if (!m_styleSheet || !m_allowNamespaceDeclarations)
1794        return;
1795    m_allowImportRules = false;
1796    m_styleSheet->parserAddNamespace(prefix, uri);
1797    if (prefix.isEmpty() && !uri.isNull())
1798        m_defaultNamespace = uri;
1799}
1800
1801QualifiedName BisonCSSParser::determineNameInNamespace(const AtomicString& prefix, const AtomicString& localName)
1802{
1803    if (!m_styleSheet)
1804        return QualifiedName(prefix, localName, m_defaultNamespace);
1805    return QualifiedName(prefix, localName, m_styleSheet->determineNamespace(prefix));
1806}
1807
1808CSSParserSelector* BisonCSSParser::rewriteSpecifiersWithNamespaceIfNeeded(CSSParserSelector* specifiers)
1809{
1810    if (m_defaultNamespace != starAtom || specifiers->crossesTreeScopes())
1811        return rewriteSpecifiersWithElementName(nullAtom, starAtom, specifiers, /*tagIsForNamespaceRule*/true);
1812    return specifiers;
1813}
1814
1815CSSParserSelector* BisonCSSParser::rewriteSpecifiersWithElementName(const AtomicString& namespacePrefix, const AtomicString& elementName, CSSParserSelector* specifiers, bool tagIsForNamespaceRule)
1816{
1817    AtomicString determinedNamespace = namespacePrefix != nullAtom && m_styleSheet ? m_styleSheet->determineNamespace(namespacePrefix) : m_defaultNamespace;
1818    QualifiedName tag(namespacePrefix, elementName, determinedNamespace);
1819
1820    if (specifiers->crossesTreeScopes())
1821        return rewriteSpecifiersWithElementNameForCustomPseudoElement(tag, elementName, specifiers, tagIsForNamespaceRule);
1822
1823    if (specifiers->isContentPseudoElement())
1824        return rewriteSpecifiersWithElementNameForContentPseudoElement(tag, elementName, specifiers, tagIsForNamespaceRule);
1825
1826    // *:host never matches, so we can't discard the * otherwise we can't tell the
1827    // difference between *:host and just :host.
1828    if (tag == anyQName() && !specifiers->hasHostPseudoSelector())
1829        return specifiers;
1830    if (specifiers->pseudoType() != CSSSelector::PseudoCue)
1831        specifiers->prependTagSelector(tag, tagIsForNamespaceRule);
1832    return specifiers;
1833}
1834
1835CSSParserSelector* BisonCSSParser::rewriteSpecifiersWithElementNameForCustomPseudoElement(const QualifiedName& tag, const AtomicString& elementName, CSSParserSelector* specifiers, bool tagIsForNamespaceRule)
1836{
1837    if (m_context.useCounter() && specifiers->pseudoType() == CSSSelector::PseudoUserAgentCustomElement)
1838        m_context.useCounter()->count(UseCounter::CSSPseudoElementUserAgentCustomPseudo);
1839
1840    CSSParserSelector* lastShadowPseudo = specifiers;
1841    CSSParserSelector* history = specifiers;
1842    while (history->tagHistory()) {
1843        history = history->tagHistory();
1844        if (history->crossesTreeScopes() || history->hasShadowPseudo())
1845            lastShadowPseudo = history;
1846    }
1847
1848    if (lastShadowPseudo->tagHistory()) {
1849        if (tag != anyQName())
1850            lastShadowPseudo->tagHistory()->prependTagSelector(tag, tagIsForNamespaceRule);
1851        return specifiers;
1852    }
1853
1854    // For shadow-ID pseudo-elements to be correctly matched, the ShadowPseudo combinator has to be used.
1855    // We therefore create a new Selector with that combinator here in any case, even if matching any (host) element in any namespace (i.e. '*').
1856    OwnPtr<CSSParserSelector> elementNameSelector = adoptPtr(new CSSParserSelector(tag));
1857    lastShadowPseudo->setTagHistory(elementNameSelector.release());
1858    lastShadowPseudo->setRelation(CSSSelector::ShadowPseudo);
1859    return specifiers;
1860}
1861
1862CSSParserSelector* BisonCSSParser::rewriteSpecifiersWithElementNameForContentPseudoElement(const QualifiedName& tag, const AtomicString& elementName, CSSParserSelector* specifiers, bool tagIsForNamespaceRule)
1863{
1864    CSSParserSelector* last = specifiers;
1865    CSSParserSelector* history = specifiers;
1866    while (history->tagHistory()) {
1867        history = history->tagHistory();
1868        if (history->isContentPseudoElement() || history->relationIsAffectedByPseudoContent())
1869            last = history;
1870    }
1871
1872    if (last->tagHistory()) {
1873        if (tag != anyQName())
1874            last->tagHistory()->prependTagSelector(tag, tagIsForNamespaceRule);
1875        return specifiers;
1876    }
1877
1878    // For shadow-ID pseudo-elements to be correctly matched, the ShadowPseudo combinator has to be used.
1879    // We therefore create a new Selector with that combinator here in any case, even if matching any (host) element in any namespace (i.e. '*').
1880    OwnPtr<CSSParserSelector> elementNameSelector = adoptPtr(new CSSParserSelector(tag));
1881    last->setTagHistory(elementNameSelector.release());
1882    last->setRelation(CSSSelector::SubSelector);
1883    return specifiers;
1884}
1885
1886CSSParserSelector* BisonCSSParser::rewriteSpecifiers(CSSParserSelector* specifiers, CSSParserSelector* newSpecifier)
1887{
1888    if (newSpecifier->crossesTreeScopes()) {
1889        // Unknown pseudo element always goes at the top of selector chain.
1890        newSpecifier->appendTagHistory(CSSSelector::ShadowPseudo, sinkFloatingSelector(specifiers));
1891        return newSpecifier;
1892    }
1893    if (newSpecifier->isContentPseudoElement()) {
1894        newSpecifier->appendTagHistory(CSSSelector::SubSelector, sinkFloatingSelector(specifiers));
1895        return newSpecifier;
1896    }
1897    if (specifiers->crossesTreeScopes()) {
1898        // Specifiers for unknown pseudo element go right behind it in the chain.
1899        specifiers->insertTagHistory(CSSSelector::SubSelector, sinkFloatingSelector(newSpecifier), CSSSelector::ShadowPseudo);
1900        return specifiers;
1901    }
1902    if (specifiers->isContentPseudoElement()) {
1903        specifiers->insertTagHistory(CSSSelector::SubSelector, sinkFloatingSelector(newSpecifier), CSSSelector::SubSelector);
1904        return specifiers;
1905    }
1906    specifiers->appendTagHistory(CSSSelector::SubSelector, sinkFloatingSelector(newSpecifier));
1907    return specifiers;
1908}
1909
1910StyleRuleBase* BisonCSSParser::createPageRule(PassOwnPtr<CSSParserSelector> pageSelector)
1911{
1912    // FIXME: Margin at-rules are ignored.
1913    m_allowImportRules = m_allowNamespaceDeclarations = false;
1914    StyleRulePage* pageRule = 0;
1915    if (pageSelector) {
1916        RefPtrWillBeRawPtr<StyleRulePage> rule = StyleRulePage::create();
1917        Vector<OwnPtr<CSSParserSelector> > selectorVector;
1918        selectorVector.append(pageSelector);
1919        rule->parserAdoptSelectorVector(selectorVector);
1920        rule->setProperties(createStylePropertySet());
1921        pageRule = rule.get();
1922        m_parsedRules.append(rule.release());
1923    }
1924    clearProperties();
1925    return pageRule;
1926}
1927
1928StyleRuleBase* BisonCSSParser::createMarginAtRule(CSSSelector::MarginBoxType /* marginBox */)
1929{
1930    // FIXME: Implement margin at-rule here, using:
1931    //        - marginBox: margin box
1932    //        - m_parsedProperties: properties at [m_numParsedPropertiesBeforeMarginBox, m_parsedProperties.size()] are for this at-rule.
1933    // 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.
1934
1935    endDeclarationsForMarginBox();
1936    return 0; // until this method is implemented.
1937}
1938
1939void BisonCSSParser::startDeclarationsForMarginBox()
1940{
1941    m_numParsedPropertiesBeforeMarginBox = m_parsedProperties.size();
1942}
1943
1944void BisonCSSParser::endDeclarationsForMarginBox()
1945{
1946    rollbackLastProperties(m_parsedProperties.size() - m_numParsedPropertiesBeforeMarginBox);
1947    m_numParsedPropertiesBeforeMarginBox = INVALID_NUM_PARSED_PROPERTIES;
1948}
1949
1950StyleKeyframe* BisonCSSParser::createKeyframe(CSSParserValueList* keys)
1951{
1952    OwnPtr<Vector<double> > keyVector = StyleKeyframe::createKeyList(keys);
1953    if (keyVector->isEmpty())
1954        return 0;
1955
1956    RefPtrWillBeRawPtr<StyleKeyframe> keyframe = StyleKeyframe::create();
1957    keyframe->setKeys(keyVector.release());
1958    keyframe->setProperties(createStylePropertySet());
1959
1960    clearProperties();
1961
1962    StyleKeyframe* keyframePtr = keyframe.get();
1963    m_parsedKeyframes.append(keyframe.release());
1964    return keyframePtr;
1965}
1966
1967void BisonCSSParser::invalidBlockHit()
1968{
1969    if (m_styleSheet && !m_hadSyntacticallyValidCSSRule)
1970        m_styleSheet->setHasSyntacticallyValidCSSHeader(false);
1971}
1972
1973void BisonCSSParser::startRule()
1974{
1975    if (!m_observer)
1976        return;
1977
1978    ASSERT(m_ruleHasHeader);
1979    m_ruleHasHeader = false;
1980}
1981
1982void BisonCSSParser::endRule(bool valid)
1983{
1984    if (!m_observer)
1985        return;
1986
1987    if (m_ruleHasHeader)
1988        m_observer->endRuleBody(m_tokenizer.safeUserStringTokenOffset(), !valid);
1989    m_ruleHasHeader = true;
1990}
1991
1992void BisonCSSParser::startRuleHeader(CSSRuleSourceData::Type ruleType)
1993{
1994    resumeErrorLogging();
1995    m_ruleHeaderType = ruleType;
1996    m_ruleHeaderStartOffset = m_tokenizer.safeUserStringTokenOffset();
1997    m_ruleHeaderStartLineNumber = m_tokenizer.m_tokenStartLineNumber;
1998    if (m_observer) {
1999        ASSERT(!m_ruleHasHeader);
2000        m_observer->startRuleHeader(ruleType, m_ruleHeaderStartOffset);
2001        m_ruleHasHeader = true;
2002    }
2003}
2004
2005void BisonCSSParser::endRuleHeader()
2006{
2007    ASSERT(m_ruleHeaderType != CSSRuleSourceData::UNKNOWN_RULE);
2008    m_ruleHeaderType = CSSRuleSourceData::UNKNOWN_RULE;
2009    if (m_observer) {
2010        ASSERT(m_ruleHasHeader);
2011        m_observer->endRuleHeader(m_tokenizer.safeUserStringTokenOffset());
2012    }
2013}
2014
2015void BisonCSSParser::startSelector()
2016{
2017    if (m_observer)
2018        m_observer->startSelector(m_tokenizer.safeUserStringTokenOffset());
2019}
2020
2021void BisonCSSParser::endSelector()
2022{
2023    if (m_observer)
2024        m_observer->endSelector(m_tokenizer.safeUserStringTokenOffset());
2025}
2026
2027void BisonCSSParser::startRuleBody()
2028{
2029    if (m_observer)
2030        m_observer->startRuleBody(m_tokenizer.safeUserStringTokenOffset());
2031}
2032
2033void BisonCSSParser::startProperty()
2034{
2035    resumeErrorLogging();
2036    if (m_observer)
2037        m_observer->startProperty(m_tokenizer.safeUserStringTokenOffset());
2038}
2039
2040void BisonCSSParser::endProperty(bool isImportantFound, bool isPropertyParsed, CSSParserError errorType)
2041{
2042    m_id = CSSPropertyInvalid;
2043    if (m_observer)
2044        m_observer->endProperty(isImportantFound, isPropertyParsed, m_tokenizer.safeUserStringTokenOffset(), errorType);
2045}
2046
2047StyleRuleBase* BisonCSSParser::createViewportRule()
2048{
2049    // Allow @viewport rules from UA stylesheets even if the feature is disabled.
2050    if (!RuntimeEnabledFeatures::cssViewportEnabled() && !isUASheetBehavior(m_context.mode()))
2051        return 0;
2052
2053    m_allowImportRules = m_allowNamespaceDeclarations = false;
2054
2055    RefPtrWillBeRawPtr<StyleRuleViewport> rule = StyleRuleViewport::create();
2056
2057    rule->setProperties(createStylePropertySet());
2058    clearProperties();
2059
2060    StyleRuleViewport* result = rule.get();
2061    m_parsedRules.append(rule.release());
2062
2063    return result;
2064}
2065
2066}
2067