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 "core/css/CSSParserValues.h"
23
24#include "core/css/CSSFunctionValue.h"
25#include "core/css/CSSSelectorList.h"
26#include "core/html/parser/HTMLParserIdioms.h"
27
28namespace WebCore {
29
30using namespace WTF;
31
32AtomicString CSSParserString::atomicSubstring(unsigned position, unsigned length) const
33{
34    ASSERT(m_length >= position + length);
35
36    if (is8Bit())
37        return AtomicString(characters8() + position, length);
38    return AtomicString(characters16() + position, length);
39}
40
41void CSSParserString::trimTrailingWhitespace()
42{
43    if (is8Bit()) {
44        while (m_length > 0 && isHTMLSpace<LChar>(m_data.characters8[m_length - 1]))
45            --m_length;
46    } else {
47        while (m_length > 0 && isHTMLSpace<UChar>(m_data.characters16[m_length - 1]))
48            --m_length;
49    }
50}
51
52CSSParserValueList::~CSSParserValueList()
53{
54    size_t numValues = m_values.size();
55    for (size_t i = 0; i < numValues; i++) {
56        if (m_values[i].unit == CSSParserValue::Function)
57            delete m_values[i].function;
58        else if (m_values[i].unit == CSSParserValue::ValueList)
59            delete m_values[i].valueList;
60    }
61}
62
63void CSSParserValueList::addValue(const CSSParserValue& v)
64{
65    m_values.append(v);
66}
67
68void CSSParserValueList::insertValueAt(unsigned i, const CSSParserValue& v)
69{
70    m_values.insert(i, v);
71}
72
73void CSSParserValueList::deleteValueAt(unsigned i)
74{
75    m_values.remove(i);
76}
77
78void CSSParserValueList::extend(CSSParserValueList& valueList)
79{
80    for (unsigned int i = 0; i < valueList.size(); ++i)
81        m_values.append(*(valueList.valueAt(i)));
82}
83
84PassRefPtr<CSSValue> CSSParserValue::createCSSValue()
85{
86    RefPtr<CSSValue> parsedValue;
87    if (id)
88        return CSSPrimitiveValue::createIdentifier(id);
89
90    if (unit == CSSParserValue::Operator) {
91        RefPtr<CSSPrimitiveValue> primitiveValue = CSSPrimitiveValue::createParserOperator(iValue);
92        primitiveValue->setPrimitiveType(CSSPrimitiveValue::CSS_PARSER_OPERATOR);
93        return primitiveValue;
94    }
95    if (unit == CSSParserValue::Function)
96        return CSSFunctionValue::create(function);
97    if (unit == CSSParserValue::ValueList)
98        return CSSValueList::createFromParserValueList(valueList);
99    if (unit >= CSSParserValue::Q_EMS)
100        return CSSPrimitiveValue::createAllowingMarginQuirk(fValue, CSSPrimitiveValue::CSS_EMS);
101
102    CSSPrimitiveValue::UnitTypes primitiveUnit = static_cast<CSSPrimitiveValue::UnitTypes>(unit);
103    switch (primitiveUnit) {
104    case CSSPrimitiveValue::CSS_IDENT:
105    case CSSPrimitiveValue::CSS_PROPERTY_ID:
106    case CSSPrimitiveValue::CSS_VALUE_ID:
107        return CSSPrimitiveValue::create(string, CSSPrimitiveValue::CSS_PARSER_IDENTIFIER);
108    case CSSPrimitiveValue::CSS_NUMBER:
109        return CSSPrimitiveValue::create(fValue, isInt ? CSSPrimitiveValue::CSS_PARSER_INTEGER : CSSPrimitiveValue::CSS_NUMBER);
110    case CSSPrimitiveValue::CSS_STRING:
111    case CSSPrimitiveValue::CSS_URI:
112    case CSSPrimitiveValue::CSS_VARIABLE_NAME:
113    case CSSPrimitiveValue::CSS_PARSER_HEXCOLOR:
114        return CSSPrimitiveValue::create(string, primitiveUnit);
115    case CSSPrimitiveValue::CSS_PERCENTAGE:
116    case CSSPrimitiveValue::CSS_EMS:
117    case CSSPrimitiveValue::CSS_EXS:
118    case CSSPrimitiveValue::CSS_PX:
119    case CSSPrimitiveValue::CSS_CM:
120    case CSSPrimitiveValue::CSS_MM:
121    case CSSPrimitiveValue::CSS_IN:
122    case CSSPrimitiveValue::CSS_PT:
123    case CSSPrimitiveValue::CSS_PC:
124    case CSSPrimitiveValue::CSS_DEG:
125    case CSSPrimitiveValue::CSS_RAD:
126    case CSSPrimitiveValue::CSS_GRAD:
127    case CSSPrimitiveValue::CSS_MS:
128    case CSSPrimitiveValue::CSS_S:
129    case CSSPrimitiveValue::CSS_HZ:
130    case CSSPrimitiveValue::CSS_KHZ:
131    case CSSPrimitiveValue::CSS_VW:
132    case CSSPrimitiveValue::CSS_VH:
133    case CSSPrimitiveValue::CSS_VMIN:
134    case CSSPrimitiveValue::CSS_VMAX:
135    case CSSPrimitiveValue::CSS_TURN:
136    case CSSPrimitiveValue::CSS_REMS:
137    case CSSPrimitiveValue::CSS_CHS:
138    case CSSPrimitiveValue::CSS_FR:
139        return CSSPrimitiveValue::create(fValue, primitiveUnit);
140    case CSSPrimitiveValue::CSS_UNKNOWN:
141    case CSSPrimitiveValue::CSS_DIMENSION:
142    case CSSPrimitiveValue::CSS_ATTR:
143    case CSSPrimitiveValue::CSS_COUNTER:
144    case CSSPrimitiveValue::CSS_RECT:
145    case CSSPrimitiveValue::CSS_RGBCOLOR:
146    case CSSPrimitiveValue::CSS_DPPX:
147    case CSSPrimitiveValue::CSS_DPI:
148    case CSSPrimitiveValue::CSS_DPCM:
149    case CSSPrimitiveValue::CSS_PAIR:
150    case CSSPrimitiveValue::CSS_UNICODE_RANGE:
151    case CSSPrimitiveValue::CSS_PARSER_OPERATOR:
152    case CSSPrimitiveValue::CSS_PARSER_INTEGER:
153    case CSSPrimitiveValue::CSS_PARSER_IDENTIFIER:
154    case CSSPrimitiveValue::CSS_COUNTER_NAME:
155    case CSSPrimitiveValue::CSS_SHAPE:
156    case CSSPrimitiveValue::CSS_QUAD:
157    case CSSPrimitiveValue::CSS_CALC:
158    case CSSPrimitiveValue::CSS_CALC_PERCENTAGE_WITH_NUMBER:
159    case CSSPrimitiveValue::CSS_CALC_PERCENTAGE_WITH_LENGTH:
160        return 0;
161    }
162
163    ASSERT_NOT_REACHED();
164    return 0;
165}
166
167CSSParserSelector::CSSParserSelector()
168    : m_selector(adoptPtr(new CSSSelector()))
169    , m_functionArgumentSelector(0)
170{
171}
172
173CSSParserSelector::CSSParserSelector(const QualifiedName& tagQName)
174    : m_selector(adoptPtr(new CSSSelector(tagQName)))
175    , m_functionArgumentSelector(0)
176{
177}
178
179CSSParserSelector::~CSSParserSelector()
180{
181    if (!m_tagHistory)
182        return;
183    Vector<OwnPtr<CSSParserSelector>, 16> toDelete;
184    OwnPtr<CSSParserSelector> selector = m_tagHistory.release();
185    while (true) {
186        OwnPtr<CSSParserSelector> next = selector->m_tagHistory.release();
187        toDelete.append(selector.release());
188        if (!next)
189            break;
190        selector = next.release();
191    }
192}
193
194void CSSParserSelector::adoptSelectorVector(Vector<OwnPtr<CSSParserSelector> >& selectorVector)
195{
196    CSSSelectorList* selectorList = new CSSSelectorList();
197    selectorList->adoptSelectorVector(selectorVector);
198    m_selector->setSelectorList(adoptPtr(selectorList));
199}
200
201bool CSSParserSelector::isSimple() const
202{
203    if (m_selector->selectorList() || m_selector->matchesPseudoElement())
204        return false;
205
206    if (!m_tagHistory)
207        return true;
208
209    if (m_selector->m_match == CSSSelector::Tag) {
210        // We can't check against anyQName() here because namespace may not be nullAtom.
211        // Example:
212        //     @namespace "http://www.w3.org/2000/svg";
213        //     svg:not(:root) { ...
214        if (m_selector->tagQName().localName() == starAtom)
215            return m_tagHistory->isSimple();
216    }
217
218    return false;
219}
220
221void CSSParserSelector::insertTagHistory(CSSSelector::Relation before, PassOwnPtr<CSSParserSelector> selector, CSSSelector::Relation after)
222{
223    if (m_tagHistory)
224        selector->setTagHistory(m_tagHistory.release());
225    setRelation(before);
226    selector->setRelation(after);
227    m_tagHistory = selector;
228}
229
230void CSSParserSelector::appendTagHistory(CSSSelector::Relation relation, PassOwnPtr<CSSParserSelector> selector)
231{
232    CSSParserSelector* end = this;
233    while (end->tagHistory())
234        end = end->tagHistory();
235    end->setRelation(relation);
236    end->setTagHistory(selector);
237}
238
239void CSSParserSelector::prependTagSelector(const QualifiedName& tagQName, bool tagIsForNamespaceRule)
240{
241    OwnPtr<CSSParserSelector> second = adoptPtr(new CSSParserSelector);
242    second->m_selector = m_selector.release();
243    second->m_tagHistory = m_tagHistory.release();
244    m_tagHistory = second.release();
245
246    m_selector = adoptPtr(new CSSSelector(tagQName, tagIsForNamespaceRule));
247    m_selector->m_relation = CSSSelector::SubSelector;
248}
249
250CSSParserSelector* CSSParserSelector::findDistributedPseudoElementSelector() const
251{
252    CSSParserSelector* selector = const_cast<CSSParserSelector*>(this);
253    do {
254        if (selector->isDistributedPseudoElement())
255            return selector;
256    } while ((selector = selector->tagHistory()));
257    return 0;
258}
259
260} // namespace WebCore
261