1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/dom/xslt/xpath/txMozillaXPathTreeWalker.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,781 @@ 1.4 +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ 1.5 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.7 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.8 + 1.9 +#include "txXPathTreeWalker.h" 1.10 +#include "nsIAtom.h" 1.11 +#include "nsIAttribute.h" 1.12 +#include "nsIDOMAttr.h" 1.13 +#include "nsIDOMDocument.h" 1.14 +#include "nsIDOMNode.h" 1.15 +#include "nsIDOMElement.h" 1.16 +#include "nsIDOMProcessingInstruction.h" 1.17 +#include "nsINodeInfo.h" 1.18 +#include "nsPrintfCString.h" 1.19 +#include "nsReadableUtils.h" 1.20 +#include "nsString.h" 1.21 +#include "nsTextFragment.h" 1.22 +#include "txXMLUtils.h" 1.23 +#include "txLog.h" 1.24 +#include "nsUnicharUtils.h" 1.25 +#include "nsAttrName.h" 1.26 +#include "nsTArray.h" 1.27 +#include "mozilla/dom/Attr.h" 1.28 +#include "mozilla/dom/Element.h" 1.29 +#include <stdint.h> 1.30 +#include <algorithm> 1.31 + 1.32 +using mozilla::dom::Attr; 1.33 + 1.34 +const uint32_t kUnknownIndex = uint32_t(-1); 1.35 + 1.36 +txXPathTreeWalker::txXPathTreeWalker(const txXPathTreeWalker& aOther) 1.37 + : mPosition(aOther.mPosition), 1.38 + mCurrentIndex(aOther.mCurrentIndex) 1.39 +{ 1.40 +} 1.41 + 1.42 +txXPathTreeWalker::txXPathTreeWalker(const txXPathNode& aNode) 1.43 + : mPosition(aNode), 1.44 + mCurrentIndex(kUnknownIndex) 1.45 +{ 1.46 +} 1.47 + 1.48 +void 1.49 +txXPathTreeWalker::moveToRoot() 1.50 +{ 1.51 + if (mPosition.isDocument()) { 1.52 + return; 1.53 + } 1.54 + 1.55 + nsIDocument* root = mPosition.mNode->GetCurrentDoc(); 1.56 + if (root) { 1.57 + mPosition.mIndex = txXPathNode::eDocument; 1.58 + mPosition.mNode = root; 1.59 + } 1.60 + else { 1.61 + nsINode *rootNode = mPosition.Root(); 1.62 + 1.63 + NS_ASSERTION(rootNode->IsNodeOfType(nsINode::eCONTENT), 1.64 + "root of subtree wasn't an nsIContent"); 1.65 + 1.66 + mPosition.mIndex = txXPathNode::eContent; 1.67 + mPosition.mNode = rootNode; 1.68 + } 1.69 + 1.70 + mCurrentIndex = kUnknownIndex; 1.71 + mDescendants.Clear(); 1.72 +} 1.73 + 1.74 +bool 1.75 +txXPathTreeWalker::moveToElementById(const nsAString& aID) 1.76 +{ 1.77 + if (aID.IsEmpty()) { 1.78 + return false; 1.79 + } 1.80 + 1.81 + nsIDocument* doc = mPosition.mNode->GetCurrentDoc(); 1.82 + 1.83 + nsCOMPtr<nsIContent> content; 1.84 + if (doc) { 1.85 + content = doc->GetElementById(aID); 1.86 + } 1.87 + else { 1.88 + // We're in a disconnected subtree, search only that subtree. 1.89 + nsINode *rootNode = mPosition.Root(); 1.90 + 1.91 + NS_ASSERTION(rootNode->IsNodeOfType(nsINode::eCONTENT), 1.92 + "root of subtree wasn't an nsIContent"); 1.93 + 1.94 + content = nsContentUtils::MatchElementId( 1.95 + static_cast<nsIContent*>(rootNode), aID); 1.96 + } 1.97 + 1.98 + if (!content) { 1.99 + return false; 1.100 + } 1.101 + 1.102 + mPosition.mIndex = txXPathNode::eContent; 1.103 + mPosition.mNode = content; 1.104 + mCurrentIndex = kUnknownIndex; 1.105 + mDescendants.Clear(); 1.106 + 1.107 + return true; 1.108 +} 1.109 + 1.110 +bool 1.111 +txXPathTreeWalker::moveToFirstAttribute() 1.112 +{ 1.113 + if (!mPosition.isContent()) { 1.114 + return false; 1.115 + } 1.116 + 1.117 + return moveToValidAttribute(0); 1.118 +} 1.119 + 1.120 +bool 1.121 +txXPathTreeWalker::moveToNextAttribute() 1.122 +{ 1.123 + // XXX an assertion should be enough here with the current code 1.124 + if (!mPosition.isAttribute()) { 1.125 + return false; 1.126 + } 1.127 + 1.128 + return moveToValidAttribute(mPosition.mIndex + 1); 1.129 +} 1.130 + 1.131 +bool 1.132 +txXPathTreeWalker::moveToValidAttribute(uint32_t aStartIndex) 1.133 +{ 1.134 + NS_ASSERTION(!mPosition.isDocument(), "documents doesn't have attrs"); 1.135 + 1.136 + uint32_t total = mPosition.Content()->GetAttrCount(); 1.137 + if (aStartIndex >= total) { 1.138 + return false; 1.139 + } 1.140 + 1.141 + uint32_t index; 1.142 + for (index = aStartIndex; index < total; ++index) { 1.143 + const nsAttrName* name = mPosition.Content()->GetAttrNameAt(index); 1.144 + 1.145 + // We need to ignore XMLNS attributes. 1.146 + if (name->NamespaceID() != kNameSpaceID_XMLNS) { 1.147 + mPosition.mIndex = index; 1.148 + 1.149 + return true; 1.150 + } 1.151 + } 1.152 + return false; 1.153 +} 1.154 + 1.155 +bool 1.156 +txXPathTreeWalker::moveToNamedAttribute(nsIAtom* aLocalName, int32_t aNSID) 1.157 +{ 1.158 + if (!mPosition.isContent()) { 1.159 + return false; 1.160 + } 1.161 + 1.162 + const nsAttrName* name; 1.163 + uint32_t i; 1.164 + for (i = 0; (name = mPosition.Content()->GetAttrNameAt(i)); ++i) { 1.165 + if (name->Equals(aLocalName, aNSID)) { 1.166 + mPosition.mIndex = i; 1.167 + 1.168 + return true; 1.169 + } 1.170 + } 1.171 + return false; 1.172 +} 1.173 + 1.174 +bool 1.175 +txXPathTreeWalker::moveToFirstChild() 1.176 +{ 1.177 + if (mPosition.isAttribute()) { 1.178 + return false; 1.179 + } 1.180 + 1.181 + NS_ASSERTION(!mPosition.isDocument() || 1.182 + (mCurrentIndex == kUnknownIndex && mDescendants.IsEmpty()), 1.183 + "we shouldn't have any position info at the document"); 1.184 + NS_ASSERTION(mCurrentIndex != kUnknownIndex || mDescendants.IsEmpty(), 1.185 + "Index should be known if parents index are"); 1.186 + 1.187 + nsIContent* child = mPosition.mNode->GetFirstChild(); 1.188 + if (!child) { 1.189 + return false; 1.190 + } 1.191 + mPosition.mIndex = txXPathNode::eContent; 1.192 + mPosition.mNode = child; 1.193 + 1.194 + if (mCurrentIndex != kUnknownIndex && 1.195 + !mDescendants.AppendValue(mCurrentIndex)) { 1.196 + mDescendants.Clear(); 1.197 + } 1.198 + mCurrentIndex = 0; 1.199 + 1.200 + return true; 1.201 +} 1.202 + 1.203 +bool 1.204 +txXPathTreeWalker::moveToLastChild() 1.205 +{ 1.206 + if (mPosition.isAttribute()) { 1.207 + return false; 1.208 + } 1.209 + 1.210 + NS_ASSERTION(!mPosition.isDocument() || 1.211 + (mCurrentIndex == kUnknownIndex && mDescendants.IsEmpty()), 1.212 + "we shouldn't have any position info at the document"); 1.213 + NS_ASSERTION(mCurrentIndex != kUnknownIndex || mDescendants.IsEmpty(), 1.214 + "Index should be known if parents index are"); 1.215 + 1.216 + uint32_t total = mPosition.mNode->GetChildCount(); 1.217 + if (!total) { 1.218 + return false; 1.219 + } 1.220 + mPosition.mNode = mPosition.mNode->GetLastChild(); 1.221 + 1.222 + if (mCurrentIndex != kUnknownIndex && 1.223 + !mDescendants.AppendValue(mCurrentIndex)) { 1.224 + mDescendants.Clear(); 1.225 + } 1.226 + mCurrentIndex = total - 1; 1.227 + 1.228 + return true; 1.229 +} 1.230 + 1.231 +bool 1.232 +txXPathTreeWalker::moveToNextSibling() 1.233 +{ 1.234 + if (!mPosition.isContent()) { 1.235 + return false; 1.236 + } 1.237 + 1.238 + return moveToSibling(1); 1.239 +} 1.240 + 1.241 +bool 1.242 +txXPathTreeWalker::moveToPreviousSibling() 1.243 +{ 1.244 + if (!mPosition.isContent()) { 1.245 + return false; 1.246 + } 1.247 + 1.248 + return moveToSibling(-1); 1.249 +} 1.250 + 1.251 +bool 1.252 +txXPathTreeWalker::moveToParent() 1.253 +{ 1.254 + if (mPosition.isDocument()) { 1.255 + return false; 1.256 + } 1.257 + 1.258 + if (mPosition.isAttribute()) { 1.259 + mPosition.mIndex = txXPathNode::eContent; 1.260 + 1.261 + return true; 1.262 + } 1.263 + 1.264 + nsINode* parent = mPosition.mNode->GetParentNode(); 1.265 + if (!parent) { 1.266 + return false; 1.267 + } 1.268 + 1.269 + uint32_t count = mDescendants.Length(); 1.270 + if (count) { 1.271 + mCurrentIndex = mDescendants.ValueAt(--count); 1.272 + mDescendants.RemoveValueAt(count); 1.273 + } 1.274 + else { 1.275 + mCurrentIndex = kUnknownIndex; 1.276 + } 1.277 + 1.278 + mPosition.mIndex = mPosition.mNode->GetParent() ? 1.279 + txXPathNode::eContent : txXPathNode::eDocument; 1.280 + mPosition.mNode = parent; 1.281 + 1.282 + return true; 1.283 +} 1.284 + 1.285 +bool 1.286 +txXPathTreeWalker::moveToSibling(int32_t aDir) 1.287 +{ 1.288 + NS_ASSERTION(mPosition.isContent(), 1.289 + "moveToSibling should only be called for content"); 1.290 + 1.291 + nsINode* parent = mPosition.mNode->GetParentNode(); 1.292 + if (!parent) { 1.293 + return false; 1.294 + } 1.295 + if (mCurrentIndex == kUnknownIndex) { 1.296 + mCurrentIndex = parent->IndexOf(mPosition.mNode); 1.297 + } 1.298 + 1.299 + // if mCurrentIndex is 0 we rely on GetChildAt returning null for an 1.300 + // index of uint32_t(-1). 1.301 + uint32_t newIndex = mCurrentIndex + aDir; 1.302 + nsIContent* newChild = parent->GetChildAt(newIndex); 1.303 + if (!newChild) { 1.304 + return false; 1.305 + } 1.306 + 1.307 + mPosition.mNode = newChild; 1.308 + mCurrentIndex = newIndex; 1.309 + 1.310 + return true; 1.311 +} 1.312 + 1.313 +txXPathNode::txXPathNode(const txXPathNode& aNode) 1.314 + : mNode(aNode.mNode), 1.315 + mRefCountRoot(aNode.mRefCountRoot), 1.316 + mIndex(aNode.mIndex) 1.317 +{ 1.318 + MOZ_COUNT_CTOR(txXPathNode); 1.319 + if (mRefCountRoot) { 1.320 + NS_ADDREF(Root()); 1.321 + } 1.322 +} 1.323 + 1.324 +txXPathNode::~txXPathNode() 1.325 +{ 1.326 + MOZ_COUNT_DTOR(txXPathNode); 1.327 + if (mRefCountRoot) { 1.328 + nsINode *root = Root(); 1.329 + NS_RELEASE(root); 1.330 + } 1.331 +} 1.332 + 1.333 +/* static */ 1.334 +bool 1.335 +txXPathNodeUtils::getAttr(const txXPathNode& aNode, nsIAtom* aLocalName, 1.336 + int32_t aNSID, nsAString& aValue) 1.337 +{ 1.338 + if (aNode.isDocument() || aNode.isAttribute()) { 1.339 + return false; 1.340 + } 1.341 + 1.342 + return aNode.Content()->GetAttr(aNSID, aLocalName, aValue); 1.343 +} 1.344 + 1.345 +/* static */ 1.346 +already_AddRefed<nsIAtom> 1.347 +txXPathNodeUtils::getLocalName(const txXPathNode& aNode) 1.348 +{ 1.349 + if (aNode.isDocument()) { 1.350 + return nullptr; 1.351 + } 1.352 + 1.353 + if (aNode.isContent()) { 1.354 + if (aNode.mNode->IsElement()) { 1.355 + nsCOMPtr<nsIAtom> localName = aNode.Content()->Tag(); 1.356 + return localName.forget(); 1.357 + } 1.358 + 1.359 + if (aNode.mNode->IsNodeOfType(nsINode::ePROCESSING_INSTRUCTION)) { 1.360 + nsCOMPtr<nsIDOMNode> node = do_QueryInterface(aNode.mNode); 1.361 + nsAutoString target; 1.362 + node->GetNodeName(target); 1.363 + 1.364 + return NS_NewAtom(target); 1.365 + } 1.366 + 1.367 + return nullptr; 1.368 + } 1.369 + 1.370 + nsCOMPtr<nsIAtom> localName = aNode.Content()-> 1.371 + GetAttrNameAt(aNode.mIndex)->LocalName(); 1.372 + 1.373 + return localName.forget(); 1.374 +} 1.375 + 1.376 +nsIAtom* 1.377 +txXPathNodeUtils::getPrefix(const txXPathNode& aNode) 1.378 +{ 1.379 + if (aNode.isDocument()) { 1.380 + return nullptr; 1.381 + } 1.382 + 1.383 + if (aNode.isContent()) { 1.384 + // All other nsIContent node types but elements have a null prefix 1.385 + // which is what we want here. 1.386 + return aNode.Content()->NodeInfo()->GetPrefixAtom(); 1.387 + } 1.388 + 1.389 + return aNode.Content()->GetAttrNameAt(aNode.mIndex)->GetPrefix(); 1.390 +} 1.391 + 1.392 +/* static */ 1.393 +void 1.394 +txXPathNodeUtils::getLocalName(const txXPathNode& aNode, nsAString& aLocalName) 1.395 +{ 1.396 + if (aNode.isDocument()) { 1.397 + aLocalName.Truncate(); 1.398 + 1.399 + return; 1.400 + } 1.401 + 1.402 + if (aNode.isContent()) { 1.403 + if (aNode.mNode->IsElement()) { 1.404 + nsINodeInfo* nodeInfo = aNode.Content()->NodeInfo(); 1.405 + nodeInfo->GetName(aLocalName); 1.406 + return; 1.407 + } 1.408 + 1.409 + if (aNode.mNode->IsNodeOfType(nsINode::ePROCESSING_INSTRUCTION)) { 1.410 + // PIs don't have a nodeinfo but do have a name 1.411 + nsCOMPtr<nsIDOMNode> node = do_QueryInterface(aNode.mNode); 1.412 + node->GetNodeName(aLocalName); 1.413 + 1.414 + return; 1.415 + } 1.416 + 1.417 + aLocalName.Truncate(); 1.418 + 1.419 + return; 1.420 + } 1.421 + 1.422 + aNode.Content()->GetAttrNameAt(aNode.mIndex)->LocalName()-> 1.423 + ToString(aLocalName); 1.424 + 1.425 + // Check for html 1.426 + if (aNode.Content()->NodeInfo()->NamespaceEquals(kNameSpaceID_None) && 1.427 + aNode.Content()->IsHTML()) { 1.428 + nsContentUtils::ASCIIToUpper(aLocalName); 1.429 + } 1.430 +} 1.431 + 1.432 +/* static */ 1.433 +void 1.434 +txXPathNodeUtils::getNodeName(const txXPathNode& aNode, nsAString& aName) 1.435 +{ 1.436 + if (aNode.isDocument()) { 1.437 + aName.Truncate(); 1.438 + 1.439 + return; 1.440 + } 1.441 + 1.442 + if (aNode.isContent()) { 1.443 + // Elements and PIs have a name 1.444 + if (aNode.mNode->IsElement() || 1.445 + aNode.mNode->NodeType() == 1.446 + nsIDOMNode::PROCESSING_INSTRUCTION_NODE) { 1.447 + aName = aNode.Content()->NodeName(); 1.448 + return; 1.449 + } 1.450 + 1.451 + aName.Truncate(); 1.452 + 1.453 + return; 1.454 + } 1.455 + 1.456 + aNode.Content()->GetAttrNameAt(aNode.mIndex)->GetQualifiedName(aName); 1.457 +} 1.458 + 1.459 +/* static */ 1.460 +int32_t 1.461 +txXPathNodeUtils::getNamespaceID(const txXPathNode& aNode) 1.462 +{ 1.463 + if (aNode.isDocument()) { 1.464 + return kNameSpaceID_None; 1.465 + } 1.466 + 1.467 + if (aNode.isContent()) { 1.468 + return aNode.Content()->GetNameSpaceID(); 1.469 + } 1.470 + 1.471 + return aNode.Content()->GetAttrNameAt(aNode.mIndex)->NamespaceID(); 1.472 +} 1.473 + 1.474 +/* static */ 1.475 +void 1.476 +txXPathNodeUtils::getNamespaceURI(const txXPathNode& aNode, nsAString& aURI) 1.477 +{ 1.478 + nsContentUtils::NameSpaceManager()->GetNameSpaceURI(getNamespaceID(aNode), aURI); 1.479 +} 1.480 + 1.481 +/* static */ 1.482 +uint16_t 1.483 +txXPathNodeUtils::getNodeType(const txXPathNode& aNode) 1.484 +{ 1.485 + if (aNode.isDocument()) { 1.486 + return txXPathNodeType::DOCUMENT_NODE; 1.487 + } 1.488 + 1.489 + if (aNode.isContent()) { 1.490 + return aNode.mNode->NodeType(); 1.491 + } 1.492 + 1.493 + return txXPathNodeType::ATTRIBUTE_NODE; 1.494 +} 1.495 + 1.496 +/* static */ 1.497 +void 1.498 +txXPathNodeUtils::appendNodeValue(const txXPathNode& aNode, nsAString& aResult) 1.499 +{ 1.500 + if (aNode.isAttribute()) { 1.501 + const nsAttrName* name = aNode.Content()->GetAttrNameAt(aNode.mIndex); 1.502 + 1.503 + if (aResult.IsEmpty()) { 1.504 + aNode.Content()->GetAttr(name->NamespaceID(), name->LocalName(), 1.505 + aResult); 1.506 + } 1.507 + else { 1.508 + nsAutoString result; 1.509 + aNode.Content()->GetAttr(name->NamespaceID(), name->LocalName(), 1.510 + result); 1.511 + aResult.Append(result); 1.512 + } 1.513 + 1.514 + return; 1.515 + } 1.516 + 1.517 + if (aNode.isDocument() || 1.518 + aNode.mNode->IsElement() || 1.519 + aNode.mNode->IsNodeOfType(nsINode::eDOCUMENT_FRAGMENT)) { 1.520 + nsContentUtils::AppendNodeTextContent(aNode.mNode, true, aResult, 1.521 + mozilla::fallible_t()); 1.522 + 1.523 + return; 1.524 + } 1.525 + 1.526 + aNode.Content()->AppendTextTo(aResult); 1.527 +} 1.528 + 1.529 +/* static */ 1.530 +bool 1.531 +txXPathNodeUtils::isWhitespace(const txXPathNode& aNode) 1.532 +{ 1.533 + NS_ASSERTION(aNode.isContent() && isText(aNode), "Wrong type!"); 1.534 + 1.535 + return aNode.Content()->TextIsOnlyWhitespace(); 1.536 +} 1.537 + 1.538 +/* static */ 1.539 +txXPathNode* 1.540 +txXPathNodeUtils::getOwnerDocument(const txXPathNode& aNode) 1.541 +{ 1.542 + return new txXPathNode(aNode.mNode->OwnerDoc()); 1.543 +} 1.544 + 1.545 +const char gPrintfFmt[] = "id0x%p"; 1.546 +const char gPrintfFmtAttr[] = "id0x%p-%010i"; 1.547 + 1.548 +/* static */ 1.549 +nsresult 1.550 +txXPathNodeUtils::getXSLTId(const txXPathNode& aNode, 1.551 + const txXPathNode& aBase, 1.552 + nsAString& aResult) 1.553 +{ 1.554 + uintptr_t nodeid = ((uintptr_t)aNode.mNode) - ((uintptr_t)aBase.mNode); 1.555 + if (!aNode.isAttribute()) { 1.556 + CopyASCIItoUTF16(nsPrintfCString(gPrintfFmt, nodeid), 1.557 + aResult); 1.558 + } 1.559 + else { 1.560 + CopyASCIItoUTF16(nsPrintfCString(gPrintfFmtAttr, 1.561 + nodeid, aNode.mIndex), aResult); 1.562 + } 1.563 + 1.564 + return NS_OK; 1.565 +} 1.566 + 1.567 +/* static */ 1.568 +void 1.569 +txXPathNodeUtils::getBaseURI(const txXPathNode& aNode, nsAString& aURI) 1.570 +{ 1.571 + aNode.mNode->GetBaseURI(aURI); 1.572 +} 1.573 + 1.574 +/* static */ 1.575 +int 1.576 +txXPathNodeUtils::comparePosition(const txXPathNode& aNode, 1.577 + const txXPathNode& aOtherNode) 1.578 +{ 1.579 + // First check for equal nodes or attribute-nodes on the same element. 1.580 + if (aNode.mNode == aOtherNode.mNode) { 1.581 + if (aNode.mIndex == aOtherNode.mIndex) { 1.582 + return 0; 1.583 + } 1.584 + 1.585 + NS_ASSERTION(!aNode.isDocument() && !aOtherNode.isDocument(), 1.586 + "documents should always have a set index"); 1.587 + 1.588 + if (aNode.isContent() || (!aOtherNode.isContent() && 1.589 + aNode.mIndex < aOtherNode.mIndex)) { 1.590 + return -1; 1.591 + } 1.592 + 1.593 + return 1; 1.594 + } 1.595 + 1.596 + // Get document for both nodes. 1.597 + nsIDocument* document = aNode.mNode->GetCurrentDoc(); 1.598 + nsIDocument* otherDocument = aOtherNode.mNode->GetCurrentDoc(); 1.599 + 1.600 + // If the nodes have different current documents, compare the document 1.601 + // pointers. 1.602 + if (document != otherDocument) { 1.603 + return document < otherDocument ? -1 : 1; 1.604 + } 1.605 + 1.606 + // Now either both nodes are in orphan trees, or they are both in the 1.607 + // same tree. 1.608 + 1.609 + // Get parents up the tree. 1.610 + nsAutoTArray<nsINode*, 8> parents, otherParents; 1.611 + nsINode* node = aNode.mNode; 1.612 + nsINode* otherNode = aOtherNode.mNode; 1.613 + nsINode* parent, *otherParent; 1.614 + while (node && otherNode) { 1.615 + parent = node->GetParentNode(); 1.616 + otherParent = otherNode->GetParentNode(); 1.617 + 1.618 + // Hopefully this is a common case. 1.619 + if (parent == otherParent) { 1.620 + if (!parent) { 1.621 + // Both node and otherNode are root nodes in respective orphan 1.622 + // tree. 1.623 + return node < otherNode ? -1 : 1; 1.624 + } 1.625 + 1.626 + return parent->IndexOf(node) < parent->IndexOf(otherNode) ? 1.627 + -1 : 1; 1.628 + } 1.629 + 1.630 + parents.AppendElement(node); 1.631 + otherParents.AppendElement(otherNode); 1.632 + node = parent; 1.633 + otherNode = otherParent; 1.634 + } 1.635 + 1.636 + while (node) { 1.637 + parents.AppendElement(node); 1.638 + node = node->GetParentNode(); 1.639 + } 1.640 + while (otherNode) { 1.641 + otherParents.AppendElement(otherNode); 1.642 + otherNode = otherNode->GetParentNode(); 1.643 + } 1.644 + 1.645 + // Walk back down along the parent-chains until we find where they split. 1.646 + int32_t total = parents.Length() - 1; 1.647 + int32_t otherTotal = otherParents.Length() - 1; 1.648 + NS_ASSERTION(total != otherTotal, "Can't have same number of parents"); 1.649 + 1.650 + int32_t lastIndex = std::min(total, otherTotal); 1.651 + int32_t i; 1.652 + parent = nullptr; 1.653 + for (i = 0; i <= lastIndex; ++i) { 1.654 + node = parents.ElementAt(total - i); 1.655 + otherNode = otherParents.ElementAt(otherTotal - i); 1.656 + if (node != otherNode) { 1.657 + if (!parent) { 1.658 + // The two nodes are in different orphan subtrees. 1.659 + NS_ASSERTION(i == 0, "this shouldn't happen"); 1.660 + return node < otherNode ? -1 : 1; 1.661 + } 1.662 + 1.663 + int32_t index = parent->IndexOf(node); 1.664 + int32_t otherIndex = parent->IndexOf(otherNode); 1.665 + NS_ASSERTION(index != otherIndex && index >= 0 && otherIndex >= 0, 1.666 + "invalid index in compareTreePosition"); 1.667 + 1.668 + return index < otherIndex ? -1 : 1; 1.669 + } 1.670 + 1.671 + parent = node; 1.672 + } 1.673 + 1.674 + // One node is a descendant of the other. The one with the shortest 1.675 + // parent-chain is first in the document. 1.676 + return total < otherTotal ? -1 : 1; 1.677 +} 1.678 + 1.679 +/* static */ 1.680 +txXPathNode* 1.681 +txXPathNativeNode::createXPathNode(nsIContent* aContent, bool aKeepRootAlive) 1.682 +{ 1.683 + nsINode* root = aKeepRootAlive ? txXPathNode::RootOf(aContent) : nullptr; 1.684 + 1.685 + return new txXPathNode(aContent, txXPathNode::eContent, root); 1.686 +} 1.687 + 1.688 +/* static */ 1.689 +txXPathNode* 1.690 +txXPathNativeNode::createXPathNode(nsIDOMNode* aNode, bool aKeepRootAlive) 1.691 +{ 1.692 + uint16_t nodeType; 1.693 + aNode->GetNodeType(&nodeType); 1.694 + 1.695 + if (nodeType == nsIDOMNode::ATTRIBUTE_NODE) { 1.696 + nsCOMPtr<nsIAttribute> attr = do_QueryInterface(aNode); 1.697 + NS_ASSERTION(attr, "doesn't implement nsIAttribute"); 1.698 + 1.699 + nsINodeInfo *nodeInfo = attr->NodeInfo(); 1.700 + mozilla::dom::Element* parent = 1.701 + static_cast<Attr*>(attr.get())->GetElement(); 1.702 + if (!parent) { 1.703 + return nullptr; 1.704 + } 1.705 + 1.706 + nsINode* root = aKeepRootAlive ? txXPathNode::RootOf(parent) : nullptr; 1.707 + 1.708 + uint32_t i, total = parent->GetAttrCount(); 1.709 + for (i = 0; i < total; ++i) { 1.710 + const nsAttrName* name = parent->GetAttrNameAt(i); 1.711 + if (nodeInfo->Equals(name->LocalName(), name->NamespaceID())) { 1.712 + return new txXPathNode(parent, i, root); 1.713 + } 1.714 + } 1.715 + 1.716 + NS_ERROR("Couldn't find the attribute in its parent!"); 1.717 + 1.718 + return nullptr; 1.719 + } 1.720 + 1.721 + nsCOMPtr<nsINode> node = do_QueryInterface(aNode); 1.722 + uint32_t index; 1.723 + nsINode* root = aKeepRootAlive ? node.get() : nullptr; 1.724 + 1.725 + if (nodeType == nsIDOMNode::DOCUMENT_NODE) { 1.726 + index = txXPathNode::eDocument; 1.727 + } 1.728 + else { 1.729 + index = txXPathNode::eContent; 1.730 + if (root) { 1.731 + root = txXPathNode::RootOf(root); 1.732 + } 1.733 + } 1.734 + 1.735 + return new txXPathNode(node, index, root); 1.736 +} 1.737 + 1.738 +/* static */ 1.739 +txXPathNode* 1.740 +txXPathNativeNode::createXPathNode(nsIDOMDocument* aDocument) 1.741 +{ 1.742 + nsCOMPtr<nsIDocument> document = do_QueryInterface(aDocument); 1.743 + return new txXPathNode(document); 1.744 +} 1.745 + 1.746 +/* static */ 1.747 +nsresult 1.748 +txXPathNativeNode::getNode(const txXPathNode& aNode, nsIDOMNode** aResult) 1.749 +{ 1.750 + if (!aNode.isAttribute()) { 1.751 + return CallQueryInterface(aNode.mNode, aResult); 1.752 + } 1.753 + 1.754 + const nsAttrName* name = aNode.Content()->GetAttrNameAt(aNode.mIndex); 1.755 + 1.756 + nsAutoString namespaceURI; 1.757 + nsContentUtils::NameSpaceManager()->GetNameSpaceURI(name->NamespaceID(), namespaceURI); 1.758 + 1.759 + nsCOMPtr<nsIDOMElement> element = do_QueryInterface(aNode.mNode); 1.760 + nsCOMPtr<nsIDOMAttr> attr; 1.761 + element->GetAttributeNodeNS(namespaceURI, 1.762 + nsDependentAtomString(name->LocalName()), 1.763 + getter_AddRefs(attr)); 1.764 + 1.765 + return CallQueryInterface(attr, aResult); 1.766 +} 1.767 + 1.768 +/* static */ 1.769 +nsIContent* 1.770 +txXPathNativeNode::getContent(const txXPathNode& aNode) 1.771 +{ 1.772 + NS_ASSERTION(aNode.isContent(), 1.773 + "Only call getContent on nsIContent wrappers!"); 1.774 + return aNode.Content(); 1.775 +} 1.776 + 1.777 +/* static */ 1.778 +nsIDocument* 1.779 +txXPathNativeNode::getDocument(const txXPathNode& aNode) 1.780 +{ 1.781 + NS_ASSERTION(aNode.isDocument(), 1.782 + "Only call getDocument on nsIDocument wrappers!"); 1.783 + return aNode.Document(); 1.784 +}