зеркало из https://github.com/mozilla/gecko-dev.git
Bug 776536 part 3. Add a WebIDL API to NodeIterator and TreeWalker. r=peterv
This commit is contained in:
Родитель
2774421a19
Коммит
a3cebd1049
|
@ -11,7 +11,6 @@
|
|||
#include "mozilla/dom/NodeIterator.h"
|
||||
|
||||
#include "nsIDOMNode.h"
|
||||
#include "nsIDOMNodeFilter.h"
|
||||
#include "nsError.h"
|
||||
|
||||
#include "nsIContent.h"
|
||||
|
@ -19,7 +18,6 @@
|
|||
#include "nsDOMClassInfoID.h"
|
||||
#include "nsContentUtils.h"
|
||||
#include "nsCOMPtr.h"
|
||||
#include "mozilla/dom/NodeFilterBinding.h"
|
||||
|
||||
DOMCI_DATA(NodeIterator, mozilla::dom::NodeIterator)
|
||||
|
||||
|
@ -186,18 +184,14 @@ NS_IMPL_CYCLE_COLLECTING_RELEASE(NodeIterator)
|
|||
/* readonly attribute nsIDOMNode root; */
|
||||
NS_IMETHODIMP NodeIterator::GetRoot(nsIDOMNode * *aRoot)
|
||||
{
|
||||
if (mRoot)
|
||||
return CallQueryInterface(mRoot, aRoot);
|
||||
|
||||
*aRoot = nullptr;
|
||||
|
||||
NS_ADDREF(*aRoot = Root()->AsDOMNode());
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
/* readonly attribute unsigned long whatToShow; */
|
||||
NS_IMETHODIMP NodeIterator::GetWhatToShow(uint32_t *aWhatToShow)
|
||||
{
|
||||
*aWhatToShow = mWhatToShow;
|
||||
*aWhatToShow = WhatToShow();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
@ -214,26 +208,23 @@ NS_IMETHODIMP NodeIterator::GetFilter(nsIDOMNodeFilter **aFilter)
|
|||
/* nsIDOMNode nextNode () raises (DOMException); */
|
||||
NS_IMETHODIMP NodeIterator::NextNode(nsIDOMNode **_retval)
|
||||
{
|
||||
return NextOrPrevNode(&NodePointer::MoveToNext, _retval);
|
||||
return ImplNodeGetter(&NodeIterator::NextNode, _retval);
|
||||
}
|
||||
|
||||
/* nsIDOMNode previousNode () raises (DOMException); */
|
||||
NS_IMETHODIMP NodeIterator::PreviousNode(nsIDOMNode **_retval)
|
||||
{
|
||||
return NextOrPrevNode(&NodePointer::MoveToPrevious, _retval);
|
||||
return ImplNodeGetter(&NodeIterator::PreviousNode, _retval);
|
||||
}
|
||||
|
||||
nsresult
|
||||
already_AddRefed<nsINode>
|
||||
NodeIterator::NextOrPrevNode(NodePointer::MoveToMethodType aMove,
|
||||
nsIDOMNode **_retval)
|
||||
ErrorResult& aResult)
|
||||
{
|
||||
nsresult rv;
|
||||
int16_t filtered;
|
||||
|
||||
*_retval = nullptr;
|
||||
|
||||
if (mDetached || mInAcceptNode)
|
||||
return NS_ERROR_DOM_INVALID_STATE_ERR;
|
||||
if (mDetached || mInAcceptNode) {
|
||||
aResult.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
mWorkingPointer = mPointer;
|
||||
|
||||
|
@ -245,19 +236,23 @@ NodeIterator::NextOrPrevNode(NodePointer::MoveToMethodType aMove,
|
|||
|
||||
while ((mWorkingPointer.*aMove)(mRoot)) {
|
||||
nsCOMPtr<nsINode> testNode = mWorkingPointer.mNode;
|
||||
rv = TestNode(testNode, &filtered);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
int16_t filtered = TestNode(testNode, aResult);
|
||||
if (aResult.Failed()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (mDetached)
|
||||
return NS_ERROR_DOM_INVALID_STATE_ERR;
|
||||
if (mDetached) {
|
||||
aResult.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (filtered == nsIDOMNodeFilter::FILTER_ACCEPT) {
|
||||
mPointer = mWorkingPointer;
|
||||
return CallQueryInterface(testNode, _retval);
|
||||
return testNode.forget();
|
||||
}
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
/* void detach (); */
|
||||
|
@ -277,17 +272,15 @@ NS_IMETHODIMP NodeIterator::Detach(void)
|
|||
/* readonly attribute nsIDOMNode referenceNode; */
|
||||
NS_IMETHODIMP NodeIterator::GetReferenceNode(nsIDOMNode * *aRefNode)
|
||||
{
|
||||
if (mPointer.mNode)
|
||||
return CallQueryInterface(mPointer.mNode, aRefNode);
|
||||
|
||||
*aRefNode = nullptr;
|
||||
nsCOMPtr<nsIDOMNode> node(do_QueryInterface(GetReferenceNode()));
|
||||
node.forget(aRefNode);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
/* readonly attribute boolean pointerBeforeReferenceNode; */
|
||||
NS_IMETHODIMP NodeIterator::GetPointerBeforeReferenceNode(bool *aBeforeNode)
|
||||
{
|
||||
*aBeforeNode = mPointer.mBeforeNode;
|
||||
*aBeforeNode = PointerBeforeReferenceNode();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
|
|
@ -18,7 +18,6 @@
|
|||
|
||||
class nsINode;
|
||||
class nsIDOMNode;
|
||||
class nsIDOMNodeFilter;
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
@ -40,6 +39,37 @@ public:
|
|||
|
||||
NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(NodeIterator, nsIDOMNodeIterator)
|
||||
|
||||
// WebIDL API
|
||||
nsINode* Root() const
|
||||
{
|
||||
return mRoot;
|
||||
}
|
||||
nsINode* GetReferenceNode() const
|
||||
{
|
||||
return mPointer.mNode;
|
||||
}
|
||||
bool PointerBeforeReferenceNode() const
|
||||
{
|
||||
return mPointer.mBeforeNode;
|
||||
}
|
||||
uint32_t WhatToShow() const
|
||||
{
|
||||
return mWhatToShow;
|
||||
}
|
||||
already_AddRefed<NodeFilter> GetFilter()
|
||||
{
|
||||
return mFilter.ToWebIDLCallback();
|
||||
}
|
||||
already_AddRefed<nsINode> NextNode(ErrorResult& aResult)
|
||||
{
|
||||
return NextOrPrevNode(&NodePointer::MoveToNext, aResult);
|
||||
}
|
||||
already_AddRefed<nsINode> PreviousNode(ErrorResult& aResult)
|
||||
{
|
||||
return NextOrPrevNode(&NodePointer::MoveToPrevious, aResult);
|
||||
}
|
||||
// The XPCOM Detach() is fine for our purposes
|
||||
|
||||
private:
|
||||
struct NodePointer {
|
||||
NodePointer() : mNode(nullptr) {}
|
||||
|
@ -60,9 +90,23 @@ private:
|
|||
bool mBeforeNode;
|
||||
};
|
||||
|
||||
inline nsresult
|
||||
NextOrPrevNode(NodePointer::MoveToMethodType aMove,
|
||||
nsIDOMNode **_retval);
|
||||
// Implementation for some of our XPCOM getters
|
||||
typedef already_AddRefed<nsINode> (NodeIterator::*NodeGetter)(ErrorResult&);
|
||||
inline nsresult ImplNodeGetter(NodeGetter aGetter, nsIDOMNode** aRetval)
|
||||
{
|
||||
mozilla::ErrorResult rv;
|
||||
nsCOMPtr<nsINode> node = (this->*aGetter)(rv);
|
||||
if (rv.Failed()) {
|
||||
return rv.ErrorCode();
|
||||
}
|
||||
*aRetval = node ? node.forget().get()->AsDOMNode() : nullptr;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// Have to return a strong ref, because the act of testing the node can
|
||||
// remove it from the DOM so we're holding the only ref to it.
|
||||
already_AddRefed<nsINode>
|
||||
NextOrPrevNode(NodePointer::MoveToMethodType aMove, ErrorResult& aResult);
|
||||
|
||||
bool mDetached;
|
||||
NodePointer mPointer;
|
||||
|
|
|
@ -11,12 +11,10 @@
|
|||
#include "mozilla/dom/TreeWalker.h"
|
||||
|
||||
#include "nsIDOMNode.h"
|
||||
#include "nsIDOMNodeFilter.h"
|
||||
#include "nsError.h"
|
||||
#include "nsINode.h"
|
||||
#include "nsDOMClassInfoID.h"
|
||||
#include "nsContentUtils.h"
|
||||
#include "mozilla/dom/NodeFilterBinding.h"
|
||||
|
||||
DOMCI_DATA(TreeWalker, mozilla::dom::TreeWalker)
|
||||
|
||||
|
@ -68,19 +66,14 @@ NS_IMPL_CYCLE_COLLECTING_RELEASE(dom::TreeWalker)
|
|||
/* readonly attribute nsIDOMNode root; */
|
||||
NS_IMETHODIMP TreeWalker::GetRoot(nsIDOMNode * *aRoot)
|
||||
{
|
||||
if (mRoot) {
|
||||
return CallQueryInterface(mRoot, aRoot);
|
||||
}
|
||||
|
||||
*aRoot = nullptr;
|
||||
|
||||
NS_ADDREF(*aRoot = Root()->AsDOMNode());
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
/* readonly attribute unsigned long whatToShow; */
|
||||
NS_IMETHODIMP TreeWalker::GetWhatToShow(uint32_t *aWhatToShow)
|
||||
{
|
||||
*aWhatToShow = mWhatToShow;
|
||||
*aWhatToShow = WhatToShow();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
@ -113,11 +106,20 @@ NS_IMETHODIMP TreeWalker::SetCurrentNode(nsIDOMNode * aCurrentNode)
|
|||
nsCOMPtr<nsINode> node = do_QueryInterface(aCurrentNode);
|
||||
NS_ENSURE_TRUE(node, NS_ERROR_UNEXPECTED);
|
||||
|
||||
nsresult rv = nsContentUtils::CheckSameOrigin(mRoot, node);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
ErrorResult rv;
|
||||
SetCurrentNode(*node, rv);
|
||||
return rv.ErrorCode();
|
||||
}
|
||||
|
||||
mCurrentNode.swap(node);
|
||||
return NS_OK;
|
||||
void
|
||||
TreeWalker::SetCurrentNode(nsINode& aNode, ErrorResult& aResult)
|
||||
{
|
||||
aResult = nsContentUtils::CheckSameOrigin(mRoot, &aNode);
|
||||
if (aResult.Failed()) {
|
||||
return;
|
||||
}
|
||||
|
||||
mCurrentNode = &aNode;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -127,110 +129,149 @@ NS_IMETHODIMP TreeWalker::SetCurrentNode(nsIDOMNode * aCurrentNode)
|
|||
/* nsIDOMNode parentNode (); */
|
||||
NS_IMETHODIMP TreeWalker::ParentNode(nsIDOMNode **_retval)
|
||||
{
|
||||
*_retval = nullptr;
|
||||
|
||||
nsresult rv;
|
||||
return ImplNodeGetter(&TreeWalker::ParentNode, _retval);
|
||||
}
|
||||
|
||||
already_AddRefed<nsINode>
|
||||
TreeWalker::ParentNode(ErrorResult& aResult)
|
||||
{
|
||||
nsCOMPtr<nsINode> node = mCurrentNode;
|
||||
|
||||
while (node && node != mRoot) {
|
||||
node = node->GetParentNode();
|
||||
|
||||
if (node) {
|
||||
int16_t filtered;
|
||||
rv = TestNode(node, &filtered);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
int16_t filtered = TestNode(node, aResult);
|
||||
if (aResult.Failed()) {
|
||||
return nullptr;
|
||||
}
|
||||
if (filtered == nsIDOMNodeFilter::FILTER_ACCEPT) {
|
||||
mCurrentNode = node;
|
||||
return CallQueryInterface(node, _retval);
|
||||
return node.forget();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
/* nsIDOMNode firstChild (); */
|
||||
NS_IMETHODIMP TreeWalker::FirstChild(nsIDOMNode **_retval)
|
||||
{
|
||||
return FirstChildInternal(false, _retval);
|
||||
return ImplNodeGetter(&TreeWalker::FirstChild, _retval);
|
||||
}
|
||||
|
||||
already_AddRefed<nsINode>
|
||||
TreeWalker::FirstChild(ErrorResult& aResult)
|
||||
{
|
||||
return FirstChildInternal(false, aResult);
|
||||
}
|
||||
|
||||
/* nsIDOMNode lastChild (); */
|
||||
NS_IMETHODIMP TreeWalker::LastChild(nsIDOMNode **_retval)
|
||||
{
|
||||
return FirstChildInternal(true, _retval);
|
||||
return ImplNodeGetter(&TreeWalker::LastChild, _retval);
|
||||
}
|
||||
|
||||
already_AddRefed<nsINode>
|
||||
TreeWalker::LastChild(ErrorResult& aResult)
|
||||
{
|
||||
return FirstChildInternal(true, aResult);
|
||||
}
|
||||
|
||||
/* nsIDOMNode previousSibling (); */
|
||||
NS_IMETHODIMP TreeWalker::PreviousSibling(nsIDOMNode **_retval)
|
||||
{
|
||||
return NextSiblingInternal(true, _retval);
|
||||
return ImplNodeGetter(&TreeWalker::PreviousSibling, _retval);
|
||||
}
|
||||
|
||||
already_AddRefed<nsINode>
|
||||
TreeWalker::PreviousSibling(ErrorResult& aResult)
|
||||
{
|
||||
return NextSiblingInternal(true, aResult);
|
||||
}
|
||||
|
||||
/* nsIDOMNode nextSibling (); */
|
||||
NS_IMETHODIMP TreeWalker::NextSibling(nsIDOMNode **_retval)
|
||||
{
|
||||
return NextSiblingInternal(false, _retval);
|
||||
return ImplNodeGetter(&TreeWalker::NextSibling, _retval);
|
||||
}
|
||||
|
||||
already_AddRefed<nsINode>
|
||||
TreeWalker::NextSibling(ErrorResult& aResult)
|
||||
{
|
||||
return NextSiblingInternal(false, aResult);
|
||||
}
|
||||
|
||||
/* nsIDOMNode previousNode (); */
|
||||
NS_IMETHODIMP TreeWalker::PreviousNode(nsIDOMNode **_retval)
|
||||
{
|
||||
nsresult rv;
|
||||
int16_t filtered;
|
||||
|
||||
*_retval = nullptr;
|
||||
return ImplNodeGetter(&TreeWalker::PreviousNode, _retval);
|
||||
}
|
||||
|
||||
already_AddRefed<nsINode>
|
||||
TreeWalker::PreviousNode(ErrorResult& aResult)
|
||||
{
|
||||
nsCOMPtr<nsINode> node = mCurrentNode;
|
||||
|
||||
while (node != mRoot) {
|
||||
while (nsINode *previousSibling = node->GetPreviousSibling()) {
|
||||
node = previousSibling;
|
||||
|
||||
rv = TestNode(node, &filtered);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
int16_t filtered = TestNode(node, aResult);
|
||||
if (aResult.Failed()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
nsINode *lastChild;
|
||||
while (filtered != nsIDOMNodeFilter::FILTER_REJECT &&
|
||||
(lastChild = node->GetLastChild())) {
|
||||
node = lastChild;
|
||||
rv = TestNode(node, &filtered);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
filtered = TestNode(node, aResult);
|
||||
if (aResult.Failed()) {
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
if (filtered == nsIDOMNodeFilter::FILTER_ACCEPT) {
|
||||
mCurrentNode = node;
|
||||
return CallQueryInterface(node, _retval);
|
||||
return node.forget();
|
||||
}
|
||||
}
|
||||
|
||||
if (node == mRoot)
|
||||
if (node == mRoot) {
|
||||
break;
|
||||
}
|
||||
|
||||
node = node->GetParentNode();
|
||||
if (!node)
|
||||
if (!node) {
|
||||
break;
|
||||
}
|
||||
|
||||
rv = TestNode(node, &filtered);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
int16_t filtered = TestNode(node, aResult);
|
||||
if (aResult.Failed()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (filtered == nsIDOMNodeFilter::FILTER_ACCEPT) {
|
||||
mCurrentNode = node;
|
||||
return CallQueryInterface(node, _retval);
|
||||
return node.forget();
|
||||
}
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
/* nsIDOMNode nextNode (); */
|
||||
NS_IMETHODIMP TreeWalker::NextNode(nsIDOMNode **_retval)
|
||||
{
|
||||
nsresult rv;
|
||||
int16_t filtered = nsIDOMNodeFilter::FILTER_ACCEPT; // pre-init for inner loop
|
||||
return ImplNodeGetter(&TreeWalker::NextNode, _retval);
|
||||
}
|
||||
|
||||
*_retval = nullptr;
|
||||
already_AddRefed<nsINode>
|
||||
TreeWalker::NextNode(ErrorResult& aResult)
|
||||
{
|
||||
int16_t filtered = nsIDOMNodeFilter::FILTER_ACCEPT; // pre-init for inner loop
|
||||
|
||||
nsCOMPtr<nsINode> node = mCurrentNode;
|
||||
|
||||
|
@ -241,13 +282,15 @@ NS_IMETHODIMP TreeWalker::NextNode(nsIDOMNode **_retval)
|
|||
(firstChild = node->GetFirstChild())) {
|
||||
node = firstChild;
|
||||
|
||||
rv = TestNode(node, &filtered);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
filtered = TestNode(node, aResult);
|
||||
if (aResult.Failed()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (filtered == nsIDOMNodeFilter::FILTER_ACCEPT) {
|
||||
// Node found
|
||||
mCurrentNode = node;
|
||||
return CallQueryInterface(node, _retval);
|
||||
return node.forget();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -270,17 +313,19 @@ NS_IMETHODIMP TreeWalker::NextNode(nsIDOMNode **_retval)
|
|||
node = sibling;
|
||||
|
||||
// Found a sibling. Either ours or ancestor's
|
||||
rv = TestNode(node, &filtered);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
filtered = TestNode(node, aResult);
|
||||
if (aResult.Failed()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (filtered == nsIDOMNodeFilter::FILTER_ACCEPT) {
|
||||
// Node found
|
||||
mCurrentNode = node;
|
||||
return CallQueryInterface(node, _retval);
|
||||
return node.forget();
|
||||
}
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -291,28 +336,26 @@ NS_IMETHODIMP TreeWalker::NextNode(nsIDOMNode **_retval)
|
|||
* Implements FirstChild and LastChild which only vary in which direction
|
||||
* they search.
|
||||
* @param aReversed Controls whether we search forwards or backwards
|
||||
* @param _retval Returned node. Null if no child is found
|
||||
* @returns Errorcode
|
||||
* @param aResult Whether we threw or not.
|
||||
* @returns The desired node. Null if no child is found
|
||||
*/
|
||||
nsresult TreeWalker::FirstChildInternal(bool aReversed, nsIDOMNode **_retval)
|
||||
already_AddRefed<nsINode>
|
||||
TreeWalker::FirstChildInternal(bool aReversed, ErrorResult& aResult)
|
||||
{
|
||||
nsresult rv;
|
||||
int16_t filtered;
|
||||
|
||||
*_retval = nullptr;
|
||||
|
||||
nsCOMPtr<nsINode> node = aReversed ? mCurrentNode->GetLastChild()
|
||||
: mCurrentNode->GetFirstChild();
|
||||
|
||||
while (node) {
|
||||
rv = TestNode(node, &filtered);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
int16_t filtered = TestNode(node, aResult);
|
||||
if (aResult.Failed()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
switch (filtered) {
|
||||
case nsIDOMNodeFilter::FILTER_ACCEPT:
|
||||
// Node found
|
||||
mCurrentNode = node;
|
||||
return CallQueryInterface(node, _retval);
|
||||
return node.forget();
|
||||
case nsIDOMNodeFilter::FILTER_SKIP: {
|
||||
nsINode *child = aReversed ? node->GetLastChild()
|
||||
: node->GetFirstChild();
|
||||
|
@ -338,7 +381,7 @@ nsresult TreeWalker::FirstChildInternal(bool aReversed, nsIDOMNode **_retval)
|
|||
nsINode *parent = node->GetParentNode();
|
||||
|
||||
if (!parent || parent == mRoot || parent == mCurrentNode) {
|
||||
return NS_OK;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
node = parent;
|
||||
|
@ -346,27 +389,24 @@ nsresult TreeWalker::FirstChildInternal(bool aReversed, nsIDOMNode **_retval)
|
|||
} while (node);
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
/*
|
||||
* Implements NextSibling and PreviousSibling which only vary in which
|
||||
* direction they search.
|
||||
* @param aReversed Controls whether we search forwards or backwards
|
||||
* @param _retval Returned node. Null if no child is found
|
||||
* @returns Errorcode
|
||||
* @param aResult Whether we threw or not.
|
||||
* @returns The desired node. Null if no child is found
|
||||
*/
|
||||
nsresult TreeWalker::NextSiblingInternal(bool aReversed, nsIDOMNode **_retval)
|
||||
already_AddRefed<nsINode>
|
||||
TreeWalker::NextSiblingInternal(bool aReversed, ErrorResult& aResult)
|
||||
{
|
||||
nsresult rv;
|
||||
int16_t filtered;
|
||||
|
||||
*_retval = nullptr;
|
||||
|
||||
nsCOMPtr<nsINode> node = mCurrentNode;
|
||||
|
||||
if (node == mRoot)
|
||||
return NS_OK;
|
||||
if (node == mRoot) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
while (1) {
|
||||
nsINode* sibling = aReversed ? node->GetPreviousSibling()
|
||||
|
@ -375,13 +415,15 @@ nsresult TreeWalker::NextSiblingInternal(bool aReversed, nsIDOMNode **_retval)
|
|||
while (sibling) {
|
||||
node = sibling;
|
||||
|
||||
rv = TestNode(node, &filtered);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
int16_t filtered = TestNode(node, aResult);
|
||||
if (aResult.Failed()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (filtered == nsIDOMNodeFilter::FILTER_ACCEPT) {
|
||||
// Node found
|
||||
mCurrentNode.swap(node);
|
||||
return CallQueryInterface(mCurrentNode, _retval);
|
||||
mCurrentNode = node;
|
||||
return node.forget();
|
||||
}
|
||||
|
||||
// If rejected or no children, try a sibling
|
||||
|
@ -395,14 +437,18 @@ nsresult TreeWalker::NextSiblingInternal(bool aReversed, nsIDOMNode **_retval)
|
|||
|
||||
node = node->GetParentNode();
|
||||
|
||||
if (!node || node == mRoot)
|
||||
return NS_OK;
|
||||
if (!node || node == mRoot) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Is parent transparent in filtered view?
|
||||
rv = TestNode(node, &filtered);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
if (filtered == nsIDOMNodeFilter::FILTER_ACCEPT)
|
||||
return NS_OK;
|
||||
int16_t filtered = TestNode(node, aResult);
|
||||
if (aResult.Failed()) {
|
||||
return nullptr;
|
||||
}
|
||||
if (filtered == nsIDOMNodeFilter::FILTER_ACCEPT) {
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -19,7 +19,6 @@
|
|||
|
||||
class nsINode;
|
||||
class nsIDOMNode;
|
||||
class nsIDOMNodeFilter;
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
@ -37,6 +36,34 @@ public:
|
|||
|
||||
NS_DECL_CYCLE_COLLECTION_CLASS(TreeWalker)
|
||||
|
||||
// WebIDL API
|
||||
nsINode* Root() const
|
||||
{
|
||||
return mRoot;
|
||||
}
|
||||
uint32_t WhatToShow() const
|
||||
{
|
||||
return mWhatToShow;
|
||||
}
|
||||
already_AddRefed<NodeFilter> GetFilter()
|
||||
{
|
||||
return mFilter.ToWebIDLCallback();
|
||||
}
|
||||
nsINode* CurrentNode() const
|
||||
{
|
||||
return mCurrentNode;
|
||||
}
|
||||
void SetCurrentNode(nsINode& aNode, ErrorResult& aResult);
|
||||
// All our traversal methods return strong refs because filtering can
|
||||
// remove nodes from the tree.
|
||||
already_AddRefed<nsINode> ParentNode(ErrorResult& aResult);
|
||||
already_AddRefed<nsINode> FirstChild(ErrorResult& aResult);
|
||||
already_AddRefed<nsINode> LastChild(ErrorResult& aResult);
|
||||
already_AddRefed<nsINode> PreviousSibling(ErrorResult& aResult);
|
||||
already_AddRefed<nsINode> NextSibling(ErrorResult& aResult);
|
||||
already_AddRefed<nsINode> PreviousNode(ErrorResult& aResult);
|
||||
already_AddRefed<nsINode> NextNode(ErrorResult& aResult);
|
||||
|
||||
private:
|
||||
nsCOMPtr<nsINode> mCurrentNode;
|
||||
|
||||
|
@ -44,19 +71,34 @@ private:
|
|||
* Implements FirstChild and LastChild which only vary in which direction
|
||||
* they search.
|
||||
* @param aReversed Controls whether we search forwards or backwards
|
||||
* @param _retval Returned node. Null if no child is found
|
||||
* @returns Errorcode
|
||||
* @param aResult Whether we threw or not.
|
||||
* @returns The desired node. Null if no child is found
|
||||
*/
|
||||
nsresult FirstChildInternal(bool aReversed, nsIDOMNode **_retval);
|
||||
already_AddRefed<nsINode> FirstChildInternal(bool aReversed,
|
||||
ErrorResult& aResult);
|
||||
|
||||
/*
|
||||
* Implements NextSibling and PreviousSibling which only vary in which
|
||||
* direction they search.
|
||||
* @param aReversed Controls whether we search forwards or backwards
|
||||
* @param _retval Returned node. Null if no child is found
|
||||
* @returns Errorcode
|
||||
* @param aResult Whether we threw or not.
|
||||
* @returns The desired node. Null if no child is found
|
||||
*/
|
||||
nsresult NextSiblingInternal(bool aReversed, nsIDOMNode **_retval);
|
||||
already_AddRefed<nsINode> NextSiblingInternal(bool aReversed,
|
||||
ErrorResult& aResult);
|
||||
|
||||
// Implementation for our various XPCOM getters
|
||||
typedef already_AddRefed<nsINode> (TreeWalker::*NodeGetter)(ErrorResult&);
|
||||
inline nsresult ImplNodeGetter(NodeGetter aGetter, nsIDOMNode** aRetval)
|
||||
{
|
||||
mozilla::ErrorResult rv;
|
||||
nsCOMPtr<nsINode> node = (this->*aGetter)(rv);
|
||||
if (rv.Failed()) {
|
||||
return rv.ErrorCode();
|
||||
}
|
||||
*aRetval = node ? node.forget().get()->AsDOMNode() : nullptr;
|
||||
return NS_OK;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
|
|
|
@ -7,10 +7,8 @@
|
|||
#include "nsTraversal.h"
|
||||
|
||||
#include "nsIDOMNode.h"
|
||||
#include "nsIDOMNodeFilter.h"
|
||||
#include "nsError.h"
|
||||
#include "nsINode.h"
|
||||
#include "mozilla/dom/NodeFilterBinding.h"
|
||||
#include "mozilla/AutoRestore.h"
|
||||
|
||||
#include "nsGkAtoms.h"
|
||||
|
@ -38,37 +36,41 @@ nsTraversal::~nsTraversal()
|
|||
* Tests if and how a node should be filtered. Uses mWhatToShow and
|
||||
* mFilter to test the node.
|
||||
* @param aNode Node to test
|
||||
* @param _filtered Returned filtervalue. See nsIDOMNodeFilter.idl
|
||||
* @returns Errorcode
|
||||
* @param aResult Whether we succeeded
|
||||
* @returns Filtervalue. See nsIDOMNodeFilter.idl
|
||||
*/
|
||||
nsresult nsTraversal::TestNode(nsINode* aNode, int16_t* _filtered)
|
||||
int16_t
|
||||
nsTraversal::TestNode(nsINode* aNode, mozilla::ErrorResult& aResult)
|
||||
{
|
||||
NS_ENSURE_TRUE(!mInAcceptNode, NS_ERROR_DOM_INVALID_STATE_ERR);
|
||||
|
||||
*_filtered = nsIDOMNodeFilter::FILTER_SKIP;
|
||||
if (mInAcceptNode) {
|
||||
aResult.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint16_t nodeType = aNode->NodeType();
|
||||
|
||||
if (nodeType <= 12 && !((1 << (nodeType-1)) & mWhatToShow)) {
|
||||
return NS_OK;
|
||||
return nsIDOMNodeFilter::FILTER_SKIP;
|
||||
}
|
||||
|
||||
if (!mFilter.GetISupports()) {
|
||||
// No filter, just accept
|
||||
*_filtered = nsIDOMNodeFilter::FILTER_ACCEPT;
|
||||
return NS_OK;
|
||||
return nsIDOMNodeFilter::FILTER_ACCEPT;
|
||||
}
|
||||
|
||||
if (mFilter.HasWebIDLCallback()) {
|
||||
AutoRestore<bool> inAcceptNode(mInAcceptNode);
|
||||
mInAcceptNode = true;
|
||||
ErrorResult res;
|
||||
*_filtered = mFilter.GetWebIDLCallback()->AcceptNode(*aNode, res);
|
||||
return res.ErrorCode();
|
||||
return mFilter.GetWebIDLCallback()->AcceptNode(*aNode, aResult);
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIDOMNode> domNode = do_QueryInterface(aNode);
|
||||
AutoRestore<bool> inAcceptNode(mInAcceptNode);
|
||||
mInAcceptNode = true;
|
||||
return mFilter.GetXPCOMCallback()->AcceptNode(domNode, _filtered);
|
||||
int16_t filtered;
|
||||
nsresult rv = mFilter.GetXPCOMCallback()->AcceptNode(domNode, &filtered);
|
||||
if (NS_FAILED(rv)) {
|
||||
aResult.Throw(rv);
|
||||
}
|
||||
return filtered;
|
||||
}
|
||||
|
|
|
@ -14,9 +14,11 @@
|
|||
#include "nsCOMPtr.h"
|
||||
#include "nsIDocument.h"
|
||||
#include "mozilla/dom/CallbackObject.h"
|
||||
#include "mozilla/ErrorResult.h"
|
||||
#include "mozilla/dom/NodeFilterBinding.h"
|
||||
#include "nsIDOMNodeFilter.h"
|
||||
|
||||
class nsINode;
|
||||
class nsIDOMNodeFilter;
|
||||
|
||||
class nsTraversal
|
||||
{
|
||||
|
@ -36,10 +38,10 @@ protected:
|
|||
* Tests if and how a node should be filtered. Uses mWhatToShow and
|
||||
* mFilter to test the node.
|
||||
* @param aNode Node to test
|
||||
* @param _filtered Returned filtervalue. See nsIDOMNodeFilter.idl
|
||||
* @returns Errorcode
|
||||
* @param aResult Whether we succeeded
|
||||
* @returns Filtervalue. See nsIDOMNodeFilter.idl
|
||||
*/
|
||||
nsresult TestNode(nsINode* aNode, int16_t* _filtered);
|
||||
int16_t TestNode(nsINode* aNode, mozilla::ErrorResult& aResult);
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -11,13 +11,20 @@
|
|||
*/
|
||||
|
||||
interface NodeIterator {
|
||||
[Constant]
|
||||
readonly attribute Node root;
|
||||
[Pure]
|
||||
readonly attribute Node? referenceNode;
|
||||
[Pure]
|
||||
readonly attribute boolean pointerBeforeReferenceNode;
|
||||
[Constant]
|
||||
readonly attribute unsigned long whatToShow;
|
||||
[Constant]
|
||||
readonly attribute NodeFilter? filter;
|
||||
|
||||
[Throws]
|
||||
Node? nextNode();
|
||||
[Throws]
|
||||
Node? previousNode();
|
||||
|
||||
void detach();
|
||||
|
|
|
@ -11,16 +11,27 @@
|
|||
*/
|
||||
|
||||
interface TreeWalker {
|
||||
[Constant]
|
||||
readonly attribute Node root;
|
||||
[Constant]
|
||||
readonly attribute unsigned long whatToShow;
|
||||
[Constant]
|
||||
readonly attribute NodeFilter? filter;
|
||||
[Pure, SetterThrows]
|
||||
attribute Node currentNode;
|
||||
|
||||
[Throws]
|
||||
Node? parentNode();
|
||||
[Throws]
|
||||
Node? firstChild();
|
||||
[Throws]
|
||||
Node? lastChild();
|
||||
[Throws]
|
||||
Node? previousSibling();
|
||||
[Throws]
|
||||
Node? nextSibling();
|
||||
[Throws]
|
||||
Node? previousNode();
|
||||
[Throws]
|
||||
Node? nextNode();
|
||||
};
|
||||
|
|
Загрузка…
Ссылка в новой задаче