LCOV - code coverage report
Current view: top level - layout/inspector - inDeepTreeWalker.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 0 194 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 29 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
       2             : /* vim: set ts=2 sw=2 et tw=79: */
       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             : #include "inDeepTreeWalker.h"
       8             : #include "inLayoutUtils.h"
       9             : 
      10             : #include "nsString.h"
      11             : #include "nsIDOMDocument.h"
      12             : #include "nsIDOMNodeFilter.h"
      13             : #include "nsIDOMNodeList.h"
      14             : #include "nsServiceManagerUtils.h"
      15             : #include "inIDOMUtils.h"
      16             : #include "nsIContent.h"
      17             : #include "nsContentList.h"
      18             : #include "ChildIterator.h"
      19             : #include "mozilla/dom/Element.h"
      20             : 
      21             : /*****************************************************************************
      22             :  * This implementation does not currently operaate according to the W3C spec.
      23             :  * In particular it does NOT handle DOM mutations during the walk.  It also
      24             :  * ignores whatToShow and the filter.
      25             :  *****************************************************************************/
      26             : 
      27             : ////////////////////////////////////////////////////
      28             : 
      29           0 : inDeepTreeWalker::inDeepTreeWalker()
      30             :   : mShowAnonymousContent(false),
      31             :     mShowSubDocuments(false),
      32             :     mShowDocumentsAsNodes(false),
      33           0 :     mWhatToShow(nsIDOMNodeFilter::SHOW_ALL)
      34             : {
      35           0 : }
      36             : 
      37           0 : inDeepTreeWalker::~inDeepTreeWalker()
      38             : {
      39           0 : }
      40             : 
      41           0 : NS_IMPL_ISUPPORTS(inDeepTreeWalker,
      42             :                   inIDeepTreeWalker)
      43             : 
      44             : ////////////////////////////////////////////////////
      45             : // inIDeepTreeWalker
      46             : 
      47             : NS_IMETHODIMP
      48           0 : inDeepTreeWalker::GetShowAnonymousContent(bool *aShowAnonymousContent)
      49             : {
      50           0 :   *aShowAnonymousContent = mShowAnonymousContent;
      51           0 :   return NS_OK;
      52             : }
      53             : 
      54             : NS_IMETHODIMP
      55           0 : inDeepTreeWalker::SetShowAnonymousContent(bool aShowAnonymousContent)
      56             : {
      57           0 :   mShowAnonymousContent = aShowAnonymousContent;
      58           0 :   return NS_OK;
      59             : }
      60             : 
      61             : NS_IMETHODIMP
      62           0 : inDeepTreeWalker::GetShowSubDocuments(bool *aShowSubDocuments)
      63             : {
      64           0 :   *aShowSubDocuments = mShowSubDocuments;
      65           0 :   return NS_OK;
      66             : }
      67             : 
      68             : NS_IMETHODIMP
      69           0 : inDeepTreeWalker::SetShowSubDocuments(bool aShowSubDocuments)
      70             : {
      71           0 :   mShowSubDocuments = aShowSubDocuments;
      72           0 :   return NS_OK;
      73             : }
      74             : 
      75             : NS_IMETHODIMP
      76           0 : inDeepTreeWalker::GetShowDocumentsAsNodes(bool *aShowDocumentsAsNodes)
      77             : {
      78           0 :   *aShowDocumentsAsNodes = mShowDocumentsAsNodes;
      79           0 :   return NS_OK;
      80             : }
      81             : 
      82             : NS_IMETHODIMP
      83           0 : inDeepTreeWalker::SetShowDocumentsAsNodes(bool aShowDocumentsAsNodes)
      84             : {
      85           0 :   mShowDocumentsAsNodes = aShowDocumentsAsNodes;
      86           0 :   return NS_OK;
      87             : }
      88             : 
      89             : NS_IMETHODIMP
      90           0 : inDeepTreeWalker::Init(nsIDOMNode* aRoot, uint32_t aWhatToShow)
      91             : {
      92           0 :   if (!aRoot) {
      93           0 :     return NS_ERROR_INVALID_ARG;
      94             :   }
      95             : 
      96           0 :   mRoot = aRoot;
      97           0 :   mCurrentNode = aRoot;
      98           0 :   mWhatToShow = aWhatToShow;
      99             : 
     100           0 :   mDOMUtils = do_GetService("@mozilla.org/inspector/dom-utils;1");
     101           0 :   return mDOMUtils ? NS_OK : NS_ERROR_UNEXPECTED;
     102             : }
     103             : 
     104             : ////////////////////////////////////////////////////
     105             : // nsIDOMTreeWalker
     106             : 
     107             : NS_IMETHODIMP
     108           0 : inDeepTreeWalker::GetRoot(nsIDOMNode** aRoot)
     109             : {
     110           0 :   *aRoot = mRoot;
     111           0 :   NS_IF_ADDREF(*aRoot);
     112           0 :   return NS_OK;
     113             : }
     114             : 
     115             : NS_IMETHODIMP
     116           0 : inDeepTreeWalker::GetWhatToShow(uint32_t* aWhatToShow)
     117             : {
     118           0 :   *aWhatToShow = mWhatToShow;
     119           0 :   return NS_OK;
     120             : }
     121             : 
     122             : NS_IMETHODIMP
     123           0 : inDeepTreeWalker::GetFilter(nsIDOMNodeFilter** aFilter)
     124             : {
     125           0 :   return NS_ERROR_NOT_IMPLEMENTED;
     126             : }
     127             : 
     128             : NS_IMETHODIMP
     129           0 : inDeepTreeWalker::GetCurrentNode(nsIDOMNode** aCurrentNode)
     130             : {
     131           0 :   *aCurrentNode = mCurrentNode;
     132           0 :   NS_IF_ADDREF(*aCurrentNode);
     133           0 :   return NS_OK;
     134             : }
     135             : 
     136             : already_AddRefed<nsIDOMNode>
     137           0 : inDeepTreeWalker::GetParent()
     138             : {
     139           0 :   if (mCurrentNode == mRoot) {
     140           0 :     return nullptr;
     141             :   }
     142             : 
     143           0 :   nsCOMPtr<nsIDOMNode> parent;
     144           0 :   MOZ_ASSERT(mDOMUtils, "mDOMUtils should have been initiated already in Init");
     145           0 :   mDOMUtils->GetParentForNode(mCurrentNode, mShowAnonymousContent,
     146           0 :                               getter_AddRefs(parent));
     147             : 
     148           0 :   uint16_t nodeType = 0;
     149           0 :   if (parent) {
     150           0 :     parent->GetNodeType(&nodeType);
     151             :   }
     152             :   // For compatibility reasons by default we skip the document nodes
     153             :   // from the walk.
     154           0 :   if (!mShowDocumentsAsNodes &&
     155           0 :       nodeType == nsIDOMNode::DOCUMENT_NODE &&
     156           0 :       parent != mRoot) {
     157           0 :     mDOMUtils->GetParentForNode(parent, mShowAnonymousContent,
     158           0 :                                 getter_AddRefs(parent));
     159             :   }
     160             : 
     161           0 :   return parent.forget();
     162             : }
     163             : 
     164             : static already_AddRefed<nsINodeList>
     165           0 : GetChildren(nsIDOMNode* aParent,
     166             :             bool aShowAnonymousContent,
     167             :             bool aShowSubDocuments)
     168             : {
     169           0 :   MOZ_ASSERT(aParent);
     170             : 
     171           0 :   nsCOMPtr<nsINodeList> ret;
     172           0 :   if (aShowSubDocuments) {
     173           0 :     nsCOMPtr<nsIDOMDocument> domdoc = inLayoutUtils::GetSubDocumentFor(aParent);
     174           0 :     if (domdoc) {
     175           0 :       aParent = domdoc;
     176             :     }
     177             :   }
     178             : 
     179           0 :   nsCOMPtr<nsIContent> parentAsContent = do_QueryInterface(aParent);
     180           0 :   if (parentAsContent && aShowAnonymousContent) {
     181           0 :       ret = parentAsContent->GetChildren(nsIContent::eAllChildren);
     182             :   } else {
     183             :     // If it's not a content, then it's a document (or an attribute but we can ignore that
     184             :     // case here). If aShowAnonymousContent is false we also want to fall back to ChildNodes
     185             :     // so we can skip any native anon content that GetChildren would return.
     186           0 :     nsCOMPtr<nsINode> parentNode = do_QueryInterface(aParent);
     187           0 :     MOZ_ASSERT(parentNode);
     188           0 :     ret = parentNode->ChildNodes();
     189             :   }
     190           0 :   return ret.forget();
     191             : }
     192             : 
     193             : NS_IMETHODIMP
     194           0 : inDeepTreeWalker::SetCurrentNode(nsIDOMNode* aCurrentNode)
     195             : {
     196             :   // mCurrentNode can only be null if init either failed, or has not been
     197             :   // called yet.
     198           0 :   if (!mCurrentNode || !aCurrentNode) {
     199           0 :     return NS_ERROR_FAILURE;
     200             :   }
     201             : 
     202             :   // If Document nodes are skipped by the walk, we should not allow
     203             :   // one to set one as the current node either.
     204           0 :   uint16_t nodeType = 0;
     205           0 :   aCurrentNode->GetNodeType(&nodeType);
     206           0 :   if (!mShowDocumentsAsNodes && nodeType == nsIDOMNode::DOCUMENT_NODE) {
     207           0 :     return NS_ERROR_FAILURE;
     208             :   }
     209             : 
     210           0 :   return SetCurrentNode(aCurrentNode, nullptr);
     211             : }
     212             : 
     213             : 
     214             : nsresult
     215           0 : inDeepTreeWalker::SetCurrentNode(nsIDOMNode* aCurrentNode,
     216             :                                  nsINodeList* aSiblings)
     217             : {
     218           0 :   MOZ_ASSERT(aCurrentNode);
     219             : 
     220             :   // We want to store the original state so in case of error
     221             :   // we can restore that.
     222           0 :   nsCOMPtr<nsINodeList> tmpSiblings = mSiblings;
     223           0 :   nsCOMPtr<nsIDOMNode> tmpCurrent = mCurrentNode;
     224           0 :   mSiblings = aSiblings;
     225           0 :   mCurrentNode = aCurrentNode;
     226             : 
     227             :   // If siblings were not passed in as argument we have to
     228             :   // get them from the parent node of aCurrentNode.
     229             :   // Note: in the mShowDoucmentsAsNodes case when a sub document
     230             :   // is set as the current, we don't want to get the children
     231             :   // from the iframe accidentally here, so let's just skip this
     232             :   // part for document nodes, they should never have siblings.
     233           0 :   uint16_t nodeType = 0;
     234           0 :   aCurrentNode->GetNodeType(&nodeType);
     235           0 :   if (!mSiblings && nodeType != nsIDOMNode::DOCUMENT_NODE) {
     236           0 :     nsCOMPtr<nsIDOMNode> parent = GetParent();
     237           0 :     if (parent) {
     238           0 :       mSiblings = GetChildren(parent,
     239           0 :                               mShowAnonymousContent,
     240           0 :                               mShowSubDocuments);
     241             :     }
     242             :   }
     243             : 
     244           0 :   if (mSiblings && mSiblings->Length()) {
     245             :     // We cached all the siblings (if there are any) of the current node, but we
     246             :     // still have to set the index too, to be able to iterate over them.
     247           0 :     nsCOMPtr<nsIContent> currentAsContent = do_QueryInterface(mCurrentNode);
     248           0 :     MOZ_ASSERT(currentAsContent);
     249           0 :     int32_t index = mSiblings->IndexOf(currentAsContent);
     250           0 :     if (index < 0) {
     251             :       // If someone tries to set current node to some value that is not reachable
     252             :       // otherwise, let's throw. (For example mShowAnonymousContent is false and some
     253             :       // XBL anon content was passed in)
     254             : 
     255             :       // Restore state first.
     256           0 :       mCurrentNode = tmpCurrent;
     257           0 :       mSiblings = tmpSiblings;
     258           0 :       return NS_ERROR_INVALID_ARG;
     259             :     }
     260           0 :     mCurrentIndex = index;
     261             :   } else {
     262           0 :     mCurrentIndex = -1;
     263             :   }
     264           0 :   return NS_OK;
     265             : }
     266             : 
     267             : NS_IMETHODIMP
     268           0 : inDeepTreeWalker::ParentNode(nsIDOMNode** _retval)
     269             : {
     270           0 :   *_retval = nullptr;
     271           0 :   if (!mCurrentNode || mCurrentNode == mRoot) {
     272           0 :     return NS_OK;
     273             :   }
     274             : 
     275           0 :   nsCOMPtr<nsIDOMNode> parent = GetParent();
     276             : 
     277           0 :   if (!parent) {
     278           0 :     return NS_OK;
     279             :   }
     280             : 
     281           0 :   nsresult rv = SetCurrentNode(parent);
     282           0 :   NS_ENSURE_SUCCESS(rv,rv);
     283             : 
     284           0 :   parent.forget(_retval);
     285           0 :   return NS_OK;
     286             : }
     287             : 
     288             : // FirstChild and LastChild are very similar methods, this is the generic
     289             : // version for internal use. With aReverse = true it returns the LastChild.
     290             : nsresult
     291           0 : inDeepTreeWalker::EdgeChild(nsIDOMNode** _retval, bool aFront)
     292             : {
     293           0 :   if (!mCurrentNode) {
     294           0 :     return NS_ERROR_FAILURE;
     295             :   }
     296             : 
     297           0 :   *_retval = nullptr;
     298             : 
     299           0 :   nsCOMPtr<nsIDOMNode> echild;
     300           0 :   if (mShowSubDocuments && mShowDocumentsAsNodes) {
     301             :     // GetChildren below, will skip the document node from
     302             :     // the walk. But if mShowDocumentsAsNodes is set to true
     303             :     // we want to include the (sub)document itself too.
     304           0 :     echild = inLayoutUtils::GetSubDocumentFor(mCurrentNode);
     305             :   }
     306             : 
     307           0 :   nsCOMPtr<nsINodeList> children;
     308           0 :   if (!echild) {
     309           0 :     children = GetChildren(mCurrentNode,
     310           0 :                            mShowAnonymousContent,
     311           0 :                            mShowSubDocuments);
     312           0 :     if (children && children->Length() > 0) {
     313           0 :       nsINode* childNode = children->Item(aFront ? 0 : children->Length() - 1);
     314           0 :       echild = childNode ? childNode->AsDOMNode() : nullptr;
     315             :     }
     316             :   }
     317             : 
     318           0 :   if (echild) {
     319           0 :     nsresult rv = SetCurrentNode(echild, children);
     320           0 :     NS_ENSURE_SUCCESS(rv, rv);
     321           0 :     NS_ADDREF(*_retval = mCurrentNode);
     322             :   }
     323             : 
     324           0 :   return NS_OK;
     325             : }
     326             : 
     327             : NS_IMETHODIMP
     328           0 : inDeepTreeWalker::FirstChild(nsIDOMNode** _retval)
     329             : {
     330           0 :   return EdgeChild(_retval, /* aFront = */ true);
     331             : }
     332             : 
     333             : NS_IMETHODIMP
     334           0 : inDeepTreeWalker::LastChild(nsIDOMNode **_retval)
     335             : {
     336           0 :   return EdgeChild(_retval, /* aFront = */ false);
     337             : }
     338             : 
     339             : NS_IMETHODIMP
     340           0 : inDeepTreeWalker::PreviousSibling(nsIDOMNode **_retval)
     341             : {
     342           0 :   *_retval = nullptr;
     343           0 :   if (!mCurrentNode || !mSiblings || mCurrentIndex < 1) {
     344           0 :     return NS_OK;
     345             :   }
     346             : 
     347           0 :   nsIContent* prev = mSiblings->Item(--mCurrentIndex);
     348           0 :   mCurrentNode = prev->AsDOMNode();
     349           0 :   NS_ADDREF(*_retval = mCurrentNode);
     350           0 :   return NS_OK;
     351             : }
     352             : 
     353             : NS_IMETHODIMP
     354           0 : inDeepTreeWalker::NextSibling(nsIDOMNode **_retval)
     355             : {
     356           0 :   *_retval = nullptr;
     357           0 :   if (!mCurrentNode || !mSiblings ||
     358           0 :       mCurrentIndex + 1 >= (int32_t) mSiblings->Length()) {
     359           0 :     return NS_OK;
     360             :   }
     361             : 
     362           0 :   nsIContent* next = mSiblings->Item(++mCurrentIndex);
     363           0 :   mCurrentNode = next->AsDOMNode();
     364           0 :   NS_ADDREF(*_retval = mCurrentNode);
     365           0 :   return NS_OK;
     366             : }
     367             : 
     368             : NS_IMETHODIMP
     369           0 : inDeepTreeWalker::PreviousNode(nsIDOMNode **_retval)
     370             : {
     371           0 :   if (!mCurrentNode || mCurrentNode == mRoot) {
     372             :     // Nowhere to go from here
     373           0 :     *_retval = nullptr;
     374           0 :     return NS_OK;
     375             :   }
     376             : 
     377           0 :   nsCOMPtr<nsIDOMNode> node;
     378           0 :   PreviousSibling(getter_AddRefs(node));
     379             : 
     380           0 :   if (!node) {
     381           0 :     return ParentNode(_retval);
     382             :   }
     383             : 
     384             :   // Now we're positioned at our previous sibling.  But since the DOM tree
     385             :   // traversal is depth-first, the previous node is its most deeply nested last
     386             :   // child.  Just loop until LastChild() returns null; since the LastChild()
     387             :   // call that returns null won't affect our position, we will then be
     388             :   // positioned at the correct node.
     389           0 :   while (node) {
     390           0 :     LastChild(getter_AddRefs(node));
     391             :   }
     392             : 
     393           0 :   NS_ADDREF(*_retval = mCurrentNode);
     394           0 :   return NS_OK;
     395             : }
     396             : 
     397             : NS_IMETHODIMP
     398           0 : inDeepTreeWalker::NextNode(nsIDOMNode **_retval)
     399             : {
     400           0 :   if (!mCurrentNode) {
     401           0 :     return NS_OK;
     402             :   }
     403             : 
     404             :   // First try our kids
     405           0 :   FirstChild(_retval);
     406             : 
     407           0 :   if (*_retval) {
     408           0 :     return NS_OK;
     409             :   }
     410             : 
     411             :   // Now keep trying next siblings up the parent chain, but if we
     412             :   // discover there's nothing else restore our state.
     413             : #ifdef DEBUG
     414           0 :   nsIDOMNode* origCurrentNode = mCurrentNode;
     415             : #endif
     416           0 :   uint32_t lastChildCallsToMake = 0;
     417             :   while (1) {
     418           0 :     NextSibling(_retval);
     419             : 
     420           0 :     if (*_retval) {
     421           0 :       return NS_OK;
     422             :     }
     423             : 
     424           0 :     nsCOMPtr<nsIDOMNode> parent;
     425           0 :     ParentNode(getter_AddRefs(parent));
     426           0 :     if (!parent) {
     427             :       // Nowhere else to go; we're done.  Restore our state.
     428           0 :       while (lastChildCallsToMake--) {
     429           0 :         nsCOMPtr<nsIDOMNode> dummy;
     430           0 :         LastChild(getter_AddRefs(dummy));
     431             :       }
     432           0 :       NS_ASSERTION(mCurrentNode == origCurrentNode,
     433             :                    "Didn't go back to the right node?");
     434           0 :       *_retval = nullptr;
     435           0 :       return NS_OK;
     436             :     }
     437           0 :     ++lastChildCallsToMake;
     438           0 :   }
     439             : 
     440             :   NS_NOTREACHED("how did we get here?");
     441             :   return NS_OK;
     442             : }

Generated by: LCOV version 1.13