1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/content/base/src/nsContentIterator.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,1474 @@ 1.4 +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 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 "nsISupports.h" 1.10 +#include "nsIDOMNodeList.h" 1.11 +#include "nsIContentIterator.h" 1.12 +#include "nsRange.h" 1.13 +#include "nsIContent.h" 1.14 +#include "nsCOMPtr.h" 1.15 +#include "nsTArray.h" 1.16 +#include "nsContentUtils.h" 1.17 +#include "nsINode.h" 1.18 +#include "nsCycleCollectionParticipant.h" 1.19 + 1.20 +// couple of utility static functs 1.21 + 1.22 +/////////////////////////////////////////////////////////////////////////// 1.23 +// NodeToParentOffset: returns the node's parent and offset. 1.24 +// 1.25 + 1.26 +static nsINode* 1.27 +NodeToParentOffset(nsINode* aNode, int32_t* aOffset) 1.28 +{ 1.29 + *aOffset = 0; 1.30 + 1.31 + nsINode* parent = aNode->GetParentNode(); 1.32 + 1.33 + if (parent) { 1.34 + *aOffset = parent->IndexOf(aNode); 1.35 + } 1.36 + 1.37 + return parent; 1.38 +} 1.39 + 1.40 +/////////////////////////////////////////////////////////////////////////// 1.41 +// NodeIsInTraversalRange: returns true if content is visited during 1.42 +// the traversal of the range in the specified mode. 1.43 +// 1.44 +static bool 1.45 +NodeIsInTraversalRange(nsINode* aNode, bool aIsPreMode, 1.46 + nsINode* aStartNode, int32_t aStartOffset, 1.47 + nsINode* aEndNode, int32_t aEndOffset) 1.48 +{ 1.49 + if (!aStartNode || !aEndNode || !aNode) { 1.50 + return false; 1.51 + } 1.52 + 1.53 + // If a chardata node contains an end point of the traversal range, it is 1.54 + // always in the traversal range. 1.55 + if (aNode->IsNodeOfType(nsINode::eDATA_NODE) && 1.56 + (aNode == aStartNode || aNode == aEndNode)) { 1.57 + return true; 1.58 + } 1.59 + 1.60 + nsINode* parent = aNode->GetParentNode(); 1.61 + if (!parent) { 1.62 + return false; 1.63 + } 1.64 + 1.65 + int32_t indx = parent->IndexOf(aNode); 1.66 + 1.67 + if (!aIsPreMode) { 1.68 + ++indx; 1.69 + } 1.70 + 1.71 + return nsContentUtils::ComparePoints(aStartNode, aStartOffset, 1.72 + parent, indx) <= 0 && 1.73 + nsContentUtils::ComparePoints(aEndNode, aEndOffset, 1.74 + parent, indx) >= 0; 1.75 +} 1.76 + 1.77 + 1.78 + 1.79 +/* 1.80 + * A simple iterator class for traversing the content in "close tag" order 1.81 + */ 1.82 +class nsContentIterator : public nsIContentIterator 1.83 +{ 1.84 +public: 1.85 + NS_DECL_CYCLE_COLLECTING_ISUPPORTS 1.86 + NS_DECL_CYCLE_COLLECTION_CLASS(nsContentIterator) 1.87 + 1.88 + explicit nsContentIterator(bool aPre); 1.89 + virtual ~nsContentIterator(); 1.90 + 1.91 + // nsIContentIterator interface methods ------------------------------ 1.92 + 1.93 + virtual nsresult Init(nsINode* aRoot); 1.94 + 1.95 + virtual nsresult Init(nsIDOMRange* aRange); 1.96 + 1.97 + virtual void First(); 1.98 + 1.99 + virtual void Last(); 1.100 + 1.101 + virtual void Next(); 1.102 + 1.103 + virtual void Prev(); 1.104 + 1.105 + virtual nsINode* GetCurrentNode(); 1.106 + 1.107 + virtual bool IsDone(); 1.108 + 1.109 + virtual nsresult PositionAt(nsINode* aCurNode); 1.110 + 1.111 +protected: 1.112 + 1.113 + // Recursively get the deepest first/last child of aRoot. This will return 1.114 + // aRoot itself if it has no children. 1.115 + nsINode* GetDeepFirstChild(nsINode* aRoot, 1.116 + nsTArray<int32_t>* aIndexes = nullptr); 1.117 + nsIContent* GetDeepFirstChild(nsIContent* aRoot, 1.118 + nsTArray<int32_t>* aIndexes = nullptr); 1.119 + nsINode* GetDeepLastChild(nsINode* aRoot, 1.120 + nsTArray<int32_t>* aIndexes = nullptr); 1.121 + nsIContent* GetDeepLastChild(nsIContent* aRoot, 1.122 + nsTArray<int32_t>* aIndexes = nullptr); 1.123 + 1.124 + // Get the next/previous sibling of aNode, or its parent's, or grandparent's, 1.125 + // etc. Returns null if aNode and all its ancestors have no next/previous 1.126 + // sibling. 1.127 + nsIContent* GetNextSibling(nsINode* aNode, 1.128 + nsTArray<int32_t>* aIndexes = nullptr); 1.129 + nsIContent* GetPrevSibling(nsINode* aNode, 1.130 + nsTArray<int32_t>* aIndexes = nullptr); 1.131 + 1.132 + nsINode* NextNode(nsINode* aNode, nsTArray<int32_t>* aIndexes = nullptr); 1.133 + nsINode* PrevNode(nsINode* aNode, nsTArray<int32_t>* aIndexes = nullptr); 1.134 + 1.135 + // WARNING: This function is expensive 1.136 + nsresult RebuildIndexStack(); 1.137 + 1.138 + void MakeEmpty(); 1.139 + 1.140 + virtual void LastRelease(); 1.141 + 1.142 + nsCOMPtr<nsINode> mCurNode; 1.143 + nsCOMPtr<nsINode> mFirst; 1.144 + nsCOMPtr<nsINode> mLast; 1.145 + nsCOMPtr<nsINode> mCommonParent; 1.146 + 1.147 + // used by nsContentIterator to cache indices 1.148 + nsAutoTArray<int32_t, 8> mIndexes; 1.149 + 1.150 + // used by nsSubtreeIterator to cache indices. Why put them in the base 1.151 + // class? Because otherwise I have to duplicate the routines GetNextSibling 1.152 + // etc across both classes, with slight variations for caching. Or 1.153 + // alternately, create a base class for the cache itself and have all the 1.154 + // cache manipulation go through a vptr. I think this is the best space and 1.155 + // speed combo, even though it's ugly. 1.156 + int32_t mCachedIndex; 1.157 + // another note about mCachedIndex: why should the subtree iterator use a 1.158 + // trivial cached index instead of the mre robust array of indicies (which is 1.159 + // what the basic content iterator uses)? The reason is that subtree 1.160 + // iterators do not do much transitioning between parents and children. They 1.161 + // tend to stay at the same level. In fact, you can prove (though I won't 1.162 + // attempt it here) that they change levels at most n+m times, where n is the 1.163 + // height of the parent hierarchy from the range start to the common 1.164 + // ancestor, and m is the the height of the parent hierarchy from the range 1.165 + // end to the common ancestor. If we used the index array, we would pay the 1.166 + // price up front for n, and then pay the cost for m on the fly later on. 1.167 + // With the simple cache, we only "pay as we go". Either way, we call 1.168 + // IndexOf() once for each change of level in the hierarchy. Since a trivial 1.169 + // index is much simpler, we use it for the subtree iterator. 1.170 + 1.171 + bool mIsDone; 1.172 + bool mPre; 1.173 + 1.174 +private: 1.175 + 1.176 + // no copies or assigns FIX ME 1.177 + nsContentIterator(const nsContentIterator&); 1.178 + nsContentIterator& operator=(const nsContentIterator&); 1.179 + 1.180 +}; 1.181 + 1.182 + 1.183 +/****************************************************** 1.184 + * repository cruft 1.185 + ******************************************************/ 1.186 + 1.187 +already_AddRefed<nsIContentIterator> 1.188 +NS_NewContentIterator() 1.189 +{ 1.190 + nsCOMPtr<nsIContentIterator> iter = new nsContentIterator(false); 1.191 + return iter.forget(); 1.192 +} 1.193 + 1.194 + 1.195 +already_AddRefed<nsIContentIterator> 1.196 +NS_NewPreContentIterator() 1.197 +{ 1.198 + nsCOMPtr<nsIContentIterator> iter = new nsContentIterator(true); 1.199 + return iter.forget(); 1.200 +} 1.201 + 1.202 + 1.203 +/****************************************************** 1.204 + * XPCOM cruft 1.205 + ******************************************************/ 1.206 + 1.207 +NS_IMPL_CYCLE_COLLECTING_ADDREF(nsContentIterator) 1.208 +NS_IMPL_CYCLE_COLLECTING_RELEASE_WITH_LAST_RELEASE(nsContentIterator, 1.209 + LastRelease()) 1.210 + 1.211 +NS_INTERFACE_MAP_BEGIN(nsContentIterator) 1.212 + NS_INTERFACE_MAP_ENTRY(nsIContentIterator) 1.213 + NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIContentIterator) 1.214 + NS_INTERFACE_MAP_ENTRIES_CYCLE_COLLECTION(nsContentIterator) 1.215 +NS_INTERFACE_MAP_END 1.216 + 1.217 +NS_IMPL_CYCLE_COLLECTION(nsContentIterator, 1.218 + mCurNode, 1.219 + mFirst, 1.220 + mLast, 1.221 + mCommonParent) 1.222 + 1.223 +void 1.224 +nsContentIterator::LastRelease() 1.225 +{ 1.226 + mCurNode = nullptr; 1.227 + mFirst = nullptr; 1.228 + mLast = nullptr; 1.229 + mCommonParent = nullptr; 1.230 +} 1.231 + 1.232 +/****************************************************** 1.233 + * constructor/destructor 1.234 + ******************************************************/ 1.235 + 1.236 +nsContentIterator::nsContentIterator(bool aPre) : 1.237 + // don't need to explicitly initialize |nsCOMPtr|s, they will automatically 1.238 + // be nullptr 1.239 + mCachedIndex(0), mIsDone(false), mPre(aPre) 1.240 +{ 1.241 +} 1.242 + 1.243 + 1.244 +nsContentIterator::~nsContentIterator() 1.245 +{ 1.246 +} 1.247 + 1.248 + 1.249 +/****************************************************** 1.250 + * Init routines 1.251 + ******************************************************/ 1.252 + 1.253 + 1.254 +nsresult 1.255 +nsContentIterator::Init(nsINode* aRoot) 1.256 +{ 1.257 + if (!aRoot) { 1.258 + return NS_ERROR_NULL_POINTER; 1.259 + } 1.260 + 1.261 + mIsDone = false; 1.262 + mIndexes.Clear(); 1.263 + 1.264 + if (mPre) { 1.265 + mFirst = aRoot; 1.266 + mLast = GetDeepLastChild(aRoot); 1.267 + } else { 1.268 + mFirst = GetDeepFirstChild(aRoot); 1.269 + mLast = aRoot; 1.270 + } 1.271 + 1.272 + mCommonParent = aRoot; 1.273 + mCurNode = mFirst; 1.274 + RebuildIndexStack(); 1.275 + return NS_OK; 1.276 +} 1.277 + 1.278 +nsresult 1.279 +nsContentIterator::Init(nsIDOMRange* aDOMRange) 1.280 +{ 1.281 + NS_ENSURE_ARG_POINTER(aDOMRange); 1.282 + nsRange* range = static_cast<nsRange*>(aDOMRange); 1.283 + 1.284 + mIsDone = false; 1.285 + 1.286 + // get common content parent 1.287 + mCommonParent = range->GetCommonAncestor(); 1.288 + NS_ENSURE_TRUE(mCommonParent, NS_ERROR_FAILURE); 1.289 + 1.290 + // get the start node and offset 1.291 + int32_t startIndx = range->StartOffset(); 1.292 + nsINode* startNode = range->GetStartParent(); 1.293 + NS_ENSURE_TRUE(startNode, NS_ERROR_FAILURE); 1.294 + 1.295 + // get the end node and offset 1.296 + int32_t endIndx = range->EndOffset(); 1.297 + nsINode* endNode = range->GetEndParent(); 1.298 + NS_ENSURE_TRUE(endNode, NS_ERROR_FAILURE); 1.299 + 1.300 + bool startIsData = startNode->IsNodeOfType(nsINode::eDATA_NODE); 1.301 + 1.302 + // short circuit when start node == end node 1.303 + if (startNode == endNode) { 1.304 + // Check to see if we have a collapsed range, if so, there is nothing to 1.305 + // iterate over. 1.306 + // 1.307 + // XXX: CharacterDataNodes (text nodes) are currently an exception, since 1.308 + // we always want to be able to iterate text nodes at the end points 1.309 + // of a range. 1.310 + 1.311 + if (!startIsData && startIndx == endIndx) { 1.312 + MakeEmpty(); 1.313 + return NS_OK; 1.314 + } 1.315 + 1.316 + if (startIsData) { 1.317 + // It's a character data node. 1.318 + mFirst = startNode->AsContent(); 1.319 + mLast = mFirst; 1.320 + mCurNode = mFirst; 1.321 + 1.322 + RebuildIndexStack(); 1.323 + return NS_OK; 1.324 + } 1.325 + } 1.326 + 1.327 + // Find first node in range. 1.328 + 1.329 + nsIContent* cChild = nullptr; 1.330 + 1.331 + if (!startIsData && startNode->HasChildren()) { 1.332 + cChild = startNode->GetChildAt(startIndx); 1.333 + } 1.334 + 1.335 + if (!cChild) { 1.336 + // no children, must be a text node 1.337 + // 1.338 + // XXXbz no children might also just mean no children. So I'm not 1.339 + // sure what that comment above is talking about. 1.340 + 1.341 + if (mPre) { 1.342 + // XXX: In the future, if start offset is after the last 1.343 + // character in the cdata node, should we set mFirst to 1.344 + // the next sibling? 1.345 + 1.346 + if (!startIsData) { 1.347 + mFirst = GetNextSibling(startNode); 1.348 + 1.349 + // Does mFirst node really intersect the range? The range could be 1.350 + // 'degenerate', i.e., not collapsed but still contain no content. 1.351 + 1.352 + if (mFirst && !NodeIsInTraversalRange(mFirst, mPre, startNode, 1.353 + startIndx, endNode, endIndx)) { 1.354 + mFirst = nullptr; 1.355 + } 1.356 + } else { 1.357 + mFirst = startNode->AsContent(); 1.358 + } 1.359 + } else { 1.360 + // post-order 1.361 + if (startNode->IsContent()) { 1.362 + mFirst = startNode->AsContent(); 1.363 + } else { 1.364 + // What else can we do? 1.365 + mFirst = nullptr; 1.366 + } 1.367 + } 1.368 + } else { 1.369 + if (mPre) { 1.370 + mFirst = cChild; 1.371 + } else { 1.372 + // post-order 1.373 + mFirst = GetDeepFirstChild(cChild); 1.374 + 1.375 + // Does mFirst node really intersect the range? The range could be 1.376 + // 'degenerate', i.e., not collapsed but still contain no content. 1.377 + 1.378 + if (mFirst && !NodeIsInTraversalRange(mFirst, mPre, startNode, startIndx, 1.379 + endNode, endIndx)) { 1.380 + mFirst = nullptr; 1.381 + } 1.382 + } 1.383 + } 1.384 + 1.385 + 1.386 + // Find last node in range. 1.387 + 1.388 + bool endIsData = endNode->IsNodeOfType(nsINode::eDATA_NODE); 1.389 + 1.390 + if (endIsData || !endNode->HasChildren() || endIndx == 0) { 1.391 + if (mPre) { 1.392 + if (endNode->IsContent()) { 1.393 + mLast = endNode->AsContent(); 1.394 + } else { 1.395 + // Not much else to do here... 1.396 + mLast = nullptr; 1.397 + } 1.398 + } else { 1.399 + // post-order 1.400 + // 1.401 + // XXX: In the future, if end offset is before the first character in the 1.402 + // cdata node, should we set mLast to the prev sibling? 1.403 + 1.404 + if (!endIsData) { 1.405 + mLast = GetPrevSibling(endNode); 1.406 + 1.407 + if (!NodeIsInTraversalRange(mLast, mPre, startNode, startIndx, 1.408 + endNode, endIndx)) { 1.409 + mLast = nullptr; 1.410 + } 1.411 + } else { 1.412 + mLast = endNode->AsContent(); 1.413 + } 1.414 + } 1.415 + } else { 1.416 + int32_t indx = endIndx; 1.417 + 1.418 + cChild = endNode->GetChildAt(--indx); 1.419 + 1.420 + if (!cChild) { 1.421 + // No child at offset! 1.422 + NS_NOTREACHED("nsContentIterator::nsContentIterator"); 1.423 + return NS_ERROR_FAILURE; 1.424 + } 1.425 + 1.426 + if (mPre) { 1.427 + mLast = GetDeepLastChild(cChild); 1.428 + 1.429 + if (!NodeIsInTraversalRange(mLast, mPre, startNode, startIndx, 1.430 + endNode, endIndx)) { 1.431 + mLast = nullptr; 1.432 + } 1.433 + } else { 1.434 + // post-order 1.435 + mLast = cChild; 1.436 + } 1.437 + } 1.438 + 1.439 + // If either first or last is null, they both have to be null! 1.440 + 1.441 + if (!mFirst || !mLast) { 1.442 + mFirst = nullptr; 1.443 + mLast = nullptr; 1.444 + } 1.445 + 1.446 + mCurNode = mFirst; 1.447 + mIsDone = !mCurNode; 1.448 + 1.449 + if (!mCurNode) { 1.450 + mIndexes.Clear(); 1.451 + } else { 1.452 + RebuildIndexStack(); 1.453 + } 1.454 + 1.455 + return NS_OK; 1.456 +} 1.457 + 1.458 + 1.459 +/****************************************************** 1.460 + * Helper routines 1.461 + ******************************************************/ 1.462 +// WARNING: This function is expensive 1.463 +nsresult 1.464 +nsContentIterator::RebuildIndexStack() 1.465 +{ 1.466 + // Make sure we start at the right indexes on the stack! Build array up 1.467 + // to common parent of start and end. Perhaps it's too many entries, but 1.468 + // that's far better than too few. 1.469 + nsINode* parent; 1.470 + nsINode* current; 1.471 + 1.472 + mIndexes.Clear(); 1.473 + current = mCurNode; 1.474 + if (!current) { 1.475 + return NS_OK; 1.476 + } 1.477 + 1.478 + while (current != mCommonParent) { 1.479 + parent = current->GetParentNode(); 1.480 + 1.481 + if (!parent) { 1.482 + return NS_ERROR_FAILURE; 1.483 + } 1.484 + 1.485 + mIndexes.InsertElementAt(0, parent->IndexOf(current)); 1.486 + 1.487 + current = parent; 1.488 + } 1.489 + 1.490 + return NS_OK; 1.491 +} 1.492 + 1.493 +void 1.494 +nsContentIterator::MakeEmpty() 1.495 +{ 1.496 + mCurNode = nullptr; 1.497 + mFirst = nullptr; 1.498 + mLast = nullptr; 1.499 + mCommonParent = nullptr; 1.500 + mIsDone = true; 1.501 + mIndexes.Clear(); 1.502 +} 1.503 + 1.504 +nsINode* 1.505 +nsContentIterator::GetDeepFirstChild(nsINode* aRoot, 1.506 + nsTArray<int32_t>* aIndexes) 1.507 +{ 1.508 + if (!aRoot || !aRoot->HasChildren()) { 1.509 + return aRoot; 1.510 + } 1.511 + // We can't pass aRoot itself to the full GetDeepFirstChild, because that 1.512 + // will only take nsIContent and aRoot might be a document. Pass aRoot's 1.513 + // child, but be sure to preserve aIndexes. 1.514 + if (aIndexes) { 1.515 + aIndexes->AppendElement(0); 1.516 + } 1.517 + return GetDeepFirstChild(aRoot->GetFirstChild(), aIndexes); 1.518 +} 1.519 + 1.520 +nsIContent* 1.521 +nsContentIterator::GetDeepFirstChild(nsIContent* aRoot, 1.522 + nsTArray<int32_t>* aIndexes) 1.523 +{ 1.524 + if (!aRoot) { 1.525 + return nullptr; 1.526 + } 1.527 + 1.528 + nsIContent* node = aRoot; 1.529 + nsIContent* child = node->GetFirstChild(); 1.530 + 1.531 + while (child) { 1.532 + if (aIndexes) { 1.533 + // Add this node to the stack of indexes 1.534 + aIndexes->AppendElement(0); 1.535 + } 1.536 + node = child; 1.537 + child = node->GetFirstChild(); 1.538 + } 1.539 + 1.540 + return node; 1.541 +} 1.542 + 1.543 +nsINode* 1.544 +nsContentIterator::GetDeepLastChild(nsINode* aRoot, 1.545 + nsTArray<int32_t>* aIndexes) 1.546 +{ 1.547 + if (!aRoot || !aRoot->HasChildren()) { 1.548 + return aRoot; 1.549 + } 1.550 + // We can't pass aRoot itself to the full GetDeepLastChild, because that will 1.551 + // only take nsIContent and aRoot might be a document. Pass aRoot's child, 1.552 + // but be sure to preserve aIndexes. 1.553 + if (aIndexes) { 1.554 + aIndexes->AppendElement(aRoot->GetChildCount() - 1); 1.555 + } 1.556 + return GetDeepLastChild(aRoot->GetLastChild(), aIndexes); 1.557 +} 1.558 + 1.559 +nsIContent* 1.560 +nsContentIterator::GetDeepLastChild(nsIContent* aRoot, 1.561 + nsTArray<int32_t>* aIndexes) 1.562 +{ 1.563 + if (!aRoot) { 1.564 + return nullptr; 1.565 + } 1.566 + 1.567 + nsIContent* node = aRoot; 1.568 + int32_t numChildren = node->GetChildCount(); 1.569 + 1.570 + while (numChildren) { 1.571 + nsIContent* child = node->GetChildAt(--numChildren); 1.572 + 1.573 + if (aIndexes) { 1.574 + // Add this node to the stack of indexes 1.575 + aIndexes->AppendElement(numChildren); 1.576 + } 1.577 + numChildren = child->GetChildCount(); 1.578 + node = child; 1.579 + } 1.580 + 1.581 + return node; 1.582 +} 1.583 + 1.584 +// Get the next sibling, or parent's next sibling, or grandpa's next sibling... 1.585 +nsIContent* 1.586 +nsContentIterator::GetNextSibling(nsINode* aNode, 1.587 + nsTArray<int32_t>* aIndexes) 1.588 +{ 1.589 + if (!aNode) { 1.590 + return nullptr; 1.591 + } 1.592 + 1.593 + nsINode* parent = aNode->GetParentNode(); 1.594 + if (!parent) { 1.595 + return nullptr; 1.596 + } 1.597 + 1.598 + int32_t indx = 0; 1.599 + 1.600 + NS_ASSERTION(!aIndexes || !aIndexes->IsEmpty(), 1.601 + "ContentIterator stack underflow"); 1.602 + if (aIndexes && !aIndexes->IsEmpty()) { 1.603 + // use the last entry on the Indexes array for the current index 1.604 + indx = (*aIndexes)[aIndexes->Length()-1]; 1.605 + } else { 1.606 + indx = mCachedIndex; 1.607 + } 1.608 + 1.609 + // reverify that the index of the current node hasn't changed. 1.610 + // not super cheap, but a lot cheaper than IndexOf(), and still O(1). 1.611 + // ignore result this time - the index may now be out of range. 1.612 + nsIContent* sib = parent->GetChildAt(indx); 1.613 + if (sib != aNode) { 1.614 + // someone changed our index - find the new index the painful way 1.615 + indx = parent->IndexOf(aNode); 1.616 + } 1.617 + 1.618 + // indx is now canonically correct 1.619 + if ((sib = parent->GetChildAt(++indx))) { 1.620 + // update index cache 1.621 + if (aIndexes && !aIndexes->IsEmpty()) { 1.622 + aIndexes->ElementAt(aIndexes->Length()-1) = indx; 1.623 + } else { 1.624 + mCachedIndex = indx; 1.625 + } 1.626 + } else { 1.627 + if (parent != mCommonParent) { 1.628 + if (aIndexes) { 1.629 + // pop node off the stack, go up one level and return parent or fail. 1.630 + // Don't leave the index empty, especially if we're 1.631 + // returning nullptr. This confuses other parts of the code. 1.632 + if (aIndexes->Length() > 1) { 1.633 + aIndexes->RemoveElementAt(aIndexes->Length()-1); 1.634 + } 1.635 + } 1.636 + } 1.637 + 1.638 + // ok to leave cache out of date here if parent == mCommonParent? 1.639 + sib = GetNextSibling(parent, aIndexes); 1.640 + } 1.641 + 1.642 + return sib; 1.643 +} 1.644 + 1.645 +// Get the prev sibling, or parent's prev sibling, or grandpa's prev sibling... 1.646 +nsIContent* 1.647 +nsContentIterator::GetPrevSibling(nsINode* aNode, 1.648 + nsTArray<int32_t>* aIndexes) 1.649 +{ 1.650 + if (!aNode) { 1.651 + return nullptr; 1.652 + } 1.653 + 1.654 + nsINode* parent = aNode->GetParentNode(); 1.655 + if (!parent) { 1.656 + return nullptr; 1.657 + } 1.658 + 1.659 + int32_t indx = 0; 1.660 + 1.661 + NS_ASSERTION(!aIndexes || !aIndexes->IsEmpty(), 1.662 + "ContentIterator stack underflow"); 1.663 + if (aIndexes && !aIndexes->IsEmpty()) { 1.664 + // use the last entry on the Indexes array for the current index 1.665 + indx = (*aIndexes)[aIndexes->Length()-1]; 1.666 + } else { 1.667 + indx = mCachedIndex; 1.668 + } 1.669 + 1.670 + // reverify that the index of the current node hasn't changed 1.671 + // ignore result this time - the index may now be out of range. 1.672 + nsIContent* sib = parent->GetChildAt(indx); 1.673 + if (sib != aNode) { 1.674 + // someone changed our index - find the new index the painful way 1.675 + indx = parent->IndexOf(aNode); 1.676 + } 1.677 + 1.678 + // indx is now canonically correct 1.679 + if (indx > 0 && (sib = parent->GetChildAt(--indx))) { 1.680 + // update index cache 1.681 + if (aIndexes && !aIndexes->IsEmpty()) { 1.682 + aIndexes->ElementAt(aIndexes->Length()-1) = indx; 1.683 + } else { 1.684 + mCachedIndex = indx; 1.685 + } 1.686 + } else if (parent != mCommonParent) { 1.687 + if (aIndexes && !aIndexes->IsEmpty()) { 1.688 + // pop node off the stack, go up one level and try again. 1.689 + aIndexes->RemoveElementAt(aIndexes->Length()-1); 1.690 + } 1.691 + return GetPrevSibling(parent, aIndexes); 1.692 + } 1.693 + 1.694 + return sib; 1.695 +} 1.696 + 1.697 +nsINode* 1.698 +nsContentIterator::NextNode(nsINode* aNode, nsTArray<int32_t>* aIndexes) 1.699 +{ 1.700 + nsINode* node = aNode; 1.701 + 1.702 + // if we are a Pre-order iterator, use pre-order 1.703 + if (mPre) { 1.704 + // if it has children then next node is first child 1.705 + if (node->HasChildren()) { 1.706 + nsIContent* firstChild = node->GetFirstChild(); 1.707 + 1.708 + // update cache 1.709 + if (aIndexes) { 1.710 + // push an entry on the index stack 1.711 + aIndexes->AppendElement(0); 1.712 + } else { 1.713 + mCachedIndex = 0; 1.714 + } 1.715 + 1.716 + return firstChild; 1.717 + } 1.718 + 1.719 + // else next sibling is next 1.720 + return GetNextSibling(node, aIndexes); 1.721 + } 1.722 + 1.723 + // post-order 1.724 + nsINode* parent = node->GetParentNode(); 1.725 + nsIContent* sibling = nullptr; 1.726 + int32_t indx = 0; 1.727 + 1.728 + // get the cached index 1.729 + NS_ASSERTION(!aIndexes || !aIndexes->IsEmpty(), 1.730 + "ContentIterator stack underflow"); 1.731 + if (aIndexes && !aIndexes->IsEmpty()) { 1.732 + // use the last entry on the Indexes array for the current index 1.733 + indx = (*aIndexes)[aIndexes->Length()-1]; 1.734 + } else { 1.735 + indx = mCachedIndex; 1.736 + } 1.737 + 1.738 + // reverify that the index of the current node hasn't changed. not super 1.739 + // cheap, but a lot cheaper than IndexOf(), and still O(1). ignore result 1.740 + // this time - the index may now be out of range. 1.741 + if (indx >= 0) { 1.742 + sibling = parent->GetChildAt(indx); 1.743 + } 1.744 + if (sibling != node) { 1.745 + // someone changed our index - find the new index the painful way 1.746 + indx = parent->IndexOf(node); 1.747 + } 1.748 + 1.749 + // indx is now canonically correct 1.750 + sibling = parent->GetChildAt(++indx); 1.751 + if (sibling) { 1.752 + // update cache 1.753 + if (aIndexes && !aIndexes->IsEmpty()) { 1.754 + // replace an entry on the index stack 1.755 + aIndexes->ElementAt(aIndexes->Length()-1) = indx; 1.756 + } else { 1.757 + mCachedIndex = indx; 1.758 + } 1.759 + 1.760 + // next node is sibling's "deep left" child 1.761 + return GetDeepFirstChild(sibling, aIndexes); 1.762 + } 1.763 + 1.764 + // else it's the parent, update cache 1.765 + if (aIndexes) { 1.766 + // Pop an entry off the index stack. Don't leave the index empty, 1.767 + // especially if we're returning nullptr. This confuses other parts of the 1.768 + // code. 1.769 + if (aIndexes->Length() > 1) { 1.770 + aIndexes->RemoveElementAt(aIndexes->Length()-1); 1.771 + } 1.772 + } else { 1.773 + // this might be wrong, but we are better off guessing 1.774 + mCachedIndex = 0; 1.775 + } 1.776 + 1.777 + return parent; 1.778 +} 1.779 + 1.780 +nsINode* 1.781 +nsContentIterator::PrevNode(nsINode* aNode, nsTArray<int32_t>* aIndexes) 1.782 +{ 1.783 + nsINode* node = aNode; 1.784 + 1.785 + // if we are a Pre-order iterator, use pre-order 1.786 + if (mPre) { 1.787 + nsINode* parent = node->GetParentNode(); 1.788 + nsIContent* sibling = nullptr; 1.789 + int32_t indx = 0; 1.790 + 1.791 + // get the cached index 1.792 + NS_ASSERTION(!aIndexes || !aIndexes->IsEmpty(), 1.793 + "ContentIterator stack underflow"); 1.794 + if (aIndexes && !aIndexes->IsEmpty()) { 1.795 + // use the last entry on the Indexes array for the current index 1.796 + indx = (*aIndexes)[aIndexes->Length()-1]; 1.797 + } else { 1.798 + indx = mCachedIndex; 1.799 + } 1.800 + 1.801 + // reverify that the index of the current node hasn't changed. not super 1.802 + // cheap, but a lot cheaper than IndexOf(), and still O(1). ignore result 1.803 + // this time - the index may now be out of range. 1.804 + if (indx >= 0) { 1.805 + sibling = parent->GetChildAt(indx); 1.806 + } 1.807 + 1.808 + if (sibling != node) { 1.809 + // someone changed our index - find the new index the painful way 1.810 + indx = parent->IndexOf(node); 1.811 + } 1.812 + 1.813 + // indx is now canonically correct 1.814 + if (indx && (sibling = parent->GetChildAt(--indx))) { 1.815 + // update cache 1.816 + if (aIndexes && !aIndexes->IsEmpty()) { 1.817 + // replace an entry on the index stack 1.818 + aIndexes->ElementAt(aIndexes->Length()-1) = indx; 1.819 + } else { 1.820 + mCachedIndex = indx; 1.821 + } 1.822 + 1.823 + // prev node is sibling's "deep right" child 1.824 + return GetDeepLastChild(sibling, aIndexes); 1.825 + } 1.826 + 1.827 + // else it's the parent, update cache 1.828 + if (aIndexes && !aIndexes->IsEmpty()) { 1.829 + // pop an entry off the index stack 1.830 + aIndexes->RemoveElementAt(aIndexes->Length()-1); 1.831 + } else { 1.832 + // this might be wrong, but we are better off guessing 1.833 + mCachedIndex = 0; 1.834 + } 1.835 + return parent; 1.836 + } 1.837 + 1.838 + // post-order 1.839 + int32_t numChildren = node->GetChildCount(); 1.840 + 1.841 + // if it has children then prev node is last child 1.842 + if (numChildren) { 1.843 + nsIContent* lastChild = node->GetLastChild(); 1.844 + numChildren--; 1.845 + 1.846 + // update cache 1.847 + if (aIndexes) { 1.848 + // push an entry on the index stack 1.849 + aIndexes->AppendElement(numChildren); 1.850 + } else { 1.851 + mCachedIndex = numChildren; 1.852 + } 1.853 + 1.854 + return lastChild; 1.855 + } 1.856 + 1.857 + // else prev sibling is previous 1.858 + return GetPrevSibling(node, aIndexes); 1.859 +} 1.860 + 1.861 +/****************************************************** 1.862 + * ContentIterator routines 1.863 + ******************************************************/ 1.864 + 1.865 +void 1.866 +nsContentIterator::First() 1.867 +{ 1.868 + if (mFirst) { 1.869 +#ifdef DEBUG 1.870 + nsresult rv = 1.871 +#endif 1.872 + PositionAt(mFirst); 1.873 + 1.874 + NS_ASSERTION(NS_SUCCEEDED(rv), "Failed to position iterator!"); 1.875 + } 1.876 + 1.877 + mIsDone = mFirst == nullptr; 1.878 +} 1.879 + 1.880 + 1.881 +void 1.882 +nsContentIterator::Last() 1.883 +{ 1.884 + NS_ASSERTION(mLast, "No last node!"); 1.885 + 1.886 + if (mLast) { 1.887 +#ifdef DEBUG 1.888 + nsresult rv = 1.889 +#endif 1.890 + PositionAt(mLast); 1.891 + 1.892 + NS_ASSERTION(NS_SUCCEEDED(rv), "Failed to position iterator!"); 1.893 + } 1.894 + 1.895 + mIsDone = mLast == nullptr; 1.896 +} 1.897 + 1.898 + 1.899 +void 1.900 +nsContentIterator::Next() 1.901 +{ 1.902 + if (mIsDone || !mCurNode) { 1.903 + return; 1.904 + } 1.905 + 1.906 + if (mCurNode == mLast) { 1.907 + mIsDone = true; 1.908 + return; 1.909 + } 1.910 + 1.911 + mCurNode = NextNode(mCurNode, &mIndexes); 1.912 +} 1.913 + 1.914 + 1.915 +void 1.916 +nsContentIterator::Prev() 1.917 +{ 1.918 + if (mIsDone || !mCurNode) { 1.919 + return; 1.920 + } 1.921 + 1.922 + if (mCurNode == mFirst) { 1.923 + mIsDone = true; 1.924 + return; 1.925 + } 1.926 + 1.927 + mCurNode = PrevNode(mCurNode, &mIndexes); 1.928 +} 1.929 + 1.930 + 1.931 +bool 1.932 +nsContentIterator::IsDone() 1.933 +{ 1.934 + return mIsDone; 1.935 +} 1.936 + 1.937 + 1.938 +// Keeping arrays of indexes for the stack of nodes makes PositionAt 1.939 +// interesting... 1.940 +nsresult 1.941 +nsContentIterator::PositionAt(nsINode* aCurNode) 1.942 +{ 1.943 + if (!aCurNode) { 1.944 + return NS_ERROR_NULL_POINTER; 1.945 + } 1.946 + 1.947 + nsINode* newCurNode = aCurNode; 1.948 + nsINode* tempNode = mCurNode; 1.949 + 1.950 + mCurNode = aCurNode; 1.951 + // take an early out if this doesn't actually change the position 1.952 + if (mCurNode == tempNode) { 1.953 + mIsDone = false; // paranoia 1.954 + return NS_OK; 1.955 + } 1.956 + 1.957 + // Check to see if the node falls within the traversal range. 1.958 + 1.959 + nsINode* firstNode = mFirst; 1.960 + nsINode* lastNode = mLast; 1.961 + int32_t firstOffset = 0, lastOffset = 0; 1.962 + 1.963 + if (firstNode && lastNode) { 1.964 + if (mPre) { 1.965 + firstNode = NodeToParentOffset(mFirst, &firstOffset); 1.966 + 1.967 + if (lastNode->GetChildCount()) { 1.968 + lastOffset = 0; 1.969 + } else { 1.970 + lastNode = NodeToParentOffset(mLast, &lastOffset); 1.971 + ++lastOffset; 1.972 + } 1.973 + } else { 1.974 + uint32_t numChildren = firstNode->GetChildCount(); 1.975 + 1.976 + if (numChildren) { 1.977 + firstOffset = numChildren; 1.978 + } else { 1.979 + firstNode = NodeToParentOffset(mFirst, &firstOffset); 1.980 + } 1.981 + 1.982 + lastNode = NodeToParentOffset(mLast, &lastOffset); 1.983 + ++lastOffset; 1.984 + } 1.985 + } 1.986 + 1.987 + // The end positions are always in the range even if it has no parent. We 1.988 + // need to allow that or 'iter->Init(root)' would assert in Last() or First() 1.989 + // for example, bug 327694. 1.990 + if (mFirst != mCurNode && mLast != mCurNode && 1.991 + (!firstNode || !lastNode || 1.992 + !NodeIsInTraversalRange(mCurNode, mPre, firstNode, firstOffset, 1.993 + lastNode, lastOffset))) { 1.994 + mIsDone = true; 1.995 + return NS_ERROR_FAILURE; 1.996 + } 1.997 + 1.998 + // We can be at ANY node in the sequence. Need to regenerate the array of 1.999 + // indexes back to the root or common parent! 1.1000 + nsAutoTArray<nsINode*, 8> oldParentStack; 1.1001 + nsAutoTArray<int32_t, 8> newIndexes; 1.1002 + 1.1003 + // Get a list of the parents up to the root, then compare the new node with 1.1004 + // entries in that array until we find a match (lowest common ancestor). If 1.1005 + // no match, use IndexOf, take the parent, and repeat. This avoids using 1.1006 + // IndexOf() N times on possibly large arrays. We still end up doing it a 1.1007 + // fair bit. It's better to use Clone() if possible. 1.1008 + 1.1009 + // we know the depth we're down (though we may not have started at the top). 1.1010 + oldParentStack.SetCapacity(mIndexes.Length() + 1); 1.1011 + 1.1012 + // We want to loop mIndexes.Length() + 1 times here, because we want to make 1.1013 + // sure we include mCommonParent in the oldParentStack, for use in the next 1.1014 + // for loop, and mIndexes only has entries for nodes from tempNode up through 1.1015 + // an ancestor of tempNode that's a child of mCommonParent. 1.1016 + for (int32_t i = mIndexes.Length() + 1; i > 0 && tempNode; i--) { 1.1017 + // Insert at head since we're walking up 1.1018 + oldParentStack.InsertElementAt(0, tempNode); 1.1019 + 1.1020 + nsINode* parent = tempNode->GetParentNode(); 1.1021 + 1.1022 + if (!parent) { 1.1023 + // this node has no parent, and thus no index 1.1024 + break; 1.1025 + } 1.1026 + 1.1027 + if (parent == mCurNode) { 1.1028 + // The position was moved to a parent of the current position. All we 1.1029 + // need to do is drop some indexes. Shortcut here. 1.1030 + mIndexes.RemoveElementsAt(mIndexes.Length() - oldParentStack.Length(), 1.1031 + oldParentStack.Length()); 1.1032 + mIsDone = false; 1.1033 + return NS_OK; 1.1034 + } 1.1035 + tempNode = parent; 1.1036 + } 1.1037 + 1.1038 + // Ok. We have the array of old parents. Look for a match. 1.1039 + while (newCurNode) { 1.1040 + nsINode* parent = newCurNode->GetParentNode(); 1.1041 + 1.1042 + if (!parent) { 1.1043 + // this node has no parent, and thus no index 1.1044 + break; 1.1045 + } 1.1046 + 1.1047 + int32_t indx = parent->IndexOf(newCurNode); 1.1048 + 1.1049 + // insert at the head! 1.1050 + newIndexes.InsertElementAt(0, indx); 1.1051 + 1.1052 + // look to see if the parent is in the stack 1.1053 + indx = oldParentStack.IndexOf(parent); 1.1054 + if (indx >= 0) { 1.1055 + // ok, the parent IS on the old stack! Rework things. We want 1.1056 + // newIndexes to replace all nodes equal to or below the match. Note 1.1057 + // that index oldParentStack.Length() - 1 is the last node, which is one 1.1058 + // BELOW the last index in the mIndexes stack. In other words, we want 1.1059 + // to remove elements starting at index (indx + 1). 1.1060 + int32_t numToDrop = oldParentStack.Length() - (1 + indx); 1.1061 + if (numToDrop > 0) { 1.1062 + mIndexes.RemoveElementsAt(mIndexes.Length() - numToDrop, numToDrop); 1.1063 + } 1.1064 + mIndexes.AppendElements(newIndexes); 1.1065 + 1.1066 + break; 1.1067 + } 1.1068 + newCurNode = parent; 1.1069 + } 1.1070 + 1.1071 + // phew! 1.1072 + 1.1073 + mIsDone = false; 1.1074 + return NS_OK; 1.1075 +} 1.1076 + 1.1077 +nsINode* 1.1078 +nsContentIterator::GetCurrentNode() 1.1079 +{ 1.1080 + if (mIsDone) { 1.1081 + return nullptr; 1.1082 + } 1.1083 + 1.1084 + NS_ASSERTION(mCurNode, "Null current node in an iterator that's not done!"); 1.1085 + 1.1086 + return mCurNode; 1.1087 +} 1.1088 + 1.1089 + 1.1090 + 1.1091 + 1.1092 + 1.1093 +/*====================================================================================*/ 1.1094 +/*====================================================================================*/ 1.1095 + 1.1096 + 1.1097 + 1.1098 + 1.1099 + 1.1100 + 1.1101 +/****************************************************** 1.1102 + * nsContentSubtreeIterator 1.1103 + ******************************************************/ 1.1104 + 1.1105 + 1.1106 +/* 1.1107 + * A simple iterator class for traversing the content in "top subtree" order 1.1108 + */ 1.1109 +class nsContentSubtreeIterator : public nsContentIterator 1.1110 +{ 1.1111 +public: 1.1112 + nsContentSubtreeIterator() : nsContentIterator(false) {} 1.1113 + virtual ~nsContentSubtreeIterator() {} 1.1114 + 1.1115 + NS_DECL_ISUPPORTS_INHERITED 1.1116 + NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(nsContentSubtreeIterator, nsContentIterator) 1.1117 + 1.1118 + // nsContentIterator overrides ------------------------------ 1.1119 + 1.1120 + virtual nsresult Init(nsINode* aRoot); 1.1121 + 1.1122 + virtual nsresult Init(nsIDOMRange* aRange); 1.1123 + 1.1124 + virtual void Next(); 1.1125 + 1.1126 + virtual void Prev(); 1.1127 + 1.1128 + virtual nsresult PositionAt(nsINode* aCurNode); 1.1129 + 1.1130 + // Must override these because we don't do PositionAt 1.1131 + virtual void First(); 1.1132 + 1.1133 + // Must override these because we don't do PositionAt 1.1134 + virtual void Last(); 1.1135 + 1.1136 +protected: 1.1137 + 1.1138 + // Returns the highest inclusive ancestor of aNode that's in the range 1.1139 + // (possibly aNode itself). Returns null if aNode is null, or is not itself 1.1140 + // in the range. A node is in the range if (node, 0) comes strictly after 1.1141 + // the range endpoint, and (node, node.length) comes strictly before it, so 1.1142 + // the range's start and end nodes will never be considered "in" it. 1.1143 + nsIContent* GetTopAncestorInRange(nsINode* aNode); 1.1144 + 1.1145 + // no copy's or assigns FIX ME 1.1146 + nsContentSubtreeIterator(const nsContentSubtreeIterator&); 1.1147 + nsContentSubtreeIterator& operator=(const nsContentSubtreeIterator&); 1.1148 + 1.1149 + virtual void LastRelease() MOZ_OVERRIDE; 1.1150 + 1.1151 + nsRefPtr<nsRange> mRange; 1.1152 + 1.1153 + // these arrays all typically are used and have elements 1.1154 + nsAutoTArray<nsIContent*, 8> mEndNodes; 1.1155 + nsAutoTArray<int32_t, 8> mEndOffsets; 1.1156 +}; 1.1157 + 1.1158 +NS_IMPL_ADDREF_INHERITED(nsContentSubtreeIterator, nsContentIterator) 1.1159 +NS_IMPL_RELEASE_INHERITED(nsContentSubtreeIterator, nsContentIterator) 1.1160 + 1.1161 +NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(nsContentSubtreeIterator) 1.1162 +NS_INTERFACE_MAP_END_INHERITING(nsContentIterator) 1.1163 + 1.1164 +NS_IMPL_CYCLE_COLLECTION_INHERITED(nsContentSubtreeIterator, nsContentIterator, 1.1165 + mRange) 1.1166 + 1.1167 +void 1.1168 +nsContentSubtreeIterator::LastRelease() 1.1169 +{ 1.1170 + mRange = nullptr; 1.1171 + nsContentIterator::LastRelease(); 1.1172 +} 1.1173 + 1.1174 +/****************************************************** 1.1175 + * repository cruft 1.1176 + ******************************************************/ 1.1177 + 1.1178 +already_AddRefed<nsIContentIterator> 1.1179 +NS_NewContentSubtreeIterator() 1.1180 +{ 1.1181 + nsCOMPtr<nsIContentIterator> iter = new nsContentSubtreeIterator(); 1.1182 + return iter.forget(); 1.1183 +} 1.1184 + 1.1185 + 1.1186 + 1.1187 +/****************************************************** 1.1188 + * Init routines 1.1189 + ******************************************************/ 1.1190 + 1.1191 + 1.1192 +nsresult 1.1193 +nsContentSubtreeIterator::Init(nsINode* aRoot) 1.1194 +{ 1.1195 + return NS_ERROR_NOT_IMPLEMENTED; 1.1196 +} 1.1197 + 1.1198 + 1.1199 +nsresult 1.1200 +nsContentSubtreeIterator::Init(nsIDOMRange* aRange) 1.1201 +{ 1.1202 + MOZ_ASSERT(aRange); 1.1203 + 1.1204 + mIsDone = false; 1.1205 + 1.1206 + mRange = static_cast<nsRange*>(aRange); 1.1207 + 1.1208 + // get the start node and offset, convert to nsINode 1.1209 + mCommonParent = mRange->GetCommonAncestor(); 1.1210 + nsINode* startParent = mRange->GetStartParent(); 1.1211 + int32_t startOffset = mRange->StartOffset(); 1.1212 + nsINode* endParent = mRange->GetEndParent(); 1.1213 + int32_t endOffset = mRange->EndOffset(); 1.1214 + MOZ_ASSERT(mCommonParent && startParent && endParent); 1.1215 + // Bug 767169 1.1216 + MOZ_ASSERT(uint32_t(startOffset) <= startParent->Length() && 1.1217 + uint32_t(endOffset) <= endParent->Length()); 1.1218 + 1.1219 + // short circuit when start node == end node 1.1220 + if (startParent == endParent) { 1.1221 + nsINode* child = startParent->GetFirstChild(); 1.1222 + 1.1223 + if (!child || startOffset == endOffset) { 1.1224 + // Text node, empty container, or collapsed 1.1225 + MakeEmpty(); 1.1226 + return NS_OK; 1.1227 + } 1.1228 + } 1.1229 + 1.1230 + // cache ancestors 1.1231 + nsContentUtils::GetAncestorsAndOffsets(endParent->AsDOMNode(), endOffset, 1.1232 + &mEndNodes, &mEndOffsets); 1.1233 + 1.1234 + nsIContent* firstCandidate = nullptr; 1.1235 + nsIContent* lastCandidate = nullptr; 1.1236 + 1.1237 + // find first node in range 1.1238 + int32_t offset = mRange->StartOffset(); 1.1239 + 1.1240 + nsINode* node; 1.1241 + if (!startParent->GetChildCount()) { 1.1242 + // no children, start at the node itself 1.1243 + node = startParent; 1.1244 + } else { 1.1245 + nsIContent* child = startParent->GetChildAt(offset); 1.1246 + if (!child) { 1.1247 + // offset after last child 1.1248 + node = startParent; 1.1249 + } else { 1.1250 + firstCandidate = child; 1.1251 + } 1.1252 + } 1.1253 + 1.1254 + if (!firstCandidate) { 1.1255 + // then firstCandidate is next node after node 1.1256 + firstCandidate = GetNextSibling(node); 1.1257 + 1.1258 + if (!firstCandidate) { 1.1259 + MakeEmpty(); 1.1260 + return NS_OK; 1.1261 + } 1.1262 + } 1.1263 + 1.1264 + firstCandidate = GetDeepFirstChild(firstCandidate); 1.1265 + 1.1266 + // confirm that this first possible contained node is indeed contained. Else 1.1267 + // we have a range that does not fully contain any node. 1.1268 + 1.1269 + bool nodeBefore, nodeAfter; 1.1270 + MOZ_ALWAYS_TRUE(NS_SUCCEEDED( 1.1271 + nsRange::CompareNodeToRange(firstCandidate, mRange, &nodeBefore, &nodeAfter))); 1.1272 + 1.1273 + if (nodeBefore || nodeAfter) { 1.1274 + MakeEmpty(); 1.1275 + return NS_OK; 1.1276 + } 1.1277 + 1.1278 + // cool, we have the first node in the range. Now we walk up its ancestors 1.1279 + // to find the most senior that is still in the range. That's the real first 1.1280 + // node. 1.1281 + mFirst = GetTopAncestorInRange(firstCandidate); 1.1282 + 1.1283 + // now to find the last node 1.1284 + offset = mRange->EndOffset(); 1.1285 + int32_t numChildren = endParent->GetChildCount(); 1.1286 + 1.1287 + if (offset > numChildren) { 1.1288 + // Can happen for text nodes 1.1289 + offset = numChildren; 1.1290 + } 1.1291 + if (!offset || !numChildren) { 1.1292 + node = endParent; 1.1293 + } else { 1.1294 + lastCandidate = endParent->GetChildAt(--offset); 1.1295 + NS_ASSERTION(lastCandidate, 1.1296 + "tree traversal trouble in nsContentSubtreeIterator::Init"); 1.1297 + } 1.1298 + 1.1299 + if (!lastCandidate) { 1.1300 + // then lastCandidate is prev node before node 1.1301 + lastCandidate = GetPrevSibling(node); 1.1302 + } 1.1303 + 1.1304 + if (!lastCandidate) { 1.1305 + MakeEmpty(); 1.1306 + return NS_OK; 1.1307 + } 1.1308 + 1.1309 + lastCandidate = GetDeepLastChild(lastCandidate); 1.1310 + 1.1311 + // confirm that this last possible contained node is indeed contained. Else 1.1312 + // we have a range that does not fully contain any node. 1.1313 + 1.1314 + MOZ_ALWAYS_TRUE(NS_SUCCEEDED( 1.1315 + nsRange::CompareNodeToRange(lastCandidate, mRange, &nodeBefore, &nodeAfter))); 1.1316 + 1.1317 + if (nodeBefore || nodeAfter) { 1.1318 + MakeEmpty(); 1.1319 + return NS_OK; 1.1320 + } 1.1321 + 1.1322 + // cool, we have the last node in the range. Now we walk up its ancestors to 1.1323 + // find the most senior that is still in the range. That's the real first 1.1324 + // node. 1.1325 + mLast = GetTopAncestorInRange(lastCandidate); 1.1326 + 1.1327 + mCurNode = mFirst; 1.1328 + 1.1329 + return NS_OK; 1.1330 +} 1.1331 + 1.1332 +/**************************************************************** 1.1333 + * nsContentSubtreeIterator overrides of ContentIterator routines 1.1334 + ****************************************************************/ 1.1335 + 1.1336 +// we can't call PositionAt in a subtree iterator... 1.1337 +void 1.1338 +nsContentSubtreeIterator::First() 1.1339 +{ 1.1340 + mIsDone = mFirst == nullptr; 1.1341 + 1.1342 + mCurNode = mFirst; 1.1343 +} 1.1344 + 1.1345 +// we can't call PositionAt in a subtree iterator... 1.1346 +void 1.1347 +nsContentSubtreeIterator::Last() 1.1348 +{ 1.1349 + mIsDone = mLast == nullptr; 1.1350 + 1.1351 + mCurNode = mLast; 1.1352 +} 1.1353 + 1.1354 + 1.1355 +void 1.1356 +nsContentSubtreeIterator::Next() 1.1357 +{ 1.1358 + if (mIsDone || !mCurNode) { 1.1359 + return; 1.1360 + } 1.1361 + 1.1362 + if (mCurNode == mLast) { 1.1363 + mIsDone = true; 1.1364 + return; 1.1365 + } 1.1366 + 1.1367 + nsINode* nextNode = GetNextSibling(mCurNode); 1.1368 + NS_ASSERTION(nextNode, "No next sibling!?! This could mean deadlock!"); 1.1369 + 1.1370 + int32_t i = mEndNodes.IndexOf(nextNode); 1.1371 + while (i != -1) { 1.1372 + // as long as we are finding ancestors of the endpoint of the range, 1.1373 + // dive down into their children 1.1374 + nextNode = nextNode->GetFirstChild(); 1.1375 + NS_ASSERTION(nextNode, "Iterator error, expected a child node!"); 1.1376 + 1.1377 + // should be impossible to get a null pointer. If we went all the way 1.1378 + // down the child chain to the bottom without finding an interior node, 1.1379 + // then the previous node should have been the last, which was 1.1380 + // was tested at top of routine. 1.1381 + i = mEndNodes.IndexOf(nextNode); 1.1382 + } 1.1383 + 1.1384 + mCurNode = nextNode; 1.1385 + 1.1386 + // This shouldn't be needed, but since our selection code can put us 1.1387 + // in a situation where mLast is in generated content, we need this 1.1388 + // to stop the iterator when we've walked past past the last node! 1.1389 + mIsDone = mCurNode == nullptr; 1.1390 +} 1.1391 + 1.1392 + 1.1393 +void 1.1394 +nsContentSubtreeIterator::Prev() 1.1395 +{ 1.1396 + // Prev should be optimized to use the mStartNodes, just as Next 1.1397 + // uses mEndNodes. 1.1398 + if (mIsDone || !mCurNode) { 1.1399 + return; 1.1400 + } 1.1401 + 1.1402 + if (mCurNode == mFirst) { 1.1403 + mIsDone = true; 1.1404 + return; 1.1405 + } 1.1406 + 1.1407 + // If any of these function calls return null, so will all succeeding ones, 1.1408 + // so mCurNode will wind up set to null. 1.1409 + nsINode* prevNode = GetDeepFirstChild(mCurNode); 1.1410 + 1.1411 + prevNode = PrevNode(prevNode); 1.1412 + 1.1413 + prevNode = GetDeepLastChild(prevNode); 1.1414 + 1.1415 + mCurNode = GetTopAncestorInRange(prevNode); 1.1416 + 1.1417 + // This shouldn't be needed, but since our selection code can put us 1.1418 + // in a situation where mFirst is in generated content, we need this 1.1419 + // to stop the iterator when we've walked past past the first node! 1.1420 + mIsDone = mCurNode == nullptr; 1.1421 +} 1.1422 + 1.1423 + 1.1424 +nsresult 1.1425 +nsContentSubtreeIterator::PositionAt(nsINode* aCurNode) 1.1426 +{ 1.1427 + NS_ERROR("Not implemented!"); 1.1428 + 1.1429 + return NS_ERROR_NOT_IMPLEMENTED; 1.1430 +} 1.1431 + 1.1432 +/**************************************************************** 1.1433 + * nsContentSubtreeIterator helper routines 1.1434 + ****************************************************************/ 1.1435 + 1.1436 +nsIContent* 1.1437 +nsContentSubtreeIterator::GetTopAncestorInRange(nsINode* aNode) 1.1438 +{ 1.1439 + if (!aNode || !aNode->GetParentNode()) { 1.1440 + return nullptr; 1.1441 + } 1.1442 + 1.1443 + // aNode has a parent, so it must be content. 1.1444 + nsIContent* content = aNode->AsContent(); 1.1445 + 1.1446 + // sanity check: aNode is itself in the range 1.1447 + bool nodeBefore, nodeAfter; 1.1448 + nsresult res = nsRange::CompareNodeToRange(aNode, mRange, 1.1449 + &nodeBefore, &nodeAfter); 1.1450 + NS_ASSERTION(NS_SUCCEEDED(res) && !nodeBefore && !nodeAfter, 1.1451 + "aNode isn't in mRange, or something else weird happened"); 1.1452 + if (NS_FAILED(res) || nodeBefore || nodeAfter) { 1.1453 + return nullptr; 1.1454 + } 1.1455 + 1.1456 + while (content) { 1.1457 + nsIContent* parent = content->GetParent(); 1.1458 + // content always has a parent. If its parent is the root, however -- 1.1459 + // i.e., either it's not content, or it is content but its own parent is 1.1460 + // null -- then we're finished, since we don't go up to the root. 1.1461 + // 1.1462 + // We have to special-case this because CompareNodeToRange treats the root 1.1463 + // node differently -- see bug 765205. 1.1464 + if (!parent || !parent->GetParentNode()) { 1.1465 + return content; 1.1466 + } 1.1467 + MOZ_ALWAYS_TRUE(NS_SUCCEEDED( 1.1468 + nsRange::CompareNodeToRange(parent, mRange, &nodeBefore, &nodeAfter))); 1.1469 + 1.1470 + if (nodeBefore || nodeAfter) { 1.1471 + return content; 1.1472 + } 1.1473 + content = parent; 1.1474 + } 1.1475 + 1.1476 + MOZ_CRASH("This should only be possible if aNode was null"); 1.1477 +}