1/*
2 * Copyright (C) 2008, 2012, 2013, 2014 Apple Inc. All rights reserved.
3 * Copyright (C) 2009 Google Inc. All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 *    notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 *    notice, this list of conditions and the following disclaimer in the
12 *    documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
15 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
17 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
18 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
19 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
20 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
21 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
22 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
24 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25 */
26
27#include "config.h"
28#include "CSSSelectorList.h"
29
30#include "CSSParserValues.h"
31#include <wtf/text/StringBuilder.h>
32
33namespace WebCore {
34
35CSSSelectorList::CSSSelectorList(const CSSSelectorList& other)
36{
37    unsigned otherComponentCount = other.componentCount();
38    ASSERT_WITH_SECURITY_IMPLICATION(otherComponentCount);
39
40    m_selectorArray = reinterpret_cast<CSSSelector*>(fastMalloc(sizeof(CSSSelector) * otherComponentCount));
41    for (unsigned i = 0; i < otherComponentCount; ++i)
42        new (NotNull, &m_selectorArray[i]) CSSSelector(other.m_selectorArray[i]);
43}
44
45CSSSelectorList::CSSSelectorList(CSSSelectorList&& other)
46    : m_selectorArray(other.m_selectorArray)
47{
48    ASSERT_WITH_SECURITY_IMPLICATION(componentCount());
49    other.m_selectorArray = nullptr;
50}
51
52void CSSSelectorList::adoptSelectorVector(Vector<std::unique_ptr<CSSParserSelector>>& selectorVector)
53{
54    ASSERT_WITH_SECURITY_IMPLICATION(!selectorVector.isEmpty());
55
56    deleteSelectors();
57    size_t flattenedSize = 0;
58    for (size_t i = 0; i < selectorVector.size(); ++i) {
59        for (CSSParserSelector* selector = selectorVector[i].get(); selector; selector = selector->tagHistory())
60            ++flattenedSize;
61    }
62    ASSERT(flattenedSize);
63    m_selectorArray = reinterpret_cast<CSSSelector*>(fastMalloc(sizeof(CSSSelector) * flattenedSize));
64    size_t arrayIndex = 0;
65    for (size_t i = 0; i < selectorVector.size(); ++i) {
66        CSSParserSelector* current = selectorVector[i].get();
67        while (current) {
68            {
69                // Move item from the parser selector vector into m_selectorArray without invoking destructor (Ugh.)
70                CSSSelector* currentSelector = current->releaseSelector().release();
71                memcpy(&m_selectorArray[arrayIndex], currentSelector, sizeof(CSSSelector));
72
73                // Free the underlying memory without invoking the destructor.
74                operator delete (currentSelector);
75            }
76            current = current->tagHistory();
77            ASSERT(!m_selectorArray[arrayIndex].isLastInSelectorList());
78            if (current)
79                m_selectorArray[arrayIndex].setNotLastInTagHistory();
80            ++arrayIndex;
81        }
82        ASSERT(m_selectorArray[arrayIndex - 1].isLastInTagHistory());
83    }
84    ASSERT(flattenedSize == arrayIndex);
85    m_selectorArray[arrayIndex - 1].setLastInSelectorList();
86    selectorVector.clear();
87}
88
89unsigned CSSSelectorList::componentCount() const
90{
91    if (!m_selectorArray)
92        return 0;
93    CSSSelector* current = m_selectorArray;
94    while (!current->isLastInSelectorList())
95        ++current;
96    return (current - m_selectorArray) + 1;
97}
98
99CSSSelectorList& CSSSelectorList::operator=(CSSSelectorList&& other)
100{
101    deleteSelectors();
102    m_selectorArray = other.m_selectorArray;
103    other.m_selectorArray = nullptr;
104
105    ASSERT_WITH_SECURITY_IMPLICATION(componentCount());
106    return *this;
107}
108
109void CSSSelectorList::deleteSelectors()
110{
111    if (!m_selectorArray)
112        return;
113
114    for (CSSSelector* s = m_selectorArray; ; ++s) {
115        s->~CSSSelector();
116        if (s->isLastInSelectorList())
117            break;
118    }
119    fastFree(m_selectorArray);
120}
121
122String CSSSelectorList::selectorsText() const
123{
124    StringBuilder result;
125
126    for (const CSSSelector* s = first(); s; s = next(s)) {
127        if (s != first())
128            result.append(", ");
129        result.append(s->selectorText());
130    }
131
132    return result.toString();
133}
134
135template <typename Functor>
136static bool forEachTagSelector(Functor& functor, const CSSSelector* selector)
137{
138    ASSERT(selector);
139
140    do {
141        if (functor(selector))
142            return true;
143        if (const CSSSelectorList* selectorList = selector->selectorList()) {
144            for (const CSSSelector* subSelector = selectorList->first(); subSelector; subSelector = CSSSelectorList::next(subSelector)) {
145                if (forEachTagSelector(functor, subSelector))
146                    return true;
147            }
148        }
149    } while ((selector = selector->tagHistory()));
150
151    return false;
152}
153
154template <typename Functor>
155static bool forEachSelector(Functor& functor, const CSSSelectorList* selectorList)
156{
157    for (const CSSSelector* selector = selectorList->first(); selector; selector = CSSSelectorList::next(selector)) {
158        if (forEachTagSelector(functor, selector))
159            return true;
160    }
161
162    return false;
163}
164
165class SelectorNeedsNamespaceResolutionFunctor {
166public:
167    bool operator()(const CSSSelector* selector)
168    {
169        if (selector->m_match == CSSSelector::Tag && selector->tagQName().prefix() != nullAtom && selector->tagQName().prefix() != starAtom)
170            return true;
171        if (selector->isAttributeSelector() && selector->attribute().prefix() != nullAtom && selector->attribute().prefix() != starAtom)
172            return true;
173        return false;
174    }
175};
176
177bool CSSSelectorList::selectorsNeedNamespaceResolution()
178{
179    SelectorNeedsNamespaceResolutionFunctor functor;
180    return forEachSelector(functor, this);
181}
182
183class SelectorHasInvalidSelectorFunctor {
184public:
185    bool operator()(const CSSSelector* selector)
186    {
187        return selector->isUnknownPseudoElement() || selector->isCustomPseudoElement();
188    }
189};
190
191bool CSSSelectorList::hasInvalidSelector() const
192{
193    SelectorHasInvalidSelectorFunctor functor;
194    return forEachSelector(functor, this);
195}
196
197} // namespace WebCore
198