LCOV - code coverage report
Current view: top level - dom/base - TreeWalker.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 0 197 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 32 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       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/. */
       6             : 
       7             : /*
       8             :  * Implementation of DOM Traversal's nsIDOMTreeWalker
       9             :  */
      10             : 
      11             : #include "mozilla/dom/TreeWalker.h"
      12             : 
      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"
      19             : 
      20             : namespace mozilla {
      21             : namespace dom {
      22             : 
      23             : /*
      24             :  * Factories, constructors and destructors
      25             :  */
      26             : 
      27           0 : TreeWalker::TreeWalker(nsINode *aRoot,
      28             :                        uint32_t aWhatToShow,
      29           0 :                        NodeFilterHolder aFilter) :
      30           0 :     nsTraversal(aRoot, aWhatToShow, Move(aFilter)),
      31           0 :     mCurrentNode(aRoot)
      32             : {
      33           0 : }
      34             : 
      35           0 : TreeWalker::~TreeWalker()
      36             : {
      37             :     /* destructor code */
      38           0 : }
      39             : 
      40             : /*
      41             :  * nsISupports and cycle collection stuff
      42             :  */
      43             : 
      44           0 : NS_IMPL_CYCLE_COLLECTION(TreeWalker, mFilter, mCurrentNode, mRoot)
      45             : 
      46             : // QueryInterface implementation for TreeWalker
      47           0 : NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(TreeWalker)
      48           0 :     NS_INTERFACE_MAP_ENTRY(nsIDOMTreeWalker)
      49           0 :     NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIDOMTreeWalker)
      50           0 : NS_INTERFACE_MAP_END
      51             : 
      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           0 : NS_IMPL_CYCLE_COLLECTING_ADDREF(dom::TreeWalker)
      56           0 : NS_IMPL_CYCLE_COLLECTING_RELEASE(dom::TreeWalker)
      57             : 
      58             : 
      59             : 
      60             : /*
      61             :  * nsIDOMTreeWalker Getters/Setters
      62             :  */
      63             : 
      64           0 : NS_IMETHODIMP TreeWalker::GetRoot(nsIDOMNode * *aRoot)
      65             : {
      66           0 :     NS_ADDREF(*aRoot = Root()->AsDOMNode());
      67           0 :     return NS_OK;
      68             : }
      69             : 
      70           0 : NS_IMETHODIMP TreeWalker::GetWhatToShow(uint32_t *aWhatToShow)
      71             : {
      72           0 :     *aWhatToShow = WhatToShow();
      73           0 :     return NS_OK;
      74             : }
      75             : 
      76           0 : NS_IMETHODIMP TreeWalker::GetFilter(nsIDOMNodeFilter * *aFilter)
      77             : {
      78           0 :     NS_ENSURE_ARG_POINTER(aFilter);
      79             : 
      80           0 :     *aFilter = mFilter.ToXPCOMCallback().take();
      81             : 
      82           0 :     return NS_OK;
      83             : }
      84             : 
      85           0 : NS_IMETHODIMP TreeWalker::GetCurrentNode(nsIDOMNode * *aCurrentNode)
      86             : {
      87           0 :     if (mCurrentNode) {
      88           0 :         return CallQueryInterface(mCurrentNode, aCurrentNode);
      89             :     }
      90             : 
      91           0 :     *aCurrentNode = nullptr;
      92             : 
      93           0 :     return NS_OK;
      94             : }
      95           0 : NS_IMETHODIMP TreeWalker::SetCurrentNode(nsIDOMNode * aCurrentNode)
      96             : {
      97           0 :     NS_ENSURE_TRUE(aCurrentNode, NS_ERROR_DOM_NOT_SUPPORTED_ERR);
      98           0 :     NS_ENSURE_TRUE(mRoot, NS_ERROR_UNEXPECTED);
      99             : 
     100           0 :     nsCOMPtr<nsINode> node = do_QueryInterface(aCurrentNode);
     101           0 :     NS_ENSURE_TRUE(node, NS_ERROR_UNEXPECTED);
     102             : 
     103           0 :     ErrorResult rv;
     104           0 :     SetCurrentNode(*node, rv);
     105           0 :     return rv.StealNSResult();
     106             : }
     107             : 
     108             : void
     109           0 : TreeWalker::SetCurrentNode(nsINode& aNode, ErrorResult& aResult)
     110             : {
     111           0 :     aResult = nsContentUtils::CheckSameOrigin(mRoot, &aNode);
     112           0 :     if (aResult.Failed()) {
     113           0 :         return;
     114             :     }
     115             : 
     116           0 :     mCurrentNode = &aNode;
     117             : }
     118             : 
     119             : /*
     120             :  * nsIDOMTreeWalker functions
     121             :  */
     122             : 
     123           0 : NS_IMETHODIMP TreeWalker::ParentNode(nsIDOMNode **_retval)
     124             : {
     125           0 :     return ImplNodeGetter(&TreeWalker::ParentNode, _retval);
     126             : }
     127             : 
     128             : already_AddRefed<nsINode>
     129           0 : TreeWalker::ParentNode(ErrorResult& aResult)
     130             : {
     131           0 :     nsCOMPtr<nsINode> node = mCurrentNode;
     132             : 
     133           0 :     while (node && node != mRoot) {
     134           0 :         node = node->GetParentNode();
     135             : 
     136           0 :         if (node) {
     137           0 :             int16_t filtered = TestNode(node, aResult);
     138           0 :             if (aResult.Failed()) {
     139           0 :                 return nullptr;
     140             :             }
     141           0 :             if (filtered == nsIDOMNodeFilter::FILTER_ACCEPT) {
     142           0 :                 mCurrentNode = node;
     143           0 :                 return node.forget();
     144             :             }
     145             :         }
     146             :     }
     147             : 
     148           0 :     return nullptr;
     149             : }
     150             : 
     151           0 : NS_IMETHODIMP TreeWalker::FirstChild(nsIDOMNode **_retval)
     152             : {
     153           0 :     return ImplNodeGetter(&TreeWalker::FirstChild, _retval);
     154             : }
     155             : 
     156             : already_AddRefed<nsINode>
     157           0 : TreeWalker::FirstChild(ErrorResult& aResult)
     158             : {
     159           0 :     return FirstChildInternal(false, aResult);
     160             : }
     161             : 
     162           0 : NS_IMETHODIMP TreeWalker::LastChild(nsIDOMNode **_retval)
     163             : {
     164           0 :     return ImplNodeGetter(&TreeWalker::LastChild, _retval);
     165             : }
     166             : 
     167             : already_AddRefed<nsINode>
     168           0 : TreeWalker::LastChild(ErrorResult& aResult)
     169             : {
     170           0 :     return FirstChildInternal(true, aResult);
     171             : }
     172             : 
     173           0 : NS_IMETHODIMP TreeWalker::PreviousSibling(nsIDOMNode **_retval)
     174             : {
     175           0 :     return ImplNodeGetter(&TreeWalker::PreviousSibling, _retval);
     176             : }
     177             : 
     178             : already_AddRefed<nsINode>
     179           0 : TreeWalker::PreviousSibling(ErrorResult& aResult)
     180             : {
     181           0 :     return NextSiblingInternal(true, aResult);
     182             : }
     183             : 
     184           0 : NS_IMETHODIMP TreeWalker::NextSibling(nsIDOMNode **_retval)
     185             : {
     186           0 :     return ImplNodeGetter(&TreeWalker::NextSibling, _retval);
     187             : }
     188             : 
     189             : already_AddRefed<nsINode>
     190           0 : TreeWalker::NextSibling(ErrorResult& aResult)
     191             : {
     192           0 :     return NextSiblingInternal(false, aResult);
     193             : }
     194             : 
     195           0 : NS_IMETHODIMP TreeWalker::PreviousNode(nsIDOMNode **_retval)
     196             : {
     197           0 :     return ImplNodeGetter(&TreeWalker::PreviousNode, _retval);
     198             : }
     199             : 
     200             : already_AddRefed<nsINode>
     201           0 : TreeWalker::PreviousNode(ErrorResult& aResult)
     202             : {
     203           0 :     nsCOMPtr<nsINode> node = mCurrentNode;
     204             : 
     205           0 :     while (node != mRoot) {
     206           0 :         while (nsINode *previousSibling = node->GetPreviousSibling()) {
     207           0 :             node = previousSibling;
     208             : 
     209           0 :             int16_t filtered = TestNode(node, aResult);
     210           0 :             if (aResult.Failed()) {
     211           0 :                 return nullptr;
     212             :             }
     213             : 
     214             :             nsINode *lastChild;
     215           0 :             while (filtered != nsIDOMNodeFilter::FILTER_REJECT &&
     216           0 :                    (lastChild = node->GetLastChild())) {
     217           0 :                 node = lastChild;
     218           0 :                 filtered = TestNode(node, aResult);
     219           0 :                 if (aResult.Failed()) {
     220           0 :                     return nullptr;
     221             :                 }
     222             :             }
     223             : 
     224           0 :             if (filtered == nsIDOMNodeFilter::FILTER_ACCEPT) {
     225           0 :                 mCurrentNode = node;
     226           0 :                 return node.forget();
     227             :             }
     228           0 :         }
     229             : 
     230           0 :         if (node == mRoot) {
     231           0 :             break;
     232             :         }
     233             : 
     234           0 :         node = node->GetParentNode();
     235           0 :         if (!node) {
     236           0 :             break;
     237             :         }
     238             : 
     239           0 :         int16_t filtered = TestNode(node, aResult);
     240           0 :         if (aResult.Failed()) {
     241           0 :             return nullptr;
     242             :         }
     243             : 
     244           0 :         if (filtered == nsIDOMNodeFilter::FILTER_ACCEPT) {
     245           0 :             mCurrentNode = node;
     246           0 :             return node.forget();
     247             :         }
     248             :     }
     249             : 
     250           0 :     return nullptr;
     251             : }
     252             : 
     253           0 : NS_IMETHODIMP TreeWalker::NextNode(nsIDOMNode **_retval)
     254             : {
     255           0 :     return ImplNodeGetter(&TreeWalker::NextNode, _retval);
     256             : }
     257             : 
     258             : already_AddRefed<nsINode>
     259           0 : TreeWalker::NextNode(ErrorResult& aResult)
     260             : {
     261           0 :     int16_t filtered = nsIDOMNodeFilter::FILTER_ACCEPT; // pre-init for inner loop
     262             : 
     263           0 :     nsCOMPtr<nsINode> node = mCurrentNode;
     264             : 
     265             :     while (1) {
     266             : 
     267             :         nsINode *firstChild;
     268           0 :         while (filtered != nsIDOMNodeFilter::FILTER_REJECT &&
     269           0 :                (firstChild = node->GetFirstChild())) {
     270           0 :             node = firstChild;
     271             : 
     272           0 :             filtered = TestNode(node, aResult);
     273           0 :             if (aResult.Failed()) {
     274           0 :                 return nullptr;
     275             :             }
     276             : 
     277           0 :             if (filtered ==  nsIDOMNodeFilter::FILTER_ACCEPT) {
     278             :                 // Node found
     279           0 :                 mCurrentNode = node;
     280           0 :                 return node.forget();
     281             :             }
     282             :         }
     283             : 
     284           0 :         nsINode *sibling = nullptr;
     285           0 :         nsINode *temp = node;
     286           0 :         do {
     287           0 :             if (temp == mRoot)
     288           0 :                 break;
     289             : 
     290           0 :             sibling = temp->GetNextSibling();
     291           0 :             if (sibling)
     292           0 :                 break;
     293             : 
     294           0 :             temp = temp->GetParentNode();
     295           0 :         } while (temp);
     296             : 
     297           0 :         if (!sibling)
     298           0 :             break;
     299             : 
     300           0 :         node = sibling;
     301             : 
     302             :         // Found a sibling. Either ours or ancestor's
     303           0 :         filtered = TestNode(node, aResult);
     304           0 :         if (aResult.Failed()) {
     305           0 :             return nullptr;
     306             :         }
     307             : 
     308           0 :         if (filtered ==  nsIDOMNodeFilter::FILTER_ACCEPT) {
     309             :             // Node found
     310           0 :             mCurrentNode = node;
     311           0 :             return node.forget();
     312             :         }
     313           0 :     }
     314             : 
     315           0 :     return nullptr;
     316             : }
     317             : 
     318             : /*
     319             :  * TreeWalker helper functions
     320             :  */
     321             : 
     322             : /*
     323             :  * Implements FirstChild and LastChild which only vary in which direction
     324             :  * they search.
     325             :  * @param aReversed Controls whether we search forwards or backwards
     326             :  * @param aResult   Whether we threw or not.
     327             :  * @returns         The desired node. Null if no child is found
     328             :  */
     329             : already_AddRefed<nsINode>
     330           0 : TreeWalker::FirstChildInternal(bool aReversed, ErrorResult& aResult)
     331             : {
     332           0 :     nsCOMPtr<nsINode> node = aReversed ? mCurrentNode->GetLastChild()
     333           0 :                                        : mCurrentNode->GetFirstChild();
     334             : 
     335           0 :     while (node) {
     336           0 :         int16_t filtered = TestNode(node, aResult);
     337           0 :         if (aResult.Failed()) {
     338           0 :             return nullptr;
     339             :         }
     340             : 
     341           0 :         switch (filtered) {
     342             :             case nsIDOMNodeFilter::FILTER_ACCEPT:
     343             :                 // Node found
     344           0 :                 mCurrentNode = node;
     345           0 :                 return node.forget();
     346             :             case nsIDOMNodeFilter::FILTER_SKIP: {
     347           0 :                     nsINode *child = aReversed ? node->GetLastChild()
     348           0 :                                                : node->GetFirstChild();
     349           0 :                     if (child) {
     350           0 :                         node = child;
     351           0 :                         continue;
     352             :                     }
     353           0 :                     break;
     354             :                 }
     355             :             case nsIDOMNodeFilter::FILTER_REJECT:
     356             :                 // Keep searching
     357           0 :                 break;
     358             :         }
     359             : 
     360           0 :         do {
     361           0 :             nsINode *sibling = aReversed ? node->GetPreviousSibling()
     362           0 :                                          : node->GetNextSibling();
     363           0 :             if (sibling) {
     364           0 :                 node = sibling;
     365           0 :                 break;
     366             :             }
     367             : 
     368           0 :             nsINode *parent = node->GetParentNode();
     369             : 
     370           0 :             if (!parent || parent == mRoot || parent == mCurrentNode) {
     371           0 :                 return nullptr;
     372             :             }
     373             : 
     374           0 :             node = parent;
     375             : 
     376             :         } while (node);
     377             :     }
     378             : 
     379           0 :     return nullptr;
     380             : }
     381             : 
     382             : /*
     383             :  * Implements NextSibling and PreviousSibling which only vary in which
     384             :  * direction they search.
     385             :  * @param aReversed Controls whether we search forwards or backwards
     386             :  * @param aResult   Whether we threw or not.
     387             :  * @returns         The desired node. Null if no child is found
     388             :  */
     389             : already_AddRefed<nsINode>
     390           0 : TreeWalker::NextSiblingInternal(bool aReversed, ErrorResult& aResult)
     391             : {
     392           0 :     nsCOMPtr<nsINode> node = mCurrentNode;
     393             : 
     394           0 :     if (node == mRoot) {
     395           0 :         return nullptr;
     396             :     }
     397             : 
     398             :     while (1) {
     399           0 :         nsINode* sibling = aReversed ? node->GetPreviousSibling()
     400           0 :                                      : node->GetNextSibling();
     401             : 
     402           0 :         while (sibling) {
     403           0 :             node = sibling;
     404             : 
     405           0 :             int16_t filtered = TestNode(node, aResult);
     406           0 :             if (aResult.Failed()) {
     407           0 :                 return nullptr;
     408             :             }
     409             : 
     410           0 :             if (filtered == nsIDOMNodeFilter::FILTER_ACCEPT) {
     411             :                 // Node found
     412           0 :                 mCurrentNode = node;
     413           0 :                 return node.forget();
     414             :             }
     415             : 
     416             :             // If rejected or no children, try a sibling
     417           0 :             if (filtered == nsIDOMNodeFilter::FILTER_REJECT ||
     418           0 :                 !(sibling = aReversed ? node->GetLastChild()
     419           0 :                                       : node->GetFirstChild())) {
     420           0 :                 sibling = aReversed ? node->GetPreviousSibling()
     421           0 :                                     : node->GetNextSibling();
     422             :             }
     423             :         }
     424             : 
     425           0 :         node = node->GetParentNode();
     426             : 
     427           0 :         if (!node || node == mRoot) {
     428           0 :             return nullptr;
     429             :         }
     430             : 
     431             :         // Is parent transparent in filtered view?
     432           0 :         int16_t filtered = TestNode(node, aResult);
     433           0 :         if (aResult.Failed()) {
     434           0 :             return nullptr;
     435             :         }
     436           0 :         if (filtered == nsIDOMNodeFilter::FILTER_ACCEPT) {
     437           0 :             return nullptr;
     438             :         }
     439           0 :     }
     440             : }
     441             : 
     442             : bool
     443           0 : TreeWalker::WrapObject(JSContext *aCx, JS::Handle<JSObject*> aGivenProto, JS::MutableHandle<JSObject*> aReflector)
     444             : {
     445           0 :     return TreeWalkerBinding::Wrap(aCx, this, aGivenProto, aReflector);
     446             : }
     447             : 
     448             : } // namespace dom
     449             : } // namespace mozilla

Generated by: LCOV version 1.13