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.
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.
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.
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.
28 #include "core/css/parser/BisonCSSParser.h"
30 #include "core/CSSValueKeywords.h"
31 #include "core/MediaTypeNames.h"
32 #include "core/StylePropertyShorthand.h"
33 #include "core/css/CSSBasicShapes.h"
34 #include "core/css/CSSBorderImage.h"
35 #include "core/css/CSSCanvasValue.h"
36 #include "core/css/CSSCrossfadeValue.h"
37 #include "core/css/CSSCursorImageValue.h"
38 #include "core/css/CSSFontFaceSrcValue.h"
39 #include "core/css/CSSFontFeatureValue.h"
40 #include "core/css/CSSFunctionValue.h"
41 #include "core/css/CSSGradientValue.h"
42 #include "core/css/CSSGridLineNamesValue.h"
43 #include "core/css/CSSGridTemplateAreasValue.h"
44 #include "core/css/CSSImageSetValue.h"
45 #include "core/css/CSSImageValue.h"
46 #include "core/css/CSSInheritedValue.h"
47 #include "core/css/CSSInitialValue.h"
48 #include "core/css/CSSKeyframeRule.h"
49 #include "core/css/CSSKeyframesRule.h"
50 #include "core/css/CSSLineBoxContainValue.h"
51 #include "core/css/CSSPrimitiveValue.h"
52 #include "core/css/CSSPropertySourceData.h"
53 #include "core/css/CSSReflectValue.h"
54 #include "core/css/CSSSelector.h"
55 #include "core/css/CSSShadowValue.h"
56 #include "core/css/CSSStyleSheet.h"
57 #include "core/css/CSSTimingFunctionValue.h"
58 #include "core/css/CSSTransformValue.h"
59 #include "core/css/CSSUnicodeRangeValue.h"
60 #include "core/css/CSSValueList.h"
61 #include "core/css/CSSValuePool.h"
62 #include "core/css/Counter.h"
63 #include "core/css/HashTools.h"
64 #include "core/css/MediaList.h"
65 #include "core/css/MediaQueryExp.h"
66 #include "core/css/Pair.h"
67 #include "core/css/Rect.h"
68 #include "core/css/StylePropertySet.h"
69 #include "core/css/StyleRule.h"
70 #include "core/css/StyleRuleImport.h"
71 #include "core/css/StyleSheetContents.h"
72 #include "core/dom/Document.h"
73 #include "core/frame/FrameConsole.h"
74 #include "core/frame/FrameHost.h"
75 #include "core/frame/Settings.h"
76 #include "core/frame/UseCounter.h"
77 #include "core/html/parser/HTMLParserIdioms.h"
78 #include "core/inspector/ConsoleMessage.h"
79 #include "core/inspector/InspectorInstrumentation.h"
80 #include "core/rendering/RenderTheme.h"
81 #include "platform/FloatConversion.h"
82 #include "platform/RuntimeEnabledFeatures.h"
83 #include "wtf/BitArray.h"
84 #include "wtf/HexNumber.h"
85 #include "wtf/text/StringBuffer.h"
86 #include "wtf/text/StringBuilder.h"
87 #include "wtf/text/StringImpl.h"
88 #include "wtf/text/TextEncoding.h"
94 extern int cssyydebug;
97 int cssyyparse(blink::BisonCSSParser*);
103 static const unsigned INVALID_NUM_PARSED_PROPERTIES = UINT_MAX;
105 BisonCSSParser::BisonCSSParser(const CSSParserContext& context)
108 , m_id(CSSPropertyInvalid)
109 , m_styleSheet(nullptr)
110 , m_supportsCondition(false)
111 , m_selectorListForParseSelector(0)
112 , m_numParsedPropertiesBeforeMarginBox(INVALID_NUM_PARSED_PROPERTIES)
113 , m_hadSyntacticallyValidCSSRule(false)
115 , m_ignoreErrors(false)
116 , m_defaultNamespace(starAtom)
119 , m_ruleHeaderType(CSSRuleSourceData::UNKNOWN_RULE)
120 , m_allowImportRules(true)
121 , m_allowNamespaceDeclarations(true)
122 , m_inViewport(false)
130 BisonCSSParser::~BisonCSSParser()
134 deleteAllValues(m_floatingSelectors);
135 deleteAllValues(m_floatingSelectorVectors);
136 deleteAllValues(m_floatingValueLists);
137 deleteAllValues(m_floatingFunctions);
140 void BisonCSSParser::setupParser(const char* prefix, unsigned prefixLength, const String& string, const char* suffix, unsigned suffixLength)
142 m_tokenizer.setupTokenizer(prefix, prefixLength, string, suffix, suffixLength);
143 m_ruleHasHeader = true;
146 void BisonCSSParser::parseSheet(StyleSheetContents* sheet, const String& string, const TextPosition& startPosition, CSSParserObserver* observer, bool logErrors)
148 setStyleSheet(sheet);
149 m_defaultNamespace = starAtom; // Reset the default namespace.
150 TemporaryChange<CSSParserObserver*> scopedObsever(m_observer, observer);
151 m_logErrors = logErrors && sheet->singleOwnerDocument() && !sheet->baseURL().isEmpty() && sheet->singleOwnerDocument()->frameHost();
152 m_ignoreErrors = false;
153 m_tokenizer.m_lineNumber = 0;
154 m_startPosition = startPosition;
156 m_tokenizer.m_internal = false;
157 setupParser("", string, "");
159 sheet->shrinkToFit();
162 m_lineEndings.clear();
163 m_ignoreErrors = false;
165 m_tokenizer.m_internal = true;
168 PassRefPtrWillBeRawPtr<StyleRuleBase> BisonCSSParser::parseRule(StyleSheetContents* sheet, const String& string)
170 setStyleSheet(sheet);
171 m_allowNamespaceDeclarations = false;
172 setupParser("@-internal-rule ", string, "");
174 return m_rule.release();
177 PassRefPtrWillBeRawPtr<StyleKeyframe> BisonCSSParser::parseKeyframeRule(StyleSheetContents* sheet, const String& string)
179 setStyleSheet(sheet);
180 setupParser("@-internal-keyframe-rule ", string, "");
182 return m_keyframe.release();
185 PassOwnPtr<Vector<double> > BisonCSSParser::parseKeyframeKeyList(const String& string)
187 setupParser("@-internal-keyframe-key-list ", string, "");
190 return StyleKeyframe::createKeyList(m_valueList.get());
193 bool BisonCSSParser::parseSupportsCondition(const String& string)
195 m_supportsCondition = false;
196 setupParser("@-internal-supports-condition ", string, "");
198 return m_supportsCondition;
201 bool BisonCSSParser::parseValue(MutableStylePropertySet* declaration, CSSPropertyID propertyID, const String& string, bool important, const CSSParserContext& context)
203 ASSERT(!string.isEmpty());
204 BisonCSSParser parser(context);
205 return parser.parseValue(declaration, propertyID, string, important);
208 bool BisonCSSParser::parseValue(MutableStylePropertySet* declaration, CSSPropertyID propertyID, const String& string, bool important)
210 if (m_context.useCounter())
211 m_context.useCounter()->count(m_context, propertyID);
213 setupParser("@-internal-value ", string, "");
216 m_important = important;
219 StyleDeclarationScope scope(this, declaration);
224 m_id = CSSPropertyInvalid;
227 if (!m_parsedProperties.isEmpty()) {
229 declaration->addParsedProperties(m_parsedProperties);
236 // The color will only be changed when string contains a valid CSS color, so callers
237 // can set it to a default color and ignore the boolean result.
238 bool BisonCSSParser::parseColor(RGBA32& color, const String& string, bool strict)
240 // First try creating a color specified by name, rgba(), rgb() or "#" syntax.
241 if (CSSPropertyParser::fastParseColor(color, string, strict))
244 BisonCSSParser parser(strictCSSParserContext());
246 // In case the fast-path parser didn't understand the color, try the full parser.
247 if (!parser.parseColor(string))
250 CSSValue* value = parser.m_parsedProperties.first().value();
251 if (!value->isPrimitiveValue())
254 CSSPrimitiveValue* primitiveValue = toCSSPrimitiveValue(value);
255 if (!primitiveValue->isRGBColor())
258 color = primitiveValue->getRGBA32Value();
262 StyleColor BisonCSSParser::colorFromRGBColorString(const String& colorString)
264 // FIXME: Rework css parser so it is more SVG aware.
266 if (parseColor(color, colorString.stripWhiteSpace()))
267 return StyleColor(color);
268 // FIXME: This branch catches the string currentColor, but we should error if we have an illegal color value.
269 return StyleColor::currentColor();
272 bool BisonCSSParser::parseColor(const String& string)
274 setupParser("@-internal-decls color:", string, "");
278 return !m_parsedProperties.isEmpty() && m_parsedProperties.first().id() == CSSPropertyColor;
281 bool BisonCSSParser::parseSystemColor(RGBA32& color, const String& string)
283 CSSParserString cssColor;
284 cssColor.init(string);
285 CSSValueID id = cssValueKeywordID(cssColor);
286 if (!CSSPropertyParser::isSystemColor(id))
289 Color parsedColor = RenderTheme::theme().systemColor(id);
290 color = parsedColor.rgb();
294 void BisonCSSParser::parseSelector(const String& string, CSSSelectorList& selectorList)
296 m_selectorListForParseSelector = &selectorList;
298 setupParser("@-internal-selector ", string, "");
302 m_selectorListForParseSelector = 0;
305 PassRefPtrWillBeRawPtr<ImmutableStylePropertySet> BisonCSSParser::parseInlineStyleDeclaration(const String& string, Element* element)
307 Document& document = element->document();
308 CSSParserContext context = CSSParserContext(document.elementSheet().contents()->parserContext(), UseCounter::getFrom(&document));
309 context.setMode((element->isHTMLElement() && !document.inQuirksMode()) ? HTMLStandardMode : HTMLQuirksMode);
310 return BisonCSSParser(context).parseDeclaration(string, document.elementSheet().contents());
313 PassRefPtrWillBeRawPtr<ImmutableStylePropertySet> BisonCSSParser::parseDeclaration(const String& string, StyleSheetContents* contextStyleSheet)
315 setStyleSheet(contextStyleSheet);
317 setupParser("@-internal-decls ", string, "");
321 RefPtrWillBeRawPtr<ImmutableStylePropertySet> style = createStylePropertySet();
323 return style.release();
327 bool BisonCSSParser::parseDeclaration(MutableStylePropertySet* declaration, const String& string, CSSParserObserver* observer, StyleSheetContents* contextStyleSheet)
329 setStyleSheet(contextStyleSheet);
331 TemporaryChange<CSSParserObserver*> scopedObsever(m_observer, observer);
333 setupParser("@-internal-decls ", string, "");
335 m_observer->startRuleHeader(CSSRuleSourceData::STYLE_RULE, 0);
336 m_observer->endRuleHeader(1);
337 m_observer->startRuleBody(0);
341 StyleDeclarationScope scope(this, declaration);
348 if (!m_parsedProperties.isEmpty()) {
350 declaration->addParsedProperties(m_parsedProperties);
355 m_observer->endRuleBody(string.length(), false);
360 bool BisonCSSParser::parseAttributeMatchType(CSSSelector::AttributeMatchType& matchType, const String& string)
362 if (!RuntimeEnabledFeatures::cssAttributeCaseSensitivityEnabled() && !isUASheetBehavior(m_context.mode()))
365 matchType = CSSSelector::CaseInsensitive;
371 static inline void filterProperties(bool important, const WillBeHeapVector<CSSProperty, 256>& input, WillBeHeapVector<CSSProperty, 256>& output, size_t& unusedEntries, BitArray<numCSSProperties>& seenProperties)
373 // Add properties in reverse order so that highest priority definitions are reached first. Duplicate definitions can then be ignored when found.
374 for (int i = input.size() - 1; i >= 0; --i) {
375 const CSSProperty& property = input[i];
376 if (property.isImportant() != important)
378 const unsigned propertyIDIndex = property.id() - firstCSSProperty;
379 if (seenProperties.get(propertyIDIndex))
381 seenProperties.set(propertyIDIndex);
382 output[--unusedEntries] = property;
386 PassRefPtrWillBeRawPtr<ImmutableStylePropertySet> BisonCSSParser::createStylePropertySet()
388 BitArray<numCSSProperties> seenProperties;
389 size_t unusedEntries = m_parsedProperties.size();
390 WillBeHeapVector<CSSProperty, 256> results(unusedEntries);
392 // Important properties have higher priority, so add them first. Duplicate definitions can then be ignored when found.
393 filterProperties(true, m_parsedProperties, results, unusedEntries, seenProperties);
394 filterProperties(false, m_parsedProperties, results, unusedEntries, seenProperties);
396 results.remove(0, unusedEntries);
398 CSSParserMode mode = inViewport() ? CSSViewportRuleMode : m_context.mode();
400 return ImmutableStylePropertySet::create(results.data(), results.size(), mode);
403 void BisonCSSParser::rollbackLastProperties(int num)
406 ASSERT(m_parsedProperties.size() >= static_cast<unsigned>(num));
407 m_parsedProperties.shrink(m_parsedProperties.size() - num);
410 void BisonCSSParser::clearProperties()
412 m_parsedProperties.clear();
413 m_numParsedPropertiesBeforeMarginBox = INVALID_NUM_PARSED_PROPERTIES;
416 void BisonCSSParser::setCurrentProperty(CSSPropertyID propId)
421 bool BisonCSSParser::parseValue(CSSPropertyID propId, bool important)
423 return CSSPropertyParser::parseValue(propId, important, m_valueList.get(), m_context, m_inViewport, m_parsedProperties, m_ruleHeaderType);
426 void BisonCSSParser::ensureLineEndings()
429 m_lineEndings = lineEndings(*m_source);
432 CSSParserSelector* BisonCSSParser::createFloatingSelectorWithTagName(const QualifiedName& tagQName)
434 CSSParserSelector* selector = new CSSParserSelector(tagQName);
435 m_floatingSelectors.append(selector);
439 CSSParserSelector* BisonCSSParser::createFloatingSelector()
441 CSSParserSelector* selector = new CSSParserSelector;
442 m_floatingSelectors.append(selector);
446 PassOwnPtr<CSSParserSelector> BisonCSSParser::sinkFloatingSelector(CSSParserSelector* selector)
449 size_t index = m_floatingSelectors.reverseFind(selector);
450 ASSERT(index != kNotFound);
451 m_floatingSelectors.remove(index);
453 return adoptPtr(selector);
456 Vector<OwnPtr<CSSParserSelector> >* BisonCSSParser::createFloatingSelectorVector()
458 Vector<OwnPtr<CSSParserSelector> >* selectorVector = new Vector<OwnPtr<CSSParserSelector> >;
459 m_floatingSelectorVectors.append(selectorVector);
460 return selectorVector;
463 PassOwnPtr<Vector<OwnPtr<CSSParserSelector> > > BisonCSSParser::sinkFloatingSelectorVector(Vector<OwnPtr<CSSParserSelector> >* selectorVector)
465 if (selectorVector) {
466 size_t index = m_floatingSelectorVectors.reverseFind(selectorVector);
467 ASSERT(index != kNotFound);
468 m_floatingSelectorVectors.remove(index);
470 return adoptPtr(selectorVector);
473 CSSParserValueList* BisonCSSParser::createFloatingValueList()
475 CSSParserValueList* list = new CSSParserValueList;
476 m_floatingValueLists.append(list);
480 PassOwnPtr<CSSParserValueList> BisonCSSParser::sinkFloatingValueList(CSSParserValueList* list)
483 size_t index = m_floatingValueLists.reverseFind(list);
484 ASSERT(index != kNotFound);
485 m_floatingValueLists.remove(index);
487 return adoptPtr(list);
490 CSSParserFunction* BisonCSSParser::createFloatingFunction(const CSSParserString& name, PassOwnPtr<CSSParserValueList> args)
492 CSSParserFunction* function = new CSSParserFunction;
493 m_floatingFunctions.append(function);
494 function->id = cssValueKeywordID(name);
495 function->args = args;
499 PassOwnPtr<CSSParserFunction> BisonCSSParser::sinkFloatingFunction(CSSParserFunction* function)
502 size_t index = m_floatingFunctions.reverseFind(function);
503 ASSERT(index != kNotFound);
504 m_floatingFunctions.remove(index);
506 return adoptPtr(function);
509 CSSParserValue& BisonCSSParser::sinkFloatingValue(CSSParserValue& value)
511 if (value.unit == CSSParserValue::Function) {
512 size_t index = m_floatingFunctions.reverseFind(value.function);
513 ASSERT(index != kNotFound);
514 m_floatingFunctions.remove(index);
519 void BisonCSSParser::startMediaValue()
523 m_mediaQueryValueStartOffset = m_tokenizer.safeUserStringTokenOffset();
526 void BisonCSSParser::endMediaValue()
530 m_mediaQueryValueEndOffset = m_tokenizer.safeUserStringTokenOffset();
533 void BisonCSSParser::startMediaQuery()
537 m_observer->startMediaQuery();
540 MediaQueryExp* BisonCSSParser::createFloatingMediaQueryExp(const AtomicString& mediaFeature, CSSParserValueList* values)
542 m_floatingMediaQueryExp = MediaQueryExp::createIfValid(mediaFeature, values);
543 if (m_observer && m_floatingMediaQueryExp.get() && values) {
544 m_observer->startMediaQueryExp(m_mediaQueryValueStartOffset);
545 m_observer->endMediaQueryExp(m_mediaQueryValueEndOffset);
547 return m_floatingMediaQueryExp.get();
550 PassOwnPtrWillBeRawPtr<MediaQueryExp> BisonCSSParser::sinkFloatingMediaQueryExp(MediaQueryExp* expression)
552 ASSERT_UNUSED(expression, expression == m_floatingMediaQueryExp);
553 return m_floatingMediaQueryExp.release();
556 WillBeHeapVector<OwnPtrWillBeMember<MediaQueryExp> >* BisonCSSParser::createFloatingMediaQueryExpList()
558 m_floatingMediaQueryExpList = adoptPtrWillBeNoop(new WillBeHeapVector<OwnPtrWillBeMember<MediaQueryExp> >);
559 return m_floatingMediaQueryExpList.get();
562 PassOwnPtrWillBeRawPtr<WillBeHeapVector<OwnPtrWillBeMember<MediaQueryExp> > > BisonCSSParser::sinkFloatingMediaQueryExpList(WillBeHeapVector<OwnPtrWillBeMember<MediaQueryExp> >* list)
564 ASSERT_UNUSED(list, list == m_floatingMediaQueryExpList);
565 return m_floatingMediaQueryExpList.release();
568 MediaQuery* BisonCSSParser::createFloatingMediaQuery(MediaQuery::Restrictor restrictor, const AtomicString& mediaType, PassOwnPtrWillBeRawPtr<WillBeHeapVector<OwnPtrWillBeMember<MediaQueryExp> > > expressions)
570 m_floatingMediaQuery = adoptPtrWillBeNoop(new MediaQuery(restrictor, mediaType, expressions));
572 m_observer->endMediaQuery();
573 return m_floatingMediaQuery.get();
576 MediaQuery* BisonCSSParser::createFloatingMediaQuery(PassOwnPtrWillBeRawPtr<WillBeHeapVector<OwnPtrWillBeMember<MediaQueryExp> > > expressions)
578 return createFloatingMediaQuery(MediaQuery::None, MediaTypeNames::all, expressions);
581 MediaQuery* BisonCSSParser::createFloatingNotAllQuery()
583 return createFloatingMediaQuery(MediaQuery::Not, MediaTypeNames::all, sinkFloatingMediaQueryExpList(createFloatingMediaQueryExpList()));
586 PassOwnPtrWillBeRawPtr<MediaQuery> BisonCSSParser::sinkFloatingMediaQuery(MediaQuery* query)
588 ASSERT_UNUSED(query, query == m_floatingMediaQuery);
589 return m_floatingMediaQuery.release();
592 WillBeHeapVector<RefPtrWillBeMember<StyleKeyframe> >* BisonCSSParser::createFloatingKeyframeVector()
594 m_floatingKeyframeVector = adoptPtrWillBeNoop(new WillBeHeapVector<RefPtrWillBeMember<StyleKeyframe> >());
595 return m_floatingKeyframeVector.get();
598 PassOwnPtrWillBeRawPtr<WillBeHeapVector<RefPtrWillBeMember<StyleKeyframe> > > BisonCSSParser::sinkFloatingKeyframeVector(WillBeHeapVector<RefPtrWillBeMember<StyleKeyframe> >* keyframeVector)
600 ASSERT_UNUSED(keyframeVector, m_floatingKeyframeVector == keyframeVector);
601 return m_floatingKeyframeVector.release();
604 MediaQuerySet* BisonCSSParser::createMediaQuerySet()
606 RefPtrWillBeRawPtr<MediaQuerySet> queries = MediaQuerySet::create();
607 MediaQuerySet* result = queries.get();
608 m_parsedMediaQuerySets.append(queries.release());
612 StyleRuleBase* BisonCSSParser::createImportRule(const CSSParserString& url, MediaQuerySet* media)
614 if (!media || !m_allowImportRules)
616 RefPtrWillBeRawPtr<StyleRuleImport> rule = StyleRuleImport::create(url, media);
617 StyleRuleImport* result = rule.get();
618 m_parsedRules.append(rule.release());
622 StyleRuleBase* BisonCSSParser::createMediaRule(MediaQuerySet* media, RuleList* rules)
624 m_allowImportRules = m_allowNamespaceDeclarations = false;
625 RefPtrWillBeRawPtr<StyleRuleMedia> rule = nullptr;
627 rule = StyleRuleMedia::create(media ? media : MediaQuerySet::create().get(), *rules);
630 rule = StyleRuleMedia::create(media ? media : MediaQuerySet::create().get(), emptyRules);
632 StyleRuleMedia* result = rule.get();
633 m_parsedRules.append(rule.release());
637 StyleRuleBase* BisonCSSParser::createSupportsRule(bool conditionIsSupported, RuleList* rules)
639 m_allowImportRules = m_allowNamespaceDeclarations = false;
641 RefPtrWillBeRawPtr<CSSRuleSourceData> data = popSupportsRuleData();
642 RefPtrWillBeRawPtr<StyleRuleSupports> rule = nullptr;
643 String conditionText;
644 unsigned conditionOffset = data->ruleHeaderRange.start + 9;
645 unsigned conditionLength = data->ruleHeaderRange.length() - 9;
647 if (m_tokenizer.is8BitSource())
648 conditionText = String(m_tokenizer.m_dataStart8.get() + conditionOffset, conditionLength).stripWhiteSpace();
650 conditionText = String(m_tokenizer.m_dataStart16.get() + conditionOffset, conditionLength).stripWhiteSpace();
653 rule = StyleRuleSupports::create(conditionText, conditionIsSupported, *rules);
656 rule = StyleRuleSupports::create(conditionText, conditionIsSupported, emptyRules);
659 StyleRuleSupports* result = rule.get();
660 m_parsedRules.append(rule.release());
665 void BisonCSSParser::markSupportsRuleHeaderStart()
667 if (!m_supportsRuleDataStack)
668 m_supportsRuleDataStack = adoptPtrWillBeNoop(new RuleSourceDataList());
670 RefPtrWillBeRawPtr<CSSRuleSourceData> data = CSSRuleSourceData::create(CSSRuleSourceData::SUPPORTS_RULE);
671 data->ruleHeaderRange.start = m_tokenizer.tokenStartOffset();
672 m_supportsRuleDataStack->append(data);
675 void BisonCSSParser::markSupportsRuleHeaderEnd()
677 ASSERT(m_supportsRuleDataStack && !m_supportsRuleDataStack->isEmpty());
679 if (m_tokenizer.is8BitSource())
680 m_supportsRuleDataStack->last()->ruleHeaderRange.end = m_tokenizer.tokenStart<LChar>() - m_tokenizer.m_dataStart8.get();
682 m_supportsRuleDataStack->last()->ruleHeaderRange.end = m_tokenizer.tokenStart<UChar>() - m_tokenizer.m_dataStart16.get();
685 PassRefPtrWillBeRawPtr<CSSRuleSourceData> BisonCSSParser::popSupportsRuleData()
687 ASSERT(m_supportsRuleDataStack && !m_supportsRuleDataStack->isEmpty());
688 RefPtrWillBeRawPtr<CSSRuleSourceData> data = m_supportsRuleDataStack->last();
689 m_supportsRuleDataStack->removeLast();
690 return data.release();
693 BisonCSSParser::RuleList* BisonCSSParser::createRuleList()
695 OwnPtrWillBeRawPtr<RuleList> list = adoptPtrWillBeNoop(new RuleList);
696 RuleList* listPtr = list.get();
698 m_parsedRuleLists.append(list.release());
702 BisonCSSParser::RuleList* BisonCSSParser::appendRule(RuleList* ruleList, StyleRuleBase* rule)
706 ruleList = createRuleList();
707 ruleList->append(rule);
712 template <typename CharacterType>
713 ALWAYS_INLINE static void makeLower(const CharacterType* input, CharacterType* output, unsigned length)
715 // FIXME: If we need Unicode lowercasing here, then we probably want the real kind
716 // that can potentially change the length of the string rather than the character
717 // by character kind. If we don't need Unicode lowercasing, it would be good to
718 // simplify this function.
720 if (charactersAreAllASCII(input, length)) {
721 // Fast case for all-ASCII.
722 for (unsigned i = 0; i < length; i++)
723 output[i] = toASCIILower(input[i]);
725 for (unsigned i = 0; i < length; i++)
726 output[i] = Unicode::toLower(input[i]);
730 void BisonCSSParser::tokenToLowerCase(CSSParserString& token)
732 // Since it's our internal token, we know that we created it out
733 // of our writable work buffers. Therefore the const_cast is just
734 // ugly and not a potential crash.
735 size_t length = token.length();
736 if (token.is8Bit()) {
737 makeLower(token.characters8(), const_cast<LChar*>(token.characters8()), length);
739 makeLower(token.characters16(), const_cast<UChar*>(token.characters16()), length);
743 void BisonCSSParser::endInvalidRuleHeader()
745 if (m_ruleHeaderType == CSSRuleSourceData::UNKNOWN_RULE)
748 CSSParserLocation location;
749 location.lineNumber = m_tokenizer.m_lineNumber;
750 location.offset = m_ruleHeaderStartOffset;
751 if (m_tokenizer.is8BitSource())
752 location.token.init(m_tokenizer.m_dataStart8.get() + m_ruleHeaderStartOffset, 0);
754 location.token.init(m_tokenizer.m_dataStart16.get() + m_ruleHeaderStartOffset, 0);
756 reportError(location, m_ruleHeaderType == CSSRuleSourceData::STYLE_RULE ? InvalidSelectorCSSError : InvalidRuleCSSError);
761 void BisonCSSParser::reportError(const CSSParserLocation&, CSSParserError)
763 // FIXME: error reporting temporatily disabled.
766 bool BisonCSSParser::isLoggingErrors()
768 return m_logErrors && !m_ignoreErrors;
771 void BisonCSSParser::logError(const String& message, const CSSParserLocation& location)
773 unsigned lineNumberInStyleSheet;
774 unsigned columnNumber = 0;
775 if (InspectorInstrumentation::hasFrontends()) {
777 TextPosition tokenPosition = TextPosition::fromOffsetAndLineEndings(location.offset, *m_lineEndings);
778 lineNumberInStyleSheet = tokenPosition.m_line.zeroBasedInt();
779 columnNumber = (lineNumberInStyleSheet ? 0 : m_startPosition.m_column.zeroBasedInt()) + tokenPosition.m_column.zeroBasedInt();
781 lineNumberInStyleSheet = location.lineNumber;
783 FrameConsole& console = m_styleSheet->singleOwnerDocument()->frame()->console();
784 console.addMessage(ConsoleMessage::create(CSSMessageSource, WarningMessageLevel, message, m_styleSheet->baseURL().string(), lineNumberInStyleSheet + m_startPosition.m_line.zeroBasedInt() + 1, columnNumber + 1));
787 StyleRuleKeyframes* BisonCSSParser::createKeyframesRule(const String& name, PassOwnPtrWillBeRawPtr<WillBeHeapVector<RefPtrWillBeMember<StyleKeyframe> > > popKeyframes, bool isPrefixed)
789 OwnPtrWillBeRawPtr<WillBeHeapVector<RefPtrWillBeMember<StyleKeyframe> > > keyframes = popKeyframes;
790 m_allowImportRules = m_allowNamespaceDeclarations = false;
791 RefPtrWillBeRawPtr<StyleRuleKeyframes> rule = StyleRuleKeyframes::create();
792 for (size_t i = 0; i < keyframes->size(); ++i)
793 rule->parserAppendKeyframe(keyframes->at(i));
795 rule->setVendorPrefixed(isPrefixed);
796 StyleRuleKeyframes* rulePtr = rule.get();
797 m_parsedRules.append(rule.release());
801 static void recordSelectorStats(const CSSParserContext& context, const CSSSelectorList& selectorList)
803 if (!context.useCounter())
806 for (const CSSSelector* selector = selectorList.first(); selector; selector = CSSSelectorList::next(*selector)) {
807 for (const CSSSelector* current = selector; current ; current = current->tagHistory()) {
808 UseCounter::Feature feature = UseCounter::NumberOfFeatures;
809 switch (current->pseudoType()) {
810 case CSSSelector::PseudoUnresolved:
811 feature = UseCounter::CSSSelectorPseudoUnresolved;
813 case CSSSelector::PseudoShadow:
814 feature = UseCounter::CSSSelectorPseudoShadow;
816 case CSSSelector::PseudoContent:
817 feature = UseCounter::CSSSelectorPseudoContent;
819 case CSSSelector::PseudoHost:
820 feature = UseCounter::CSSSelectorPseudoHost;
822 case CSSSelector::PseudoHostContext:
823 feature = UseCounter::CSSSelectorPseudoHostContext;
828 if (feature != UseCounter::NumberOfFeatures)
829 context.useCounter()->count(feature);
830 if (current->relation() == CSSSelector::ShadowDeep)
831 context.useCounter()->count(UseCounter::CSSDeepCombinator);
832 if (current->selectorList())
833 recordSelectorStats(context, *current->selectorList());
838 StyleRuleBase* BisonCSSParser::createStyleRule(Vector<OwnPtr<CSSParserSelector> >* selectors)
840 StyleRule* result = 0;
842 m_allowImportRules = m_allowNamespaceDeclarations = false;
843 RefPtrWillBeRawPtr<StyleRule> rule = StyleRule::create();
844 rule->parserAdoptSelectorVector(*selectors);
845 rule->setProperties(createStylePropertySet());
847 m_parsedRules.append(rule.release());
848 recordSelectorStats(m_context, result->selectorList());
854 StyleRuleBase* BisonCSSParser::createFontFaceRule()
856 m_allowImportRules = m_allowNamespaceDeclarations = false;
857 for (unsigned i = 0; i < m_parsedProperties.size(); ++i) {
858 CSSProperty& property = m_parsedProperties[i];
859 if (property.id() == CSSPropertyFontVariant && property.value()->isPrimitiveValue())
860 property.wrapValueInCommaSeparatedList();
861 else if (property.id() == CSSPropertyFontFamily && (!property.value()->isValueList() || toCSSValueList(property.value())->length() != 1)) {
862 // Unlike font-family property, font-family descriptor in @font-face rule
863 // has to be a value list with exactly one family name. It cannot have a
864 // have 'initial' value and cannot 'inherit' from parent.
865 // See http://dev.w3.org/csswg/css3-fonts/#font-family-desc
870 RefPtrWillBeRawPtr<StyleRuleFontFace> rule = StyleRuleFontFace::create();
871 rule->setProperties(createStylePropertySet());
873 StyleRuleFontFace* result = rule.get();
874 m_parsedRules.append(rule.release());
876 m_styleSheet->setHasFontFaceRule(true);
880 void BisonCSSParser::addNamespace(const AtomicString& prefix, const AtomicString& uri)
882 if (!m_styleSheet || !m_allowNamespaceDeclarations)
884 m_allowImportRules = false;
885 m_styleSheet->parserAddNamespace(prefix, uri);
886 if (prefix.isEmpty() && !uri.isNull())
887 m_defaultNamespace = uri;
890 QualifiedName BisonCSSParser::determineNameInNamespace(const AtomicString& prefix, const AtomicString& localName)
893 return QualifiedName(prefix, localName, m_defaultNamespace);
894 return QualifiedName(prefix, localName, m_styleSheet->determineNamespace(prefix));
897 CSSParserSelector* BisonCSSParser::rewriteSpecifiersWithNamespaceIfNeeded(CSSParserSelector* specifiers)
899 if (m_defaultNamespace != starAtom || specifiers->crossesTreeScopes())
900 return rewriteSpecifiersWithElementName(nullAtom, starAtom, specifiers, /*tagIsForNamespaceRule*/true);
904 CSSParserSelector* BisonCSSParser::rewriteSpecifiersWithElementName(const AtomicString& namespacePrefix, const AtomicString& elementName, CSSParserSelector* specifiers, bool tagIsForNamespaceRule)
906 AtomicString determinedNamespace = namespacePrefix != nullAtom && m_styleSheet ? m_styleSheet->determineNamespace(namespacePrefix) : m_defaultNamespace;
907 QualifiedName tag(namespacePrefix, elementName, determinedNamespace);
909 if (specifiers->crossesTreeScopes())
910 return rewriteSpecifiersWithElementNameForCustomPseudoElement(tag, elementName, specifiers, tagIsForNamespaceRule);
912 if (specifiers->isContentPseudoElement())
913 return rewriteSpecifiersWithElementNameForContentPseudoElement(tag, elementName, specifiers, tagIsForNamespaceRule);
915 // *:host never matches, so we can't discard the * otherwise we can't tell the
916 // difference between *:host and just :host.
917 if (tag == anyQName() && !specifiers->hasHostPseudoSelector())
919 if (specifiers->pseudoType() != CSSSelector::PseudoCue)
920 specifiers->prependTagSelector(tag, tagIsForNamespaceRule);
924 CSSParserSelector* BisonCSSParser::rewriteSpecifiersWithElementNameForCustomPseudoElement(const QualifiedName& tag, const AtomicString& elementName, CSSParserSelector* specifiers, bool tagIsForNamespaceRule)
926 CSSParserSelector* lastShadowPseudo = specifiers;
927 CSSParserSelector* history = specifiers;
928 while (history->tagHistory()) {
929 history = history->tagHistory();
930 if (history->crossesTreeScopes() || history->hasShadowPseudo())
931 lastShadowPseudo = history;
934 if (lastShadowPseudo->tagHistory()) {
935 if (tag != anyQName())
936 lastShadowPseudo->tagHistory()->prependTagSelector(tag, tagIsForNamespaceRule);
940 // For shadow-ID pseudo-elements to be correctly matched, the ShadowPseudo combinator has to be used.
941 // We therefore create a new Selector with that combinator here in any case, even if matching any (host) element in any namespace (i.e. '*').
942 OwnPtr<CSSParserSelector> elementNameSelector = adoptPtr(new CSSParserSelector(tag));
943 lastShadowPseudo->setTagHistory(elementNameSelector.release());
944 lastShadowPseudo->setRelation(CSSSelector::ShadowPseudo);
948 CSSParserSelector* BisonCSSParser::rewriteSpecifiersWithElementNameForContentPseudoElement(const QualifiedName& tag, const AtomicString& elementName, CSSParserSelector* specifiers, bool tagIsForNamespaceRule)
950 CSSParserSelector* last = specifiers;
951 CSSParserSelector* history = specifiers;
952 while (history->tagHistory()) {
953 history = history->tagHistory();
954 if (history->isContentPseudoElement() || history->relationIsAffectedByPseudoContent())
958 if (last->tagHistory()) {
959 if (tag != anyQName())
960 last->tagHistory()->prependTagSelector(tag, tagIsForNamespaceRule);
964 // For shadow-ID pseudo-elements to be correctly matched, the ShadowPseudo combinator has to be used.
965 // We therefore create a new Selector with that combinator here in any case, even if matching any (host) element in any namespace (i.e. '*').
966 OwnPtr<CSSParserSelector> elementNameSelector = adoptPtr(new CSSParserSelector(tag));
967 last->setTagHistory(elementNameSelector.release());
971 CSSParserSelector* BisonCSSParser::rewriteSpecifiers(CSSParserSelector* specifiers, CSSParserSelector* newSpecifier)
973 if (newSpecifier->crossesTreeScopes()) {
974 // Unknown pseudo element always goes at the top of selector chain.
975 newSpecifier->appendTagHistory(CSSSelector::ShadowPseudo, sinkFloatingSelector(specifiers));
978 if (newSpecifier->isContentPseudoElement()) {
979 newSpecifier->appendTagHistory(CSSSelector::SubSelector, sinkFloatingSelector(specifiers));
982 if (specifiers->crossesTreeScopes()) {
983 // Specifiers for unknown pseudo element go right behind it in the chain.
984 specifiers->insertTagHistory(CSSSelector::SubSelector, sinkFloatingSelector(newSpecifier), CSSSelector::ShadowPseudo);
987 if (specifiers->isContentPseudoElement()) {
988 specifiers->insertTagHistory(CSSSelector::SubSelector, sinkFloatingSelector(newSpecifier), CSSSelector::SubSelector);
991 specifiers->appendTagHistory(CSSSelector::SubSelector, sinkFloatingSelector(newSpecifier));
995 StyleRuleBase* BisonCSSParser::createPageRule(PassOwnPtr<CSSParserSelector> pageSelector)
997 // FIXME: Margin at-rules are ignored.
998 m_allowImportRules = m_allowNamespaceDeclarations = false;
999 StyleRulePage* pageRule = 0;
1001 RefPtrWillBeRawPtr<StyleRulePage> rule = StyleRulePage::create();
1002 Vector<OwnPtr<CSSParserSelector> > selectorVector;
1003 selectorVector.append(pageSelector);
1004 rule->parserAdoptSelectorVector(selectorVector);
1005 rule->setProperties(createStylePropertySet());
1006 pageRule = rule.get();
1007 m_parsedRules.append(rule.release());
1013 StyleRuleBase* BisonCSSParser::createMarginAtRule(CSSSelector::MarginBoxType /* marginBox */)
1015 // FIXME: Implement margin at-rule here, using:
1016 // - marginBox: margin box
1017 // - m_parsedProperties: properties at [m_numParsedPropertiesBeforeMarginBox, m_parsedProperties.size()] are for this at-rule.
1018 // 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.
1020 endDeclarationsForMarginBox();
1021 return 0; // until this method is implemented.
1024 void BisonCSSParser::startDeclarationsForMarginBox()
1026 m_numParsedPropertiesBeforeMarginBox = m_parsedProperties.size();
1029 void BisonCSSParser::endDeclarationsForMarginBox()
1031 rollbackLastProperties(m_parsedProperties.size() - m_numParsedPropertiesBeforeMarginBox);
1032 m_numParsedPropertiesBeforeMarginBox = INVALID_NUM_PARSED_PROPERTIES;
1035 StyleKeyframe* BisonCSSParser::createKeyframe(CSSParserValueList* keys)
1037 OwnPtr<Vector<double> > keyVector = StyleKeyframe::createKeyList(keys);
1038 if (keyVector->isEmpty())
1041 RefPtrWillBeRawPtr<StyleKeyframe> keyframe = StyleKeyframe::create();
1042 keyframe->setKeys(keyVector.release());
1043 keyframe->setProperties(createStylePropertySet());
1047 StyleKeyframe* keyframePtr = keyframe.get();
1048 m_parsedKeyframes.append(keyframe.release());
1052 void BisonCSSParser::invalidBlockHit()
1054 if (m_styleSheet && !m_hadSyntacticallyValidCSSRule)
1055 m_styleSheet->setHasSyntacticallyValidCSSHeader(false);
1058 void BisonCSSParser::startRule()
1063 ASSERT(m_ruleHasHeader);
1064 m_ruleHasHeader = false;
1067 void BisonCSSParser::endRule(bool valid)
1072 if (m_ruleHasHeader)
1073 m_observer->endRuleBody(m_tokenizer.safeUserStringTokenOffset(), !valid);
1074 m_ruleHasHeader = true;
1077 void BisonCSSParser::startRuleHeader(CSSRuleSourceData::Type ruleType)
1079 resumeErrorLogging();
1080 m_ruleHeaderType = ruleType;
1081 m_ruleHeaderStartOffset = m_tokenizer.safeUserStringTokenOffset();
1082 m_ruleHeaderStartLineNumber = m_tokenizer.m_tokenStartLineNumber;
1084 ASSERT(!m_ruleHasHeader);
1085 m_observer->startRuleHeader(ruleType, m_ruleHeaderStartOffset);
1086 m_ruleHasHeader = true;
1090 void BisonCSSParser::endRuleHeader()
1092 ASSERT(m_ruleHeaderType != CSSRuleSourceData::UNKNOWN_RULE);
1093 m_ruleHeaderType = CSSRuleSourceData::UNKNOWN_RULE;
1095 ASSERT(m_ruleHasHeader);
1096 m_observer->endRuleHeader(m_tokenizer.safeUserStringTokenOffset());
1100 void BisonCSSParser::startSelector()
1103 m_observer->startSelector(m_tokenizer.safeUserStringTokenOffset());
1106 void BisonCSSParser::endSelector()
1109 m_observer->endSelector(m_tokenizer.safeUserStringTokenOffset());
1112 void BisonCSSParser::startRuleBody()
1115 m_observer->startRuleBody(m_tokenizer.safeUserStringTokenOffset());
1118 void BisonCSSParser::startProperty()
1120 resumeErrorLogging();
1122 m_observer->startProperty(m_tokenizer.safeUserStringTokenOffset());
1125 void BisonCSSParser::endProperty(bool isImportantFound, bool isPropertyParsed, CSSParserError errorType)
1127 m_id = CSSPropertyInvalid;
1129 m_observer->endProperty(isImportantFound, isPropertyParsed, m_tokenizer.safeUserStringTokenOffset(), errorType);
1132 StyleRuleBase* BisonCSSParser::createViewportRule()
1134 // Allow @viewport rules from UA stylesheets even if the feature is disabled.
1135 if (!RuntimeEnabledFeatures::cssViewportEnabled() && !isUASheetBehavior(m_context.mode()))
1138 m_allowImportRules = m_allowNamespaceDeclarations = false;
1140 RefPtrWillBeRawPtr<StyleRuleViewport> rule = StyleRuleViewport::create();
1142 rule->setProperties(createStylePropertySet());
1145 StyleRuleViewport* result = rule.get();
1146 m_parsedRules.append(rule.release());