1/*
2 * Copyright (C) 2003 Lars Knoll (knoll@kde.org)
3 * Copyright (C) 2004, 2005, 2006, 2008 Apple Inc. All rights reserved.
4 *
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.
9 *
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.
14 *
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.
19 */
20
21#include "config.h"
22#include "CSSParserValues.h"
23
24#include "CSSPrimitiveValue.h"
25#include "CSSFunctionValue.h"
26#include "CSSSelector.h"
27#include "CSSSelectorList.h"
28#include "SelectorPseudoTypeMap.h"
29
30namespace WebCore {
31
32using namespace WTF;
33
34void destroy(const CSSParserValue& value)
35{
36    if (value.unit == CSSParserValue::Function)
37        delete value.function;
38    else if (value.unit == CSSParserValue::ValueList)
39        delete value.valueList;
40}
41
42CSSParserValueList::~CSSParserValueList()
43{
44    for (size_t i = 0, size = m_values.size(); i < size; i++)
45        destroy(m_values[i]);
46}
47
48void CSSParserValueList::addValue(const CSSParserValue& v)
49{
50    m_values.append(v);
51}
52
53void CSSParserValueList::insertValueAt(unsigned i, const CSSParserValue& v)
54{
55    m_values.insert(i, v);
56}
57
58void CSSParserValueList::deleteValueAt(unsigned i)
59{
60    m_values.remove(i);
61}
62
63void CSSParserValueList::extend(CSSParserValueList& valueList)
64{
65    for (unsigned int i = 0; i < valueList.size(); ++i)
66        m_values.append(*(valueList.valueAt(i)));
67}
68
69PassRefPtr<CSSValue> CSSParserValue::createCSSValue()
70{
71    RefPtr<CSSValue> parsedValue;
72    if (id)
73        return CSSPrimitiveValue::createIdentifier(id);
74
75    if (unit == CSSParserValue::Operator) {
76        RefPtr<CSSPrimitiveValue> primitiveValue = CSSPrimitiveValue::createParserOperator(iValue);
77        primitiveValue->setPrimitiveType(CSSPrimitiveValue::CSS_PARSER_OPERATOR);
78        return primitiveValue.release();
79    }
80    if (unit == CSSParserValue::Function)
81        return CSSFunctionValue::create(function);
82    if (unit == CSSParserValue::ValueList)
83        return CSSValueList::createFromParserValueList(*valueList);
84    if (unit >= CSSParserValue::Q_EMS)
85        return CSSPrimitiveValue::createAllowingMarginQuirk(fValue, CSSPrimitiveValue::CSS_EMS);
86
87    CSSPrimitiveValue::UnitTypes primitiveUnit = static_cast<CSSPrimitiveValue::UnitTypes>(unit);
88    switch (primitiveUnit) {
89    case CSSPrimitiveValue::CSS_IDENT:
90    case CSSPrimitiveValue::CSS_PROPERTY_ID:
91    case CSSPrimitiveValue::CSS_VALUE_ID:
92        return CSSPrimitiveValue::create(string, CSSPrimitiveValue::CSS_PARSER_IDENTIFIER);
93    case CSSPrimitiveValue::CSS_NUMBER:
94        return CSSPrimitiveValue::create(fValue, isInt ? CSSPrimitiveValue::CSS_PARSER_INTEGER : CSSPrimitiveValue::CSS_NUMBER);
95    case CSSPrimitiveValue::CSS_STRING:
96    case CSSPrimitiveValue::CSS_URI:
97    case CSSPrimitiveValue::CSS_PARSER_HEXCOLOR:
98        return CSSPrimitiveValue::create(string, primitiveUnit);
99    case CSSPrimitiveValue::CSS_PERCENTAGE:
100    case CSSPrimitiveValue::CSS_EMS:
101    case CSSPrimitiveValue::CSS_EXS:
102    case CSSPrimitiveValue::CSS_PX:
103    case CSSPrimitiveValue::CSS_CM:
104    case CSSPrimitiveValue::CSS_MM:
105    case CSSPrimitiveValue::CSS_IN:
106    case CSSPrimitiveValue::CSS_PT:
107    case CSSPrimitiveValue::CSS_PC:
108    case CSSPrimitiveValue::CSS_DEG:
109    case CSSPrimitiveValue::CSS_RAD:
110    case CSSPrimitiveValue::CSS_GRAD:
111    case CSSPrimitiveValue::CSS_MS:
112    case CSSPrimitiveValue::CSS_S:
113    case CSSPrimitiveValue::CSS_HZ:
114    case CSSPrimitiveValue::CSS_KHZ:
115    case CSSPrimitiveValue::CSS_VW:
116    case CSSPrimitiveValue::CSS_VH:
117    case CSSPrimitiveValue::CSS_VMIN:
118    case CSSPrimitiveValue::CSS_VMAX:
119    case CSSPrimitiveValue::CSS_TURN:
120    case CSSPrimitiveValue::CSS_REMS:
121    case CSSPrimitiveValue::CSS_CHS:
122    case CSSPrimitiveValue::CSS_FR:
123        return CSSPrimitiveValue::create(fValue, primitiveUnit);
124    case CSSPrimitiveValue::CSS_UNKNOWN:
125    case CSSPrimitiveValue::CSS_DIMENSION:
126    case CSSPrimitiveValue::CSS_ATTR:
127    case CSSPrimitiveValue::CSS_COUNTER:
128    case CSSPrimitiveValue::CSS_RECT:
129    case CSSPrimitiveValue::CSS_RGBCOLOR:
130    case CSSPrimitiveValue::CSS_DPPX:
131    case CSSPrimitiveValue::CSS_DPI:
132    case CSSPrimitiveValue::CSS_DPCM:
133    case CSSPrimitiveValue::CSS_PAIR:
134#if ENABLE(DASHBOARD_SUPPORT)
135    case CSSPrimitiveValue::CSS_DASHBOARD_REGION:
136#endif
137    case CSSPrimitiveValue::CSS_UNICODE_RANGE:
138    case CSSPrimitiveValue::CSS_PARSER_OPERATOR:
139    case CSSPrimitiveValue::CSS_PARSER_INTEGER:
140    case CSSPrimitiveValue::CSS_PARSER_IDENTIFIER:
141    case CSSPrimitiveValue::CSS_COUNTER_NAME:
142    case CSSPrimitiveValue::CSS_SHAPE:
143    case CSSPrimitiveValue::CSS_QUAD:
144    case CSSPrimitiveValue::CSS_CALC:
145    case CSSPrimitiveValue::CSS_CALC_PERCENTAGE_WITH_NUMBER:
146    case CSSPrimitiveValue::CSS_CALC_PERCENTAGE_WITH_LENGTH:
147        return 0;
148    }
149
150    ASSERT_NOT_REACHED();
151    return 0;
152}
153
154CSSParserSelector* CSSParserSelector::parsePagePseudoSelector(const CSSParserString& pseudoTypeString)
155{
156    CSSSelector::PagePseudoClassType pseudoType;
157    if (pseudoTypeString.equalIgnoringCase("first"))
158        pseudoType = CSSSelector::PagePseudoClassFirst;
159    else if (pseudoTypeString.equalIgnoringCase("left"))
160        pseudoType = CSSSelector::PagePseudoClassLeft;
161    else if (pseudoTypeString.equalIgnoringCase("right"))
162        pseudoType = CSSSelector::PagePseudoClassRight;
163    else
164        return nullptr;
165
166    auto selector = std::make_unique<CSSParserSelector>();
167    selector->m_selector->m_match = CSSSelector::PagePseudoClass;
168    selector->m_selector->setPagePseudoType(pseudoType);
169    return selector.release();
170}
171
172CSSParserSelector* CSSParserSelector::parsePseudoElementSelector(CSSParserString& pseudoTypeString)
173{
174    pseudoTypeString.lower();
175    AtomicString name = pseudoTypeString;
176
177    CSSSelector::PseudoElementType pseudoType = CSSSelector::parsePseudoElementType(name);
178    if (pseudoType == CSSSelector::PseudoElementUnknown)
179        return nullptr;
180
181    auto selector = std::make_unique<CSSParserSelector>();
182    selector->m_selector->m_match = CSSSelector::PseudoElement;
183    selector->m_selector->setPseudoElementType(pseudoType);
184    selector->m_selector->setValue(name);
185    return selector.release();
186}
187
188#if ENABLE(VIDEO_TRACK)
189CSSParserSelector* CSSParserSelector::parsePseudoElementCueFunctionSelector(const CSSParserString& functionIdentifier, Vector<std::unique_ptr<CSSParserSelector>>* parsedSelectorVector)
190{
191    ASSERT_UNUSED(functionIdentifier, String(functionIdentifier) == "cue(");
192
193    std::unique_ptr<Vector<std::unique_ptr<CSSParserSelector>>> selectorVector(parsedSelectorVector);
194
195    if (!selectorVector)
196        return nullptr;
197
198    auto selector = std::make_unique<CSSParserSelector>();
199    selector->m_selector->m_match = CSSSelector::PseudoElement;
200    selector->m_selector->setPseudoElementType(CSSSelector::PseudoElementCue);
201    selector->adoptSelectorVector(*selectorVector);
202    return selector.release();
203}
204#endif
205
206CSSParserSelector* CSSParserSelector::parsePseudoClassAndCompatibilityElementSelector(CSSParserString& pseudoTypeString)
207{
208    PseudoClassOrCompatibilityPseudoElement pseudoType = parsePseudoClassAndCompatibilityElementString(pseudoTypeString);
209    if (pseudoType.pseudoClass != CSSSelector::PseudoClassUnknown) {
210        auto selector = std::make_unique<CSSParserSelector>();
211        selector->m_selector->m_match = CSSSelector::PseudoClass;
212        selector->m_selector->m_pseudoType = pseudoType.pseudoClass;
213        return selector.release();
214    }
215    if (pseudoType.compatibilityPseudoElement != CSSSelector::PseudoElementUnknown) {
216        auto selector = std::make_unique<CSSParserSelector>();
217        selector->m_selector->m_match = CSSSelector::PseudoElement;
218        selector->m_selector->setPseudoElementType(pseudoType.compatibilityPseudoElement);
219        AtomicString name = pseudoTypeString;
220        selector->m_selector->setValue(name);
221        return selector.release();
222    }
223    return nullptr;
224}
225
226CSSParserSelector::CSSParserSelector()
227    : m_selector(std::make_unique<CSSSelector>())
228{
229}
230
231CSSParserSelector::CSSParserSelector(const QualifiedName& tagQName)
232    : m_selector(std::make_unique<CSSSelector>(tagQName))
233{
234}
235
236CSSParserSelector::~CSSParserSelector()
237{
238    if (!m_tagHistory)
239        return;
240    Vector<std::unique_ptr<CSSParserSelector>, 16> toDelete;
241    std::unique_ptr<CSSParserSelector> selector = WTF::move(m_tagHistory);
242    while (true) {
243        std::unique_ptr<CSSParserSelector> next = WTF::move(selector->m_tagHistory);
244        toDelete.append(WTF::move(selector));
245        if (!next)
246            break;
247        selector = WTF::move(next);
248    }
249}
250
251void CSSParserSelector::adoptSelectorVector(Vector<std::unique_ptr<CSSParserSelector>>& selectorVector)
252{
253    auto selectorList = std::make_unique<CSSSelectorList>();
254    selectorList->adoptSelectorVector(selectorVector);
255    m_selector->setSelectorList(WTF::move(selectorList));
256}
257
258void CSSParserSelector::setPseudoClassValue(const CSSParserString& pseudoClassString)
259{
260    ASSERT(m_selector->m_match == CSSSelector::PseudoClass);
261
262    PseudoClassOrCompatibilityPseudoElement pseudoType = parsePseudoClassAndCompatibilityElementString(pseudoClassString);
263    m_selector->m_pseudoType = pseudoType.pseudoClass;
264}
265
266bool CSSParserSelector::isSimple() const
267{
268    if (m_selector->selectorList() || m_selector->matchesPseudoElement())
269        return false;
270
271    if (!m_tagHistory)
272        return true;
273
274    if (m_selector->m_match == CSSSelector::Tag) {
275        // We can't check against anyQName() here because namespace may not be nullAtom.
276        // Example:
277        //     @namespace "http://www.w3.org/2000/svg";
278        //     svg:not(:root) { ...
279        if (m_selector->tagQName().localName() == starAtom)
280            return m_tagHistory->isSimple();
281    }
282
283    return false;
284}
285
286void CSSParserSelector::insertTagHistory(CSSSelector::Relation before, std::unique_ptr<CSSParserSelector> selector, CSSSelector::Relation after)
287{
288    if (m_tagHistory)
289        selector->setTagHistory(WTF::move(m_tagHistory));
290    setRelation(before);
291    selector->setRelation(after);
292    m_tagHistory = WTF::move(selector);
293}
294
295void CSSParserSelector::appendTagHistory(CSSSelector::Relation relation, std::unique_ptr<CSSParserSelector> selector)
296{
297    CSSParserSelector* end = this;
298    while (end->tagHistory())
299        end = end->tagHistory();
300    end->setRelation(relation);
301    end->setTagHistory(WTF::move(selector));
302}
303
304void CSSParserSelector::prependTagSelector(const QualifiedName& tagQName, bool tagIsForNamespaceRule)
305{
306    auto second = std::make_unique<CSSParserSelector>();
307    second->m_selector = WTF::move(m_selector);
308    second->m_tagHistory = WTF::move(m_tagHistory);
309    m_tagHistory = WTF::move(second);
310
311    m_selector = std::make_unique<CSSSelector>(tagQName, tagIsForNamespaceRule);
312    m_selector->m_relation = CSSSelector::SubSelector;
313}
314
315}
316
317