Move parseFontFaceDescriptor to CSSPropertyParser.cpp
[chromium-blink-merge.git] / third_party / WebKit / Source / core / xml / XPathNodeSet.cpp
bloba8d96afde270866859a175d856f9f7a4ec04ee2e
1 /*
2 * Copyright (C) 2007 Alexey Proskuryakov <ap@webkit.org>
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * 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.
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
15 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
16 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
17 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
18 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
19 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
20 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
21 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
23 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 #include "config.h"
27 #include "core/xml/XPathNodeSet.h"
29 #include "core/dom/Attr.h"
30 #include "core/dom/Document.h"
31 #include "core/dom/Element.h"
32 #include "core/dom/NodeTraversal.h"
34 namespace blink {
35 namespace XPath {
37 // When a node set is large, sorting it by traversing the whole document is
38 // better (we can assume that we aren't dealing with documents that we cannot
39 // even traverse in reasonable time).
40 const unsigned traversalSortCutoff = 10000;
42 typedef WillBeHeapVector<RawPtrWillBeMember<Node>> NodeSetVector;
44 NodeSet* NodeSet::create(const NodeSet& other)
46 NodeSet* nodeSet = NodeSet::create();
47 nodeSet->m_isSorted = other.m_isSorted;
48 nodeSet->m_subtreesAreDisjoint = other.m_subtreesAreDisjoint;
49 nodeSet->m_nodes.appendVector(other.m_nodes);
50 return nodeSet;
53 static inline Node* parentWithDepth(unsigned depth, const NodeSetVector& parents)
55 ASSERT(parents.size() >= depth + 1);
56 return parents[parents.size() - 1 - depth];
59 static void sortBlock(unsigned from, unsigned to, WillBeHeapVector<NodeSetVector>& parentMatrix, bool mayContainAttributeNodes)
61 // Should not call this function with less that two nodes to sort.
62 ASSERT(from + 1 < to);
63 unsigned minDepth = UINT_MAX;
64 for (unsigned i = from; i < to; ++i) {
65 unsigned depth = parentMatrix[i].size() - 1;
66 if (minDepth > depth)
67 minDepth = depth;
70 // Find the common ancestor.
71 unsigned commonAncestorDepth = minDepth;
72 Node* commonAncestor;
73 while (true) {
74 commonAncestor = parentWithDepth(commonAncestorDepth, parentMatrix[from]);
75 if (commonAncestorDepth == 0)
76 break;
78 bool allEqual = true;
79 for (unsigned i = from + 1; i < to; ++i) {
80 if (commonAncestor != parentWithDepth(commonAncestorDepth, parentMatrix[i])) {
81 allEqual = false;
82 break;
85 if (allEqual)
86 break;
88 --commonAncestorDepth;
91 if (commonAncestorDepth == minDepth) {
92 // One of the nodes is the common ancestor => it is the first in
93 // document order. Find it and move it to the beginning.
94 for (unsigned i = from; i < to; ++i) {
95 if (commonAncestor == parentMatrix[i][0]) {
96 parentMatrix[i].swap(parentMatrix[from]);
97 if (from + 2 < to)
98 sortBlock(from + 1, to, parentMatrix, mayContainAttributeNodes);
99 return;
104 if (mayContainAttributeNodes && commonAncestor->isElementNode()) {
105 // The attribute nodes and namespace nodes of an element occur before
106 // the children of the element. The namespace nodes are defined to occur
107 // before the attribute nodes. The relative order of namespace nodes is
108 // implementation-dependent. The relative order of attribute nodes is
109 // implementation-dependent.
110 unsigned sortedEnd = from;
111 // FIXME: namespace nodes are not implemented.
112 for (unsigned i = sortedEnd; i < to; ++i) {
113 Node* n = parentMatrix[i][0];
114 if (n->isAttributeNode() && toAttr(n)->ownerElement() == commonAncestor)
115 parentMatrix[i].swap(parentMatrix[sortedEnd++]);
117 if (sortedEnd != from) {
118 if (to - sortedEnd > 1)
119 sortBlock(sortedEnd, to, parentMatrix, mayContainAttributeNodes);
120 return;
124 // Children nodes of the common ancestor induce a subdivision of our
125 // node-set. Sort it according to this subdivision, and recursively sort
126 // each group.
127 WillBeHeapHashSet<RawPtrWillBeMember<Node>> parentNodes;
128 for (unsigned i = from; i < to; ++i)
129 parentNodes.add(parentWithDepth(commonAncestorDepth + 1, parentMatrix[i]));
131 unsigned previousGroupEnd = from;
132 unsigned groupEnd = from;
133 for (Node* n = commonAncestor->firstChild(); n; n = n->nextSibling()) {
134 // If parentNodes contains the node, perform a linear search to move its
135 // children in the node-set to the beginning.
136 if (parentNodes.contains(n)) {
137 for (unsigned i = groupEnd; i < to; ++i) {
138 if (parentWithDepth(commonAncestorDepth + 1, parentMatrix[i]) == n)
139 parentMatrix[i].swap(parentMatrix[groupEnd++]);
142 if (groupEnd - previousGroupEnd > 1)
143 sortBlock(previousGroupEnd, groupEnd, parentMatrix, mayContainAttributeNodes);
145 ASSERT(previousGroupEnd != groupEnd);
146 previousGroupEnd = groupEnd;
147 #if ENABLE(ASSERT)
148 parentNodes.remove(n);
149 #endif
153 ASSERT(parentNodes.isEmpty());
156 void NodeSet::sort() const
158 if (m_isSorted)
159 return;
161 unsigned nodeCount = m_nodes.size();
162 if (nodeCount < 2) {
163 const_cast<bool&>(m_isSorted) = true;
164 return;
167 if (nodeCount > traversalSortCutoff) {
168 traversalSort();
169 return;
172 bool containsAttributeNodes = false;
174 WillBeHeapVector<NodeSetVector> parentMatrix(nodeCount);
175 for (unsigned i = 0; i < nodeCount; ++i) {
176 NodeSetVector& parentsVector = parentMatrix[i];
177 Node* n = m_nodes[i].get();
178 parentsVector.append(n);
179 if (n->isAttributeNode()) {
180 n = toAttr(n)->ownerElement();
181 parentsVector.append(n);
182 containsAttributeNodes = true;
184 for (n = n->parentNode(); n; n = n->parentNode())
185 parentsVector.append(n);
187 sortBlock(0, nodeCount, parentMatrix, containsAttributeNodes);
189 // It is not possible to just assign the result to m_nodes, because some
190 // nodes may get dereferenced and destroyed.
191 WillBeHeapVector<RefPtrWillBeMember<Node>> sortedNodes;
192 sortedNodes.reserveInitialCapacity(nodeCount);
193 for (unsigned i = 0; i < nodeCount; ++i)
194 sortedNodes.append(parentMatrix[i][0]);
196 const_cast<WillBeHeapVector<RefPtrWillBeMember<Node>>&>(m_nodes).swap(sortedNodes);
199 static Node* findRootNode(Node* node)
201 if (node->isAttributeNode())
202 node = toAttr(node)->ownerElement();
203 if (node->inDocument()) {
204 node = &node->document();
205 } else {
206 while (Node* parent = node->parentNode())
207 node = parent;
209 return node;
212 void NodeSet::traversalSort() const
214 WillBeHeapHashSet<RawPtrWillBeMember<Node>> nodes;
215 bool containsAttributeNodes = false;
217 unsigned nodeCount = m_nodes.size();
218 ASSERT(nodeCount > 1);
219 for (unsigned i = 0; i < nodeCount; ++i) {
220 Node* node = m_nodes[i].get();
221 nodes.add(node);
222 if (node->isAttributeNode())
223 containsAttributeNodes = true;
226 WillBeHeapVector<RefPtrWillBeMember<Node>> sortedNodes;
227 sortedNodes.reserveInitialCapacity(nodeCount);
229 for (Node& n : NodeTraversal::startsAt(findRootNode(m_nodes.first().get()))) {
230 if (nodes.contains(&n))
231 sortedNodes.append(&n);
233 if (!containsAttributeNodes || !n.isElementNode())
234 continue;
236 Element* element = toElement(&n);
237 AttributeCollection attributes = element->attributes();
238 for (auto& attribute : attributes) {
239 RefPtrWillBeRawPtr<Attr> attr = element->attrIfExists(attribute.name());
240 if (attr && nodes.contains(attr.get()))
241 sortedNodes.append(attr);
245 ASSERT(sortedNodes.size() == nodeCount);
246 const_cast<WillBeHeapVector<RefPtrWillBeMember<Node>>&>(m_nodes).swap(sortedNodes);
249 void NodeSet::reverse()
251 if (m_nodes.isEmpty())
252 return;
254 unsigned from = 0;
255 unsigned to = m_nodes.size() - 1;
256 while (from < to) {
257 m_nodes[from].swap(m_nodes[to]);
258 ++from;
259 --to;
263 Node* NodeSet::firstNode() const
265 if (isEmpty())
266 return nullptr;
268 // FIXME: fully sorting the node-set just to find its first node is
269 // wasteful.
270 sort();
271 return m_nodes.at(0).get();
274 Node* NodeSet::anyNode() const
276 if (isEmpty())
277 return nullptr;
279 return m_nodes.at(0).get();