1 /*
2 * Copyright (C) 2008, 2012 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 "core/css/CSSSelectorList.h"
29
30 #include "core/css/parser/CSSParserValues.h"
31 #include "wtf/text/StringBuilder.h"
32
33 namespace blink {
34
~CSSSelectorList()35 CSSSelectorList::~CSSSelectorList()
36 {
37 deleteSelectors();
38 }
39
CSSSelectorList(const CSSSelectorList & other)40 CSSSelectorList::CSSSelectorList(const CSSSelectorList& other)
41 {
42 unsigned otherLength = other.length();
43 m_selectorArray = reinterpret_cast<CSSSelector*>(fastMalloc(sizeof(CSSSelector) * otherLength));
44 for (unsigned i = 0; i < otherLength; ++i)
45 new (&m_selectorArray[i]) CSSSelector(other.m_selectorArray[i]);
46 }
47
adopt(CSSSelectorList & list)48 void CSSSelectorList::adopt(CSSSelectorList& list)
49 {
50 deleteSelectors();
51 m_selectorArray = list.m_selectorArray;
52 list.m_selectorArray = 0;
53 }
54
adoptSelectorVector(Vector<OwnPtr<CSSParserSelector>> & selectorVector)55 void CSSSelectorList::adoptSelectorVector(Vector<OwnPtr<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 // Move item from the parser selector vector into m_selectorArray without invoking destructor (Ugh.)
70 CSSSelector* currentSelector = current->releaseSelector().leakPtr();
71 memcpy(&m_selectorArray[arrayIndex], currentSelector, sizeof(CSSSelector));
72 fastFree(currentSelector);
73
74 current = current->tagHistory();
75 ASSERT(!m_selectorArray[arrayIndex].isLastInSelectorList());
76 if (current)
77 m_selectorArray[arrayIndex].setNotLastInTagHistory();
78 ++arrayIndex;
79 }
80 ASSERT(m_selectorArray[arrayIndex - 1].isLastInTagHistory());
81 }
82 ASSERT(flattenedSize == arrayIndex);
83 m_selectorArray[arrayIndex - 1].setLastInSelectorList();
84 selectorVector.clear();
85 }
86
length() const87 unsigned CSSSelectorList::length() const
88 {
89 if (!m_selectorArray)
90 return 0;
91 CSSSelector* current = m_selectorArray;
92 while (!current->isLastInSelectorList())
93 ++current;
94 return (current - m_selectorArray) + 1;
95 }
96
deleteSelectors()97 void CSSSelectorList::deleteSelectors()
98 {
99 if (!m_selectorArray)
100 return;
101
102 bool finished = false;
103 for (CSSSelector* s = m_selectorArray; !finished; ++s) {
104 finished = s->isLastInSelectorList();
105 s->~CSSSelector();
106 }
107
108 fastFree(m_selectorArray);
109 }
110
selectorsText() const111 String CSSSelectorList::selectorsText() const
112 {
113 StringBuilder result;
114
115 for (const CSSSelector* s = first(); s; s = next(*s)) {
116 if (s != first())
117 result.appendLiteral(", ");
118 result.append(s->selectorText());
119 }
120
121 return result.toString();
122 }
123
124 template <typename Functor>
forEachTagSelector(Functor & functor,const CSSSelector & selector)125 static bool forEachTagSelector(Functor& functor, const CSSSelector& selector)
126 {
127 for (const CSSSelector* current = &selector; current; current = current->tagHistory()) {
128 if (functor(*current))
129 return true;
130 if (const CSSSelectorList* selectorList = current->selectorList()) {
131 for (const CSSSelector* subSelector = selectorList->first(); subSelector; subSelector = CSSSelectorList::next(*subSelector)) {
132 if (forEachTagSelector(functor, *subSelector))
133 return true;
134 }
135 }
136 }
137
138 return false;
139 }
140
141 template <typename Functor>
forEachSelector(Functor & functor,const CSSSelectorList * selectorList)142 static bool forEachSelector(Functor& functor, const CSSSelectorList* selectorList)
143 {
144 for (const CSSSelector* selector = selectorList->first(); selector; selector = CSSSelectorList::next(*selector)) {
145 if (forEachTagSelector(functor, *selector))
146 return true;
147 }
148
149 return false;
150 }
151
152 class SelectorNeedsNamespaceResolutionFunctor {
153 public:
operator ()(const CSSSelector & selector)154 bool operator()(const CSSSelector& selector)
155 {
156 if (selector.match() == CSSSelector::Tag && selector.tagQName().prefix() != nullAtom && selector.tagQName().prefix() != starAtom)
157 return true;
158 if (selector.isAttributeSelector() && selector.attribute().prefix() != nullAtom && selector.attribute().prefix() != starAtom)
159 return true;
160 return false;
161 }
162 };
163
selectorsNeedNamespaceResolution()164 bool CSSSelectorList::selectorsNeedNamespaceResolution()
165 {
166 SelectorNeedsNamespaceResolutionFunctor functor;
167 return forEachSelector(functor, this);
168 }
169
170 class SelectorHasShadowDistributed {
171 public:
operator ()(const CSSSelector & selector)172 bool operator()(const CSSSelector& selector)
173 {
174 return selector.relationIsAffectedByPseudoContent();
175 }
176 };
177
hasShadowDistributedAt(size_t index) const178 bool CSSSelectorList::hasShadowDistributedAt(size_t index) const
179 {
180 SelectorHasShadowDistributed functor;
181 return forEachTagSelector(functor, selectorAt(index));
182 }
183
184 class SelectorCrossesTreeScopes {
185 public:
operator ()(const CSSSelector & selector)186 bool operator()(const CSSSelector& selector)
187 {
188 return selector.relation() == CSSSelector::ShadowDeep || selector.isShadowPseudoElement();
189 }
190 };
191
selectorCrossesTreeScopes(size_t index) const192 bool CSSSelectorList::selectorCrossesTreeScopes(size_t index) const
193 {
194 SelectorCrossesTreeScopes functor;
195 return forEachTagSelector(functor, selectorAt(index));
196 }
197
198 } // namespace blink
199