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