1 /*
2 * Copyright (C) 2008 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
32 namespace WebCore {
33
34 static CSSSelector* const freedSelectorArrayMarker = reinterpret_cast<CSSSelector*>(0xbbadbeef);
35
~CSSSelectorList()36 CSSSelectorList::~CSSSelectorList()
37 {
38 deleteSelectors();
39 }
40
adopt(CSSSelectorList & list)41 void CSSSelectorList::adopt(CSSSelectorList& list)
42 {
43 deleteSelectors();
44 m_selectorArray = list.m_selectorArray;
45 list.m_selectorArray = 0;
46 }
47
adoptSelectorVector(Vector<OwnPtr<CSSParserSelector>> & selectorVector)48 void CSSSelectorList::adoptSelectorVector(Vector<OwnPtr<CSSParserSelector> >& selectorVector)
49 {
50 deleteSelectors();
51 const size_t vectorSize = selectorVector.size();
52 size_t flattenedSize = 0;
53 for (size_t i = 0; i < vectorSize; ++i) {
54 for (CSSParserSelector* selector = selectorVector[i].get(); selector; selector = selector->tagHistory())
55 ++flattenedSize;
56 }
57 ASSERT(flattenedSize);
58 if (flattenedSize == 1) {
59 m_selectorArray = selectorVector[0]->releaseSelector().leakPtr();
60 m_selectorArray->setLastInSelectorList();
61 ASSERT(m_selectorArray->isLastInTagHistory());
62 selectorVector.shrink(0);
63 return;
64 }
65 m_selectorArray = reinterpret_cast<CSSSelector*>(fastMalloc(sizeof(CSSSelector) * flattenedSize));
66 size_t arrayIndex = 0;
67 for (size_t i = 0; i < vectorSize; ++i) {
68 CSSParserSelector* current = selectorVector[i].get();
69 while (current) {
70 OwnPtr<CSSSelector> selector = current->releaseSelector();
71 current = current->tagHistory();
72 move(selector.release(), &m_selectorArray[arrayIndex]);
73 ASSERT(!m_selectorArray[arrayIndex].isLastInSelectorList());
74 if (current)
75 m_selectorArray[arrayIndex].setNotLastInTagHistory();
76 ++arrayIndex;
77 }
78 ASSERT(m_selectorArray[arrayIndex - 1].isLastInTagHistory());
79 }
80 ASSERT(flattenedSize == arrayIndex);
81 m_selectorArray[arrayIndex - 1].setLastInSelectorList();
82 selectorVector.shrink(0);
83 }
84
deleteSelectors()85 void CSSSelectorList::deleteSelectors()
86 {
87 if (!m_selectorArray)
88 return;
89
90 // FIXME: Remove once http://webkit.org/b/56124 is fixed.
91 if (m_selectorArray == freedSelectorArrayMarker)
92 CRASH();
93
94 // We had two cases in adoptSelectVector. The fast case of a 1 element
95 // vector took the CSSSelector directly, which was allocated with new.
96 // The second case we allocated a new fastMalloc buffer, which should be
97 // freed with fastFree, and the destructors called manually.
98 CSSSelector* s = m_selectorArray;
99 bool done = s->isLastInSelectorList();
100 if (done)
101 delete s;
102 else {
103 while (1) {
104 s->~CSSSelector();
105 if (done)
106 break;
107 ++s;
108 done = s->isLastInSelectorList();
109 }
110 fastFree(m_selectorArray);
111 }
112
113 m_selectorArray = freedSelectorArrayMarker;
114 }
115
116
117 template <typename Functor>
forEachTagSelector(Functor & functor,CSSSelector * selector)118 static bool forEachTagSelector(Functor& functor, CSSSelector* selector)
119 {
120 ASSERT(selector);
121
122 do {
123 if (functor(selector))
124 return true;
125 if (CSSSelectorList* selectorList = selector->selectorList()) {
126 for (CSSSelector* subSelector = selectorList->first(); subSelector; subSelector = CSSSelectorList::next(subSelector)) {
127 if (forEachTagSelector(functor, subSelector))
128 return true;
129 }
130 }
131 } while ((selector = selector->tagHistory()));
132
133 return false;
134 }
135
136 template <typename Functor>
forEachSelector(Functor & functor,const CSSSelectorList * selectorList)137 static bool forEachSelector(Functor& functor, const CSSSelectorList* selectorList)
138 {
139 for (CSSSelector* selector = selectorList->first(); selector; selector = CSSSelectorList::next(selector)) {
140 if (forEachTagSelector(functor, selector))
141 return true;
142 }
143
144 return false;
145 }
146
147 class SelectorNeedsNamespaceResolutionFunctor {
148 public:
operator ()(CSSSelector * selector)149 bool operator()(CSSSelector* selector)
150 {
151 if (selector->hasTag() && selector->tag().prefix() != nullAtom && selector->tag().prefix() != starAtom)
152 return true;
153 if (selector->hasAttribute() && selector->attribute().prefix() != nullAtom && selector->attribute().prefix() != starAtom)
154 return true;
155 return false;
156 }
157 };
158
selectorsNeedNamespaceResolution()159 bool CSSSelectorList::selectorsNeedNamespaceResolution()
160 {
161 SelectorNeedsNamespaceResolutionFunctor functor;
162 return forEachSelector(functor, this);
163 }
164
165 class SelectorHasUnknownPseudoElementFunctor {
166 public:
operator ()(CSSSelector * selector)167 bool operator()(CSSSelector* selector)
168 {
169 return selector->isUnknownPseudoElement();
170 }
171 };
172
hasUnknownPseudoElements() const173 bool CSSSelectorList::hasUnknownPseudoElements() const
174 {
175 SelectorHasUnknownPseudoElementFunctor functor;
176 return forEachSelector(functor, this);
177 }
178
179
180
181 } // namespace WebCore
182