1 /* 2 * Copyright (C) 2005 Frerich Raabe <raabe (at) kde.org> 3 * Copyright (C) 2006, 2009 Apple Inc. 4 * Copyright (C) 2007 Alexey Proskuryakov <ap (at) webkit.org> 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 17 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 18 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 19 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 20 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 21 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 22 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 23 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 25 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 */ 27 28 #include "config.h" 29 #include "core/xml/XPathPath.h" 30 31 #include "core/dom/Document.h" 32 #include "core/dom/NodeTraversal.h" 33 #include "core/xml/XPathPredicate.h" 34 #include "core/xml/XPathStep.h" 35 #include "core/xml/XPathValue.h" 36 37 namespace blink { 38 namespace XPath { 39 40 Filter::Filter(PassOwnPtrWillBeRawPtr<Expression> expr, WillBeHeapVector<OwnPtrWillBeMember<Predicate> >& predicates) 41 : m_expr(expr) 42 { 43 m_predicates.swap(predicates); 44 setIsContextNodeSensitive(m_expr->isContextNodeSensitive()); 45 setIsContextPositionSensitive(m_expr->isContextPositionSensitive()); 46 setIsContextSizeSensitive(m_expr->isContextSizeSensitive()); 47 } 48 49 Filter::~Filter() 50 { 51 } 52 53 void Filter::trace(Visitor* visitor) 54 { 55 visitor->trace(m_expr); 56 visitor->trace(m_predicates); 57 Expression::trace(visitor); 58 } 59 60 Value Filter::evaluate(EvaluationContext& evaluationContext) const 61 { 62 Value v = m_expr->evaluate(evaluationContext); 63 64 NodeSet& nodes = v.modifiableNodeSet(evaluationContext); 65 nodes.sort(); 66 67 for (unsigned i = 0; i < m_predicates.size(); i++) { 68 OwnPtrWillBeRawPtr<NodeSet> newNodes(NodeSet::create()); 69 evaluationContext.size = nodes.size(); 70 evaluationContext.position = 0; 71 72 for (unsigned j = 0; j < nodes.size(); j++) { 73 Node* node = nodes[j]; 74 75 evaluationContext.node = node; 76 ++evaluationContext.position; 77 78 if (m_predicates[i]->evaluate(evaluationContext)) 79 newNodes->append(node); 80 } 81 nodes.swap(*newNodes); 82 } 83 84 return v; 85 } 86 87 LocationPath::LocationPath() 88 : m_absolute(false) 89 { 90 setIsContextNodeSensitive(true); 91 } 92 93 LocationPath::~LocationPath() 94 { 95 #if !ENABLE(OILPAN) 96 deleteAllValues(m_steps); 97 #endif 98 } 99 100 void LocationPath::trace(Visitor* visitor) 101 { 102 #if ENABLE(OILPAN) 103 visitor->trace(m_steps); 104 #endif 105 Expression::trace(visitor); 106 } 107 108 Value LocationPath::evaluate(EvaluationContext& evaluationContext) const 109 { 110 EvaluationContext clonedContext = evaluationContext; 111 // http://www.w3.org/TR/xpath/ 112 // Section 2, Location Paths: 113 // "/ selects the document root (which is always the parent of the document element)" 114 // "A / by itself selects the root node of the document containing the context node." 115 // In the case of a tree that is detached from the document, we violate 116 // the spec and treat / as the root node of the detached tree. 117 // This is for compatibility with Firefox, and also seems like a more 118 // logical treatment of where you would expect the "root" to be. 119 Node* context = evaluationContext.node.get(); 120 if (m_absolute && context->nodeType() != Node::DOCUMENT_NODE) { 121 if (context->inDocument()) 122 context = context->ownerDocument(); 123 else 124 context = &NodeTraversal::highestAncestorOrSelf(*context); 125 } 126 127 OwnPtrWillBeRawPtr<NodeSet> nodes(NodeSet::create()); 128 nodes->append(context); 129 evaluate(clonedContext, *nodes); 130 131 return Value(nodes.release(), Value::adopt); 132 } 133 134 void LocationPath::evaluate(EvaluationContext& context, NodeSet& nodes) const 135 { 136 bool resultIsSorted = nodes.isSorted(); 137 138 for (unsigned i = 0; i < m_steps.size(); i++) { 139 Step* step = m_steps[i]; 140 OwnPtrWillBeRawPtr<NodeSet> newNodes(NodeSet::create()); 141 WillBeHeapHashSet<RawPtrWillBeMember<Node> > newNodesSet; 142 143 bool needToCheckForDuplicateNodes = !nodes.subtreesAreDisjoint() || (step->axis() != Step::ChildAxis && step->axis() != Step::SelfAxis 144 && step->axis() != Step::DescendantAxis && step->axis() != Step::DescendantOrSelfAxis && step->axis() != Step::AttributeAxis); 145 146 if (needToCheckForDuplicateNodes) 147 resultIsSorted = false; 148 149 // This is a simplified check that can be improved to handle more cases. 150 if (nodes.subtreesAreDisjoint() && (step->axis() == Step::ChildAxis || step->axis() == Step::SelfAxis)) 151 newNodes->markSubtreesDisjoint(true); 152 153 for (unsigned j = 0; j < nodes.size(); j++) { 154 OwnPtrWillBeRawPtr<NodeSet> matches(NodeSet::create()); 155 step->evaluate(context, nodes[j], *matches); 156 157 if (!matches->isSorted()) 158 resultIsSorted = false; 159 160 for (size_t nodeIndex = 0; nodeIndex < matches->size(); ++nodeIndex) { 161 Node* node = (*matches)[nodeIndex]; 162 if (!needToCheckForDuplicateNodes || newNodesSet.add(node).isNewEntry) 163 newNodes->append(node); 164 } 165 } 166 167 nodes.swap(*newNodes); 168 } 169 170 nodes.markSorted(resultIsSorted); 171 } 172 173 void LocationPath::appendStep(Step* step) 174 { 175 unsigned stepCount = m_steps.size(); 176 if (stepCount) { 177 bool dropSecondStep; 178 optimizeStepPair(m_steps[stepCount - 1], step, dropSecondStep); 179 if (dropSecondStep) { 180 #if !ENABLE(OILPAN) 181 delete step; 182 #endif 183 return; 184 } 185 } 186 step->optimize(); 187 m_steps.append(step); 188 } 189 190 void LocationPath::insertFirstStep(Step* step) 191 { 192 if (m_steps.size()) { 193 bool dropSecondStep; 194 optimizeStepPair(step, m_steps[0], dropSecondStep); 195 if (dropSecondStep) { 196 #if !ENABLE(OILPAN) 197 delete m_steps[0]; 198 #endif 199 m_steps[0] = step; 200 return; 201 } 202 } 203 step->optimize(); 204 m_steps.insert(0, step); 205 } 206 207 Path::Path(Expression* filter, LocationPath* path) 208 : m_filter(adoptPtrWillBeNoop(filter)) 209 , m_path(adoptPtrWillBeNoop(path)) 210 { 211 setIsContextNodeSensitive(filter->isContextNodeSensitive()); 212 setIsContextPositionSensitive(filter->isContextPositionSensitive()); 213 setIsContextSizeSensitive(filter->isContextSizeSensitive()); 214 } 215 216 Path::~Path() 217 { 218 } 219 220 void Path::trace(Visitor* visitor) 221 { 222 visitor->trace(m_filter); 223 visitor->trace(m_path); 224 Expression::trace(visitor); 225 } 226 227 Value Path::evaluate(EvaluationContext& context) const 228 { 229 Value v = m_filter->evaluate(context); 230 231 NodeSet& nodes = v.modifiableNodeSet(context); 232 m_path->evaluate(context, nodes); 233 234 return v; 235 } 236 237 } 238 } 239