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