File indexing completed on 2024-04-28 11:39:29

0001 /**
0002  * This file is part of the DOM implementation for KDE.
0003  *
0004  * Copyright (C) 1999 Lars Knoll <knoll@kde.org>
0005  * Copyright (C) 2000 Frederik Holljen <frederik.holljen@hig.no>
0006  * Copyright (C) 2001 Peter Kelly <pmk@post.com>
0007  * Copyright (C) 2008 Maksim Orlovich <maksim@kde.org>
0008  *
0009  * This library is free software; you can redistribute it and/or
0010  * modify it under the terms of the GNU Library General Public
0011  * License as published by the Free Software Foundation; either
0012  * version 2 of the License, or (at your option) any later version.
0013  *
0014  * This library is distributed in the hope that it will be useful,
0015  * but WITHOUT ANY WARRANTY; without even the implied warranty of
0016  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
0017  * Library General Public License for more details.
0018  *
0019  * You should have received a copy of the GNU Library General Public License
0020  * along with this library; see the file COPYING.LIB.  If not, write to
0021  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
0022  * Boston, MA 02110-1301, USA.
0023  */
0024 
0025 #include "dom/dom_exception.h"
0026 #include "xml/dom_docimpl.h"
0027 
0028 /**
0029  Robustness notes: we protect the object we hold on to, to
0030  prevent crashes. To ensure termination in JS used, we propagate exceptions,
0031  and rely on the JS CPU guard to set one to force us to bail out.
0032 
0033  ### TODO/CHECKONE
0034 */
0035 
0036 using namespace DOM;
0037 
0038 NodeIteratorImpl::NodeIteratorImpl(NodeImpl *_root, unsigned long _whatToShow,
0039                                    NodeFilterImpl *_filter, bool _entityReferenceExpansion)
0040 {
0041     m_root = _root;
0042     m_whatToShow = _whatToShow;
0043     m_filter = _filter;
0044     m_expandEntityReferences = _entityReferenceExpansion;
0045 
0046     m_referenceNode = _root;
0047     m_position = ITER_BEFORE_REF;
0048 
0049     m_doc = m_root->document();
0050     m_doc->attachNodeIterator(this);
0051     m_doc->ref();
0052 
0053     m_detached = false;
0054 }
0055 
0056 NodeIteratorImpl::~NodeIteratorImpl()
0057 {
0058     m_doc->detachNodeIterator(this);
0059     m_doc->deref();
0060 }
0061 
0062 NodeImpl *NodeIteratorImpl::root()
0063 {
0064     return m_root.get();
0065 }
0066 
0067 unsigned long NodeIteratorImpl::whatToShow()
0068 {
0069     return m_whatToShow;
0070 }
0071 
0072 NodeFilterImpl *NodeIteratorImpl::filter()
0073 {
0074     return m_filter.get();
0075 }
0076 
0077 bool NodeIteratorImpl::expandEntityReferences()
0078 {
0079     return m_expandEntityReferences;
0080 }
0081 
0082 SharedPtr<NodeImpl> NodeIteratorImpl::nextNode(int &exceptioncode, void *&propagatedExceptionObject)
0083 {
0084     propagatedExceptionObject = nullptr;
0085     if (m_detached) {
0086         exceptioncode = DOMException::INVALID_STATE_ERR;
0087         return nullptr;
0088     }
0089 
0090     SharedPtr<NodeImpl> oldReferenceNode = m_referenceNode;
0091     Position oldPosition = m_position;
0092     while (true) {
0093         SharedPtr<NodeImpl> cand = m_referenceNode;
0094         // If we're before a node, it's the next node to return, and we'll
0095         // be positioned after.
0096         if (m_position == ITER_BEFORE_REF) {
0097             m_position = ITER_AFTER_REF;
0098             if (isAccepted(m_referenceNode.get(), propagatedExceptionObject) == NodeFilter::FILTER_ACCEPT) {
0099                 return cand;
0100             }
0101             if (propagatedExceptionObject) {
0102                 m_position = oldPosition;
0103                 m_referenceNode = oldReferenceNode;
0104                 return nullptr;
0105             }
0106         } else {
0107             // Robustness note here: the filter could potentially yank any nodes out,
0108             // so we can't keep any state in the temporaries. We hence always rely on
0109             // m_referenceNode, which would be sync'd by the delete handler
0110             cand = getNextNode(m_referenceNode.get());
0111             if (!cand) {
0112                 return nullptr;
0113             }
0114             m_referenceNode = cand;
0115             if (isAccepted(cand.get(), propagatedExceptionObject) == NodeFilter::FILTER_ACCEPT) {
0116                 return cand;
0117             }
0118             if (propagatedExceptionObject) {
0119                 m_position = oldPosition;
0120                 m_referenceNode = oldReferenceNode;
0121                 return nullptr;
0122             }
0123         }
0124     }
0125     return nullptr;
0126 }
0127 
0128 SharedPtr<NodeImpl> NodeIteratorImpl::previousNode(int &exceptioncode, void *&propagatedExceptionObject)
0129 {
0130     propagatedExceptionObject = nullptr;
0131     if (m_detached) {
0132         exceptioncode = DOMException::INVALID_STATE_ERR;
0133         return nullptr;
0134     }
0135 
0136     SharedPtr<NodeImpl> oldReferenceNode = m_referenceNode;
0137     Position oldPosition = m_position;
0138     while (true) {
0139         SharedPtr<NodeImpl> cand = m_referenceNode;
0140         if (m_position == ITER_AFTER_REF) {
0141             m_position = ITER_BEFORE_REF;
0142             if (isAccepted(m_referenceNode.get(), propagatedExceptionObject) == NodeFilter::FILTER_ACCEPT) {
0143                 return cand;
0144             }
0145 
0146             if (propagatedExceptionObject) {
0147                 m_position = oldPosition;
0148                 m_referenceNode = oldReferenceNode;
0149                 return nullptr;
0150             }
0151         } else {
0152             cand = getPrevNode(m_referenceNode.get());
0153             if (!cand) {
0154                 return nullptr;
0155             }
0156 
0157             m_referenceNode = cand;
0158             if (isAccepted(cand.get(), propagatedExceptionObject) == NodeFilter::FILTER_ACCEPT) {
0159                 return cand;
0160             }
0161             if (propagatedExceptionObject) {
0162                 m_position = oldPosition;
0163                 m_referenceNode = oldReferenceNode;
0164                 return nullptr;
0165             }
0166         }
0167     }
0168     return nullptr;
0169 }
0170 
0171 NodeImpl *NodeIteratorImpl::getNextNode(NodeImpl *from)
0172 {
0173     return from->traverseNextNode(m_root.get());
0174 }
0175 
0176 NodeImpl *NodeIteratorImpl::getPrevNode(NodeImpl *from)
0177 {
0178     if (from == m_root) {
0179         return nullptr;
0180     } else {
0181         return from->traversePreviousNode();
0182     }
0183 }
0184 
0185 NodeImpl *NodeIteratorImpl::getLastNode(NodeImpl *in)
0186 {
0187     while (NodeImpl *cand = in->lastChild()) {
0188         in = cand;
0189     }
0190     return in;
0191 }
0192 
0193 void NodeIteratorImpl::detach(int &/*exceptioncode*/)
0194 {
0195     m_doc->detachNodeIterator(this);
0196     m_detached = true;
0197 }
0198 
0199 void NodeIteratorImpl::notifyBeforeNodeRemoval(NodeImpl *removed)
0200 {
0201     // We care about removals if they happen on the path between us and root,
0202     // and not if it's just the root being yanked out.
0203     if (removed == m_root) {
0204         return;
0205     }
0206 
0207     // Scan up from the reference node to root see if the removed node is there..
0208     NodeImpl *c;
0209     for (c = m_referenceNode.get(); c != m_root; c = c->parentNode()) {
0210         if (c == removed) {
0211             break;
0212         }
0213     }
0214 
0215     // If nothing was found, we were unaffected.
0216     if (c == m_root) {
0217         return;
0218     }
0219 
0220     // Update the position.. Thankfully we don't have to call filters here.
0221     if (m_position == ITER_BEFORE_REF) {
0222         // We were positioned before some node in the removed subtree...
0223         // We want to be positioned before the first node after the
0224         // removed subtree.
0225         NodeImpl *next = getNextNode(getLastNode(removed));
0226         if (next) {
0227             m_referenceNode = next;
0228         } else {
0229             // There is no where to go after this --- pick a node before the tree,
0230             // which in preorder is the immediate pred. of the remove root.
0231             m_position = ITER_AFTER_REF;
0232             m_referenceNode = getPrevNode(removed);
0233         }
0234     } else { // Iterator after ref.
0235         // We were after some node in the removed subtree, we want to be
0236         // after the node immediately before it. There -must- be one,
0237         // since at least the root preceeds it!
0238         m_referenceNode = getPrevNode(removed);
0239     }
0240 }
0241 
0242 short NodeIteratorImpl::isAccepted(NodeImpl *n, void *&propagatedExceptionObject)
0243 {
0244     // if XML is implemented we have to check expandEntityRerefences in this function
0245     if (((1 << (n->nodeType() - 1)) & m_whatToShow) != 0) {
0246         if (!m_filter.isNull()) {
0247             return m_filter->acceptNode(n, propagatedExceptionObject);
0248         } else {
0249             return NodeFilter::FILTER_ACCEPT;
0250         }
0251     }
0252     return NodeFilter::FILTER_SKIP;
0253 }
0254 
0255 // --------------------------------------------------------------
0256 
0257 NodeFilterImpl::NodeFilterImpl()
0258 {
0259     m_customNodeFilter = nullptr;
0260 }
0261 
0262 NodeFilterImpl::~NodeFilterImpl()
0263 {
0264     if (m_customNodeFilter) {
0265         m_customNodeFilter->deref();
0266     }
0267 }
0268 
0269 bool NodeFilterImpl::isJSFilter() const
0270 {
0271     return false;
0272 }
0273 
0274 short NodeFilterImpl::acceptNode(const Node &n, void *& /*bindingsException*/)
0275 {
0276     if (m_customNodeFilter) {
0277         return m_customNodeFilter->acceptNode(n);
0278     } else {
0279         return NodeFilter::FILTER_ACCEPT;
0280     }
0281 }
0282 
0283 void NodeFilterImpl::setCustomNodeFilter(CustomNodeFilter *custom)
0284 {
0285     m_customNodeFilter = custom;
0286     if (m_customNodeFilter) {
0287         m_customNodeFilter->ref();
0288     }
0289 }
0290 
0291 CustomNodeFilter *NodeFilterImpl::customNodeFilter()
0292 {
0293     return m_customNodeFilter;
0294 }
0295 
0296 // --------------------------------------------------------------
0297 
0298 TreeWalkerImpl::TreeWalkerImpl(NodeImpl *n, long _whatToShow, NodeFilterImpl *f,
0299                                bool entityReferenceExpansion)
0300 {
0301     m_currentNode = n;
0302     m_rootNode = n;
0303     m_whatToShow = _whatToShow;
0304     m_filter = f;
0305     if (m_filter) {
0306         m_filter->ref();
0307     }
0308     m_expandEntityReferences = entityReferenceExpansion;
0309     m_doc = m_rootNode->document();
0310     m_doc->ref();
0311 }
0312 
0313 TreeWalkerImpl::~TreeWalkerImpl()
0314 {
0315     m_doc->deref();
0316     if (m_filter) {
0317         m_filter->deref();
0318     }
0319 }
0320 
0321 NodeImpl *TreeWalkerImpl::getRoot() const
0322 {
0323     return m_rootNode.get();
0324 }
0325 
0326 unsigned long TreeWalkerImpl::getWhatToShow() const
0327 {
0328     return m_whatToShow;
0329 }
0330 
0331 NodeFilterImpl *TreeWalkerImpl::getFilter() const
0332 {
0333     return m_filter;
0334 }
0335 
0336 bool TreeWalkerImpl::getExpandEntityReferences() const
0337 {
0338     return m_expandEntityReferences;
0339 }
0340 
0341 NodeImpl *TreeWalkerImpl::getCurrentNode() const
0342 {
0343     return m_currentNode.get();
0344 }
0345 
0346 void TreeWalkerImpl::setWhatToShow(long _whatToShow)
0347 {
0348     // do some testing whether this is an accepted value
0349     m_whatToShow = _whatToShow;
0350 }
0351 
0352 void TreeWalkerImpl::setFilter(NodeFilterImpl *_filter)
0353 {
0354     m_filter->deref();
0355     m_filter = _filter;
0356     if (m_filter) {
0357         m_filter->ref();
0358     }
0359 }
0360 
0361 void TreeWalkerImpl::setExpandEntityReferences(bool value)
0362 {
0363     m_expandEntityReferences = value;
0364 }
0365 
0366 void TreeWalkerImpl::setCurrentNode(NodeImpl *n, int &exceptionCode)
0367 {
0368     if (n) {
0369         m_currentNode = n;
0370     } else {
0371         exceptionCode = DOMException::NOT_SUPPORTED_ERR;
0372     }
0373 }
0374 
0375 NodeImpl *TreeWalkerImpl::parentNode(void *&filterException)
0376 {
0377     NodePtr n = getParentNode(m_currentNode, filterException);
0378     if (n) {
0379         m_currentNode = n;
0380     }
0381     return n.get();
0382 }
0383 
0384 NodeImpl *TreeWalkerImpl::firstChild(void *&filterException)
0385 {
0386     NodePtr n = getFirstChild(m_currentNode, filterException);
0387     if (n) {
0388         m_currentNode = n;
0389     }
0390     return n.get();
0391 }
0392 
0393 NodeImpl *TreeWalkerImpl::lastChild(void *&filterException)
0394 {
0395     NodePtr n = getLastChild(m_currentNode, filterException);
0396     if (n) {
0397         m_currentNode = n;
0398     }
0399     return n.get();
0400 }
0401 
0402 NodeImpl *TreeWalkerImpl::previousSibling(void *&filterException)
0403 {
0404     NodePtr n = getPreviousSibling(m_currentNode, filterException);
0405     if (n) {
0406         m_currentNode = n;
0407     }
0408     return n.get();
0409 }
0410 
0411 NodeImpl *TreeWalkerImpl::nextSibling(void *&filterException)
0412 {
0413     NodePtr n = getNextSibling(m_currentNode, filterException);
0414     if (n) {
0415         m_currentNode = n;
0416     }
0417     return n.get();
0418 }
0419 
0420 NodeImpl *TreeWalkerImpl::nextNode(void *&filterException)
0421 {
0422     NodePtr n = getNextNode(filterException);
0423     if (n) {
0424         m_currentNode = n;
0425     }
0426     return n.get();
0427 }
0428 
0429 NodeImpl *TreeWalkerImpl::previousNode(void *&filterException)
0430 {
0431     NodePtr n = getPreviousNode(filterException);
0432     if (n) {
0433         m_currentNode = n;
0434     }
0435     return n.get();
0436 }
0437 
0438 TreeWalkerImpl::NodePtr TreeWalkerImpl::getPreviousNode(void *&filterException)
0439 {
0440     filterException = nullptr;
0441     /* 1. last node in my previous sibling's subtree
0442      * 2. my previous sibling (special case of the above)
0443      * 3. my parent
0444      */
0445 
0446     NodePtr n = getPreviousSibling(m_currentNode, filterException);
0447     if (filterException) {
0448         return nullptr;
0449     }
0450     if (n) {
0451         // Find the last kid in the subtree's preorder traversal, if any,
0452         // by following the lastChild links.
0453         NodePtr desc = getLastChild(n, filterException);
0454         if (filterException) {
0455             return nullptr;
0456         }
0457         while (desc) {
0458             n    = desc;
0459             desc = getLastChild(desc, filterException);
0460             if (filterException) {
0461                 return nullptr;
0462             }
0463         }
0464         return n;
0465     }
0466 
0467     return getParentNode(m_currentNode, filterException);
0468 }
0469 
0470 TreeWalkerImpl::NodePtr TreeWalkerImpl::getNextNode(void *&filterException)
0471 {
0472     filterException = nullptr;
0473     /*  1. my first child
0474      *  2. my next sibling
0475      *  3. my parents sibling, or their parents sibling (loop)
0476      *  4. not found
0477      */
0478 
0479     NodePtr n = getFirstChild(m_currentNode, filterException);
0480     if (filterException) {
0481         return nullptr;
0482     }
0483     if (n) { // my first child
0484         return n;
0485     }
0486 
0487     n = getNextSibling(m_currentNode, filterException); // my next sibling
0488     if (filterException) {
0489         return nullptr;
0490     }
0491     if (n) {
0492         return n;
0493     }
0494 
0495     NodePtr parent = getParentNode(m_currentNode, filterException);
0496     if (filterException) {
0497         return nullptr;
0498     }
0499     while (parent) { // parent's sibling
0500         n = getNextSibling(parent, filterException);
0501         if (filterException) {
0502             return nullptr;
0503         }
0504         if (n) {
0505             return n;
0506         }
0507 
0508         parent = getParentNode(parent, filterException);
0509         if (filterException) {
0510             return nullptr;
0511         }
0512     }
0513     return nullptr;
0514 }
0515 
0516 short TreeWalkerImpl::isAccepted(TreeWalkerImpl::NodePtr n, void *&filterException)
0517 {
0518     // if XML is implemented we have to check expandEntityRerefences in this function
0519     if (((1 << (n->nodeType() - 1)) & m_whatToShow) != 0) {
0520         if (m_filter) {
0521             return m_filter->acceptNode(n.get(), filterException);
0522         } else {
0523             return NodeFilter::FILTER_ACCEPT;
0524         }
0525     }
0526     return NodeFilter::FILTER_SKIP;
0527 }
0528 
0529 /**
0530  This is quite a bit more complicated than it would at first seem, due to the following note:
0531  "Note that the structure of a TreeWalker's filtered view of a document may differ significantly from that of the document itself. For example, a TreeWalker with only SHOW_TEXT specified in its whatToShow parameter would present all the Text nodes as if they were siblings of each other yet had no parent."
0532 
0533  My read of this is that e.g. that when a node is  FILTER_SKIP'd, its children are handled
0534  as the children of its parent. -M.O.
0535 */
0536 
0537 TreeWalkerImpl::NodePtr TreeWalkerImpl::getParentNode(TreeWalkerImpl::NodePtr n, void *&filterException)
0538 {
0539     filterException = nullptr;
0540     // Already on top of root's subtree tree...
0541     if (n == m_rootNode) {
0542         return nullptr;
0543     }
0544 
0545     // Walk up, to find the first visible node != n, until we run out of
0546     // document or into the root (which we don't have to be inside of!)
0547     NodePtr cursor = n->parentNode();
0548     while (cursor) {
0549         if (isAccepted(cursor, filterException) == NodeFilter::FILTER_ACCEPT) {
0550             return cursor;
0551         }
0552         if (filterException) {
0553             return nullptr;
0554         }
0555 
0556         if (cursor == m_rootNode) { // We just checked root -- no where else to go up.
0557             return nullptr;
0558         }
0559         cursor = cursor->parentNode();
0560     }
0561 
0562     return nullptr;
0563 }
0564 
0565 TreeWalkerImpl::NodePtr TreeWalkerImpl::getFirstChild(TreeWalkerImpl::NodePtr n, void *&filterException)
0566 {
0567     filterException = nullptr;
0568     NodePtr cursor;
0569     for (cursor = n->firstChild(); cursor; cursor = cursor->nextSibling()) {
0570         switch (isAccepted(cursor, filterException)) {
0571         case NodeFilter::FILTER_ACCEPT:
0572             return cursor;
0573         case NodeFilter::FILTER_SKIP: {
0574             // We ignore this candidate proper, but perhaps it has a kid?
0575             NodePtr cand = getFirstChild(cursor, filterException);
0576             if (filterException) {
0577                 return nullptr;
0578             }
0579             if (cand) {
0580                 return cand;
0581             }
0582             break;
0583         }
0584         case NodeFilter::FILTER_REJECT:
0585             // It effectively doesn't exist, or exception
0586             if (filterException) {
0587                 return nullptr;
0588             }
0589             break;
0590         }
0591         // ### this is unclear: what should happen if we "pass through" the root??
0592     }
0593 
0594     // Nothing found..
0595     return nullptr;
0596 }
0597 
0598 TreeWalkerImpl::NodePtr TreeWalkerImpl::getLastChild(TreeWalkerImpl::NodePtr n, void *&filterException)
0599 {
0600     filterException = nullptr;
0601     TreeWalkerImpl::NodePtr cursor;
0602     for (cursor = n->lastChild(); cursor; cursor = cursor->previousSibling()) {
0603         switch (isAccepted(cursor, filterException)) {
0604         case NodeFilter::FILTER_ACCEPT:
0605             return cursor;
0606         case NodeFilter::FILTER_SKIP: {
0607             // We ignore this candidate proper, but perhaps it has a kid?
0608             TreeWalkerImpl::NodePtr cand = getLastChild(cursor, filterException);
0609             if (filterException) {
0610                 return nullptr;
0611             }
0612             if (cand) {
0613                 return cand;
0614             }
0615             break;
0616         }
0617         case NodeFilter::FILTER_REJECT:
0618             // It effectively doesn't exist..
0619             if (filterException) {
0620                 return nullptr;
0621             }
0622             break;
0623         }
0624         // ### this is unclear: what should happen if we "pass through" the root??
0625     }
0626 
0627     // Nothing found..
0628     return nullptr;
0629 }
0630 
0631 TreeWalkerImpl::NodePtr TreeWalkerImpl::getNextSibling(TreeWalkerImpl::NodePtr n, void *&filterException)
0632 {
0633     filterException = nullptr;
0634 
0635     // If we're the root node, clearly we don't have any siblings.
0636     if (n == m_rootNode) {
0637         return nullptr;
0638     }
0639 
0640     // What would can our siblings be? Well, they can be our actual siblings,
0641     // or if those are 'skip' their first kid. We may also have to walk up
0642     // through any skipped nodes.
0643     NodePtr cursor;
0644     for (cursor = n->nextSibling(); cursor; cursor = cursor->nextSibling()) {
0645         switch (isAccepted(cursor, filterException)) {
0646         case NodeFilter::FILTER_ACCEPT:
0647             return cursor;
0648         case NodeFilter::FILTER_SKIP: {
0649             NodePtr cand = getFirstChild(cursor, filterException);
0650             if (filterException) {
0651                 return nullptr;
0652             }
0653             if (cand) {
0654                 return cand;
0655             }
0656             break;
0657         }
0658         case NodeFilter::FILTER_REJECT:
0659             if (filterException) {
0660                 return nullptr;
0661             }
0662             break;
0663         }
0664     }
0665 
0666     // Now, we have scanned through all of our parent's kids. Our siblings may also be
0667     // above if we could have skipped the parent, and are not captured by it.
0668     NodePtr parent = n->parentNode();
0669     if (!parent || parent == m_rootNode) {
0670         return nullptr;
0671     }
0672 
0673     /* "In particular: If the currentNode becomes part of a subtree that would otherwise have
0674         been Rejected by the filter, that entire subtree may be added as transient members of the
0675         logical view. You will be able to navigate within that subtree (subject to all the usual
0676         filtering) until you move upward past the Rejected ancestor. The behavior is as if the Rejected
0677         node had only been Skipped (since we somehow wound up inside its subtree) until we leave it;
0678         thereafter, standard filtering applies.*/
0679     if (isAccepted(parent, filterException) == NodeFilter::FILTER_ACCEPT) {
0680         return nullptr;
0681     }
0682     if (filterException) {
0683         return nullptr;
0684     }
0685 
0686     return getNextSibling(parent, filterException);
0687 }
0688 
0689 TreeWalkerImpl::NodePtr TreeWalkerImpl::getPreviousSibling(TreeWalkerImpl::NodePtr n, void *&filterException)
0690 {
0691     filterException = nullptr;
0692     // See the above for all the comments :-)
0693     if (n == m_rootNode) {
0694         return nullptr;
0695     }
0696 
0697     NodePtr cursor;
0698     for (cursor = n->previousSibling(); cursor; cursor = cursor->previousSibling()) {
0699         switch (isAccepted(cursor, filterException)) {
0700         case NodeFilter::FILTER_ACCEPT:
0701             return cursor;
0702         case NodeFilter::FILTER_SKIP: {
0703             NodePtr cand = getLastChild(cursor, filterException);
0704             if (filterException) {
0705                 return nullptr;
0706             }
0707             if (cand) {
0708                 return cand;
0709             }
0710             break;
0711         }
0712         case NodeFilter::FILTER_REJECT:
0713             if (filterException) {
0714                 return nullptr;
0715             }
0716             break;
0717         }
0718     }
0719 
0720     NodePtr parent = n->parentNode();
0721     if (!parent || parent == m_rootNode) {
0722         return nullptr;
0723     }
0724 
0725     if (isAccepted(parent, filterException) == NodeFilter::FILTER_ACCEPT) {
0726         return nullptr;
0727     }
0728     if (filterException) {
0729         return nullptr;
0730     }
0731 
0732     return getPreviousSibling(parent, filterException);
0733 }
0734