LCOV - code coverage report
Current view: directory - editor/txtsvc/src - nsFilteredContentIterator.cpp (source / functions) Found Hit Coverage
Test: app.info Lines: 194 2 1.0 %
Date: 2012-06-02 Functions: 26 2 7.7 %

       1                 : /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
       2                 : /* ***** BEGIN LICENSE BLOCK *****
       3                 :  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
       4                 :  *
       5                 :  * The contents of this file are subject to the Mozilla Public License Version
       6                 :  * 1.1 (the "License"); you may not use this file except in compliance with
       7                 :  * the License. You may obtain a copy of the License at
       8                 :  * http://www.mozilla.org/MPL/
       9                 :  *
      10                 :  * Software distributed under the License is distributed on an "AS IS" basis,
      11                 :  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
      12                 :  * for the specific language governing rights and limitations under the
      13                 :  * License.
      14                 :  *
      15                 :  * The Original Code is mozilla.org code.
      16                 :  *
      17                 :  * The Initial Developer of the Original Code is
      18                 :  * Netscape Communications Corporation.
      19                 :  * Portions created by the Initial Developer are Copyright (C) 1998
      20                 :  * the Initial Developer. All Rights Reserved.
      21                 :  *
      22                 :  * Contributor(s):
      23                 :  *
      24                 :  * Alternatively, the contents of this file may be used under the terms of
      25                 :  * either of the GNU General Public License Version 2 or later (the "GPL"),
      26                 :  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
      27                 :  * in which case the provisions of the GPL or the LGPL are applicable instead
      28                 :  * of those above. If you wish to allow use of your version of this file only
      29                 :  * under the terms of either the GPL or the LGPL, and not to allow others to
      30                 :  * use your version of this file under the terms of the MPL, indicate your
      31                 :  * decision by deleting the provisions above and replace them with the notice
      32                 :  * and other provisions required by the GPL or the LGPL. If you do not delete
      33                 :  * the provisions above, a recipient may use your version of this file under
      34                 :  * the terms of any one of the MPL, the GPL or the LGPL.
      35                 :  *
      36                 :  * ***** END LICENSE BLOCK ***** */
      37                 : 
      38                 : #include "nsFilteredContentIterator.h"
      39                 : #include "nsIContentIterator.h"
      40                 : #include "nsComponentManagerUtils.h"
      41                 : #include "nsIContent.h"
      42                 : #include "nsString.h"
      43                 : #include "nsIEnumerator.h"
      44                 : 
      45                 : #include "nsContentUtils.h"
      46                 : 
      47                 : #include "nsIDOMNode.h"
      48                 : 
      49                 : //------------------------------------------------------------
      50               0 : nsFilteredContentIterator::nsFilteredContentIterator(nsITextServicesFilter* aFilter) :
      51                 :   mFilter(aFilter),
      52                 :   mDidSkip(false),
      53                 :   mIsOutOfRange(false),
      54               0 :   mDirection(eDirNotSet)
      55                 : {
      56               0 :   mIterator = do_CreateInstance("@mozilla.org/content/post-content-iterator;1");
      57               0 :   mPreIterator = do_CreateInstance("@mozilla.org/content/pre-content-iterator;1");
      58               0 : }
      59                 : 
      60                 : //------------------------------------------------------------
      61               0 : nsFilteredContentIterator::~nsFilteredContentIterator()
      62                 : {
      63               0 : }
      64                 : 
      65                 : //------------------------------------------------------------
      66               0 : NS_IMPL_CYCLE_COLLECTING_ADDREF(nsFilteredContentIterator)
      67               0 : NS_IMPL_CYCLE_COLLECTING_RELEASE(nsFilteredContentIterator)
      68                 : 
      69               0 : NS_INTERFACE_MAP_BEGIN(nsFilteredContentIterator)
      70               0 :   NS_INTERFACE_MAP_ENTRY(nsIContentIterator)
      71               0 :   NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIContentIterator)
      72               0 :   NS_INTERFACE_MAP_ENTRIES_CYCLE_COLLECTION(nsFilteredContentIterator)
      73               0 : NS_INTERFACE_MAP_END
      74                 : 
      75            1464 : NS_IMPL_CYCLE_COLLECTION_5(nsFilteredContentIterator,
      76                 :                            mCurrentIterator,
      77                 :                            mIterator,
      78                 :                            mPreIterator,
      79                 :                            mFilter,
      80                 :                            mRange)
      81                 : 
      82                 : //------------------------------------------------------------
      83                 : nsresult
      84               0 : nsFilteredContentIterator::Init(nsINode* aRoot)
      85                 : {
      86               0 :   NS_ENSURE_TRUE(mPreIterator, NS_ERROR_FAILURE);
      87               0 :   NS_ENSURE_TRUE(mIterator, NS_ERROR_FAILURE);
      88               0 :   mIsOutOfRange    = false;
      89               0 :   mDirection       = eForward;
      90               0 :   mCurrentIterator = mPreIterator;
      91                 : 
      92               0 :   mRange = new nsRange();
      93               0 :   nsCOMPtr<nsIDOMNode> domNode(do_QueryInterface(aRoot));
      94               0 :   if (domNode) {
      95               0 :     mRange->SelectNode(domNode);
      96                 :   }
      97                 : 
      98               0 :   nsresult rv = mPreIterator->Init(mRange);
      99               0 :   NS_ENSURE_SUCCESS(rv, rv);
     100               0 :   return mIterator->Init(mRange);
     101                 : }
     102                 : 
     103                 : //------------------------------------------------------------
     104                 : nsresult
     105               0 : nsFilteredContentIterator::Init(nsIDOMRange* aRange)
     106                 : {
     107               0 :   NS_ENSURE_TRUE(mPreIterator, NS_ERROR_FAILURE);
     108               0 :   NS_ENSURE_TRUE(mIterator, NS_ERROR_FAILURE);
     109               0 :   NS_ENSURE_ARG_POINTER(aRange);
     110               0 :   mIsOutOfRange    = false;
     111               0 :   mDirection       = eForward;
     112               0 :   mCurrentIterator = mPreIterator;
     113                 : 
     114               0 :   nsCOMPtr<nsIDOMRange> domRange;
     115               0 :   nsresult rv = aRange->CloneRange(getter_AddRefs(domRange));
     116               0 :   NS_ENSURE_SUCCESS(rv, rv);
     117               0 :   mRange = do_QueryInterface(domRange);
     118                 : 
     119               0 :   rv = mPreIterator->Init(domRange);
     120               0 :   NS_ENSURE_SUCCESS(rv, rv);
     121               0 :   return mIterator->Init(domRange);
     122                 : }
     123                 : 
     124                 : //------------------------------------------------------------
     125                 : nsresult 
     126               0 : nsFilteredContentIterator::SwitchDirections(bool aChangeToForward)
     127                 : {
     128               0 :   nsINode *node = mCurrentIterator->GetCurrentNode();
     129                 : 
     130               0 :   if (aChangeToForward) {
     131               0 :     mCurrentIterator = mPreIterator;
     132               0 :     mDirection       = eForward;
     133                 :   } else {
     134               0 :     mCurrentIterator = mIterator;
     135               0 :     mDirection       = eBackward;
     136                 :   }
     137                 : 
     138               0 :   if (node) {
     139               0 :     nsresult rv = mCurrentIterator->PositionAt(node);
     140               0 :     if (NS_FAILED(rv)) {
     141               0 :       mIsOutOfRange = true;
     142               0 :       return rv;
     143                 :     }
     144                 :   }
     145               0 :   return NS_OK;
     146                 : }
     147                 : 
     148                 : //------------------------------------------------------------
     149                 : void
     150               0 : nsFilteredContentIterator::First()
     151                 : {
     152               0 :   if (!mCurrentIterator) {
     153               0 :     NS_ERROR("Missing iterator!");
     154                 : 
     155               0 :     return;
     156                 :   }
     157                 : 
     158                 :   // If we are switching directions then
     159                 :   // we need to switch how we process the nodes
     160               0 :   if (mDirection != eForward) {
     161               0 :     mCurrentIterator = mPreIterator;
     162               0 :     mDirection       = eForward;
     163               0 :     mIsOutOfRange    = false;
     164                 :   }
     165                 : 
     166               0 :   mCurrentIterator->First();
     167                 : 
     168               0 :   if (mCurrentIterator->IsDone()) {
     169               0 :     return;
     170                 :   }
     171                 : 
     172               0 :   nsINode *currentNode = mCurrentIterator->GetCurrentNode();
     173               0 :   nsCOMPtr<nsIDOMNode> node(do_QueryInterface(currentNode));
     174                 : 
     175                 :   bool didCross;
     176               0 :   CheckAdvNode(node, didCross, eForward);
     177                 : }
     178                 : 
     179                 : //------------------------------------------------------------
     180                 : void
     181               0 : nsFilteredContentIterator::Last()
     182                 : {
     183               0 :   if (!mCurrentIterator) {
     184               0 :     NS_ERROR("Missing iterator!");
     185                 : 
     186               0 :     return;
     187                 :   }
     188                 : 
     189                 :   // If we are switching directions then
     190                 :   // we need to switch how we process the nodes
     191               0 :   if (mDirection != eBackward) {
     192               0 :     mCurrentIterator = mIterator;
     193               0 :     mDirection       = eBackward;
     194               0 :     mIsOutOfRange    = false;
     195                 :   }
     196                 : 
     197               0 :   mCurrentIterator->Last();
     198                 : 
     199               0 :   if (mCurrentIterator->IsDone()) {
     200               0 :     return;
     201                 :   }
     202                 : 
     203               0 :   nsINode *currentNode = mCurrentIterator->GetCurrentNode();
     204               0 :   nsCOMPtr<nsIDOMNode> node(do_QueryInterface(currentNode));
     205                 : 
     206                 :   bool didCross;
     207               0 :   CheckAdvNode(node, didCross, eBackward);
     208                 : }
     209                 : 
     210                 : ///////////////////////////////////////////////////////////////////////////
     211                 : // ContentToParentOffset: returns the content node's parent and offset.
     212                 : //
     213                 : static void
     214               0 : ContentToParentOffset(nsIContent *aContent, nsIDOMNode **aParent,
     215                 :                       PRInt32 *aOffset)
     216                 : {
     217               0 :   if (!aParent || !aOffset)
     218               0 :     return;
     219                 : 
     220               0 :   *aParent = nsnull;
     221               0 :   *aOffset  = 0;
     222                 : 
     223               0 :   if (!aContent)
     224               0 :     return;
     225                 : 
     226               0 :   nsIContent* parent = aContent->GetParent();
     227                 : 
     228               0 :   if (!parent)
     229               0 :     return;
     230                 : 
     231               0 :   *aOffset = parent->IndexOf(aContent);
     232                 : 
     233               0 :   CallQueryInterface(parent, aParent);
     234                 : }
     235                 : 
     236                 : ///////////////////////////////////////////////////////////////////////////
     237                 : // ContentIsInTraversalRange: returns true if content is visited during
     238                 : // the traversal of the range in the specified mode.
     239                 : //
     240                 : static bool
     241               0 : ContentIsInTraversalRange(nsIContent *aContent,   bool aIsPreMode,
     242                 :                           nsIDOMNode *aStartNode, PRInt32 aStartOffset,
     243                 :                           nsIDOMNode *aEndNode,   PRInt32 aEndOffset)
     244                 : {
     245               0 :   NS_ENSURE_TRUE(aStartNode && aEndNode && aContent, false);
     246                 : 
     247               0 :   nsCOMPtr<nsIDOMNode> parentNode;
     248               0 :   PRInt32 indx = 0;
     249                 : 
     250               0 :   ContentToParentOffset(aContent, getter_AddRefs(parentNode), &indx);
     251                 : 
     252               0 :   NS_ENSURE_TRUE(parentNode, false);
     253                 : 
     254               0 :   if (!aIsPreMode)
     255               0 :     ++indx;
     256                 : 
     257                 :   PRInt32 startRes = nsContentUtils::ComparePoints(aStartNode, aStartOffset,
     258               0 :                                                    parentNode, indx);
     259                 :   PRInt32 endRes = nsContentUtils::ComparePoints(aEndNode, aEndOffset,
     260               0 :                                                  parentNode, indx);
     261               0 :   return (startRes <= 0) && (endRes >= 0);
     262                 : }
     263                 : 
     264                 : static bool
     265               0 : ContentIsInTraversalRange(nsIDOMRange *aRange, nsIDOMNode* aNextNode, bool aIsPreMode)
     266                 : {
     267               0 :   nsCOMPtr<nsIContent> content(do_QueryInterface(aNextNode));
     268               0 :   NS_ENSURE_TRUE(content && aRange, false);
     269                 : 
     270               0 :   nsCOMPtr<nsIDOMNode> sNode;
     271               0 :   nsCOMPtr<nsIDOMNode> eNode;
     272                 :   PRInt32 sOffset;
     273                 :   PRInt32 eOffset;
     274               0 :   aRange->GetStartContainer(getter_AddRefs(sNode));
     275               0 :   aRange->GetStartOffset(&sOffset);
     276               0 :   aRange->GetEndContainer(getter_AddRefs(eNode));
     277               0 :   aRange->GetEndOffset(&eOffset);
     278               0 :   return ContentIsInTraversalRange(content, aIsPreMode, sNode, sOffset, eNode, eOffset);
     279                 : }
     280                 : 
     281                 : //------------------------------------------------------------
     282                 : // Helper function to advance to the next or previous node
     283                 : nsresult 
     284               0 : nsFilteredContentIterator::AdvanceNode(nsIDOMNode* aNode, nsIDOMNode*& aNewNode, eDirectionType aDir)
     285                 : {
     286               0 :   nsCOMPtr<nsIDOMNode> nextNode;
     287               0 :   if (aDir == eForward) {
     288               0 :     aNode->GetNextSibling(getter_AddRefs(nextNode));
     289                 :   } else {
     290               0 :     aNode->GetPreviousSibling(getter_AddRefs(nextNode));
     291                 :   }
     292                 : 
     293               0 :   if (nextNode) {
     294                 :     // If we got here, that means we found the nxt/prv node
     295                 :     // make sure it is in our DOMRange
     296               0 :     bool intersects = ContentIsInTraversalRange(mRange, nextNode, aDir == eForward);
     297               0 :     if (intersects) {
     298               0 :       aNewNode = nextNode;
     299               0 :       NS_ADDREF(aNewNode);
     300               0 :       return NS_OK;
     301                 :     }
     302                 :   } else {
     303                 :     // The next node was null so we need to walk up the parent(s)
     304               0 :     nsCOMPtr<nsIDOMNode> parent;
     305               0 :     aNode->GetParentNode(getter_AddRefs(parent));
     306               0 :     NS_ASSERTION(parent, "parent can't be NULL");
     307                 : 
     308                 :     // Make sure the parent is in the DOMRange before going further
     309               0 :     bool intersects = ContentIsInTraversalRange(mRange, nextNode, aDir == eForward);
     310               0 :     if (intersects) {
     311                 :       // Now find the nxt/prv node after/before this node
     312               0 :       nsresult rv = AdvanceNode(parent, aNewNode, aDir);
     313               0 :       if (NS_SUCCEEDED(rv) && aNewNode) {
     314               0 :         return NS_OK;
     315                 :       }
     316                 :     }
     317                 :   }
     318                 : 
     319                 :   // if we get here it pretty much means 
     320                 :   // we went out of the DOM Range
     321               0 :   mIsOutOfRange = true;
     322                 : 
     323               0 :   return NS_ERROR_FAILURE;
     324                 : }
     325                 : 
     326                 : //------------------------------------------------------------
     327                 : // Helper function to see if the next/prev node should be skipped
     328                 : void
     329               0 : nsFilteredContentIterator::CheckAdvNode(nsIDOMNode* aNode, bool& aDidSkip, eDirectionType aDir)
     330                 : {
     331               0 :   aDidSkip      = false;
     332               0 :   mIsOutOfRange = false;
     333                 : 
     334               0 :   if (aNode && mFilter) {
     335               0 :     nsCOMPtr<nsIDOMNode> currentNode = aNode;
     336                 :     bool skipIt;
     337               0 :     while (1) {
     338               0 :       nsresult rv = mFilter->Skip(aNode, &skipIt);
     339               0 :       if (NS_SUCCEEDED(rv) && skipIt) {
     340               0 :         aDidSkip = true;
     341                 :         // Get the next/prev node and then 
     342                 :         // see if we should skip that
     343               0 :         nsCOMPtr<nsIDOMNode> advNode;
     344               0 :         rv = AdvanceNode(aNode, *getter_AddRefs(advNode), aDir);
     345               0 :         if (NS_SUCCEEDED(rv) && advNode) {
     346               0 :           aNode = advNode;
     347                 :         } else {
     348                 :           return; // fell out of range
     349                 :         }
     350                 :       } else {
     351               0 :         if (aNode != currentNode) {
     352               0 :           nsCOMPtr<nsIContent> content(do_QueryInterface(aNode));
     353               0 :           mCurrentIterator->PositionAt(content);
     354                 :         }
     355                 :         return; // found something
     356                 :       }
     357                 :     }
     358                 :   }
     359                 : }
     360                 : 
     361                 : void
     362               0 : nsFilteredContentIterator::Next()
     363                 : {
     364               0 :   if (mIsOutOfRange || !mCurrentIterator) {
     365               0 :     NS_ASSERTION(mCurrentIterator, "Missing iterator!");
     366                 : 
     367               0 :     return;
     368                 :   }
     369                 : 
     370                 :   // If we are switching directions then
     371                 :   // we need to switch how we process the nodes
     372               0 :   if (mDirection != eForward) {
     373               0 :     nsresult rv = SwitchDirections(true);
     374               0 :     if (NS_FAILED(rv)) {
     375               0 :       return;
     376                 :     }
     377                 :   }
     378                 : 
     379               0 :   mCurrentIterator->Next();
     380                 : 
     381               0 :   if (mCurrentIterator->IsDone()) {
     382               0 :     return;
     383                 :   }
     384                 : 
     385                 :   // If we can't get the current node then 
     386                 :   // don't check to see if we can skip it
     387               0 :   nsINode *currentNode = mCurrentIterator->GetCurrentNode();
     388                 : 
     389               0 :   nsCOMPtr<nsIDOMNode> node(do_QueryInterface(currentNode));
     390               0 :   CheckAdvNode(node, mDidSkip, eForward);
     391                 : }
     392                 : 
     393                 : void
     394               0 : nsFilteredContentIterator::Prev()
     395                 : {
     396               0 :   if (mIsOutOfRange || !mCurrentIterator) {
     397               0 :     NS_ASSERTION(mCurrentIterator, "Missing iterator!");
     398                 : 
     399               0 :     return;
     400                 :   }
     401                 : 
     402                 :   // If we are switching directions then
     403                 :   // we need to switch how we process the nodes
     404               0 :   if (mDirection != eBackward) {
     405               0 :     nsresult rv = SwitchDirections(false);
     406               0 :     if (NS_FAILED(rv)) {
     407               0 :       return;
     408                 :     }
     409                 :   }
     410                 : 
     411               0 :   mCurrentIterator->Prev();
     412                 : 
     413               0 :   if (mCurrentIterator->IsDone()) {
     414               0 :     return;
     415                 :   }
     416                 : 
     417                 :   // If we can't get the current node then 
     418                 :   // don't check to see if we can skip it
     419               0 :   nsINode *currentNode = mCurrentIterator->GetCurrentNode();
     420                 : 
     421               0 :   nsCOMPtr<nsIDOMNode> node(do_QueryInterface(currentNode));
     422               0 :   CheckAdvNode(node, mDidSkip, eBackward);
     423                 : }
     424                 : 
     425                 : nsINode *
     426               0 : nsFilteredContentIterator::GetCurrentNode()
     427                 : {
     428               0 :   if (mIsOutOfRange || !mCurrentIterator) {
     429               0 :     return nsnull;
     430                 :   }
     431                 : 
     432               0 :   return mCurrentIterator->GetCurrentNode();
     433                 : }
     434                 : 
     435                 : bool
     436               0 : nsFilteredContentIterator::IsDone()
     437                 : {
     438               0 :   if (mIsOutOfRange || !mCurrentIterator) {
     439               0 :     return true;
     440                 :   }
     441                 : 
     442               0 :   return mCurrentIterator->IsDone();
     443                 : }
     444                 : 
     445                 : nsresult
     446               0 : nsFilteredContentIterator::PositionAt(nsINode* aCurNode)
     447                 : {
     448               0 :   NS_ENSURE_TRUE(mCurrentIterator, NS_ERROR_FAILURE);
     449               0 :   mIsOutOfRange = false;
     450               0 :   return mCurrentIterator->PositionAt(aCurNode);
     451            4392 : }

Generated by: LCOV version 1.7