1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/content/base/src/NodeIterator.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,298 @@ 1.4 +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- 1.5 + * 1.6 + * This Source Code Form is subject to the terms of the Mozilla Public 1.7 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.8 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.9 + 1.10 +/* 1.11 + * Implementation of DOM Traversal's nsIDOMNodeIterator 1.12 + */ 1.13 + 1.14 +#include "mozilla/dom/NodeIterator.h" 1.15 + 1.16 +#include "nsIDOMNode.h" 1.17 +#include "nsError.h" 1.18 + 1.19 +#include "nsIContent.h" 1.20 +#include "nsIDocument.h" 1.21 +#include "nsContentUtils.h" 1.22 +#include "nsCOMPtr.h" 1.23 +#include "mozilla/dom/NodeIteratorBinding.h" 1.24 + 1.25 +namespace mozilla { 1.26 +namespace dom { 1.27 + 1.28 +/* 1.29 + * NodePointer implementation 1.30 + */ 1.31 +NodeIterator::NodePointer::NodePointer(nsINode *aNode, bool aBeforeNode) : 1.32 + mNode(aNode), 1.33 + mBeforeNode(aBeforeNode) 1.34 +{ 1.35 +} 1.36 + 1.37 +bool NodeIterator::NodePointer::MoveToNext(nsINode *aRoot) 1.38 +{ 1.39 + if (!mNode) 1.40 + return false; 1.41 + 1.42 + if (mBeforeNode) { 1.43 + mBeforeNode = false; 1.44 + return true; 1.45 + } 1.46 + 1.47 + nsINode* child = mNode->GetFirstChild(); 1.48 + if (child) { 1.49 + mNode = child; 1.50 + return true; 1.51 + } 1.52 + 1.53 + return MoveForward(aRoot, mNode); 1.54 +} 1.55 + 1.56 +bool NodeIterator::NodePointer::MoveToPrevious(nsINode *aRoot) 1.57 +{ 1.58 + if (!mNode) 1.59 + return false; 1.60 + 1.61 + if (!mBeforeNode) { 1.62 + mBeforeNode = true; 1.63 + return true; 1.64 + } 1.65 + 1.66 + if (mNode == aRoot) 1.67 + return false; 1.68 + 1.69 + MoveBackward(mNode->GetParentNode(), mNode->GetPreviousSibling()); 1.70 + 1.71 + return true; 1.72 +} 1.73 + 1.74 +void NodeIterator::NodePointer::AdjustAfterRemoval(nsINode *aRoot, 1.75 + nsINode *aContainer, 1.76 + nsIContent *aChild, 1.77 + nsIContent *aPreviousSibling) 1.78 +{ 1.79 + // If mNode is null or the root there is nothing to do. 1.80 + if (!mNode || mNode == aRoot) 1.81 + return; 1.82 + 1.83 + // check if ancestor was removed 1.84 + if (!nsContentUtils::ContentIsDescendantOf(mNode, aChild)) 1.85 + return; 1.86 + 1.87 + if (mBeforeNode) { 1.88 + 1.89 + // Try the next sibling 1.90 + nsINode *nextSibling = aPreviousSibling ? aPreviousSibling->GetNextSibling() 1.91 + : aContainer->GetFirstChild(); 1.92 + 1.93 + if (nextSibling) { 1.94 + mNode = nextSibling; 1.95 + return; 1.96 + } 1.97 + 1.98 + // Next try siblings of ancestors 1.99 + if (MoveForward(aRoot, aContainer)) 1.100 + return; 1.101 + 1.102 + // No suitable node was found so try going backwards 1.103 + mBeforeNode = false; 1.104 + } 1.105 + 1.106 + MoveBackward(aContainer, aPreviousSibling); 1.107 +} 1.108 + 1.109 +bool NodeIterator::NodePointer::MoveForward(nsINode *aRoot, nsINode *aNode) 1.110 +{ 1.111 + while (1) { 1.112 + if (aNode == aRoot) 1.113 + break; 1.114 + 1.115 + nsINode *sibling = aNode->GetNextSibling(); 1.116 + if (sibling) { 1.117 + mNode = sibling; 1.118 + return true; 1.119 + } 1.120 + aNode = aNode->GetParentNode(); 1.121 + } 1.122 + 1.123 + return false; 1.124 +} 1.125 + 1.126 +void NodeIterator::NodePointer::MoveBackward(nsINode *aParent, nsINode *aNode) 1.127 +{ 1.128 + if (aNode) { 1.129 + do { 1.130 + mNode = aNode; 1.131 + aNode = aNode->GetLastChild(); 1.132 + } while (aNode); 1.133 + } else { 1.134 + mNode = aParent; 1.135 + } 1.136 +} 1.137 + 1.138 +/* 1.139 + * Factories, constructors and destructors 1.140 + */ 1.141 + 1.142 +NodeIterator::NodeIterator(nsINode *aRoot, 1.143 + uint32_t aWhatToShow, 1.144 + const NodeFilterHolder &aFilter) : 1.145 + nsTraversal(aRoot, aWhatToShow, aFilter), 1.146 + mPointer(mRoot, true) 1.147 +{ 1.148 + aRoot->AddMutationObserver(this); 1.149 +} 1.150 + 1.151 +NodeIterator::~NodeIterator() 1.152 +{ 1.153 + /* destructor code */ 1.154 + if (mRoot) 1.155 + mRoot->RemoveMutationObserver(this); 1.156 +} 1.157 + 1.158 +/* 1.159 + * nsISupports and cycle collection stuff 1.160 + */ 1.161 + 1.162 +NS_IMPL_CYCLE_COLLECTION_CLASS(NodeIterator) 1.163 + 1.164 +NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(NodeIterator) 1.165 + if (tmp->mRoot) 1.166 + tmp->mRoot->RemoveMutationObserver(tmp); 1.167 + NS_IMPL_CYCLE_COLLECTION_UNLINK(mRoot) 1.168 + NS_IMPL_CYCLE_COLLECTION_UNLINK(mFilter) 1.169 +NS_IMPL_CYCLE_COLLECTION_UNLINK_END 1.170 +NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(NodeIterator) 1.171 + NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mRoot) 1.172 + NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mFilter) 1.173 +NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END 1.174 + 1.175 +// QueryInterface implementation for NodeIterator 1.176 +NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(NodeIterator) 1.177 + NS_INTERFACE_MAP_ENTRY(nsIDOMNodeIterator) 1.178 + NS_INTERFACE_MAP_ENTRY(nsIMutationObserver) 1.179 + NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIDOMNodeIterator) 1.180 +NS_INTERFACE_MAP_END 1.181 + 1.182 +NS_IMPL_CYCLE_COLLECTING_ADDREF(NodeIterator) 1.183 +NS_IMPL_CYCLE_COLLECTING_RELEASE(NodeIterator) 1.184 + 1.185 +/* readonly attribute nsIDOMNode root; */ 1.186 +NS_IMETHODIMP NodeIterator::GetRoot(nsIDOMNode * *aRoot) 1.187 +{ 1.188 + NS_ADDREF(*aRoot = Root()->AsDOMNode()); 1.189 + return NS_OK; 1.190 +} 1.191 + 1.192 +/* readonly attribute unsigned long whatToShow; */ 1.193 +NS_IMETHODIMP NodeIterator::GetWhatToShow(uint32_t *aWhatToShow) 1.194 +{ 1.195 + *aWhatToShow = WhatToShow(); 1.196 + return NS_OK; 1.197 +} 1.198 + 1.199 +/* readonly attribute nsIDOMNodeFilter filter; */ 1.200 +NS_IMETHODIMP NodeIterator::GetFilter(nsIDOMNodeFilter **aFilter) 1.201 +{ 1.202 + NS_ENSURE_ARG_POINTER(aFilter); 1.203 + 1.204 + *aFilter = mFilter.ToXPCOMCallback().take(); 1.205 + 1.206 + return NS_OK; 1.207 +} 1.208 + 1.209 +/* nsIDOMNode nextNode () raises (DOMException); */ 1.210 +NS_IMETHODIMP NodeIterator::NextNode(nsIDOMNode **_retval) 1.211 +{ 1.212 + return ImplNodeGetter(&NodeIterator::NextNode, _retval); 1.213 +} 1.214 + 1.215 +/* nsIDOMNode previousNode () raises (DOMException); */ 1.216 +NS_IMETHODIMP NodeIterator::PreviousNode(nsIDOMNode **_retval) 1.217 +{ 1.218 + return ImplNodeGetter(&NodeIterator::PreviousNode, _retval); 1.219 +} 1.220 + 1.221 +already_AddRefed<nsINode> 1.222 +NodeIterator::NextOrPrevNode(NodePointer::MoveToMethodType aMove, 1.223 + ErrorResult& aResult) 1.224 +{ 1.225 + if (mInAcceptNode) { 1.226 + aResult.Throw(NS_ERROR_DOM_INVALID_STATE_ERR); 1.227 + return nullptr; 1.228 + } 1.229 + 1.230 + mWorkingPointer = mPointer; 1.231 + 1.232 + struct AutoClear { 1.233 + NodePointer* mPtr; 1.234 + AutoClear(NodePointer* ptr) : mPtr(ptr) {} 1.235 + ~AutoClear() { mPtr->Clear(); } 1.236 + } ac(&mWorkingPointer); 1.237 + 1.238 + while ((mWorkingPointer.*aMove)(mRoot)) { 1.239 + nsCOMPtr<nsINode> testNode = mWorkingPointer.mNode; 1.240 + int16_t filtered = TestNode(testNode, aResult); 1.241 + if (aResult.Failed()) { 1.242 + return nullptr; 1.243 + } 1.244 + 1.245 + if (filtered == nsIDOMNodeFilter::FILTER_ACCEPT) { 1.246 + mPointer = mWorkingPointer; 1.247 + return testNode.forget(); 1.248 + } 1.249 + } 1.250 + 1.251 + return nullptr; 1.252 +} 1.253 + 1.254 +/* void detach (); */ 1.255 +NS_IMETHODIMP NodeIterator::Detach(void) 1.256 +{ 1.257 + if (mRoot) { 1.258 + mRoot->OwnerDoc()->WarnOnceAbout(nsIDocument::eNodeIteratorDetach); 1.259 + } 1.260 + return NS_OK; 1.261 +} 1.262 + 1.263 +/* readonly attribute nsIDOMNode referenceNode; */ 1.264 +NS_IMETHODIMP NodeIterator::GetReferenceNode(nsIDOMNode * *aRefNode) 1.265 +{ 1.266 + nsCOMPtr<nsIDOMNode> node(do_QueryInterface(GetReferenceNode())); 1.267 + node.forget(aRefNode); 1.268 + return NS_OK; 1.269 +} 1.270 + 1.271 +/* readonly attribute boolean pointerBeforeReferenceNode; */ 1.272 +NS_IMETHODIMP NodeIterator::GetPointerBeforeReferenceNode(bool *aBeforeNode) 1.273 +{ 1.274 + *aBeforeNode = PointerBeforeReferenceNode(); 1.275 + return NS_OK; 1.276 +} 1.277 + 1.278 +/* 1.279 + * nsIMutationObserver interface 1.280 + */ 1.281 + 1.282 +void NodeIterator::ContentRemoved(nsIDocument *aDocument, 1.283 + nsIContent *aContainer, 1.284 + nsIContent *aChild, 1.285 + int32_t aIndexInContainer, 1.286 + nsIContent *aPreviousSibling) 1.287 +{ 1.288 + nsINode *container = NODE_FROM(aContainer, aDocument); 1.289 + 1.290 + mPointer.AdjustAfterRemoval(mRoot, container, aChild, aPreviousSibling); 1.291 + mWorkingPointer.AdjustAfterRemoval(mRoot, container, aChild, aPreviousSibling); 1.292 +} 1.293 + 1.294 +JSObject* 1.295 +NodeIterator::WrapObject(JSContext *cx) 1.296 +{ 1.297 + return NodeIteratorBinding::Wrap(cx, this); 1.298 +} 1.299 + 1.300 +} // namespace dom 1.301 +} // namespace mozilla