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