1 /*
2  * Copyright (C) 2007 Alexey Proskuryakov <ap@webkit.org>
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  *
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 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.
24  */
25 
26 #include "third_party/blink/renderer/core/xml/xpath_node_set.h"
27 
28 #include "third_party/blink/renderer/core/dom/attr.h"
29 #include "third_party/blink/renderer/core/dom/document.h"
30 #include "third_party/blink/renderer/core/dom/element.h"
31 #include "third_party/blink/renderer/core/dom/node_traversal.h"
32 
33 namespace blink {
34 namespace xpath {
35 
36 // When a node set is large, sorting it by traversing the whole document is
37 // better (we can assume that we aren't dealing with documents that we cannot
38 // even traverse in reasonable time).
39 const unsigned kTraversalSortCutoff = 10000;
40 
41 typedef HeapVector<Member<Node>> NodeSetVector;
42 
Create(const NodeSet & other)43 NodeSet* NodeSet::Create(const NodeSet& other) {
44   NodeSet* node_set = NodeSet::Create();
45   node_set->is_sorted_ = other.is_sorted_;
46   node_set->subtrees_are_disjoint_ = other.subtrees_are_disjoint_;
47   node_set->nodes_.AppendVector(other.nodes_);
48   return node_set;
49 }
50 
ParentWithDepth(unsigned depth,const NodeSetVector & parents)51 static inline Node* ParentWithDepth(unsigned depth,
52                                     const NodeSetVector& parents) {
53   DCHECK_GE(parents.size(), depth + 1);
54   return parents[parents.size() - 1 - depth];
55 }
56 
SortBlock(unsigned from,unsigned to,HeapVector<NodeSetVector> & parent_matrix,bool may_contain_attribute_nodes)57 static void SortBlock(unsigned from,
58                       unsigned to,
59                       HeapVector<NodeSetVector>& parent_matrix,
60                       bool may_contain_attribute_nodes) {
61   // Should not call this function with less that two nodes to sort.
62   DCHECK_LT(from + 1, to);
63   unsigned min_depth = UINT_MAX;
64   for (unsigned i = from; i < to; ++i) {
65     unsigned depth = parent_matrix[i].size() - 1;
66     if (min_depth > depth)
67       min_depth = depth;
68   }
69 
70   // Find the common ancestor.
71   unsigned common_ancestor_depth = min_depth;
72   Node* common_ancestor;
73   while (true) {
74     common_ancestor =
75         ParentWithDepth(common_ancestor_depth, parent_matrix[from]);
76     if (common_ancestor_depth == 0)
77       break;
78 
79     bool all_equal = true;
80     for (unsigned i = from + 1; i < to; ++i) {
81       if (common_ancestor !=
82           ParentWithDepth(common_ancestor_depth, parent_matrix[i])) {
83         all_equal = false;
84         break;
85       }
86     }
87     if (all_equal)
88       break;
89 
90     --common_ancestor_depth;
91   }
92 
93   if (common_ancestor_depth == min_depth) {
94     // One of the nodes is the common ancestor => it is the first in
95     // document order. Find it and move it to the beginning.
96     for (unsigned i = from; i < to; ++i) {
97       if (common_ancestor == parent_matrix[i][0]) {
98         parent_matrix[i].swap(parent_matrix[from]);
99         if (from + 2 < to)
100           SortBlock(from + 1, to, parent_matrix, may_contain_attribute_nodes);
101         return;
102       }
103     }
104   }
105 
106   if (may_contain_attribute_nodes && common_ancestor->IsElementNode()) {
107     // The attribute nodes and namespace nodes of an element occur before
108     // the children of the element. The namespace nodes are defined to occur
109     // before the attribute nodes. The relative order of namespace nodes is
110     // implementation-dependent. The relative order of attribute nodes is
111     // implementation-dependent.
112     unsigned sorted_end = from;
113     // FIXME: namespace nodes are not implemented.
114     for (unsigned i = sorted_end; i < to; ++i) {
115       Node* n = parent_matrix[i][0];
116       auto* attr = DynamicTo<Attr>(n);
117       if (attr && attr->ownerElement() == common_ancestor)
118         parent_matrix[i].swap(parent_matrix[sorted_end++]);
119     }
120     if (sorted_end != from) {
121       if (to - sorted_end > 1)
122         SortBlock(sorted_end, to, parent_matrix, may_contain_attribute_nodes);
123       return;
124     }
125   }
126 
127   // Children nodes of the common ancestor induce a subdivision of our
128   // node-set. Sort it according to this subdivision, and recursively sort
129   // each group.
130   HeapHashSet<Member<Node>> parent_nodes;
131   for (unsigned i = from; i < to; ++i)
132     parent_nodes.insert(
133         ParentWithDepth(common_ancestor_depth + 1, parent_matrix[i]));
134 
135   unsigned previous_group_end = from;
136   unsigned group_end = from;
137   for (Node* n = common_ancestor->firstChild(); n; n = n->nextSibling()) {
138     // If parentNodes contains the node, perform a linear search to move its
139     // children in the node-set to the beginning.
140     if (parent_nodes.Contains(n)) {
141       for (unsigned i = group_end; i < to; ++i) {
142         if (ParentWithDepth(common_ancestor_depth + 1, parent_matrix[i]) == n)
143           parent_matrix[i].swap(parent_matrix[group_end++]);
144       }
145 
146       if (group_end - previous_group_end > 1)
147         SortBlock(previous_group_end, group_end, parent_matrix,
148                   may_contain_attribute_nodes);
149 
150       DCHECK_NE(previous_group_end, group_end);
151       previous_group_end = group_end;
152 #if DCHECK_IS_ON()
153       parent_nodes.erase(n);
154 #endif
155     }
156   }
157 
158   DCHECK(parent_nodes.IsEmpty());
159 }
160 
Sort() const161 void NodeSet::Sort() const {
162   if (is_sorted_)
163     return;
164 
165   unsigned node_count = nodes_.size();
166   if (node_count < 2) {
167     const_cast<bool&>(is_sorted_) = true;
168     return;
169   }
170 
171   if (node_count > kTraversalSortCutoff) {
172     TraversalSort();
173     return;
174   }
175 
176   bool contains_attribute_nodes = false;
177 
178   HeapVector<NodeSetVector> parent_matrix(node_count);
179   for (unsigned i = 0; i < node_count; ++i) {
180     NodeSetVector& parents_vector = parent_matrix[i];
181     Node* n = nodes_[i].Get();
182     parents_vector.push_back(n);
183     if (auto* attr = DynamicTo<Attr>(n)) {
184       n = attr->ownerElement();
185       parents_vector.push_back(n);
186       contains_attribute_nodes = true;
187     }
188     for (n = n->parentNode(); n; n = n->parentNode())
189       parents_vector.push_back(n);
190   }
191   SortBlock(0, node_count, parent_matrix, contains_attribute_nodes);
192 
193   // It is not possible to just assign the result to m_nodes, because some
194   // nodes may get dereferenced and destroyed.
195   HeapVector<Member<Node>> sorted_nodes;
196   sorted_nodes.ReserveInitialCapacity(node_count);
197   for (unsigned i = 0; i < node_count; ++i)
198     sorted_nodes.push_back(parent_matrix[i][0]);
199 
200   const_cast<HeapVector<Member<Node>>&>(nodes_).swap(sorted_nodes);
201 }
202 
FindRootNode(Node * node)203 static Node* FindRootNode(Node* node) {
204   if (auto* attr = DynamicTo<Attr>(node))
205     node = attr->ownerElement();
206   if (node->isConnected()) {
207     node = &node->GetDocument();
208   } else {
209     while (Node* parent = node->parentNode())
210       node = parent;
211   }
212   return node;
213 }
214 
TraversalSort() const215 void NodeSet::TraversalSort() const {
216   HeapHashSet<Member<Node>> nodes;
217   bool contains_attribute_nodes = false;
218 
219   unsigned node_count = nodes_.size();
220   DCHECK_GT(node_count, 1u);
221   for (unsigned i = 0; i < node_count; ++i) {
222     Node* node = nodes_[i].Get();
223     nodes.insert(node);
224     if (node->IsAttributeNode())
225       contains_attribute_nodes = true;
226   }
227 
228   HeapVector<Member<Node>> sorted_nodes;
229   sorted_nodes.ReserveInitialCapacity(node_count);
230 
231   for (Node& n : NodeTraversal::StartsAt(*FindRootNode(nodes_.front()))) {
232     if (nodes.Contains(&n))
233       sorted_nodes.push_back(&n);
234 
235     auto* element = DynamicTo<Element>(&n);
236     if (!element || !contains_attribute_nodes)
237       continue;
238 
239     AttributeCollection attributes = element->Attributes();
240     for (auto& attribute : attributes) {
241       Attr* attr = element->AttrIfExists(attribute.GetName());
242       if (attr && nodes.Contains(attr))
243         sorted_nodes.push_back(attr);
244     }
245   }
246 
247   DCHECK_EQ(sorted_nodes.size(), node_count);
248   const_cast<HeapVector<Member<Node>>&>(nodes_).swap(sorted_nodes);
249 }
250 
Reverse()251 void NodeSet::Reverse() {
252   if (nodes_.IsEmpty())
253     return;
254 
255   unsigned from = 0;
256   unsigned to = nodes_.size() - 1;
257   while (from < to) {
258     nodes_[from].Swap(nodes_[to]);
259     ++from;
260     --to;
261   }
262 }
263 
FirstNode() const264 Node* NodeSet::FirstNode() const {
265   if (IsEmpty())
266     return nullptr;
267 
268   // FIXME: fully sorting the node-set just to find its first node is
269   // wasteful.
270   Sort();
271   return nodes_.at(0).Get();
272 }
273 
AnyNode() const274 Node* NodeSet::AnyNode() const {
275   if (IsEmpty())
276     return nullptr;
277 
278   return nodes_.at(0).Get();
279 }
280 
281 }  // namespace xpath
282 }  // namespace blink
283