2 * Copyright (C) 2003 Lars Knoll (knoll@kde.org)
3 * Copyright (C) 2004, 2005, 2006, 2008, 2014 Apple Inc. All rights reserved.
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Library General Public
7 * License as published by the Free Software Foundation; either
8 * version 2 of the License, or (at your option) any later version.
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Library General Public License for more details.
15 * You should have received a copy of the GNU Library General Public License
16 * along with this library; see the file COPYING.LIB. If not, write to
17 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18 * Boston, MA 02110-1301, USA.
22 #include "CSSParserValues.h"
24 #include "CSSCustomPropertyValue.h"
25 #include "CSSParserIdioms.h"
26 #include "CSSPrimitiveValue.h"
27 #include "CSSFunctionValue.h"
28 #include "CSSSelector.h"
29 #include "CSSSelectorList.h"
30 #include "CSSVariableValue.h"
31 #include "SelectorPseudoTypeMap.h"
34 // See https://msdn.microsoft.com/en-us/library/1wea5zwe.aspx
35 #pragma warning(disable: 4701)
42 void destroy(const CSSParserValue& value)
44 if (value.unit == CSSParserValue::Function)
45 delete value.function;
46 else if (value.unit == CSSParserValue::ValueList)
47 delete value.valueList;
48 else if (value.unit == CSSParserValue::Variable)
49 delete value.variable;
52 CSSParserValueList::~CSSParserValueList()
54 for (auto& value : m_values)
58 void CSSParserValueList::addValue(const CSSParserValue& value)
60 m_values.append(value);
63 void CSSParserValueList::insertValueAt(unsigned i, const CSSParserValue& value)
65 m_values.insert(i, value);
68 void CSSParserValueList::extend(CSSParserValueList& other)
70 for (auto& value : other.m_values) {
71 m_values.append(value);
72 value.unit = 0; // We moved the CSSParserValue from the other list; this acts like std::move.
76 bool CSSParserValueList::containsVariables() const
78 for (unsigned i = 0; i < size(); i++) {
79 auto* parserValue = &m_values[i];
80 if (parserValue->unit == CSSParserValue::Variable)
82 if (parserValue->unit == CSSParserValue::Function && parserValue->function->args
83 && parserValue->function->args->containsVariables())
85 if (parserValue->unit == CSSParserValue::ValueList && parserValue->valueList->containsVariables())
91 RefPtr<CSSValue> CSSParserValue::createCSSValue()
93 RefPtr<CSSValue> parsedValue;
95 return CSSPrimitiveValue::createIdentifier(id);
97 if (unit == CSSParserValue::Operator)
98 return CSSPrimitiveValue::createParserOperator(iValue);
99 if (unit == CSSParserValue::Function)
100 return CSSFunctionValue::create(function);
101 if (unit == CSSParserValue::Variable)
102 return CSSVariableValue::create(variable);
103 if (unit == CSSParserValue::ValueList)
104 return CSSValueList::createFromParserValueList(*valueList);
106 if (unit >= CSSParserValue::Q_EMS)
107 return CSSPrimitiveValue::createAllowingMarginQuirk(fValue, CSSPrimitiveValue::CSS_EMS);
109 CSSPrimitiveValue::UnitTypes primitiveUnit = static_cast<CSSPrimitiveValue::UnitTypes>(unit);
110 switch (primitiveUnit) {
111 case CSSPrimitiveValue::CSS_IDENT:
112 case CSSPrimitiveValue::CSS_PROPERTY_ID:
113 case CSSPrimitiveValue::CSS_VALUE_ID:
114 return CSSPrimitiveValue::create(string, CSSPrimitiveValue::CSS_PARSER_IDENTIFIER);
115 case CSSPrimitiveValue::CSS_NUMBER:
116 return CSSPrimitiveValue::create(fValue, isInt ? CSSPrimitiveValue::CSS_PARSER_INTEGER : CSSPrimitiveValue::CSS_NUMBER);
117 case CSSPrimitiveValue::CSS_STRING:
118 case CSSPrimitiveValue::CSS_URI:
119 case CSSPrimitiveValue::CSS_PARSER_HEXCOLOR:
120 case CSSPrimitiveValue::CSS_DIMENSION:
121 case CSSPrimitiveValue::CSS_UNICODE_RANGE:
122 case CSSPrimitiveValue::CSS_PARSER_WHITESPACE:
123 return CSSPrimitiveValue::create(string, primitiveUnit);
124 case CSSPrimitiveValue::CSS_PERCENTAGE:
125 case CSSPrimitiveValue::CSS_EMS:
126 case CSSPrimitiveValue::CSS_QUIRKY_EMS:
127 case CSSPrimitiveValue::CSS_EXS:
128 case CSSPrimitiveValue::CSS_PX:
129 case CSSPrimitiveValue::CSS_CM:
130 case CSSPrimitiveValue::CSS_MM:
131 case CSSPrimitiveValue::CSS_IN:
132 case CSSPrimitiveValue::CSS_PT:
133 case CSSPrimitiveValue::CSS_PC:
134 case CSSPrimitiveValue::CSS_DEG:
135 case CSSPrimitiveValue::CSS_RAD:
136 case CSSPrimitiveValue::CSS_GRAD:
137 case CSSPrimitiveValue::CSS_MS:
138 case CSSPrimitiveValue::CSS_S:
139 case CSSPrimitiveValue::CSS_HZ:
140 case CSSPrimitiveValue::CSS_KHZ:
141 case CSSPrimitiveValue::CSS_VW:
142 case CSSPrimitiveValue::CSS_VH:
143 case CSSPrimitiveValue::CSS_VMIN:
144 case CSSPrimitiveValue::CSS_VMAX:
145 case CSSPrimitiveValue::CSS_TURN:
146 case CSSPrimitiveValue::CSS_REMS:
147 case CSSPrimitiveValue::CSS_CHS:
148 case CSSPrimitiveValue::CSS_FR:
149 return CSSPrimitiveValue::create(fValue, primitiveUnit);
150 case CSSPrimitiveValue::CSS_UNKNOWN:
151 case CSSPrimitiveValue::CSS_ATTR:
152 case CSSPrimitiveValue::CSS_COUNTER:
153 case CSSPrimitiveValue::CSS_RECT:
154 case CSSPrimitiveValue::CSS_RGBCOLOR:
155 case CSSPrimitiveValue::CSS_DPPX:
156 case CSSPrimitiveValue::CSS_DPI:
157 case CSSPrimitiveValue::CSS_DPCM:
158 case CSSPrimitiveValue::CSS_PAIR:
159 #if ENABLE(DASHBOARD_SUPPORT)
160 case CSSPrimitiveValue::CSS_DASHBOARD_REGION:
162 case CSSPrimitiveValue::CSS_PARSER_OPERATOR:
163 case CSSPrimitiveValue::CSS_PARSER_INTEGER:
164 case CSSPrimitiveValue::CSS_PARSER_IDENTIFIER:
165 case CSSPrimitiveValue::CSS_COUNTER_NAME:
166 case CSSPrimitiveValue::CSS_SHAPE:
167 case CSSPrimitiveValue::CSS_FONT_FAMILY:
168 case CSSPrimitiveValue::CSS_QUAD:
169 #if ENABLE(CSS_SCROLL_SNAP)
170 case CSSPrimitiveValue::CSS_LENGTH_REPEAT:
172 case CSSPrimitiveValue::CSS_CALC:
173 case CSSPrimitiveValue::CSS_CALC_PERCENTAGE_WITH_NUMBER:
174 case CSSPrimitiveValue::CSS_CALC_PERCENTAGE_WITH_LENGTH:
178 ASSERT_NOT_REACHED();
182 CSSParserSelector* CSSParserSelector::parsePagePseudoSelector(const CSSParserString& pseudoTypeString)
184 CSSSelector::PagePseudoClassType pseudoType;
185 if (equalLettersIgnoringASCIICase(pseudoTypeString, "first"))
186 pseudoType = CSSSelector::PagePseudoClassFirst;
187 else if (equalLettersIgnoringASCIICase(pseudoTypeString, "left"))
188 pseudoType = CSSSelector::PagePseudoClassLeft;
189 else if (equalLettersIgnoringASCIICase(pseudoTypeString, "right"))
190 pseudoType = CSSSelector::PagePseudoClassRight;
194 auto selector = std::make_unique<CSSParserSelector>();
195 selector->m_selector->setMatch(CSSSelector::PagePseudoClass);
196 selector->m_selector->setPagePseudoType(pseudoType);
197 return selector.release();
200 CSSParserSelector* CSSParserSelector::parsePagePseudoSelector(const AtomicString& pseudoTypeString)
202 CSSSelector::PagePseudoClassType pseudoType;
203 if (equalLettersIgnoringASCIICase(pseudoTypeString, "first"))
204 pseudoType = CSSSelector::PagePseudoClassFirst;
205 else if (equalLettersIgnoringASCIICase(pseudoTypeString, "left"))
206 pseudoType = CSSSelector::PagePseudoClassLeft;
207 else if (equalLettersIgnoringASCIICase(pseudoTypeString, "right"))
208 pseudoType = CSSSelector::PagePseudoClassRight;
212 auto selector = std::make_unique<CSSParserSelector>();
213 selector->m_selector->setMatch(CSSSelector::PagePseudoClass);
214 selector->m_selector->setPagePseudoType(pseudoType);
215 return selector.release();
218 CSSParserSelector* CSSParserSelector::parsePseudoElementSelector(CSSParserString& pseudoTypeString)
220 pseudoTypeString.convertToASCIILowercaseInPlace();
221 AtomicString name = pseudoTypeString;
223 CSSSelector::PseudoElementType pseudoType = CSSSelector::parsePseudoElementType(name);
224 if (pseudoType == CSSSelector::PseudoElementUnknown)
227 auto selector = std::make_unique<CSSParserSelector>();
228 selector->m_selector->setMatch(CSSSelector::PseudoElement);
229 selector->m_selector->setPseudoElementType(pseudoType);
230 if (pseudoType == CSSSelector::PseudoElementWebKitCustomLegacyPrefixed) {
231 ASSERT_WITH_MESSAGE(name == "-webkit-input-placeholder", "-webkit-input-placeholder is the only LegacyPrefix pseudo type.");
232 if (name == "-webkit-input-placeholder")
233 name = AtomicString("placeholder", AtomicString::ConstructFromLiteral);
235 selector->m_selector->setValue(name);
236 return selector.release();
239 CSSParserSelector* CSSParserSelector::parsePseudoElementSelectorFromStringView(StringView& pseudoTypeString)
241 convertToASCIILowercaseInPlace(pseudoTypeString);
242 AtomicString name = pseudoTypeString.toAtomicString();
244 CSSSelector::PseudoElementType pseudoType = CSSSelector::parsePseudoElementType(name);
245 if (pseudoType == CSSSelector::PseudoElementUnknown)
248 auto selector = std::make_unique<CSSParserSelector>();
249 selector->m_selector->setMatch(CSSSelector::PseudoElement);
250 selector->m_selector->setPseudoElementType(pseudoType);
251 if (pseudoType == CSSSelector::PseudoElementWebKitCustomLegacyPrefixed) {
252 ASSERT_WITH_MESSAGE(name == "-webkit-input-placeholder", "-webkit-input-placeholder is the only LegacyPrefix pseudo type.");
253 if (name == "-webkit-input-placeholder")
254 name = AtomicString("placeholder", AtomicString::ConstructFromLiteral);
256 selector->m_selector->setValue(name);
257 return selector.release();
260 #if ENABLE(VIDEO_TRACK)
261 CSSParserSelector* CSSParserSelector::parsePseudoElementCueFunctionSelector(const CSSParserString& functionIdentifier, Vector<std::unique_ptr<CSSParserSelector>>* parsedSelectorVector)
263 ASSERT_UNUSED(functionIdentifier, String(functionIdentifier) == "cue(");
265 std::unique_ptr<Vector<std::unique_ptr<CSSParserSelector>>> selectorVector(parsedSelectorVector);
270 auto selector = std::make_unique<CSSParserSelector>();
271 selector->m_selector->setMatch(CSSSelector::PseudoElement);
272 selector->m_selector->setPseudoElementType(CSSSelector::PseudoElementCue);
273 selector->adoptSelectorVector(*selectorVector);
274 return selector.release();
278 CSSParserSelector* CSSParserSelector::parsePseudoElementSlottedFunctionSelector(const CSSParserString& functionIdentifier, CSSParserSelector* parsedSelector)
280 ASSERT_UNUSED(functionIdentifier, String(functionIdentifier) == "slotted(");
285 std::unique_ptr<CSSParserSelector> ownedParsedSelector(parsedSelector);
287 for (auto* component = parsedSelector; component; component = component->tagHistory()) {
288 if (component->matchesPseudoElement())
292 auto selectorVector = std::make_unique<Vector<std::unique_ptr<CSSParserSelector>>>();
293 selectorVector->append(WTFMove(ownedParsedSelector));
295 auto selector = std::make_unique<CSSParserSelector>();
296 selector->m_selector->setMatch(CSSSelector::PseudoElement);
297 selector->m_selector->setPseudoElementType(CSSSelector::PseudoElementSlotted);
298 selector->adoptSelectorVector(*selectorVector);
299 return selector.release();
302 CSSParserSelector* CSSParserSelector::parsePseudoClassHostFunctionSelector(const CSSParserString& functionIdentifier, CSSParserSelector* parsedSelector)
304 ASSERT_UNUSED(functionIdentifier, String(functionIdentifier) == "host(");
309 std::unique_ptr<CSSParserSelector> ownedParsedSelector(parsedSelector);
311 for (auto* component = parsedSelector; component; component = component->tagHistory()) {
312 if (component->matchesPseudoElement())
316 auto selectorVector = std::make_unique<Vector<std::unique_ptr<CSSParserSelector>>>();
317 selectorVector->append(WTFMove(ownedParsedSelector));
319 auto selector = std::make_unique<CSSParserSelector>();
320 selector->m_selector->setMatch(CSSSelector::PseudoClass);
321 selector->m_selector->setPseudoClassType(CSSSelector::PseudoClassHost);
322 selector->adoptSelectorVector(*selectorVector);
323 return selector.release();
326 CSSParserSelector* CSSParserSelector::parsePseudoClassAndCompatibilityElementSelector(CSSParserString& pseudoTypeString)
328 if (pseudoTypeString.length() && pseudoTypeString[pseudoTypeString.length() - 1] == '(')
331 PseudoClassOrCompatibilityPseudoElement pseudoType = parsePseudoClassAndCompatibilityElementString(pseudoTypeString);
332 if (pseudoType.pseudoClass != CSSSelector::PseudoClassUnknown) {
333 auto selector = std::make_unique<CSSParserSelector>();
334 selector->m_selector->setMatch(CSSSelector::PseudoClass);
335 selector->m_selector->setPseudoClassType(pseudoType.pseudoClass);
336 return selector.release();
338 if (pseudoType.compatibilityPseudoElement != CSSSelector::PseudoElementUnknown) {
339 auto selector = std::make_unique<CSSParserSelector>();
340 selector->m_selector->setMatch(CSSSelector::PseudoElement);
341 selector->m_selector->setPseudoElementType(pseudoType.compatibilityPseudoElement);
342 AtomicString name = pseudoTypeString;
343 selector->m_selector->setValue(name);
344 return selector.release();
349 CSSParserSelector* CSSParserSelector::parsePseudoClassSelectorFromStringView(StringView& pseudoTypeString)
351 if (pseudoTypeString.length() && pseudoTypeString[pseudoTypeString.length() - 1] == '(')
354 PseudoClassOrCompatibilityPseudoElement pseudoType = parsePseudoClassAndCompatibilityElementString(pseudoTypeString);
355 if (pseudoType.pseudoClass != CSSSelector::PseudoClassUnknown) {
356 auto selector = std::make_unique<CSSParserSelector>();
357 selector->m_selector->setMatch(CSSSelector::PseudoClass);
358 selector->m_selector->setPseudoClassType(pseudoType.pseudoClass);
359 return selector.release();
361 if (pseudoType.compatibilityPseudoElement != CSSSelector::PseudoElementUnknown) {
362 auto selector = std::make_unique<CSSParserSelector>();
363 selector->m_selector->setMatch(CSSSelector::PseudoElement);
364 selector->m_selector->setPseudoElementType(pseudoType.compatibilityPseudoElement);
365 AtomicString name = pseudoTypeString.toAtomicString();
366 selector->m_selector->setValue(name);
367 return selector.release();
372 CSSParserSelector::CSSParserSelector()
373 : m_selector(std::make_unique<CSSSelector>())
377 CSSParserSelector::CSSParserSelector(const QualifiedName& tagQName)
378 : m_selector(std::make_unique<CSSSelector>(tagQName))
382 CSSParserSelector::~CSSParserSelector()
386 Vector<std::unique_ptr<CSSParserSelector>, 16> toDelete;
387 std::unique_ptr<CSSParserSelector> selector = WTFMove(m_tagHistory);
389 std::unique_ptr<CSSParserSelector> next = WTFMove(selector->m_tagHistory);
390 toDelete.append(WTFMove(selector));
393 selector = WTFMove(next);
397 void CSSParserSelector::adoptSelectorVector(Vector<std::unique_ptr<CSSParserSelector>>& selectorVector)
399 auto selectorList = std::make_unique<CSSSelectorList>();
400 selectorList->adoptSelectorVector(selectorVector);
401 m_selector->setSelectorList(WTFMove(selectorList));
404 void CSSParserSelector::setLangArgumentList(const Vector<CSSParserString>& stringVector)
406 ASSERT_WITH_MESSAGE(!stringVector.isEmpty(), "No CSS Selector takes an empty argument list.");
407 auto argumentList = std::make_unique<Vector<AtomicString>>();
408 argumentList->reserveInitialCapacity(stringVector.size());
409 for (const AtomicString& languageArgument : stringVector)
410 argumentList->append(languageArgument);
411 m_selector->setLangArgumentList(WTFMove(argumentList));
414 void CSSParserSelector::setSelectorList(std::unique_ptr<CSSSelectorList> selectorList)
416 m_selector->setSelectorList(WTFMove(selectorList));
419 void CSSParserSelector::setPseudoClassValue(const CSSParserString& pseudoClassString)
421 ASSERT(m_selector->match() == CSSSelector::PseudoClass);
423 PseudoClassOrCompatibilityPseudoElement pseudoType = parsePseudoClassAndCompatibilityElementString(pseudoClassString);
424 m_selector->setPseudoClassType(pseudoType.pseudoClass);
427 static bool selectorListMatchesPseudoElement(const CSSSelectorList* selectorList)
432 for (const CSSSelector* subSelector = selectorList->first(); subSelector; subSelector = CSSSelectorList::next(subSelector)) {
433 for (const CSSSelector* selector = subSelector; selector; selector = selector->tagHistory()) {
434 if (selector->matchesPseudoElement())
436 if (const CSSSelectorList* subselectorList = selector->selectorList()) {
437 if (selectorListMatchesPseudoElement(subselectorList))
445 bool CSSParserSelector::matchesPseudoElement() const
447 return m_selector->matchesPseudoElement() || selectorListMatchesPseudoElement(m_selector->selectorList());
450 void CSSParserSelector::insertTagHistory(CSSSelector::RelationType before, std::unique_ptr<CSSParserSelector> selector, CSSSelector::RelationType after)
453 selector->setTagHistory(WTFMove(m_tagHistory));
455 selector->setRelation(after);
456 m_tagHistory = WTFMove(selector);
459 void CSSParserSelector::appendTagHistory(CSSSelector::RelationType relation, std::unique_ptr<CSSParserSelector> selector)
461 CSSParserSelector* end = this;
462 while (end->tagHistory())
463 end = end->tagHistory();
465 end->setRelation(relation);
466 end->setTagHistory(WTFMove(selector));
469 void CSSParserSelector::appendTagHistory(CSSParserSelectorCombinator relation, std::unique_ptr<CSSParserSelector> selector)
471 CSSParserSelector* end = this;
472 while (end->tagHistory())
473 end = end->tagHistory();
475 CSSSelector::RelationType selectorRelation;
477 case CSSParserSelectorCombinator::Child:
478 selectorRelation = CSSSelector::Child;
480 case CSSParserSelectorCombinator::DescendantSpace:
481 selectorRelation = CSSSelector::Descendant;
483 #if ENABLE(CSS_SELECTORS_LEVEL4)
484 case CSSParserSelectorCombinator::DescendantDoubleChild:
485 selectorRelation = CSSSelector::Descendant;
488 case CSSParserSelectorCombinator::DirectAdjacent:
489 selectorRelation = CSSSelector::DirectAdjacent;
491 case CSSParserSelectorCombinator::IndirectAdjacent:
492 selectorRelation = CSSSelector::IndirectAdjacent;
494 case CSSParserSelectorCombinator::ShadowDeep:
495 selectorRelation = CSSSelector::ShadowDeep;
497 case CSSParserSelectorCombinator::ShadowPseudo:
498 selectorRelation = CSSSelector::ShadowPseudo;
500 case CSSParserSelectorCombinator::ShadowSlot:
501 selectorRelation = CSSSelector::ShadowSlot;
504 end->setRelation(selectorRelation);
506 #if ENABLE(CSS_SELECTORS_LEVEL4)
507 if (relation == CSSParserSelectorCombinator::DescendantDoubleChild)
508 end->setDescendantUseDoubleChildSyntax();
511 end->setTagHistory(WTFMove(selector));
514 void CSSParserSelector::prependTagSelector(const QualifiedName& tagQName, bool tagIsForNamespaceRule)
516 auto second = std::make_unique<CSSParserSelector>();
517 second->m_selector = WTFMove(m_selector);
518 second->m_tagHistory = WTFMove(m_tagHistory);
519 m_tagHistory = WTFMove(second);
521 m_selector = std::make_unique<CSSSelector>(tagQName, tagIsForNamespaceRule);
522 m_selector->setRelation(CSSSelector::Subselector);
525 std::unique_ptr<CSSParserSelector> CSSParserSelector::releaseTagHistory()
527 setRelation(CSSSelector::Subselector);
528 return WTFMove(m_tagHistory);
531 // FIXME-NEWPARSER: Add support for :host-context
532 bool CSSParserSelector::isHostPseudoSelector() const
534 return match() == CSSSelector::PseudoClass && pseudoClassType() == CSSSelector::PseudoClassHost;