content/base/src/TreeWalker.cpp

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

     1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
     2 /* vim: set ts=4 et sw=4 tw=80: */
     3 /* This Source Code Form is subject to the terms of the Mozilla Public
     4  * License, v. 2.0. If a copy of the MPL was not distributed with this
     5  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     7 /*
     8  * Implementation of DOM Traversal's nsIDOMTreeWalker
     9  */
    11 #include "mozilla/dom/TreeWalker.h"
    13 #include "nsIContent.h"
    14 #include "nsIDOMNode.h"
    15 #include "nsError.h"
    16 #include "nsINode.h"
    17 #include "nsContentUtils.h"
    18 #include "mozilla/dom/TreeWalkerBinding.h"
    20 namespace mozilla {
    21 namespace dom {
    23 /*
    24  * Factories, constructors and destructors
    25  */
    27 TreeWalker::TreeWalker(nsINode *aRoot,
    28                        uint32_t aWhatToShow,
    29                        const NodeFilterHolder &aFilter) :
    30     nsTraversal(aRoot, aWhatToShow, aFilter),
    31     mCurrentNode(aRoot)
    32 {
    33 }
    35 TreeWalker::~TreeWalker()
    36 {
    37     /* destructor code */
    38 }
    40 /*
    41  * nsISupports and cycle collection stuff
    42  */
    44 NS_IMPL_CYCLE_COLLECTION(TreeWalker, mFilter, mCurrentNode, mRoot)
    46 // QueryInterface implementation for TreeWalker
    47 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(TreeWalker)
    48     NS_INTERFACE_MAP_ENTRY(nsIDOMTreeWalker)
    49     NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIDOMTreeWalker)
    50 NS_INTERFACE_MAP_END
    52 // Have to pass in dom::TreeWalker because a11y has an a11y::TreeWalker that
    53 // passes TreeWalker so refcount logging would get confused on the name
    54 // collision.
    55 NS_IMPL_CYCLE_COLLECTING_ADDREF(dom::TreeWalker)
    56 NS_IMPL_CYCLE_COLLECTING_RELEASE(dom::TreeWalker)
    60 /*
    61  * nsIDOMTreeWalker Getters/Setters
    62  */
    64 /* readonly attribute nsIDOMNode root; */
    65 NS_IMETHODIMP TreeWalker::GetRoot(nsIDOMNode * *aRoot)
    66 {
    67     NS_ADDREF(*aRoot = Root()->AsDOMNode());
    68     return NS_OK;
    69 }
    71 /* readonly attribute unsigned long whatToShow; */
    72 NS_IMETHODIMP TreeWalker::GetWhatToShow(uint32_t *aWhatToShow)
    73 {
    74     *aWhatToShow = WhatToShow();
    75     return NS_OK;
    76 }
    78 /* readonly attribute nsIDOMNodeFilter filter; */
    79 NS_IMETHODIMP TreeWalker::GetFilter(nsIDOMNodeFilter * *aFilter)
    80 {
    81     NS_ENSURE_ARG_POINTER(aFilter);
    83     *aFilter = mFilter.ToXPCOMCallback().take();
    85     return NS_OK;
    86 }
    88 /* attribute nsIDOMNode currentNode; */
    89 NS_IMETHODIMP TreeWalker::GetCurrentNode(nsIDOMNode * *aCurrentNode)
    90 {
    91     if (mCurrentNode) {
    92         return CallQueryInterface(mCurrentNode, aCurrentNode);
    93     }
    95     *aCurrentNode = nullptr;
    97     return NS_OK;
    98 }
    99 NS_IMETHODIMP TreeWalker::SetCurrentNode(nsIDOMNode * aCurrentNode)
   100 {
   101     NS_ENSURE_TRUE(aCurrentNode, NS_ERROR_DOM_NOT_SUPPORTED_ERR);
   102     NS_ENSURE_TRUE(mRoot, NS_ERROR_UNEXPECTED);
   104     nsCOMPtr<nsINode> node = do_QueryInterface(aCurrentNode);
   105     NS_ENSURE_TRUE(node, NS_ERROR_UNEXPECTED);
   107     ErrorResult rv;
   108     SetCurrentNode(*node, rv);
   109     return rv.ErrorCode();
   110 }
   112 void
   113 TreeWalker::SetCurrentNode(nsINode& aNode, ErrorResult& aResult)
   114 {
   115     aResult = nsContentUtils::CheckSameOrigin(mRoot, &aNode);
   116     if (aResult.Failed()) {
   117         return;
   118     }
   120     mCurrentNode = &aNode;
   121 }
   123 /*
   124  * nsIDOMTreeWalker functions
   125  */
   127 /* nsIDOMNode parentNode (); */
   128 NS_IMETHODIMP TreeWalker::ParentNode(nsIDOMNode **_retval)
   129 {
   130     return ImplNodeGetter(&TreeWalker::ParentNode, _retval);
   131 }
   133 already_AddRefed<nsINode>
   134 TreeWalker::ParentNode(ErrorResult& aResult)
   135 {
   136     nsCOMPtr<nsINode> node = mCurrentNode;
   138     while (node && node != mRoot) {
   139         node = node->GetParentNode();
   141         if (node) {
   142             int16_t filtered = TestNode(node, aResult);
   143             if (aResult.Failed()) {
   144                 return nullptr;
   145             }
   146             if (filtered == nsIDOMNodeFilter::FILTER_ACCEPT) {
   147                 mCurrentNode = node;
   148                 return node.forget();
   149             }
   150         }
   151     }
   153     return nullptr;
   154 }
   156 /* nsIDOMNode firstChild (); */
   157 NS_IMETHODIMP TreeWalker::FirstChild(nsIDOMNode **_retval)
   158 {
   159     return ImplNodeGetter(&TreeWalker::FirstChild, _retval);
   160 }
   162 already_AddRefed<nsINode>
   163 TreeWalker::FirstChild(ErrorResult& aResult)
   164 {
   165     return FirstChildInternal(false, aResult);
   166 }
   168 /* nsIDOMNode lastChild (); */
   169 NS_IMETHODIMP TreeWalker::LastChild(nsIDOMNode **_retval)
   170 {
   171     return ImplNodeGetter(&TreeWalker::LastChild, _retval);
   172 }
   174 already_AddRefed<nsINode>
   175 TreeWalker::LastChild(ErrorResult& aResult)
   176 {
   177     return FirstChildInternal(true, aResult);
   178 }
   180 /* nsIDOMNode previousSibling (); */
   181 NS_IMETHODIMP TreeWalker::PreviousSibling(nsIDOMNode **_retval)
   182 {
   183     return ImplNodeGetter(&TreeWalker::PreviousSibling, _retval);
   184 }
   186 already_AddRefed<nsINode>
   187 TreeWalker::PreviousSibling(ErrorResult& aResult)
   188 {
   189     return NextSiblingInternal(true, aResult);
   190 }
   192 /* nsIDOMNode nextSibling (); */
   193 NS_IMETHODIMP TreeWalker::NextSibling(nsIDOMNode **_retval)
   194 {
   195     return ImplNodeGetter(&TreeWalker::NextSibling, _retval);
   196 }
   198 already_AddRefed<nsINode>
   199 TreeWalker::NextSibling(ErrorResult& aResult)
   200 {
   201     return NextSiblingInternal(false, aResult);
   202 }
   204 /* nsIDOMNode previousNode (); */
   205 NS_IMETHODIMP TreeWalker::PreviousNode(nsIDOMNode **_retval)
   206 {
   207     return ImplNodeGetter(&TreeWalker::PreviousNode, _retval);
   208 }
   210 already_AddRefed<nsINode>
   211 TreeWalker::PreviousNode(ErrorResult& aResult)
   212 {
   213     nsCOMPtr<nsINode> node = mCurrentNode;
   215     while (node != mRoot) {
   216         while (nsINode *previousSibling = node->GetPreviousSibling()) {
   217             node = previousSibling;
   219             int16_t filtered = TestNode(node, aResult);
   220             if (aResult.Failed()) {
   221                 return nullptr;
   222             }
   224             nsINode *lastChild;
   225             while (filtered != nsIDOMNodeFilter::FILTER_REJECT &&
   226                    (lastChild = node->GetLastChild())) {
   227                 node = lastChild;
   228                 filtered = TestNode(node, aResult);
   229                 if (aResult.Failed()) {
   230                     return nullptr;
   231                 }
   232             }
   234             if (filtered == nsIDOMNodeFilter::FILTER_ACCEPT) {
   235                 mCurrentNode = node;
   236                 return node.forget();
   237             }
   238         }
   240         if (node == mRoot) {
   241             break;
   242         }
   244         node = node->GetParentNode();
   245         if (!node) {
   246             break;
   247         }
   249         int16_t filtered = TestNode(node, aResult);
   250         if (aResult.Failed()) {
   251             return nullptr;
   252         }
   254         if (filtered == nsIDOMNodeFilter::FILTER_ACCEPT) {
   255             mCurrentNode = node;
   256             return node.forget();
   257         }
   258     }
   260     return nullptr;
   261 }
   263 /* nsIDOMNode nextNode (); */
   264 NS_IMETHODIMP TreeWalker::NextNode(nsIDOMNode **_retval)
   265 {
   266     return ImplNodeGetter(&TreeWalker::NextNode, _retval);
   267 }
   269 already_AddRefed<nsINode>
   270 TreeWalker::NextNode(ErrorResult& aResult)
   271 {
   272     int16_t filtered = nsIDOMNodeFilter::FILTER_ACCEPT; // pre-init for inner loop
   274     nsCOMPtr<nsINode> node = mCurrentNode;
   276     while (1) {
   278         nsINode *firstChild;
   279         while (filtered != nsIDOMNodeFilter::FILTER_REJECT &&
   280                (firstChild = node->GetFirstChild())) {
   281             node = firstChild;
   283             filtered = TestNode(node, aResult);
   284             if (aResult.Failed()) {
   285                 return nullptr;
   286             }
   288             if (filtered ==  nsIDOMNodeFilter::FILTER_ACCEPT) {
   289                 // Node found
   290                 mCurrentNode = node;
   291                 return node.forget();
   292             }
   293         }
   295         nsINode *sibling = nullptr;
   296         nsINode *temp = node;
   297         do {
   298             if (temp == mRoot)
   299                 break;
   301             sibling = temp->GetNextSibling();
   302             if (sibling)
   303                 break;
   305             temp = temp->GetParentNode();
   306         } while (temp);
   308         if (!sibling)
   309             break;
   311         node = sibling;
   313         // Found a sibling. Either ours or ancestor's
   314         filtered = TestNode(node, aResult);
   315         if (aResult.Failed()) {
   316             return nullptr;
   317         }
   319         if (filtered ==  nsIDOMNodeFilter::FILTER_ACCEPT) {
   320             // Node found
   321             mCurrentNode = node;
   322             return node.forget();
   323         }
   324     }
   326     return nullptr;
   327 }
   329 /*
   330  * TreeWalker helper functions
   331  */
   333 /*
   334  * Implements FirstChild and LastChild which only vary in which direction
   335  * they search.
   336  * @param aReversed Controls whether we search forwards or backwards
   337  * @param aResult   Whether we threw or not.
   338  * @returns         The desired node. Null if no child is found
   339  */
   340 already_AddRefed<nsINode>
   341 TreeWalker::FirstChildInternal(bool aReversed, ErrorResult& aResult)
   342 {
   343     nsCOMPtr<nsINode> node = aReversed ? mCurrentNode->GetLastChild()
   344                                        : mCurrentNode->GetFirstChild();
   346     while (node) {
   347         int16_t filtered = TestNode(node, aResult);
   348         if (aResult.Failed()) {
   349             return nullptr;
   350         }
   352         switch (filtered) {
   353             case nsIDOMNodeFilter::FILTER_ACCEPT:
   354                 // Node found
   355                 mCurrentNode = node;
   356                 return node.forget();
   357             case nsIDOMNodeFilter::FILTER_SKIP: {
   358                     nsINode *child = aReversed ? node->GetLastChild()
   359                                                : node->GetFirstChild();
   360                     if (child) {
   361                         node = child;
   362                         continue;
   363                     }
   364                     break;
   365                 }
   366             case nsIDOMNodeFilter::FILTER_REJECT:
   367                 // Keep searching
   368                 break;
   369         }
   371         do {
   372             nsINode *sibling = aReversed ? node->GetPreviousSibling()
   373                                          : node->GetNextSibling();
   374             if (sibling) {
   375                 node = sibling;
   376                 break;
   377             }
   379             nsINode *parent = node->GetParentNode();
   381             if (!parent || parent == mRoot || parent == mCurrentNode) {
   382                 return nullptr;
   383             }
   385             node = parent;
   387         } while (node);
   388     }
   390     return nullptr;
   391 }
   393 /*
   394  * Implements NextSibling and PreviousSibling which only vary in which
   395  * direction they search.
   396  * @param aReversed Controls whether we search forwards or backwards
   397  * @param aResult   Whether we threw or not.
   398  * @returns         The desired node. Null if no child is found
   399  */
   400 already_AddRefed<nsINode>
   401 TreeWalker::NextSiblingInternal(bool aReversed, ErrorResult& aResult)
   402 {
   403     nsCOMPtr<nsINode> node = mCurrentNode;
   405     if (node == mRoot) {
   406         return nullptr;
   407     }
   409     while (1) {
   410         nsINode* sibling = aReversed ? node->GetPreviousSibling()
   411                                      : node->GetNextSibling();
   413         while (sibling) {
   414             node = sibling;
   416             int16_t filtered = TestNode(node, aResult);
   417             if (aResult.Failed()) {
   418                 return nullptr;
   419             }
   421             if (filtered == nsIDOMNodeFilter::FILTER_ACCEPT) {
   422                 // Node found
   423                 mCurrentNode = node;
   424                 return node.forget();
   425             }
   427             // If rejected or no children, try a sibling
   428             if (filtered == nsIDOMNodeFilter::FILTER_REJECT ||
   429                 !(sibling = aReversed ? node->GetLastChild()
   430                                       : node->GetFirstChild())) {
   431                 sibling = aReversed ? node->GetPreviousSibling()
   432                                     : node->GetNextSibling();
   433             }
   434         }
   436         node = node->GetParentNode();
   438         if (!node || node == mRoot) {
   439             return nullptr;
   440         }
   442         // Is parent transparent in filtered view?
   443         int16_t filtered = TestNode(node, aResult);
   444         if (aResult.Failed()) {
   445             return nullptr;
   446         }
   447         if (filtered == nsIDOMNodeFilter::FILTER_ACCEPT) {
   448             return nullptr;
   449         }
   450     }
   451 }
   453 JSObject*
   454 TreeWalker::WrapObject(JSContext *cx)
   455 {
   456     return TreeWalkerBinding::Wrap(cx, this);
   457 }
   459 } // namespace dom
   460 } // namespace mozilla

mercurial