a675d1a9927be2483eeeaa1c0dbe8060a4c5774f
[WebKit-https.git] / Source / WebCore / css / CSSSelectorList.cpp
1 /*
2  * Copyright (C) 2008, 2012, 2013 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
33 namespace WebCore {
34
35 CSSSelectorList::~CSSSelectorList()
36 {
37     deleteSelectors();
38 }
39
40 CSSSelectorList::CSSSelectorList(const CSSSelectorList& other)
41 {
42     unsigned otherComponentCount = other.componentCount();
43     m_selectorArray = reinterpret_cast<CSSSelector*>(fastMalloc(sizeof(CSSSelector) * otherComponentCount));
44     for (unsigned i = 0; i < otherComponentCount; ++i)
45         new (NotNull, &m_selectorArray[i]) CSSSelector(other.m_selectorArray[i]);
46 }
47
48 void CSSSelectorList::adopt(CSSSelectorList& list)
49 {
50     deleteSelectors();
51     m_selectorArray = list.m_selectorArray;
52     list.m_selectorArray = 0;
53 }
54
55 void CSSSelectorList::adoptSelectorVector(Vector<std::unique_ptr<CSSParserSelector>>& selectorVector)
56 {
57     deleteSelectors();
58     size_t flattenedSize = 0;
59     for (size_t i = 0; i < selectorVector.size(); ++i) {
60         for (CSSParserSelector* selector = selectorVector[i].get(); selector; selector = selector->tagHistory())
61             ++flattenedSize;
62     }
63     ASSERT(flattenedSize);
64     m_selectorArray = reinterpret_cast<CSSSelector*>(fastMalloc(sizeof(CSSSelector) * flattenedSize));
65     size_t arrayIndex = 0;
66     for (size_t i = 0; i < selectorVector.size(); ++i) {
67         CSSParserSelector* current = selectorVector[i].get();
68         while (current) {
69             {
70                 // Move item from the parser selector vector into m_selectorArray without invoking destructor (Ugh.)
71                 CSSSelector* currentSelector = current->releaseSelector().release();
72                 memcpy(&m_selectorArray[arrayIndex], currentSelector, sizeof(CSSSelector));
73
74                 // Free the underlying memory without invoking the destructor.
75                 operator delete (currentSelector);
76             }
77             current = current->tagHistory();
78             ASSERT(!m_selectorArray[arrayIndex].isLastInSelectorList());
79             if (current)
80                 m_selectorArray[arrayIndex].setNotLastInTagHistory();
81             ++arrayIndex;
82         }
83         ASSERT(m_selectorArray[arrayIndex - 1].isLastInTagHistory());
84     }
85     ASSERT(flattenedSize == arrayIndex);
86     m_selectorArray[arrayIndex - 1].setLastInSelectorList();
87     selectorVector.clear();
88 }
89
90 unsigned CSSSelectorList::componentCount() const
91 {
92     if (!m_selectorArray)
93         return 0;
94     CSSSelector* current = m_selectorArray;
95     while (!current->isLastInSelectorList())
96         ++current;
97     return (current - m_selectorArray) + 1;
98 }
99
100 void CSSSelectorList::deleteSelectors()
101 {
102     if (!m_selectorArray)
103         return;
104
105     for (CSSSelector* s = m_selectorArray; ; ++s) {
106         s->~CSSSelector();
107         if (s->isLastInSelectorList())
108             break;
109     }
110     fastFree(m_selectorArray);
111 }
112
113 String CSSSelectorList::selectorsText() const
114 {
115     StringBuilder result;
116
117     for (const CSSSelector* s = first(); s; s = next(s)) {
118         if (s != first())
119             result.append(", ");
120         result.append(s->selectorText());
121     }
122
123     return result.toString();
124 }
125
126 template <typename Functor>
127 static bool forEachTagSelector(Functor& functor, const CSSSelector* selector)
128 {
129     ASSERT(selector);
130
131     do {
132         if (functor(selector))
133             return true;
134         if (const CSSSelectorList* selectorList = selector->selectorList()) {
135             for (const CSSSelector* subSelector = selectorList->first(); subSelector; subSelector = CSSSelectorList::next(subSelector)) {
136                 if (forEachTagSelector(functor, subSelector))
137                     return true;
138             }
139         }
140     } while ((selector = selector->tagHistory()));
141
142     return false;
143 }
144
145 template <typename Functor>
146 static bool forEachSelector(Functor& functor, const CSSSelectorList* selectorList)
147 {
148     for (const CSSSelector* selector = selectorList->first(); selector; selector = CSSSelectorList::next(selector)) {
149         if (forEachTagSelector(functor, selector))
150             return true;
151     }
152
153     return false;
154 }
155
156 class SelectorNeedsNamespaceResolutionFunctor {
157 public:
158     bool operator()(const CSSSelector* selector)
159     {
160         if (selector->m_match == CSSSelector::Tag && selector->tagQName().prefix() != nullAtom && selector->tagQName().prefix() != starAtom)
161             return true;
162         if (selector->isAttributeSelector() && selector->attribute().prefix() != nullAtom && selector->attribute().prefix() != starAtom)
163             return true;
164         return false;
165     }
166 };
167
168 bool CSSSelectorList::selectorsNeedNamespaceResolution()
169 {
170     SelectorNeedsNamespaceResolutionFunctor functor;
171     return forEachSelector(functor, this);
172 }
173
174 class SelectorHasInvalidSelectorFunctor {
175 public:
176     bool operator()(const CSSSelector* selector)
177     {
178         return selector->isUnknownPseudoElement() || selector->isCustomPseudoElement();
179     }
180 };
181
182 bool CSSSelectorList::hasInvalidSelector() const
183 {
184     SelectorHasInvalidSelectorFunctor functor;
185     return forEachSelector(functor, this);
186 }
187
188 } // namespace WebCore