diff options
author | Matt A. Tobin <mattatobin@localhost.localdomain> | 2018-02-02 04:16:08 -0500 |
---|---|---|
committer | Matt A. Tobin <mattatobin@localhost.localdomain> | 2018-02-02 04:16:08 -0500 |
commit | 5f8de423f190bbb79a62f804151bc24824fa32d8 (patch) | |
tree | 10027f336435511475e392454359edea8e25895d /layout/inspector/inDeepTreeWalker.cpp | |
parent | 49ee0794b5d912db1f95dce6eb52d781dc210db5 (diff) | |
download | UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar.gz UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar.lz UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar.xz UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.zip |
Add m-esr52 at 52.6.0
Diffstat (limited to 'layout/inspector/inDeepTreeWalker.cpp')
-rw-r--r-- | layout/inspector/inDeepTreeWalker.cpp | 442 |
1 files changed, 442 insertions, 0 deletions
diff --git a/layout/inspector/inDeepTreeWalker.cpp b/layout/inspector/inDeepTreeWalker.cpp new file mode 100644 index 000000000..a0c504980 --- /dev/null +++ b/layout/inspector/inDeepTreeWalker.cpp @@ -0,0 +1,442 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=2 sw=2 et tw=79: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "inDeepTreeWalker.h" +#include "inLayoutUtils.h" + +#include "nsString.h" +#include "nsIDOMDocument.h" +#include "nsIDOMNodeFilter.h" +#include "nsIDOMNodeList.h" +#include "nsServiceManagerUtils.h" +#include "inIDOMUtils.h" +#include "nsIContent.h" +#include "nsContentList.h" +#include "ChildIterator.h" +#include "mozilla/dom/Element.h" + +/***************************************************************************** + * This implementation does not currently operaate according to the W3C spec. + * In particular it does NOT handle DOM mutations during the walk. It also + * ignores whatToShow and the filter. + *****************************************************************************/ + +//////////////////////////////////////////////////// + +inDeepTreeWalker::inDeepTreeWalker() + : mShowAnonymousContent(false), + mShowSubDocuments(false), + mShowDocumentsAsNodes(false), + mWhatToShow(nsIDOMNodeFilter::SHOW_ALL) +{ +} + +inDeepTreeWalker::~inDeepTreeWalker() +{ +} + +NS_IMPL_ISUPPORTS(inDeepTreeWalker, + inIDeepTreeWalker) + +//////////////////////////////////////////////////// +// inIDeepTreeWalker + +NS_IMETHODIMP +inDeepTreeWalker::GetShowAnonymousContent(bool *aShowAnonymousContent) +{ + *aShowAnonymousContent = mShowAnonymousContent; + return NS_OK; +} + +NS_IMETHODIMP +inDeepTreeWalker::SetShowAnonymousContent(bool aShowAnonymousContent) +{ + mShowAnonymousContent = aShowAnonymousContent; + return NS_OK; +} + +NS_IMETHODIMP +inDeepTreeWalker::GetShowSubDocuments(bool *aShowSubDocuments) +{ + *aShowSubDocuments = mShowSubDocuments; + return NS_OK; +} + +NS_IMETHODIMP +inDeepTreeWalker::SetShowSubDocuments(bool aShowSubDocuments) +{ + mShowSubDocuments = aShowSubDocuments; + return NS_OK; +} + +NS_IMETHODIMP +inDeepTreeWalker::GetShowDocumentsAsNodes(bool *aShowDocumentsAsNodes) +{ + *aShowDocumentsAsNodes = mShowDocumentsAsNodes; + return NS_OK; +} + +NS_IMETHODIMP +inDeepTreeWalker::SetShowDocumentsAsNodes(bool aShowDocumentsAsNodes) +{ + mShowDocumentsAsNodes = aShowDocumentsAsNodes; + return NS_OK; +} + +NS_IMETHODIMP +inDeepTreeWalker::Init(nsIDOMNode* aRoot, uint32_t aWhatToShow) +{ + if (!aRoot) { + return NS_ERROR_INVALID_ARG; + } + + mRoot = aRoot; + mCurrentNode = aRoot; + mWhatToShow = aWhatToShow; + + mDOMUtils = do_GetService("@mozilla.org/inspector/dom-utils;1"); + return mDOMUtils ? NS_OK : NS_ERROR_UNEXPECTED; +} + +//////////////////////////////////////////////////// +// nsIDOMTreeWalker + +NS_IMETHODIMP +inDeepTreeWalker::GetRoot(nsIDOMNode** aRoot) +{ + *aRoot = mRoot; + NS_IF_ADDREF(*aRoot); + return NS_OK; +} + +NS_IMETHODIMP +inDeepTreeWalker::GetWhatToShow(uint32_t* aWhatToShow) +{ + *aWhatToShow = mWhatToShow; + return NS_OK; +} + +NS_IMETHODIMP +inDeepTreeWalker::GetFilter(nsIDOMNodeFilter** aFilter) +{ + return NS_ERROR_NOT_IMPLEMENTED; +} + +NS_IMETHODIMP +inDeepTreeWalker::GetCurrentNode(nsIDOMNode** aCurrentNode) +{ + *aCurrentNode = mCurrentNode; + NS_IF_ADDREF(*aCurrentNode); + return NS_OK; +} + +already_AddRefed<nsIDOMNode> +inDeepTreeWalker::GetParent() +{ + if (mCurrentNode == mRoot) { + return nullptr; + } + + nsCOMPtr<nsIDOMNode> parent; + MOZ_ASSERT(mDOMUtils, "mDOMUtils should have been initiated already in Init"); + mDOMUtils->GetParentForNode(mCurrentNode, mShowAnonymousContent, + getter_AddRefs(parent)); + + uint16_t nodeType = 0; + if (parent) { + parent->GetNodeType(&nodeType); + } + // For compatibility reasons by default we skip the document nodes + // from the walk. + if (!mShowDocumentsAsNodes && + nodeType == nsIDOMNode::DOCUMENT_NODE && + parent != mRoot) { + mDOMUtils->GetParentForNode(parent, mShowAnonymousContent, + getter_AddRefs(parent)); + } + + return parent.forget(); +} + +static already_AddRefed<nsINodeList> +GetChildren(nsIDOMNode* aParent, + bool aShowAnonymousContent, + bool aShowSubDocuments) +{ + MOZ_ASSERT(aParent); + + nsCOMPtr<nsINodeList> ret; + if (aShowSubDocuments) { + nsCOMPtr<nsIDOMDocument> domdoc = inLayoutUtils::GetSubDocumentFor(aParent); + if (domdoc) { + aParent = domdoc; + } + } + + nsCOMPtr<nsIContent> parentAsContent = do_QueryInterface(aParent); + if (parentAsContent && aShowAnonymousContent) { + ret = parentAsContent->GetChildren(nsIContent::eAllChildren); + } else { + // If it's not a content, then it's a document (or an attribute but we can ignore that + // case here). If aShowAnonymousContent is false we also want to fall back to ChildNodes + // so we can skip any native anon content that GetChildren would return. + nsCOMPtr<nsINode> parentNode = do_QueryInterface(aParent); + MOZ_ASSERT(parentNode); + ret = parentNode->ChildNodes(); + } + return ret.forget(); +} + +NS_IMETHODIMP +inDeepTreeWalker::SetCurrentNode(nsIDOMNode* aCurrentNode) +{ + // mCurrentNode can only be null if init either failed, or has not been + // called yet. + if (!mCurrentNode || !aCurrentNode) { + return NS_ERROR_FAILURE; + } + + // If Document nodes are skipped by the walk, we should not allow + // one to set one as the current node either. + uint16_t nodeType = 0; + aCurrentNode->GetNodeType(&nodeType); + if (!mShowDocumentsAsNodes && nodeType == nsIDOMNode::DOCUMENT_NODE) { + return NS_ERROR_FAILURE; + } + + return SetCurrentNode(aCurrentNode, nullptr); +} + + +nsresult +inDeepTreeWalker::SetCurrentNode(nsIDOMNode* aCurrentNode, + nsINodeList* aSiblings) +{ + MOZ_ASSERT(aCurrentNode); + + // We want to store the original state so in case of error + // we can restore that. + nsCOMPtr<nsINodeList> tmpSiblings = mSiblings; + nsCOMPtr<nsIDOMNode> tmpCurrent = mCurrentNode; + mSiblings = aSiblings; + mCurrentNode = aCurrentNode; + + // If siblings were not passed in as argument we have to + // get them from the parent node of aCurrentNode. + // Note: in the mShowDoucmentsAsNodes case when a sub document + // is set as the current, we don't want to get the children + // from the iframe accidentally here, so let's just skip this + // part for document nodes, they should never have siblings. + uint16_t nodeType = 0; + aCurrentNode->GetNodeType(&nodeType); + if (!mSiblings && nodeType != nsIDOMNode::DOCUMENT_NODE) { + nsCOMPtr<nsIDOMNode> parent = GetParent(); + if (parent) { + mSiblings = GetChildren(parent, + mShowAnonymousContent, + mShowSubDocuments); + } + } + + if (mSiblings && mSiblings->Length()) { + // We cached all the siblings (if there are any) of the current node, but we + // still have to set the index too, to be able to iterate over them. + nsCOMPtr<nsIContent> currentAsContent = do_QueryInterface(mCurrentNode); + MOZ_ASSERT(currentAsContent); + int32_t index = mSiblings->IndexOf(currentAsContent); + if (index < 0) { + // If someone tries to set current node to some value that is not reachable + // otherwise, let's throw. (For example mShowAnonymousContent is false and some + // XBL anon content was passed in) + + // Restore state first. + mCurrentNode = tmpCurrent; + mSiblings = tmpSiblings; + return NS_ERROR_INVALID_ARG; + } + mCurrentIndex = index; + } else { + mCurrentIndex = -1; + } + return NS_OK; +} + +NS_IMETHODIMP +inDeepTreeWalker::ParentNode(nsIDOMNode** _retval) +{ + *_retval = nullptr; + if (!mCurrentNode || mCurrentNode == mRoot) { + return NS_OK; + } + + nsCOMPtr<nsIDOMNode> parent = GetParent(); + + if (!parent) { + return NS_OK; + } + + nsresult rv = SetCurrentNode(parent); + NS_ENSURE_SUCCESS(rv,rv); + + parent.forget(_retval); + return NS_OK; +} + +// FirstChild and LastChild are very similar methods, this is the generic +// version for internal use. With aReverse = true it returns the LastChild. +nsresult +inDeepTreeWalker::EdgeChild(nsIDOMNode** _retval, bool aFront) +{ + if (!mCurrentNode) { + return NS_ERROR_FAILURE; + } + + *_retval = nullptr; + + nsCOMPtr<nsIDOMNode> echild; + if (mShowSubDocuments && mShowDocumentsAsNodes) { + // GetChildren below, will skip the document node from + // the walk. But if mShowDocumentsAsNodes is set to true + // we want to include the (sub)document itself too. + echild = inLayoutUtils::GetSubDocumentFor(mCurrentNode); + } + + nsCOMPtr<nsINodeList> children; + if (!echild) { + children = GetChildren(mCurrentNode, + mShowAnonymousContent, + mShowSubDocuments); + if (children && children->Length() > 0) { + nsINode* childNode = children->Item(aFront ? 0 : children->Length() - 1); + echild = childNode ? childNode->AsDOMNode() : nullptr; + } + } + + if (echild) { + nsresult rv = SetCurrentNode(echild, children); + NS_ENSURE_SUCCESS(rv, rv); + NS_ADDREF(*_retval = mCurrentNode); + } + + return NS_OK; +} + +NS_IMETHODIMP +inDeepTreeWalker::FirstChild(nsIDOMNode** _retval) +{ + return EdgeChild(_retval, /* aFront = */ true); +} + +NS_IMETHODIMP +inDeepTreeWalker::LastChild(nsIDOMNode **_retval) +{ + return EdgeChild(_retval, /* aFront = */ false); +} + +NS_IMETHODIMP +inDeepTreeWalker::PreviousSibling(nsIDOMNode **_retval) +{ + *_retval = nullptr; + if (!mCurrentNode || !mSiblings || mCurrentIndex < 1) { + return NS_OK; + } + + nsIContent* prev = mSiblings->Item(--mCurrentIndex); + mCurrentNode = prev->AsDOMNode(); + NS_ADDREF(*_retval = mCurrentNode); + return NS_OK; +} + +NS_IMETHODIMP +inDeepTreeWalker::NextSibling(nsIDOMNode **_retval) +{ + *_retval = nullptr; + if (!mCurrentNode || !mSiblings || + mCurrentIndex + 1 >= (int32_t) mSiblings->Length()) { + return NS_OK; + } + + nsIContent* next = mSiblings->Item(++mCurrentIndex); + mCurrentNode = next->AsDOMNode(); + NS_ADDREF(*_retval = mCurrentNode); + return NS_OK; +} + +NS_IMETHODIMP +inDeepTreeWalker::PreviousNode(nsIDOMNode **_retval) +{ + if (!mCurrentNode || mCurrentNode == mRoot) { + // Nowhere to go from here + *_retval = nullptr; + return NS_OK; + } + + nsCOMPtr<nsIDOMNode> node; + PreviousSibling(getter_AddRefs(node)); + + if (!node) { + return ParentNode(_retval); + } + + // Now we're positioned at our previous sibling. But since the DOM tree + // traversal is depth-first, the previous node is its most deeply nested last + // child. Just loop until LastChild() returns null; since the LastChild() + // call that returns null won't affect our position, we will then be + // positioned at the correct node. + while (node) { + LastChild(getter_AddRefs(node)); + } + + NS_ADDREF(*_retval = mCurrentNode); + return NS_OK; +} + +NS_IMETHODIMP +inDeepTreeWalker::NextNode(nsIDOMNode **_retval) +{ + if (!mCurrentNode) { + return NS_OK; + } + + // First try our kids + FirstChild(_retval); + + if (*_retval) { + return NS_OK; + } + + // Now keep trying next siblings up the parent chain, but if we + // discover there's nothing else restore our state. +#ifdef DEBUG + nsIDOMNode* origCurrentNode = mCurrentNode; +#endif + uint32_t lastChildCallsToMake = 0; + while (1) { + NextSibling(_retval); + + if (*_retval) { + return NS_OK; + } + + nsCOMPtr<nsIDOMNode> parent; + ParentNode(getter_AddRefs(parent)); + if (!parent) { + // Nowhere else to go; we're done. Restore our state. + while (lastChildCallsToMake--) { + nsCOMPtr<nsIDOMNode> dummy; + LastChild(getter_AddRefs(dummy)); + } + NS_ASSERTION(mCurrentNode == origCurrentNode, + "Didn't go back to the right node?"); + *_retval = nullptr; + return NS_OK; + } + ++lastChildCallsToMake; + } + + NS_NOTREACHED("how did we get here?"); + return NS_OK; +} |