LCOV - code coverage report
Current view: directory - content/base/src - nsRange.cpp (source / functions) Found Hit Coverage
Test: app.info Lines: 1170 446 38.1 %
Date: 2012-06-02 Functions: 86 44 51.2 %

       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                 :  *   Mats Palmgren <matspal@gmail.com>
      24                 :  *
      25                 :  * Alternatively, the contents of this file may be used under the terms of
      26                 :  * either of the GNU General Public License Version 2 or later (the "GPL"),
      27                 :  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
      28                 :  * in which case the provisions of the GPL or the LGPL are applicable instead
      29                 :  * of those above. If you wish to allow use of your version of this file only
      30                 :  * under the terms of either the GPL or the LGPL, and not to allow others to
      31                 :  * use your version of this file under the terms of the MPL, indicate your
      32                 :  * decision by deleting the provisions above and replace them with the notice
      33                 :  * and other provisions required by the GPL or the LGPL. If you do not delete
      34                 :  * the provisions above, a recipient may use your version of this file under
      35                 :  * the terms of any one of the MPL, the GPL or the LGPL.
      36                 :  *
      37                 :  * ***** END LICENSE BLOCK ***** */
      38                 : 
      39                 : /*
      40                 :  * Implementation of the DOM nsIDOMRange object.
      41                 :  */
      42                 : 
      43                 : #include "nscore.h"
      44                 : #include "nsRange.h"
      45                 : 
      46                 : #include "nsString.h"
      47                 : #include "nsReadableUtils.h"
      48                 : #include "nsIDOMNode.h"
      49                 : #include "nsIDOMDocument.h"
      50                 : #include "nsIDOMDocumentFragment.h"
      51                 : #include "nsIContent.h"
      52                 : #include "nsIDocument.h"
      53                 : #include "nsIDOMText.h"
      54                 : #include "nsDOMError.h"
      55                 : #include "nsIContentIterator.h"
      56                 : #include "nsIDOMNodeList.h"
      57                 : #include "nsGkAtoms.h"
      58                 : #include "nsContentUtils.h"
      59                 : #include "nsGenericDOMDataNode.h"
      60                 : #include "nsClientRect.h"
      61                 : #include "nsLayoutUtils.h"
      62                 : #include "nsTextFrame.h"
      63                 : #include "nsFontFaceList.h"
      64                 : 
      65                 : nsresult NS_NewContentIterator(nsIContentIterator** aInstancePtrResult);
      66                 : nsresult NS_NewContentSubtreeIterator(nsIContentIterator** aInstancePtrResult);
      67                 : 
      68                 : /******************************************************
      69                 :  * stack based utilty class for managing monitor
      70                 :  ******************************************************/
      71                 : 
      72                 : // NS_ERROR_DOM_NOT_OBJECT_ERR is not the correct one to throw, but spec doesn't say
      73                 : // what is
      74                 : #define VALIDATE_ACCESS(node_)                                                     \
      75                 :   PR_BEGIN_MACRO                                                                   \
      76                 :     if (!node_) {                                                                  \
      77                 :       return NS_ERROR_DOM_NOT_OBJECT_ERR;                                          \
      78                 :     }                                                                              \
      79                 :     if (!nsContentUtils::CanCallerAccess(node_)) {                                 \
      80                 :       return NS_ERROR_DOM_SECURITY_ERR;                                            \
      81                 :     }                                                                              \
      82                 :     if (mIsDetached) {                                                             \
      83                 :       return NS_ERROR_DOM_INVALID_STATE_ERR;                                       \
      84                 :     }                                                                              \
      85                 :   PR_END_MACRO
      86                 : 
      87               0 : static void InvalidateAllFrames(nsINode* aNode)
      88                 : {
      89               0 :   NS_PRECONDITION(aNode, "bad arg");
      90                 : 
      91               0 :   nsIFrame* frame = nsnull;
      92               0 :   switch (aNode->NodeType()) {
      93                 :     case nsIDOMNode::TEXT_NODE:
      94                 :     case nsIDOMNode::ELEMENT_NODE:
      95                 :     {
      96               0 :       nsIContent* content = static_cast<nsIContent*>(aNode);
      97               0 :       frame = content->GetPrimaryFrame();
      98               0 :       break;
      99                 :     }
     100                 :     case nsIDOMNode::DOCUMENT_NODE:
     101                 :     {
     102               0 :       nsIDocument* doc = static_cast<nsIDocument*>(aNode);
     103               0 :       nsIPresShell* shell = doc ? doc->GetShell() : nsnull;
     104               0 :       frame = shell ? shell->GetRootFrame() : nsnull;
     105               0 :       break;
     106                 :     }
     107                 :   }
     108               0 :   for (nsIFrame* f = frame; f; f = f->GetNextContinuation()) {
     109               0 :     f->InvalidateFrameSubtree();
     110                 :   }
     111               0 : }
     112                 : 
     113                 : // Utility routine to detect if a content node is completely contained in a range
     114                 : // If outNodeBefore is returned true, then the node starts before the range does.
     115                 : // If outNodeAfter is returned true, then the node ends after the range does.
     116                 : // Note that both of the above might be true.
     117                 : // If neither are true, the node is contained inside of the range.
     118                 : // XXX - callers responsibility to ensure node in same doc as range! 
     119                 : 
     120                 : // static
     121                 : nsresult
     122              48 : nsRange::CompareNodeToRange(nsINode* aNode, nsRange* aRange,
     123                 :                             bool *outNodeBefore, bool *outNodeAfter)
     124                 : {
     125              48 :   NS_ENSURE_STATE(aNode);
     126                 :   // create a pair of dom points that expresses location of node:
     127                 :   //     NODE(start), NODE(end)
     128                 :   // Let incoming range be:
     129                 :   //    {RANGE(start), RANGE(end)}
     130                 :   // if (RANGE(start) <= NODE(start))  and (RANGE(end) => NODE(end))
     131                 :   // then the Node is contained (completely) by the Range.
     132                 :   
     133              48 :   if (!aRange || !aRange->IsPositioned()) 
     134               0 :     return NS_ERROR_UNEXPECTED; 
     135                 :   
     136                 :   // gather up the dom point info
     137                 :   PRInt32 nodeStart, nodeEnd;
     138              48 :   nsINode* parent = aNode->GetNodeParent();
     139              48 :   if (!parent) {
     140                 :     // can't make a parent/offset pair to represent start or 
     141                 :     // end of the root node, because it has no parent.
     142                 :     // so instead represent it by (node,0) and (node,numChildren)
     143              16 :     parent = aNode;
     144              16 :     nodeStart = 0;
     145              16 :     nodeEnd = aNode->GetChildCount();
     146                 :   }
     147                 :   else {
     148              32 :     nodeStart = parent->IndexOf(aNode);
     149              32 :     nodeEnd = nodeStart + 1;
     150                 :   }
     151                 : 
     152              48 :   nsINode* rangeStartParent = aRange->GetStartParent();
     153              48 :   nsINode* rangeEndParent = aRange->GetEndParent();
     154              48 :   PRInt32 rangeStartOffset = aRange->StartOffset();
     155              48 :   PRInt32 rangeEndOffset = aRange->EndOffset();
     156                 : 
     157                 :   // is RANGE(start) <= NODE(start) ?
     158              48 :   bool disconnected = false;
     159                 :   *outNodeBefore = nsContentUtils::ComparePoints(rangeStartParent,
     160                 :                                                  rangeStartOffset,
     161                 :                                                  parent, nodeStart,
     162              48 :                                                  &disconnected) > 0;
     163              48 :   NS_ENSURE_TRUE(!disconnected, NS_ERROR_DOM_WRONG_DOCUMENT_ERR);
     164                 : 
     165                 :   // is RANGE(end) >= NODE(end) ?
     166                 :   *outNodeAfter = nsContentUtils::ComparePoints(rangeEndParent,
     167                 :                                                 rangeEndOffset,
     168                 :                                                 parent, nodeEnd,
     169              48 :                                                 &disconnected) < 0;
     170              48 :   NS_ENSURE_TRUE(!disconnected, NS_ERROR_DOM_WRONG_DOCUMENT_ERR);
     171              48 :   return NS_OK;
     172                 : }
     173                 : 
     174                 : struct FindSelectedRangeData
     175                 : {
     176                 :   nsINode*  mNode;
     177                 :   nsRange* mResult;
     178                 :   PRUint32  mStartOffset;
     179                 :   PRUint32  mEndOffset;
     180                 : };
     181                 : 
     182                 : static PLDHashOperator
     183               0 : FindSelectedRange(nsPtrHashKey<nsRange>* aEntry, void* userArg)
     184                 : {
     185               0 :   nsRange* range = aEntry->GetKey();
     186               0 :   if (range->IsInSelection() && !range->Collapsed()) {
     187               0 :     FindSelectedRangeData* data = static_cast<FindSelectedRangeData*>(userArg);
     188                 :     PRInt32 cmp = nsContentUtils::ComparePoints(data->mNode, data->mEndOffset,
     189                 :                                                 range->GetStartParent(),
     190               0 :                                                 range->StartOffset());
     191               0 :     if (cmp == 1) {
     192                 :       cmp = nsContentUtils::ComparePoints(data->mNode, data->mStartOffset,
     193                 :                                           range->GetEndParent(),
     194               0 :                                           range->EndOffset());
     195               0 :       if (cmp == -1) {
     196               0 :         data->mResult = range;
     197               0 :         return PL_DHASH_STOP;
     198                 :       }
     199                 :     }
     200                 :   }
     201               0 :   return PL_DHASH_NEXT;
     202                 : }
     203                 : 
     204                 : static nsINode*
     205               0 : GetNextRangeCommonAncestor(nsINode* aNode)
     206                 : {
     207               0 :   while (aNode && !aNode->IsCommonAncestorForRangeInSelection()) {
     208               0 :     if (!aNode->IsDescendantOfCommonAncestorForRangeInSelection()) {
     209               0 :       return nsnull;
     210                 :     }
     211               0 :     aNode = aNode->GetNodeParent();
     212                 :   }
     213               0 :   return aNode;
     214                 : }
     215                 : 
     216                 : /* static */ bool
     217               0 : nsRange::IsNodeSelected(nsINode* aNode, PRUint32 aStartOffset,
     218                 :                         PRUint32 aEndOffset)
     219                 : {
     220               0 :   NS_PRECONDITION(aNode, "bad arg");
     221                 : 
     222               0 :   FindSelectedRangeData data = { aNode, nsnull, aStartOffset, aEndOffset };
     223               0 :   nsINode* n = GetNextRangeCommonAncestor(aNode);
     224               0 :   NS_ASSERTION(n || !aNode->IsSelectionDescendant(),
     225                 :                "orphan selection descendant");
     226               0 :   for (; n; n = GetNextRangeCommonAncestor(n->GetNodeParent())) {
     227                 :     RangeHashTable* ranges =
     228               0 :       static_cast<RangeHashTable*>(n->GetProperty(nsGkAtoms::range));
     229               0 :     ranges->EnumerateEntries(FindSelectedRange, &data);
     230               0 :     if (data.mResult) {
     231               0 :       return true;
     232                 :     }
     233                 :   }
     234               0 :   return false;
     235                 : }
     236                 : 
     237                 : /******************************************************
     238                 :  * constructor/destructor
     239                 :  ******************************************************/
     240                 : 
     241              93 : nsRange::~nsRange() 
     242                 : {
     243              31 :   NS_ASSERTION(!IsInSelection(), "deleting nsRange that is in use");
     244                 : 
     245                 :   // we want the side effects (releases and list removals)
     246              31 :   DoSetRange(nsnull, 0, nsnull, 0, nsnull);
     247             124 : } 
     248                 : 
     249                 : /* static */
     250                 : nsresult
     251               0 : nsRange::CreateRange(nsIDOMNode* aStartParent, PRInt32 aStartOffset,
     252                 :                      nsIDOMNode* aEndParent, PRInt32 aEndOffset,
     253                 :                      nsRange** aRange)
     254                 : {
     255               0 :   MOZ_ASSERT(aRange);
     256               0 :   *aRange = NULL;
     257                 : 
     258               0 :   nsRefPtr<nsRange> range = new nsRange();
     259                 : 
     260               0 :   nsresult rv = range->SetStart(aStartParent, aStartOffset);
     261               0 :   NS_ENSURE_SUCCESS(rv, rv);
     262                 : 
     263               0 :   rv = range->SetEnd(aEndParent, aEndOffset);
     264               0 :   NS_ENSURE_SUCCESS(rv, rv);
     265                 : 
     266               0 :   range.forget(aRange);
     267               0 :   return NS_OK;
     268                 : }
     269                 : 
     270                 : /* static */
     271                 : nsresult
     272               0 : nsRange::CreateRange(nsIDOMNode* aStartParent, PRInt32 aStartOffset,
     273                 :                      nsIDOMNode* aEndParent, PRInt32 aEndOffset,
     274                 :                      nsIDOMRange** aRange)
     275                 : {
     276               0 :   nsRefPtr<nsRange> range;
     277                 :   nsresult rv = nsRange::CreateRange(aStartParent, aStartOffset, aEndParent,
     278               0 :                                      aEndOffset, getter_AddRefs(range));
     279               0 :   range.forget(aRange);
     280               0 :   return rv;
     281                 : }
     282                 : 
     283                 : /******************************************************
     284                 :  * nsISupports
     285                 :  ******************************************************/
     286                 : 
     287            1464 : NS_IMPL_CYCLE_COLLECTION_CLASS(nsRange)
     288                 : 
     289             271 : NS_IMPL_CYCLE_COLLECTING_ADDREF(nsRange)
     290             271 : NS_IMPL_CYCLE_COLLECTING_RELEASE(nsRange)
     291                 : 
     292                 : DOMCI_DATA(Range, nsRange)
     293                 : 
     294                 : // QueryInterface implementation for nsRange
     295             733 : NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsRange)
     296             530 :   NS_INTERFACE_MAP_ENTRY(nsIDOMRange)
     297             327 :   NS_INTERFACE_MAP_ENTRY(nsIMutationObserver)
     298             327 :   NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIDOMRange)
     299             296 :   NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(Range)
     300             265 : NS_INTERFACE_MAP_END
     301                 : 
     302               0 : NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsRange)
     303               0 :   tmp->Reset();
     304               0 : NS_IMPL_CYCLE_COLLECTION_UNLINK_END
     305                 : 
     306               0 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsRange)
     307               0 :   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mStartParent)
     308               0 :   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mEndParent)
     309               0 :   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mRoot)
     310               0 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
     311                 : 
     312                 : static void
     313               0 : RangeHashTableDtor(void* aObject, nsIAtom* aPropertyName, void* aPropertyValue,
     314                 :                    void* aData)
     315                 : {
     316                 :   nsRange::RangeHashTable* ranges =
     317               0 :     static_cast<nsRange::RangeHashTable*>(aPropertyValue);
     318               0 :   delete ranges;
     319               0 : }
     320                 : 
     321               0 : static void MarkDescendants(nsINode* aNode)
     322                 : {
     323                 :   // Set NodeIsDescendantOfCommonAncestorForRangeInSelection on aNode's
     324                 :   // descendants unless aNode is already marked as a range common ancestor
     325                 :   // or a descendant of one, in which case all of our descendants have the
     326                 :   // bit set already.
     327               0 :   if (!aNode->IsSelectionDescendant()) {
     328                 :     // don't set the Descendant bit on |aNode| itself
     329               0 :     nsINode* node = aNode->GetNextNode(aNode);
     330               0 :     while (node) {
     331               0 :       node->SetDescendantOfCommonAncestorForRangeInSelection();
     332               0 :       if (!node->IsCommonAncestorForRangeInSelection()) {
     333               0 :         node = node->GetNextNode(aNode);
     334                 :       } else {
     335                 :         // optimize: skip this sub-tree since it's marked already.
     336               0 :         node = node->GetNextNonChildNode(aNode);
     337                 :       }
     338                 :     }
     339                 :   }
     340               0 : }
     341                 : 
     342               0 : static void UnmarkDescendants(nsINode* aNode)
     343                 : {
     344                 :   // Unset NodeIsDescendantOfCommonAncestorForRangeInSelection on aNode's
     345                 :   // descendants unless aNode is a descendant of another range common ancestor.
     346                 :   // Also, exclude descendants of range common ancestors (but not the common
     347                 :   // ancestor itself).
     348               0 :   if (!aNode->IsDescendantOfCommonAncestorForRangeInSelection()) {
     349                 :     // we know |aNode| doesn't have any bit set
     350               0 :     nsINode* node = aNode->GetNextNode(aNode);
     351               0 :     while (node) {
     352               0 :       node->ClearDescendantOfCommonAncestorForRangeInSelection();
     353               0 :       if (!node->IsCommonAncestorForRangeInSelection()) {
     354               0 :         node = node->GetNextNode(aNode);
     355                 :       } else {
     356                 :         // We found an ancestor of an overlapping range, skip its descendants.
     357               0 :         node = node->GetNextNonChildNode(aNode);
     358                 :       }
     359                 :     }
     360                 :   }
     361               0 : }
     362                 : 
     363                 : void
     364               0 : nsRange::RegisterCommonAncestor(nsINode* aNode)
     365                 : {
     366               0 :   NS_PRECONDITION(aNode, "bad arg");
     367               0 :   NS_ASSERTION(IsInSelection(), "registering range not in selection");
     368                 : 
     369               0 :   MarkDescendants(aNode);
     370                 : 
     371                 :   RangeHashTable* ranges =
     372               0 :     static_cast<RangeHashTable*>(aNode->GetProperty(nsGkAtoms::range));
     373               0 :   if (!ranges) {
     374               0 :     ranges = new RangeHashTable;
     375               0 :     ranges->Init();
     376               0 :     aNode->SetProperty(nsGkAtoms::range, ranges, RangeHashTableDtor, true);
     377                 :   }
     378               0 :   ranges->PutEntry(this);
     379               0 :   aNode->SetCommonAncestorForRangeInSelection();
     380               0 : }
     381                 : 
     382                 : void
     383               0 : nsRange::UnregisterCommonAncestor(nsINode* aNode)
     384                 : {
     385               0 :   NS_PRECONDITION(aNode, "bad arg");
     386               0 :   NS_ASSERTION(aNode->IsCommonAncestorForRangeInSelection(), "wrong node");
     387                 :   RangeHashTable* ranges =
     388               0 :     static_cast<RangeHashTable*>(aNode->GetProperty(nsGkAtoms::range));
     389               0 :   NS_ASSERTION(ranges->GetEntry(this), "unknown range");
     390                 : 
     391               0 :   if (ranges->Count() == 1) {
     392               0 :     aNode->ClearCommonAncestorForRangeInSelection();
     393               0 :     aNode->DeleteProperty(nsGkAtoms::range);
     394               0 :     UnmarkDescendants(aNode);
     395                 :   } else {
     396               0 :     ranges->RemoveEntry(this);
     397                 :   }
     398               0 : }
     399                 : 
     400                 : /******************************************************
     401                 :  * nsIMutationObserver implementation
     402                 :  ******************************************************/
     403                 : 
     404                 : void
     405              13 : nsRange::CharacterDataChanged(nsIDocument* aDocument,
     406                 :                               nsIContent* aContent,
     407                 :                               CharacterDataChangeInfo* aInfo)
     408                 : {
     409              13 :   NS_ASSERTION(mIsPositioned, "shouldn't be notified if not positioned");
     410                 : 
     411              13 :   nsINode* newRoot = nsnull;
     412              13 :   nsINode* newStartNode = nsnull;
     413              13 :   nsINode* newEndNode = nsnull;
     414              13 :   PRUint32 newStartOffset = 0;
     415              13 :   PRUint32 newEndOffset = 0;
     416                 : 
     417                 :   // If the changed node contains our start boundary and the change starts
     418                 :   // before the boundary we'll need to adjust the offset.
     419              13 :   if (aContent == mStartParent &&
     420                 :       aInfo->mChangeStart < static_cast<PRUint32>(mStartOffset)) {
     421               0 :     if (aInfo->mDetails) {
     422                 :       // splitText(), aInfo->mDetails->mNextSibling is the new text node
     423               0 :       NS_ASSERTION(aInfo->mDetails->mType ==
     424                 :                    CharacterDataChangeInfo::Details::eSplit,
     425                 :                    "only a split can start before the end");
     426               0 :       NS_ASSERTION(static_cast<PRUint32>(mStartOffset) <= aInfo->mChangeEnd + 1,
     427                 :                    "mStartOffset is beyond the end of this node");
     428               0 :       newStartOffset = static_cast<PRUint32>(mStartOffset) - aInfo->mChangeStart;
     429               0 :       newStartNode = aInfo->mDetails->mNextSibling;
     430               0 :       if (NS_UNLIKELY(aContent == mRoot)) {
     431               0 :         newRoot = IsValidBoundary(newStartNode);
     432                 :       }
     433                 : 
     434               0 :       bool isCommonAncestor = IsInSelection() && mStartParent == mEndParent;
     435               0 :       if (isCommonAncestor) {
     436               0 :         UnregisterCommonAncestor(mStartParent);
     437               0 :         RegisterCommonAncestor(newStartNode);
     438                 :       }
     439               0 :       if (mStartParent->IsDescendantOfCommonAncestorForRangeInSelection()) {
     440               0 :         newStartNode->SetDescendantOfCommonAncestorForRangeInSelection();
     441                 :       }
     442                 :     } else {
     443                 :       // If boundary is inside changed text, position it before change
     444                 :       // else adjust start offset for the change in length.
     445                 :       mStartOffset = static_cast<PRUint32>(mStartOffset) <= aInfo->mChangeEnd ?
     446                 :         aInfo->mChangeStart :
     447                 :         mStartOffset + aInfo->mChangeStart - aInfo->mChangeEnd +
     448               0 :           aInfo->mReplaceLength;
     449                 :     }
     450                 :   }
     451                 : 
     452                 :   // Do the same thing for the end boundary, except for splitText of a node
     453                 :   // with no parent then only switch to the new node if the start boundary
     454                 :   // did so too (otherwise the range would end up with disconnected nodes).
     455              13 :   if (aContent == mEndParent &&
     456                 :       aInfo->mChangeStart < static_cast<PRUint32>(mEndOffset)) {
     457              11 :     if (aInfo->mDetails && (aContent->GetNodeParent() || newStartNode)) {
     458                 :       // splitText(), aInfo->mDetails->mNextSibling is the new text node
     459               0 :       NS_ASSERTION(aInfo->mDetails->mType ==
     460                 :                    CharacterDataChangeInfo::Details::eSplit,
     461                 :                    "only a split can start before the end");
     462               0 :       NS_ASSERTION(static_cast<PRUint32>(mEndOffset) <= aInfo->mChangeEnd + 1,
     463                 :                    "mEndOffset is beyond the end of this node");
     464               0 :       newEndOffset = static_cast<PRUint32>(mEndOffset) - aInfo->mChangeStart;
     465               0 :       newEndNode = aInfo->mDetails->mNextSibling;
     466                 : 
     467               0 :       bool isCommonAncestor = IsInSelection() && mStartParent == mEndParent;
     468               0 :       if (isCommonAncestor && !newStartNode) {
     469                 :         // The split occurs inside the range.
     470               0 :         UnregisterCommonAncestor(mStartParent);
     471               0 :         RegisterCommonAncestor(mStartParent->GetNodeParent());
     472               0 :         newEndNode->SetDescendantOfCommonAncestorForRangeInSelection();
     473               0 :       } else if (mEndParent->IsDescendantOfCommonAncestorForRangeInSelection()) {
     474               0 :         newEndNode->SetDescendantOfCommonAncestorForRangeInSelection();
     475                 :       }
     476                 :     } else {
     477                 :       mEndOffset = static_cast<PRUint32>(mEndOffset) <= aInfo->mChangeEnd ?
     478                 :         aInfo->mChangeStart :
     479                 :         mEndOffset + aInfo->mChangeStart - aInfo->mChangeEnd +
     480              11 :           aInfo->mReplaceLength;
     481                 :     }
     482                 :   }
     483                 : 
     484              13 :   if (aInfo->mDetails &&
     485                 :       aInfo->mDetails->mType == CharacterDataChangeInfo::Details::eMerge) {
     486                 :     // normalize(), aInfo->mDetails->mNextSibling is the merged text node
     487                 :     // that will be removed
     488               0 :     nsIContent* removed = aInfo->mDetails->mNextSibling;
     489               0 :     if (removed == mStartParent) {
     490               0 :       newStartOffset = static_cast<PRUint32>(mStartOffset) + aInfo->mChangeStart;
     491               0 :       newStartNode = aContent;
     492               0 :       if (NS_UNLIKELY(removed == mRoot)) {
     493               0 :         newRoot = IsValidBoundary(newStartNode);
     494                 :       }
     495                 :     }
     496               0 :     if (removed == mEndParent) {
     497               0 :       newEndOffset = static_cast<PRUint32>(mEndOffset) + aInfo->mChangeStart;
     498               0 :       newEndNode = aContent;
     499               0 :       if (NS_UNLIKELY(removed == mRoot)) {
     500               0 :         newRoot = IsValidBoundary(newEndNode);
     501                 :       }
     502                 :     }
     503                 :   }
     504              13 :   if (newStartNode || newEndNode) {
     505               0 :     if (!newStartNode) {
     506               0 :       newStartNode = mStartParent;
     507               0 :       newStartOffset = mStartOffset;
     508                 :     }
     509               0 :     if (!newEndNode) {
     510               0 :       newEndNode = mEndParent;
     511               0 :       newEndOffset = mEndOffset;
     512                 :     }
     513                 :     DoSetRange(newStartNode, newStartOffset, newEndNode, newEndOffset,
     514               0 :                newRoot ? newRoot : mRoot.get(),
     515               0 :                !newEndNode->GetNodeParent() || !newStartNode->GetNodeParent());
     516                 :   }
     517              13 : }
     518                 : 
     519                 : void
     520               0 : nsRange::ContentAppended(nsIDocument* aDocument,
     521                 :                          nsIContent*  aContainer,
     522                 :                          nsIContent*  aFirstNewContent,
     523                 :                          PRInt32      aNewIndexInContainer)
     524                 : {
     525               0 :   NS_ASSERTION(mIsPositioned, "shouldn't be notified if not positioned");
     526                 : 
     527               0 :   nsINode* container = NODE_FROM(aContainer, aDocument);
     528               0 :   if (container->IsSelectionDescendant() && IsInSelection()) {
     529               0 :     nsINode* child = aFirstNewContent;
     530               0 :     while (child) {
     531               0 :       if (!child->IsDescendantOfCommonAncestorForRangeInSelection()) {
     532               0 :         MarkDescendants(child);
     533               0 :         child->SetDescendantOfCommonAncestorForRangeInSelection();
     534                 :       }
     535               0 :       child = child->GetNextSibling();
     536                 :     }
     537                 :   }
     538               0 : }
     539                 : 
     540                 : void
     541               4 : nsRange::ContentInserted(nsIDocument* aDocument,
     542                 :                          nsIContent* aContainer,
     543                 :                          nsIContent* aChild,
     544                 :                          PRInt32 aIndexInContainer)
     545                 : {
     546               4 :   NS_ASSERTION(mIsPositioned, "shouldn't be notified if not positioned");
     547                 : 
     548               4 :   nsINode* container = NODE_FROM(aContainer, aDocument);
     549                 : 
     550                 :   // Adjust position if a sibling was inserted.
     551               4 :   if (container == mStartParent && aIndexInContainer < mStartOffset) {
     552               0 :     ++mStartOffset;
     553                 :   }
     554               4 :   if (container == mEndParent && aIndexInContainer < mEndOffset) {
     555               0 :     ++mEndOffset;
     556                 :   }
     557               4 :   if (container->IsSelectionDescendant() &&
     558               0 :       !aChild->IsDescendantOfCommonAncestorForRangeInSelection()) {
     559               0 :     MarkDescendants(aChild);
     560               0 :     aChild->SetDescendantOfCommonAncestorForRangeInSelection();
     561                 :   }
     562               4 : }
     563                 : 
     564                 : void
     565              14 : nsRange::ContentRemoved(nsIDocument* aDocument,
     566                 :                         nsIContent* aContainer,
     567                 :                         nsIContent* aChild,
     568                 :                         PRInt32 aIndexInContainer,
     569                 :                         nsIContent* aPreviousSibling)
     570                 : {
     571              14 :   NS_ASSERTION(mIsPositioned, "shouldn't be notified if not positioned");
     572                 : 
     573              14 :   nsINode* container = NODE_FROM(aContainer, aDocument);
     574              14 :   bool gravitateStart = false;
     575              14 :   bool gravitateEnd = false;
     576                 : 
     577                 :   // Adjust position if a sibling was removed...
     578              14 :   if (container == mStartParent) {
     579               8 :     if (aIndexInContainer < mStartOffset) {
     580               0 :       --mStartOffset;
     581                 :     }
     582                 :   }
     583                 :   // ...or gravitate if an ancestor was removed.
     584               6 :   else if (nsContentUtils::ContentIsDescendantOf(mStartParent, aChild)) {
     585               0 :     gravitateStart = true;
     586                 :   }
     587                 : 
     588                 :   // Do same thing for end boundry.
     589              14 :   if (container == mEndParent) {
     590               8 :     if (aIndexInContainer < mEndOffset) {
     591               8 :       --mEndOffset;
     592                 :     }
     593                 :   }
     594               6 :   else if (nsContentUtils::ContentIsDescendantOf(mEndParent, aChild)) {
     595               0 :     gravitateEnd = true;
     596                 :   }
     597                 : 
     598              14 :   if (gravitateStart || gravitateEnd) {
     599               0 :     DoSetRange(gravitateStart ? container : mStartParent.get(),
     600                 :                gravitateStart ? aIndexInContainer : mStartOffset,
     601               0 :                gravitateEnd ? container : mEndParent.get(),
     602                 :                gravitateEnd ? aIndexInContainer : mEndOffset,
     603               0 :                mRoot);
     604                 :   }
     605              14 :   if (container->IsSelectionDescendant() &&
     606               0 :       aChild->IsDescendantOfCommonAncestorForRangeInSelection()) {
     607               0 :     aChild->ClearDescendantOfCommonAncestorForRangeInSelection();
     608               0 :     UnmarkDescendants(aChild);
     609                 :   }
     610              14 : }
     611                 : 
     612                 : void
     613               0 : nsRange::ParentChainChanged(nsIContent *aContent)
     614                 : {
     615               0 :   NS_ASSERTION(mRoot == aContent, "Wrong ParentChainChanged notification?");
     616               0 :   nsINode* newRoot = IsValidBoundary(mStartParent);
     617               0 :   NS_ASSERTION(newRoot, "No valid boundary or root found!");
     618               0 :   NS_ASSERTION(newRoot == IsValidBoundary(mEndParent),
     619                 :                "Start parent and end parent give different root!");
     620                 :   // This is safe without holding a strong ref to self as long as the change
     621                 :   // of mRoot is the last thing in DoSetRange.
     622               0 :   DoSetRange(mStartParent, mStartOffset, mEndParent, mEndOffset, newRoot);
     623               0 : }
     624                 : 
     625                 : /******************************************************
     626                 :  * Utilities for comparing points: API from nsIDOMRange
     627                 :  ******************************************************/
     628                 : NS_IMETHODIMP
     629               0 : nsRange::IsPointInRange(nsIDOMNode* aParent, PRInt32 aOffset, bool* aResult)
     630                 : {
     631               0 :   PRInt16 compareResult = 0;
     632               0 :   nsresult rv = ComparePoint(aParent, aOffset, &compareResult);
     633                 :   // If the node isn't in the range's document, it clearly isn't in the range.
     634               0 :   if (rv == NS_ERROR_DOM_WRONG_DOCUMENT_ERR) {
     635               0 :     *aResult = false;
     636               0 :     return NS_OK;
     637                 :   }
     638                 : 
     639               0 :   *aResult = compareResult == 0;
     640                 : 
     641               0 :   return rv;
     642                 : }
     643                 :   
     644                 : // returns -1 if point is before range, 0 if point is in range,
     645                 : // 1 if point is after range.
     646                 : NS_IMETHODIMP
     647               0 : nsRange::ComparePoint(nsIDOMNode* aParent, PRInt32 aOffset, PRInt16* aResult)
     648                 : {
     649               0 :   if (mIsDetached)
     650               0 :     return NS_ERROR_DOM_INVALID_STATE_ERR;
     651                 : 
     652                 :   // our range is in a good state?
     653               0 :   if (!mIsPositioned) 
     654               0 :     return NS_ERROR_NOT_INITIALIZED;
     655                 : 
     656               0 :   nsCOMPtr<nsINode> parent = do_QueryInterface(aParent);
     657               0 :   NS_ENSURE_TRUE(parent, NS_ERROR_DOM_HIERARCHY_REQUEST_ERR);
     658                 : 
     659               0 :   if (!nsContentUtils::ContentIsDescendantOf(parent, mRoot)) {
     660               0 :     return NS_ERROR_DOM_WRONG_DOCUMENT_ERR;
     661                 :   }
     662                 :   
     663                 :   PRInt32 cmp;
     664               0 :   if ((cmp = nsContentUtils::ComparePoints(parent, aOffset,
     665               0 :                                            mStartParent, mStartOffset)) <= 0) {
     666                 :     
     667               0 :     *aResult = cmp;
     668                 :   }
     669               0 :   else if (nsContentUtils::ComparePoints(mEndParent, mEndOffset,
     670               0 :                                          parent, aOffset) == -1) {
     671               0 :     *aResult = 1;
     672                 :   }
     673                 :   else {
     674               0 :     *aResult = 0;
     675                 :   }
     676                 :   
     677               0 :   return NS_OK;
     678                 : }
     679                 :   
     680                 : /******************************************************
     681                 :  * Private helper routines
     682                 :  ******************************************************/
     683                 : 
     684                 : // Get the length of aNode
     685             129 : static PRUint32 GetNodeLength(nsINode *aNode)
     686                 : {
     687             129 :   if(aNode->IsNodeOfType(nsINode::eDATA_NODE)) {
     688              49 :     return static_cast<nsIContent*>(aNode)->TextLength();
     689                 :   }
     690                 : 
     691              80 :   return aNode->GetChildCount();
     692                 : }
     693                 : 
     694                 : // It's important that all setting of the range start/end points 
     695                 : // go through this function, which will do all the right voodoo
     696                 : // for content notification of range ownership.  
     697                 : // Calling DoSetRange with either parent argument null will collapse
     698                 : // the range to have both endpoints point to the other node
     699                 : void
     700             171 : nsRange::DoSetRange(nsINode* aStartN, PRInt32 aStartOffset,
     701                 :                     nsINode* aEndN, PRInt32 aEndOffset,
     702                 :                     nsINode* aRoot, bool aNotInsertedYet)
     703                 : {
     704             171 :   NS_PRECONDITION((aStartN && aEndN && aRoot) ||
     705                 :                   (!aStartN && !aEndN && !aRoot),
     706                 :                   "Set all or none");
     707             171 :   NS_PRECONDITION(!aRoot || aNotInsertedYet ||
     708                 :                   (nsContentUtils::ContentIsDescendantOf(aStartN, aRoot) &&
     709                 :                    nsContentUtils::ContentIsDescendantOf(aEndN, aRoot) &&
     710                 :                    aRoot == IsValidBoundary(aStartN) &&
     711                 :                    aRoot == IsValidBoundary(aEndN)),
     712                 :                   "Wrong root");
     713             171 :   NS_PRECONDITION(!aRoot ||
     714                 :                   (aStartN->IsNodeOfType(nsINode::eCONTENT) &&
     715                 :                    aEndN->IsNodeOfType(nsINode::eCONTENT) &&
     716                 :                    aRoot ==
     717                 :                     static_cast<nsIContent*>(aStartN)->GetBindingParent() &&
     718                 :                    aRoot ==
     719                 :                     static_cast<nsIContent*>(aEndN)->GetBindingParent()) ||
     720                 :                   (!aRoot->GetNodeParent() &&
     721                 :                    (aRoot->IsNodeOfType(nsINode::eDOCUMENT) ||
     722                 :                     aRoot->IsNodeOfType(nsINode::eATTRIBUTE) ||
     723                 :                     aRoot->IsNodeOfType(nsINode::eDOCUMENT_FRAGMENT) ||
     724                 :                      /*For backward compatibility*/
     725                 :                     aRoot->IsNodeOfType(nsINode::eCONTENT))),
     726                 :                   "Bad root");
     727                 : 
     728             171 :   if (mRoot != aRoot) {
     729              93 :     if (mRoot) {
     730              62 :       mRoot->RemoveMutationObserver(this);
     731                 :     }
     732              93 :     if (aRoot) {
     733              62 :       aRoot->AddMutationObserver(this);
     734                 :     }
     735                 :   }
     736             246 :   bool checkCommonAncestor = (mStartParent != aStartN || mEndParent != aEndN) &&
     737             246 :                              IsInSelection() && !aNotInsertedYet;
     738             171 :   nsINode* oldCommonAncestor = checkCommonAncestor ? GetCommonAncestor() : nsnull;
     739             171 :   mStartParent = aStartN;
     740             171 :   mStartOffset = aStartOffset;
     741             171 :   mEndParent = aEndN;
     742             171 :   mEndOffset = aEndOffset;
     743             171 :   mIsPositioned = !!mStartParent;
     744             171 :   if (checkCommonAncestor) {
     745               0 :     nsINode* newCommonAncestor = GetCommonAncestor();
     746               0 :     if (newCommonAncestor != oldCommonAncestor) {
     747               0 :       if (oldCommonAncestor) {
     748               0 :         UnregisterCommonAncestor(oldCommonAncestor);
     749                 :       }
     750               0 :       if (newCommonAncestor) {
     751               0 :         RegisterCommonAncestor(newCommonAncestor);
     752                 :       } else {
     753               0 :         NS_ASSERTION(mIsDetached || !mIsPositioned,
     754                 :                      "unexpected disconnected nodes");
     755               0 :         mInSelection = false;
     756                 :       }
     757                 :     }
     758                 :   }
     759                 : 
     760                 :   // This needs to be the last thing this function does.  See comment
     761                 :   // in ParentChainChanged.
     762             171 :   mRoot = aRoot;
     763             171 : }
     764                 : 
     765                 : static PRInt32
     766               0 : IndexOf(nsIDOMNode* aChildNode)
     767                 : {
     768                 :   // convert node to nsIContent, so that we can find the child index
     769                 : 
     770               0 :   nsCOMPtr<nsINode> child = do_QueryInterface(aChildNode);
     771               0 :   if (!child) {
     772               0 :     return -1;
     773                 :   }
     774                 : 
     775               0 :   nsINode *parent = child->GetNodeParent();
     776                 : 
     777                 :   // finally we get the index
     778               0 :   return parent ? parent->IndexOf(child) : -1;
     779                 : }
     780                 : 
     781                 : nsINode*
     782               0 : nsRange::GetCommonAncestor() const
     783                 : {
     784                 :   return mIsPositioned ?
     785               0 :     nsContentUtils::GetCommonAncestor(mStartParent, mEndParent) :
     786               0 :     nsnull;
     787                 : }
     788                 : 
     789                 : void
     790               0 : nsRange::Reset()
     791                 : {
     792               0 :   DoSetRange(nsnull, 0, nsnull, 0, nsnull);
     793               0 : }
     794                 : 
     795                 : /******************************************************
     796                 :  * public functionality
     797                 :  ******************************************************/
     798                 : 
     799                 : NS_IMETHODIMP
     800              46 : nsRange::GetStartContainer(nsIDOMNode** aStartParent)
     801                 : {
     802              46 :   if (!mIsPositioned)
     803               0 :     return NS_ERROR_NOT_INITIALIZED;
     804                 : 
     805              46 :   return CallQueryInterface(mStartParent, aStartParent);
     806                 : }
     807                 : 
     808                 : NS_IMETHODIMP
     809              21 : nsRange::GetStartOffset(PRInt32* aStartOffset)
     810                 : {
     811              21 :   if (!mIsPositioned)
     812               0 :     return NS_ERROR_NOT_INITIALIZED;
     813                 : 
     814              21 :   *aStartOffset = mStartOffset;
     815                 : 
     816              21 :   return NS_OK;
     817                 : }
     818                 : 
     819                 : NS_IMETHODIMP
     820              47 : nsRange::GetEndContainer(nsIDOMNode** aEndParent)
     821                 : {
     822              47 :   if (!mIsPositioned)
     823               0 :     return NS_ERROR_NOT_INITIALIZED;
     824                 : 
     825              47 :   return CallQueryInterface(mEndParent, aEndParent);
     826                 : }
     827                 : 
     828                 : NS_IMETHODIMP
     829              18 : nsRange::GetEndOffset(PRInt32* aEndOffset)
     830                 : {
     831              18 :   if (!mIsPositioned)
     832               0 :     return NS_ERROR_NOT_INITIALIZED;
     833                 : 
     834              18 :   *aEndOffset = mEndOffset;
     835                 : 
     836              18 :   return NS_OK;
     837                 : }
     838                 : 
     839                 : NS_IMETHODIMP
     840              41 : nsRange::GetCollapsed(bool* aIsCollapsed)
     841                 : {
     842              41 :   if(mIsDetached)
     843               0 :     return NS_ERROR_DOM_INVALID_STATE_ERR;
     844              41 :   if (!mIsPositioned)
     845               0 :     return NS_ERROR_NOT_INITIALIZED;
     846                 : 
     847              41 :   *aIsCollapsed = Collapsed();
     848                 : 
     849              41 :   return NS_OK;
     850                 : }
     851                 : 
     852                 : NS_IMETHODIMP
     853              27 : nsRange::GetCommonAncestorContainer(nsIDOMNode** aCommonParent)
     854                 : {
     855              27 :   *aCommonParent = nsnull;
     856              27 :   if(mIsDetached)
     857               0 :     return NS_ERROR_DOM_INVALID_STATE_ERR;
     858              27 :   if (!mIsPositioned)
     859               0 :     return NS_ERROR_NOT_INITIALIZED;
     860                 : 
     861              27 :   nsINode* container = nsContentUtils::GetCommonAncestor(mStartParent, mEndParent);
     862              27 :   if (container) {
     863              27 :     return CallQueryInterface(container, aCommonParent);
     864                 :   }
     865                 : 
     866               0 :   return NS_ERROR_NOT_INITIALIZED;
     867                 : }
     868                 : 
     869                 : nsINode*
     870             393 : nsRange::IsValidBoundary(nsINode* aNode)
     871                 : {
     872             393 :   if (!aNode) {
     873               0 :     return nsnull;
     874                 :   }
     875                 : 
     876             393 :   if (aNode->IsNodeOfType(nsINode::eCONTENT)) {
     877             207 :     nsIContent* content = static_cast<nsIContent*>(aNode);
     878             207 :     if (content->Tag() == nsGkAtoms::documentTypeNodeName) {
     879               0 :       return nsnull;
     880                 :     }
     881                 : 
     882             207 :     if (!mMaySpanAnonymousSubtrees) {
     883                 :       // If the node has a binding parent, that should be the root.
     884                 :       // XXXbz maybe only for native anonymous content?
     885             207 :       nsINode* root = content->GetBindingParent();
     886             207 :       if (root) {
     887               0 :         return root;
     888                 :       }
     889                 :     }
     890                 :   }
     891                 : 
     892                 :   // Elements etc. must be in document or in document fragment,
     893                 :   // text nodes in document, in document fragment or in attribute.
     894             393 :   nsINode* root = aNode->GetCurrentDoc();
     895             393 :   if (root) {
     896             192 :     return root;
     897                 :   }
     898                 : 
     899             201 :   root = aNode;
     900             539 :   while ((aNode = aNode->GetNodeParent())) {
     901             137 :     root = aNode;
     902                 :   }
     903                 : 
     904             201 :   NS_ASSERTION(!root->IsNodeOfType(nsINode::eDOCUMENT),
     905                 :                "GetCurrentDoc should have returned a doc");
     906                 : 
     907                 : #ifdef DEBUG_smaug
     908                 :   NS_WARN_IF_FALSE(root->IsNodeOfType(nsINode::eDOCUMENT_FRAGMENT) ||
     909                 :                    root->IsNodeOfType(nsINode::eATTRIBUTE),
     910                 :                    "Creating a DOM Range using root which isn't in DOM!");
     911                 : #endif
     912                 : 
     913                 :   // We allow this because of backward compatibility.
     914             201 :   return root;
     915                 : }
     916                 : 
     917                 : NS_IMETHODIMP
     918              36 : nsRange::SetStart(nsIDOMNode* aParent, PRInt32 aOffset)
     919                 : {
     920              36 :   VALIDATE_ACCESS(aParent);
     921                 : 
     922              68 :   nsCOMPtr<nsINode> parent = do_QueryInterface(aParent);
     923              68 :   AutoInvalidateSelection atEndOfBlock(this);
     924              34 :   return SetStart(parent, aOffset);
     925                 : }
     926                 : 
     927                 : /* virtual */ nsresult
     928              65 : nsRange::SetStart(nsINode* aParent, PRInt32 aOffset)
     929                 : {
     930              65 :   nsINode* newRoot = IsValidBoundary(aParent);
     931              65 :   NS_ENSURE_TRUE(newRoot, NS_ERROR_DOM_INVALID_NODE_TYPE_ERR);
     932                 : 
     933              65 :   PRInt32 len = GetNodeLength(aParent);
     934              65 :   if (aOffset < 0 || aOffset > len)
     935               2 :     return NS_ERROR_DOM_INDEX_SIZE_ERR;
     936                 : 
     937                 :   // Collapse if not positioned yet, if positioned in another doc or
     938                 :   // if the new start is after end.
     939              65 :   if (!mIsPositioned || newRoot != mRoot ||
     940                 :       nsContentUtils::ComparePoints(aParent, aOffset,
     941               2 :                                     mEndParent, mEndOffset) == 1) {
     942              63 :     DoSetRange(aParent, aOffset, aParent, aOffset, newRoot);
     943                 : 
     944              63 :     return NS_OK;
     945                 :   }
     946                 : 
     947               0 :   DoSetRange(aParent, aOffset, mEndParent, mEndOffset, mRoot);
     948                 :   
     949               0 :   return NS_OK;
     950                 : }
     951                 : 
     952                 : NS_IMETHODIMP
     953               0 : nsRange::SetStartBefore(nsIDOMNode* aSibling)
     954                 : {
     955               0 :   VALIDATE_ACCESS(aSibling);
     956                 :   
     957               0 :   nsCOMPtr<nsIDOMNode> parent;
     958               0 :   nsresult rv = aSibling->GetParentNode(getter_AddRefs(parent));
     959               0 :   if (NS_FAILED(rv) || !parent) {
     960               0 :     return NS_ERROR_DOM_INVALID_NODE_TYPE_ERR;
     961                 :   }
     962                 : 
     963               0 :   return SetStart(parent, IndexOf(aSibling));
     964                 : }
     965                 : 
     966                 : NS_IMETHODIMP
     967               0 : nsRange::SetStartAfter(nsIDOMNode* aSibling)
     968                 : {
     969               0 :   VALIDATE_ACCESS(aSibling);
     970                 : 
     971               0 :   nsCOMPtr<nsIDOMNode> nParent;
     972               0 :   nsresult res = aSibling->GetParentNode(getter_AddRefs(nParent));
     973               0 :   if (NS_FAILED(res) || !nParent) {
     974               0 :     return NS_ERROR_DOM_INVALID_NODE_TYPE_ERR;
     975                 :   }
     976                 : 
     977               0 :   return SetStart(nParent, IndexOf(aSibling) + 1);
     978                 : }
     979                 : 
     980                 : NS_IMETHODIMP
     981              33 : nsRange::SetEnd(nsIDOMNode* aParent, PRInt32 aOffset)
     982                 : {
     983              33 :   VALIDATE_ACCESS(aParent);
     984                 : 
     985              66 :   AutoInvalidateSelection atEndOfBlock(this);
     986              66 :   nsCOMPtr<nsINode> parent = do_QueryInterface(aParent);
     987              33 :   return SetEnd(parent, aOffset);
     988                 : }
     989                 : 
     990                 : 
     991                 : /* virtual */ nsresult
     992              64 : nsRange::SetEnd(nsINode* aParent, PRInt32 aOffset)
     993                 : {
     994              64 :   nsINode* newRoot = IsValidBoundary(aParent);
     995              64 :   NS_ENSURE_TRUE(newRoot, NS_ERROR_DOM_INVALID_NODE_TYPE_ERR);
     996                 : 
     997              64 :   PRInt32 len = GetNodeLength(aParent);
     998              64 :   if (aOffset < 0 || aOffset > len) {
     999               0 :     return NS_ERROR_DOM_INDEX_SIZE_ERR;
    1000                 :   }
    1001                 : 
    1002                 :   // Collapse if not positioned yet, if positioned in another doc or
    1003                 :   // if the new end is before start.
    1004             127 :   if (!mIsPositioned || newRoot != mRoot ||
    1005                 :       nsContentUtils::ComparePoints(mStartParent, mStartOffset,
    1006              63 :                                     aParent, aOffset) == 1) {
    1007               2 :     DoSetRange(aParent, aOffset, aParent, aOffset, newRoot);
    1008                 : 
    1009               2 :     return NS_OK;
    1010                 :   }
    1011                 : 
    1012              62 :   DoSetRange(mStartParent, mStartOffset, aParent, aOffset, mRoot);
    1013                 : 
    1014              62 :   return NS_OK;
    1015                 : }
    1016                 : 
    1017                 : NS_IMETHODIMP
    1018               0 : nsRange::SetEndBefore(nsIDOMNode* aSibling)
    1019                 : {
    1020               0 :   VALIDATE_ACCESS(aSibling);
    1021                 :   
    1022               0 :   nsCOMPtr<nsIDOMNode> nParent;
    1023               0 :   nsresult rv = aSibling->GetParentNode(getter_AddRefs(nParent));
    1024               0 :   if (NS_FAILED(rv) || !nParent) {
    1025               0 :     return NS_ERROR_DOM_INVALID_NODE_TYPE_ERR;
    1026                 :   }
    1027                 : 
    1028               0 :   return SetEnd(nParent, IndexOf(aSibling));
    1029                 : }
    1030                 : 
    1031                 : NS_IMETHODIMP
    1032               0 : nsRange::SetEndAfter(nsIDOMNode* aSibling)
    1033                 : {
    1034               0 :   VALIDATE_ACCESS(aSibling);
    1035                 :   
    1036               0 :   nsCOMPtr<nsIDOMNode> nParent;
    1037               0 :   nsresult res = aSibling->GetParentNode(getter_AddRefs(nParent));
    1038               0 :   if (NS_FAILED(res) || !nParent) {
    1039               0 :     return NS_ERROR_DOM_INVALID_NODE_TYPE_ERR;
    1040                 :   }
    1041                 : 
    1042               0 :   return SetEnd(nParent, IndexOf(aSibling) + 1);
    1043                 : }
    1044                 : 
    1045                 : NS_IMETHODIMP
    1046               2 : nsRange::Collapse(bool aToStart)
    1047                 : {
    1048               2 :   if(mIsDetached)
    1049               0 :     return NS_ERROR_DOM_INVALID_STATE_ERR;
    1050               2 :   if (!mIsPositioned)
    1051               0 :     return NS_ERROR_NOT_INITIALIZED;
    1052                 : 
    1053               4 :   AutoInvalidateSelection atEndOfBlock(this);
    1054               2 :   if (aToStart)
    1055               0 :     DoSetRange(mStartParent, mStartOffset, mStartParent, mStartOffset, mRoot);
    1056                 :   else
    1057               2 :     DoSetRange(mEndParent, mEndOffset, mEndParent, mEndOffset, mRoot);
    1058                 : 
    1059               2 :   return NS_OK;
    1060                 : }
    1061                 : 
    1062                 : NS_IMETHODIMP
    1063               2 : nsRange::SelectNode(nsIDOMNode* aN)
    1064                 : {
    1065               2 :   VALIDATE_ACCESS(aN);
    1066                 :   
    1067               4 :   nsCOMPtr<nsINode> node = do_QueryInterface(aN);
    1068               2 :   NS_ENSURE_TRUE(node, NS_ERROR_DOM_INVALID_NODE_TYPE_ERR);
    1069                 : 
    1070               2 :   nsINode* parent = node->GetNodeParent();
    1071               2 :   nsINode* newRoot = IsValidBoundary(parent);
    1072               2 :   NS_ENSURE_TRUE(newRoot, NS_ERROR_DOM_INVALID_NODE_TYPE_ERR);
    1073                 : 
    1074               2 :   PRInt32 index = parent->IndexOf(node);
    1075               2 :   if (index < 0) {
    1076               0 :     return NS_ERROR_DOM_INVALID_NODE_TYPE_ERR;
    1077                 :   }
    1078                 : 
    1079               4 :   AutoInvalidateSelection atEndOfBlock(this);
    1080               2 :   DoSetRange(parent, index, parent, index + 1, newRoot);
    1081                 :   
    1082               2 :   return NS_OK;
    1083                 : }
    1084                 : 
    1085                 : NS_IMETHODIMP
    1086               0 : nsRange::SelectNodeContents(nsIDOMNode* aN)
    1087                 : {
    1088               0 :   VALIDATE_ACCESS(aN);
    1089                 : 
    1090               0 :   nsCOMPtr<nsINode> node = do_QueryInterface(aN);
    1091               0 :   nsINode* newRoot = IsValidBoundary(node);
    1092               0 :   NS_ENSURE_TRUE(newRoot, NS_ERROR_DOM_INVALID_NODE_TYPE_ERR);
    1093                 :   
    1094               0 :   AutoInvalidateSelection atEndOfBlock(this);
    1095               0 :   DoSetRange(node, 0, node, GetNodeLength(node), newRoot);
    1096                 :   
    1097               0 :   return NS_OK;
    1098                 : }
    1099                 : 
    1100                 : // The Subtree Content Iterator only returns subtrees that are
    1101                 : // completely within a given range. It doesn't return a CharacterData
    1102                 : // node that contains either the start or end point of the range.,
    1103                 : // nor does it return element nodes when nothing in the element is selected.
    1104                 : // We need an iterator that will also include these start/end points
    1105                 : // so that our methods/algorithms aren't cluttered with special
    1106                 : // case code that tries to include these points while iterating.
    1107                 : //
    1108                 : // The RangeSubtreeIterator class mimics the nsIContentIterator
    1109                 : // methods we need, so should the Content Iterator support the
    1110                 : // start/end points in the future, we can switchover relatively
    1111                 : // easy.
    1112                 : 
    1113                 : class NS_STACK_CLASS RangeSubtreeIterator
    1114                 : {
    1115                 : private:
    1116                 : 
    1117                 :   enum RangeSubtreeIterState { eDone=0,
    1118                 :                                eUseStart,
    1119                 :                                eUseIterator,
    1120                 :                                eUseEnd };
    1121                 : 
    1122                 :   nsCOMPtr<nsIContentIterator>  mIter;
    1123                 :   RangeSubtreeIterState         mIterState;
    1124                 : 
    1125                 :   nsCOMPtr<nsIDOMNode> mStart;
    1126                 :   nsCOMPtr<nsIDOMNode> mEnd;
    1127                 : 
    1128                 : public:
    1129                 : 
    1130              19 :   RangeSubtreeIterator()
    1131              19 :     : mIterState(eDone)
    1132                 :   {
    1133              19 :   }
    1134              19 :   ~RangeSubtreeIterator()
    1135              19 :   {
    1136              19 :   }
    1137                 : 
    1138                 :   nsresult Init(nsIDOMRange *aRange);
    1139                 :   already_AddRefed<nsIDOMNode> GetCurrentNode();
    1140                 :   void First();
    1141                 :   void Last();
    1142                 :   void Next();
    1143                 :   void Prev();
    1144                 : 
    1145              92 :   bool IsDone()
    1146                 :   {
    1147              92 :     return mIterState == eDone;
    1148                 :   }
    1149                 : };
    1150                 : 
    1151                 : nsresult
    1152              19 : RangeSubtreeIterator::Init(nsIDOMRange *aRange)
    1153                 : {
    1154              19 :   mIterState = eDone;
    1155                 :   bool collapsed;
    1156              19 :   aRange->GetCollapsed(&collapsed);
    1157              19 :   if (collapsed) {
    1158               4 :     return NS_OK;
    1159                 :   }
    1160                 : 
    1161              30 :   nsCOMPtr<nsIDOMNode> node;
    1162                 : 
    1163                 :   // Grab the start point of the range and QI it to
    1164                 :   // a CharacterData pointer. If it is CharacterData store
    1165                 :   // a pointer to the node.
    1166                 : 
    1167              15 :   nsresult res = aRange->GetStartContainer(getter_AddRefs(node));
    1168              15 :   if (!node) return NS_ERROR_FAILURE;
    1169                 : 
    1170              30 :   nsCOMPtr<nsIDOMCharacterData> startData = do_QueryInterface(node);
    1171              15 :   if (startData) {
    1172              11 :     mStart = node;
    1173                 :   } else {
    1174                 :     PRInt32 startIndex;
    1175               4 :     aRange->GetStartOffset(&startIndex);
    1176               8 :     nsCOMPtr<nsINode> iNode = do_QueryInterface(node);
    1177               4 :     if (iNode->IsElement() && 
    1178               0 :         PRInt32(iNode->AsElement()->GetChildCount()) == startIndex) {
    1179               0 :       mStart = node;
    1180                 :     }
    1181                 :   }
    1182                 : 
    1183                 :   // Grab the end point of the range and QI it to
    1184                 :   // a CharacterData pointer. If it is CharacterData store
    1185                 :   // a pointer to the node.
    1186                 : 
    1187              15 :   res = aRange->GetEndContainer(getter_AddRefs(node));
    1188              15 :   if (!node) return NS_ERROR_FAILURE;
    1189                 : 
    1190              30 :   nsCOMPtr<nsIDOMCharacterData> endData = do_QueryInterface(node);
    1191              15 :   if (endData) {
    1192              11 :     mEnd = node;
    1193                 :   } else {
    1194                 :     PRInt32 endIndex;
    1195               4 :     aRange->GetEndOffset(&endIndex);
    1196               8 :     nsCOMPtr<nsINode> iNode = do_QueryInterface(node);
    1197               4 :     if (iNode->IsElement() && endIndex == 0) {
    1198               0 :       mEnd = node;
    1199                 :     }
    1200                 :   }
    1201                 : 
    1202              15 :   if (mStart && mStart == mEnd)
    1203                 :   {
    1204                 :     // The range starts and stops in the same CharacterData
    1205                 :     // node. Null out the end pointer so we only visit the
    1206                 :     // node once!
    1207                 : 
    1208               9 :     mEnd = nsnull;
    1209                 :   }
    1210                 :   else
    1211                 :   {
    1212                 :     // Now create a Content Subtree Iterator to be used
    1213                 :     // for the subtrees between the end points!
    1214                 : 
    1215               6 :     res = NS_NewContentSubtreeIterator(getter_AddRefs(mIter));
    1216               6 :     if (NS_FAILED(res)) return res;
    1217                 : 
    1218               6 :     res = mIter->Init(aRange);
    1219               6 :     if (NS_FAILED(res)) return res;
    1220                 : 
    1221               6 :     if (mIter->IsDone())
    1222                 :     {
    1223                 :       // The subtree iterator thinks there's nothing
    1224                 :       // to iterate over, so just free it up so we
    1225                 :       // don't accidentally call into it.
    1226                 : 
    1227               0 :       mIter = nsnull;
    1228                 :     }
    1229                 :   }
    1230                 : 
    1231                 :   // Initialize the iterator by calling First().
    1232                 :   // Note that we are ignoring the return value on purpose!
    1233                 : 
    1234              15 :   First();
    1235                 : 
    1236              15 :   return NS_OK;
    1237                 : }
    1238                 : 
    1239                 : already_AddRefed<nsIDOMNode>
    1240              27 : RangeSubtreeIterator::GetCurrentNode()
    1241                 : {
    1242              27 :   nsIDOMNode *node = nsnull;
    1243                 : 
    1244              27 :   if (mIterState == eUseStart && mStart) {
    1245              12 :     NS_ADDREF(node = mStart);
    1246              15 :   } else if (mIterState == eUseEnd && mEnd)
    1247               2 :     NS_ADDREF(node = mEnd);
    1248              13 :   else if (mIterState == eUseIterator && mIter)
    1249                 :   {
    1250              13 :     nsINode* n = mIter->GetCurrentNode();
    1251                 : 
    1252              13 :     if (n) {
    1253              13 :       CallQueryInterface(n, &node);
    1254                 :     }
    1255                 :   }
    1256                 : 
    1257              27 :   return node;
    1258                 : }
    1259                 : 
    1260                 : void
    1261              15 : RangeSubtreeIterator::First()
    1262                 : {
    1263              15 :   if (mStart)
    1264              11 :     mIterState = eUseStart;
    1265               4 :   else if (mIter)
    1266                 :   {
    1267               4 :     mIter->First();
    1268                 : 
    1269               4 :     mIterState = eUseIterator;
    1270                 :   }
    1271               0 :   else if (mEnd)
    1272               0 :     mIterState = eUseEnd;
    1273                 :   else
    1274               0 :     mIterState = eDone;
    1275              15 : }
    1276                 : 
    1277                 : void
    1278              15 : RangeSubtreeIterator::Last()
    1279                 : {
    1280              15 :   if (mEnd)
    1281               2 :     mIterState = eUseEnd;
    1282              13 :   else if (mIter)
    1283                 :   {
    1284               4 :     mIter->Last();
    1285                 : 
    1286               4 :     mIterState = eUseIterator;
    1287                 :   }
    1288               9 :   else if (mStart)
    1289               9 :     mIterState = eUseStart;
    1290                 :   else
    1291               0 :     mIterState = eDone;
    1292              15 : }
    1293                 : 
    1294                 : void
    1295               0 : RangeSubtreeIterator::Next()
    1296                 : {
    1297               0 :   if (mIterState == eUseStart)
    1298                 :   {
    1299               0 :     if (mIter)
    1300                 :     {
    1301               0 :       mIter->First();
    1302                 : 
    1303               0 :       mIterState = eUseIterator;
    1304                 :     }
    1305               0 :     else if (mEnd)
    1306               0 :       mIterState = eUseEnd;
    1307                 :     else
    1308               0 :       mIterState = eDone;
    1309                 :   }
    1310               0 :   else if (mIterState == eUseIterator)
    1311                 :   {
    1312               0 :     mIter->Next();
    1313                 : 
    1314               0 :     if (mIter->IsDone())
    1315                 :     {
    1316               0 :       if (mEnd)
    1317               0 :         mIterState = eUseEnd;
    1318                 :       else
    1319               0 :         mIterState = eDone;
    1320                 :     }
    1321                 :   }
    1322                 :   else
    1323               0 :     mIterState = eDone;
    1324               0 : }
    1325                 : 
    1326                 : void
    1327              23 : RangeSubtreeIterator::Prev()
    1328                 : {
    1329              23 :   if (mIterState == eUseEnd)
    1330                 :   {
    1331               2 :     if (mIter)
    1332                 :     {
    1333               2 :       mIter->Last();
    1334                 : 
    1335               2 :       mIterState = eUseIterator;
    1336                 :     }
    1337               0 :     else if (mStart)
    1338               0 :       mIterState = eUseStart;
    1339                 :     else
    1340               0 :       mIterState = eDone;
    1341                 :   }
    1342              21 :   else if (mIterState == eUseIterator)
    1343                 :   {
    1344              10 :     mIter->Prev();
    1345                 : 
    1346              10 :     if (mIter->IsDone())
    1347                 :     {
    1348               6 :       if (mStart)
    1349               2 :         mIterState = eUseStart;
    1350                 :       else
    1351               4 :         mIterState = eDone;
    1352                 :     }
    1353                 :   }
    1354                 :   else
    1355              11 :     mIterState = eDone;
    1356              23 : }
    1357                 : 
    1358                 : 
    1359                 : // CollapseRangeAfterDelete() is a utility method that is used by
    1360                 : // DeleteContents() and ExtractContents() to collapse the range
    1361                 : // in the correct place, under the range's root container (the
    1362                 : // range end points common container) as outlined by the Range spec:
    1363                 : //
    1364                 : // http://www.w3.org/TR/2000/REC-DOM-Level-2-Traversal-Range-20001113/ranges.html
    1365                 : // The assumption made by this method is that the delete or extract
    1366                 : // has been done already, and left the range in a state where there is
    1367                 : // no content between the 2 end points.
    1368                 : 
    1369                 : static nsresult
    1370              19 : CollapseRangeAfterDelete(nsIDOMRange *aRange)
    1371                 : {
    1372              19 :   NS_ENSURE_ARG_POINTER(aRange);
    1373                 : 
    1374                 :   // Check if range gravity took care of collapsing the range for us!
    1375                 : 
    1376              19 :   bool isCollapsed = false;
    1377              19 :   nsresult res = aRange->GetCollapsed(&isCollapsed);
    1378              19 :   if (NS_FAILED(res)) return res;
    1379                 : 
    1380              19 :   if (isCollapsed)
    1381                 :   {
    1382                 :     // aRange is collapsed so there's nothing for us to do.
    1383                 :     //
    1384                 :     // There are 2 possible scenarios here:
    1385                 :     //
    1386                 :     // 1. aRange could've been collapsed prior to the delete/extract,
    1387                 :     //    which would've resulted in nothing being removed, so aRange
    1388                 :     //    is already where it should be.
    1389                 :     //
    1390                 :     // 2. Prior to the delete/extract, aRange's start and end were in
    1391                 :     //    the same container which would mean everything between them
    1392                 :     //    was removed, causing range gravity to collapse the range.
    1393                 : 
    1394              17 :     return NS_OK;
    1395                 :   }
    1396                 : 
    1397                 :   // aRange isn't collapsed so figure out the appropriate place to collapse!
    1398                 :   // First get both end points and their common ancestor.
    1399                 : 
    1400               4 :   nsCOMPtr<nsIDOMNode> commonAncestor;
    1401               2 :   res = aRange->GetCommonAncestorContainer(getter_AddRefs(commonAncestor));
    1402               2 :   if(NS_FAILED(res)) return res;
    1403                 : 
    1404               4 :   nsCOMPtr<nsIDOMNode> startContainer, endContainer;
    1405                 : 
    1406               2 :   res = aRange->GetStartContainer(getter_AddRefs(startContainer));
    1407               2 :   if (NS_FAILED(res)) return res;
    1408                 : 
    1409               2 :   res = aRange->GetEndContainer(getter_AddRefs(endContainer));
    1410               2 :   if (NS_FAILED(res)) return res;
    1411                 : 
    1412                 :   // Collapse to one of the end points if they are already in the
    1413                 :   // commonAncestor. This should work ok since this method is called
    1414                 :   // immediately after a delete or extract that leaves no content
    1415                 :   // between the 2 end points!
    1416                 : 
    1417               2 :   if (startContainer == commonAncestor)
    1418               0 :     return aRange->Collapse(true);
    1419               2 :   if (endContainer == commonAncestor)
    1420               0 :     return aRange->Collapse(false);
    1421                 : 
    1422                 :   // End points are at differing levels. We want to collapse to the
    1423                 :   // point that is between the 2 subtrees that contain each point,
    1424                 :   // under the common ancestor.
    1425                 : 
    1426               4 :   nsCOMPtr<nsIDOMNode> nodeToSelect(startContainer), parent;
    1427                 : 
    1428               4 :   while (nodeToSelect)
    1429                 :   {
    1430               2 :     nsresult res = nodeToSelect->GetParentNode(getter_AddRefs(parent));
    1431               2 :     if (NS_FAILED(res)) return res;
    1432                 : 
    1433               2 :     if (parent == commonAncestor)
    1434               2 :       break; // We found the nodeToSelect!
    1435                 : 
    1436               0 :     nodeToSelect = parent;
    1437                 :   }
    1438                 : 
    1439               2 :   if (!nodeToSelect)
    1440               0 :     return NS_ERROR_FAILURE; // This should never happen!
    1441                 : 
    1442               2 :   res = aRange->SelectNode(nodeToSelect);
    1443               2 :   if (NS_FAILED(res)) return res;
    1444                 : 
    1445               2 :   return aRange->Collapse(false);
    1446                 : }
    1447                 : 
    1448                 : /**
    1449                 :  * Remove a node from the DOM entirely.
    1450                 :  *
    1451                 :  * @param aNode The node to remove.
    1452                 :  */
    1453                 : static nsresult
    1454               7 : RemoveNode(nsIDOMNode* aNode)
    1455                 : {
    1456              14 :   nsCOMPtr<nsINode> node = do_QueryInterface(aNode);
    1457              14 :   nsCOMPtr<nsINode> parent = node->GetNodeParent();
    1458               7 :   return parent ? parent->RemoveChild(node) : NS_OK;
    1459                 : }
    1460                 : 
    1461                 : /**
    1462                 :  * Split a data node into two parts.
    1463                 :  *
    1464                 :  * @param aStartNode          The original node we are trying to split.
    1465                 :  * @param aStartIndex         The index at which to split.
    1466                 :  * @param aEndNode            The second node.
    1467                 :  * @param aCloneAfterOriginal Set false if the original node should be the
    1468                 :  *                            latter one after split.
    1469                 :  */
    1470               4 : static nsresult SplitDataNode(nsIDOMCharacterData* aStartNode,
    1471                 :                               PRUint32 aStartIndex,
    1472                 :                               nsIDOMCharacterData** aEndNode,
    1473                 :                               bool aCloneAfterOriginal = true)
    1474                 : {
    1475                 :   nsresult rv;
    1476               8 :   nsCOMPtr<nsINode> node = do_QueryInterface(aStartNode);
    1477               4 :   NS_ENSURE_STATE(node && node->IsNodeOfType(nsINode::eDATA_NODE));
    1478               4 :   nsGenericDOMDataNode* dataNode = static_cast<nsGenericDOMDataNode*>(node.get());
    1479                 : 
    1480               8 :   nsCOMPtr<nsIContent> newData;
    1481               4 :   rv = dataNode->SplitData(aStartIndex, getter_AddRefs(newData),
    1482               4 :                            aCloneAfterOriginal);
    1483               4 :   NS_ENSURE_SUCCESS(rv, rv);
    1484               4 :   return CallQueryInterface(newData, aEndNode);
    1485                 : }
    1486                 : 
    1487                 : NS_IMETHODIMP
    1488              12 : PrependChild(nsIDOMNode* aParent, nsIDOMNode* aChild)
    1489                 : {
    1490              24 :   nsCOMPtr<nsIDOMNode> first, tmpNode;
    1491              12 :   aParent->GetFirstChild(getter_AddRefs(first));
    1492              12 :   return aParent->InsertBefore(aChild, first, getter_AddRefs(tmpNode));
    1493                 : }
    1494                 : 
    1495              37 : nsresult nsRange::CutContents(nsIDOMDocumentFragment** aFragment)
    1496                 : { 
    1497              37 :   if (aFragment) {
    1498              19 :     *aFragment = nsnull;
    1499                 :   }
    1500                 : 
    1501              37 :   if (IsDetached())
    1502              18 :     return NS_ERROR_DOM_INVALID_STATE_ERR;
    1503                 : 
    1504                 :   nsresult rv;
    1505                 : 
    1506              38 :   nsCOMPtr<nsIDocument> doc = mStartParent->OwnerDoc();
    1507                 : 
    1508              38 :   nsCOMPtr<nsIDOMNode> commonAncestor;
    1509              19 :   rv = GetCommonAncestorContainer(getter_AddRefs(commonAncestor));
    1510              19 :   NS_ENSURE_SUCCESS(rv, rv);
    1511                 : 
    1512                 :   // If aFragment isn't null, create a temporary fragment to hold our return.
    1513              38 :   nsCOMPtr<nsIDOMDocumentFragment> retval;
    1514              19 :   if (aFragment) {
    1515              10 :     rv = NS_NewDocumentFragment(getter_AddRefs(retval),
    1516              10 :                                 doc->NodeInfoManager());
    1517              10 :     NS_ENSURE_SUCCESS(rv, rv);
    1518                 :   }
    1519              38 :   nsCOMPtr<nsIDOMNode> commonCloneAncestor(do_QueryInterface(retval));
    1520                 : 
    1521                 :   // Batch possible DOMSubtreeModified events.
    1522              38 :   mozAutoSubtreeModified subtree(mRoot ? mRoot->OwnerDoc(): nsnull, nsnull);
    1523                 : 
    1524                 :   // Save the range end points locally to avoid interference
    1525                 :   // of Range gravity during our edits!
    1526                 : 
    1527              38 :   nsCOMPtr<nsIDOMNode> startContainer = do_QueryInterface(mStartParent);
    1528              19 :   PRInt32              startOffset = mStartOffset;
    1529              38 :   nsCOMPtr<nsIDOMNode> endContainer = do_QueryInterface(mEndParent);
    1530              19 :   PRInt32              endOffset = mEndOffset;
    1531                 : 
    1532                 :   // Create and initialize a subtree iterator that will give
    1533                 :   // us all the subtrees within the range.
    1534                 : 
    1535              38 :   RangeSubtreeIterator iter;
    1536                 : 
    1537              19 :   rv = iter.Init(this);
    1538              19 :   if (NS_FAILED(rv)) return rv;
    1539                 : 
    1540              19 :   if (iter.IsDone())
    1541                 :   {
    1542                 :     // There's nothing for us to delete.
    1543               4 :     rv = CollapseRangeAfterDelete(this);
    1544               4 :     if (NS_SUCCEEDED(rv) && aFragment) {
    1545               2 :       NS_ADDREF(*aFragment = retval);
    1546                 :     }
    1547               4 :     return rv;
    1548                 :   }
    1549                 : 
    1550                 :   // We delete backwards to avoid iterator problems!
    1551                 : 
    1552              15 :   iter.Last();
    1553                 : 
    1554              15 :   bool handled = false;
    1555                 : 
    1556                 :   // With the exception of text nodes that contain one of the range
    1557                 :   // end points, the subtree iterator should only give us back subtrees
    1558                 :   // that are completely contained between the range's end points.
    1559                 : 
    1560              53 :   while (!iter.IsDone())
    1561                 :   {
    1562              46 :     nsCOMPtr<nsIDOMNode> nodeToResult;
    1563              46 :     nsCOMPtr<nsIDOMNode> node(iter.GetCurrentNode());
    1564                 : 
    1565                 :     // Before we delete anything, advance the iterator to the
    1566                 :     // next subtree.
    1567                 : 
    1568              23 :     iter.Prev();
    1569                 : 
    1570              23 :     handled = false;
    1571                 : 
    1572                 :     // If it's CharacterData, make sure we might need to delete
    1573                 :     // part of the data, instead of removing the whole node.
    1574                 :     //
    1575                 :     // XXX_kin: We need to also handle ProcessingInstruction
    1576                 :     // XXX_kin: according to the spec.
    1577                 : 
    1578              46 :     nsCOMPtr<nsIDOMCharacterData> charData(do_QueryInterface(node));
    1579                 : 
    1580              23 :     if (charData)
    1581                 :     {
    1582              17 :       PRUint32 dataLength = 0;
    1583                 : 
    1584              17 :       if (node == startContainer)
    1585                 :       {
    1586              11 :         if (node == endContainer)
    1587                 :         {
    1588                 :           // This range is completely contained within a single text node.
    1589                 :           // Delete or extract the data between startOffset and endOffset.
    1590                 : 
    1591               9 :           if (endOffset > startOffset)
    1592                 :           {
    1593               9 :             if (retval) {
    1594              10 :               nsAutoString cutValue;
    1595               5 :               rv = charData->SubstringData(startOffset, endOffset - startOffset,
    1596               5 :                                            cutValue);
    1597               5 :               NS_ENSURE_SUCCESS(rv, rv);
    1598              10 :               nsCOMPtr<nsIDOMNode> clone;
    1599               5 :               rv = charData->CloneNode(false, 1, getter_AddRefs(clone));
    1600               5 :               NS_ENSURE_SUCCESS(rv, rv);
    1601               5 :               clone->SetNodeValue(cutValue);
    1602              10 :               nodeToResult = clone;
    1603                 :             }
    1604                 : 
    1605               9 :             rv = charData->DeleteData(startOffset, endOffset - startOffset);
    1606               9 :             NS_ENSURE_SUCCESS(rv, rv);
    1607                 :           }
    1608                 : 
    1609               9 :           handled = true;
    1610                 :         }
    1611                 :         else
    1612                 :         {
    1613                 :           // Delete or extract everything after startOffset.
    1614                 : 
    1615               2 :           rv = charData->GetLength(&dataLength);
    1616               2 :           NS_ENSURE_SUCCESS(rv, rv);
    1617                 : 
    1618               2 :           if (dataLength >= (PRUint32)startOffset)
    1619                 :           {
    1620               4 :             nsCOMPtr<nsIDOMCharacterData> cutNode;
    1621               2 :             rv = SplitDataNode(charData, startOffset, getter_AddRefs(cutNode));
    1622               2 :             NS_ENSURE_SUCCESS(rv, rv);
    1623               4 :             nodeToResult = cutNode;
    1624                 :           }
    1625                 : 
    1626               2 :           handled = true;
    1627                 :         }
    1628                 :       }
    1629               6 :       else if (node == endContainer)
    1630                 :       {
    1631                 :         // Delete or extract everything before endOffset.
    1632                 : 
    1633               2 :         if (endOffset >= 0)
    1634                 :         {
    1635               4 :           nsCOMPtr<nsIDOMCharacterData> cutNode;
    1636                 :           /* The Range spec clearly states clones get cut and original nodes
    1637                 :              remain behind, so use false as the last parameter.
    1638                 :           */
    1639               2 :           rv = SplitDataNode(charData, endOffset, getter_AddRefs(cutNode),
    1640               2 :                              false);
    1641               2 :           NS_ENSURE_SUCCESS(rv, rv);
    1642               4 :           nodeToResult = cutNode;
    1643                 :         }
    1644                 : 
    1645               2 :         handled = true;
    1646                 :       }       
    1647                 :     }
    1648                 : 
    1649              23 :     if (!handled && (node == endContainer || node == startContainer))
    1650                 :     {
    1651               0 :       nsCOMPtr<nsINode> iNode = do_QueryInterface(node);
    1652               0 :       if (iNode && iNode->IsElement() &&
    1653               0 :           ((node == endContainer && endOffset == 0) ||
    1654               0 :            (node == startContainer &&
    1655               0 :             PRInt32(iNode->AsElement()->GetChildCount()) == startOffset)))
    1656                 :       {
    1657               0 :         if (retval) {
    1658               0 :           nsCOMPtr<nsIDOMNode> clone;
    1659               0 :           rv = node->CloneNode(false, 1, getter_AddRefs(clone));
    1660               0 :           NS_ENSURE_SUCCESS(rv, rv);
    1661               0 :           nodeToResult = clone;
    1662                 :         }
    1663               0 :         handled = true;
    1664                 :       }
    1665                 :     }
    1666                 : 
    1667              23 :     if (!handled)
    1668                 :     {
    1669                 :       // node was not handled above, so it must be completely contained
    1670                 :       // within the range. Just remove it from the tree!
    1671              10 :       nodeToResult = node;
    1672                 :     }
    1673                 : 
    1674              23 :     PRUint32 parentCount = 0;
    1675              46 :     nsCOMPtr<nsIDOMNode> tmpNode;
    1676                 :     // Set the result to document fragment if we have 'retval'.
    1677              23 :     if (retval) {
    1678              24 :       nsCOMPtr<nsIDOMNode> oldCommonAncestor = commonAncestor;
    1679              12 :       if (!iter.IsDone()) {
    1680                 :         // Setup the parameters for the next iteration of the loop.
    1681               8 :         nsCOMPtr<nsIDOMNode> prevNode(iter.GetCurrentNode());
    1682               4 :         NS_ENSURE_STATE(prevNode);
    1683                 : 
    1684                 :         // Get node's and prevNode's common parent. Do this before moving
    1685                 :         // nodes from original DOM to result fragment.
    1686                 :         nsContentUtils::GetCommonAncestor(node, prevNode,
    1687               4 :                                           getter_AddRefs(commonAncestor));
    1688               4 :         NS_ENSURE_STATE(commonAncestor);
    1689                 : 
    1690               8 :         nsCOMPtr<nsIDOMNode> parentCounterNode = node;
    1691               4 :         while (parentCounterNode && parentCounterNode != commonAncestor)
    1692                 :         {
    1693               4 :           ++parentCount;
    1694               4 :           tmpNode = parentCounterNode;
    1695               4 :           tmpNode->GetParentNode(getter_AddRefs(parentCounterNode));
    1696               4 :           NS_ENSURE_STATE(parentCounterNode);
    1697                 :         }
    1698                 :       }
    1699                 : 
    1700                 :       // Clone the parent hierarchy between commonAncestor and node.
    1701              24 :       nsCOMPtr<nsIDOMNode> closestAncestor, farthestAncestor;
    1702                 :       rv = CloneParentsBetween(oldCommonAncestor, node,
    1703              12 :                                getter_AddRefs(closestAncestor),
    1704              24 :                                getter_AddRefs(farthestAncestor));
    1705              12 :       NS_ENSURE_SUCCESS(rv, rv);
    1706                 : 
    1707              12 :       if (farthestAncestor)
    1708                 :       {
    1709               0 :         rv = PrependChild(commonCloneAncestor, farthestAncestor);
    1710               0 :         NS_ENSURE_SUCCESS(rv, rv);
    1711                 :       }
    1712                 : 
    1713               0 :       rv = closestAncestor ? PrependChild(closestAncestor, nodeToResult)
    1714              12 :                            : PrependChild(commonCloneAncestor, nodeToResult);
    1715              12 :       NS_ENSURE_SUCCESS(rv, rv);
    1716              11 :     } else if (nodeToResult) {
    1717               7 :       rv = RemoveNode(nodeToResult);
    1718               7 :       NS_ENSURE_SUCCESS(rv, rv);
    1719                 :     }
    1720                 : 
    1721              23 :     if (!iter.IsDone() && retval) {
    1722                 :       // Find the equivalent of commonAncestor in the cloned tree.
    1723               8 :       nsCOMPtr<nsIDOMNode> newCloneAncestor = nodeToResult;
    1724               8 :       for (PRUint32 i = parentCount; i; --i)
    1725                 :       {
    1726               4 :         tmpNode = newCloneAncestor;
    1727               4 :         tmpNode->GetParentNode(getter_AddRefs(newCloneAncestor));
    1728               4 :         NS_ENSURE_STATE(newCloneAncestor);
    1729                 :       }
    1730               8 :       commonCloneAncestor = newCloneAncestor;
    1731                 :     }
    1732                 :   }
    1733                 : 
    1734              15 :   rv = CollapseRangeAfterDelete(this);
    1735              15 :   if (NS_SUCCEEDED(rv) && aFragment) {
    1736               8 :     NS_ADDREF(*aFragment = retval);
    1737                 :   }
    1738              15 :   return rv;
    1739                 : }
    1740                 : 
    1741                 : NS_IMETHODIMP
    1742              18 : nsRange::DeleteContents()
    1743                 : {
    1744              18 :   return CutContents(nsnull);
    1745                 : }
    1746                 : 
    1747                 : NS_IMETHODIMP
    1748              19 : nsRange::ExtractContents(nsIDOMDocumentFragment** aReturn)
    1749                 : {
    1750              19 :   NS_ENSURE_ARG_POINTER(aReturn);
    1751              19 :   return CutContents(aReturn);
    1752                 : }
    1753                 : 
    1754                 : NS_IMETHODIMP
    1755               0 : nsRange::CompareBoundaryPoints(PRUint16 aHow, nsIDOMRange* aOtherRange,
    1756                 :                                PRInt16* aCmpRet)
    1757                 : {
    1758               0 :   nsRange* otherRange = static_cast<nsRange*>(aOtherRange);
    1759               0 :   NS_ENSURE_TRUE(otherRange, NS_ERROR_NULL_POINTER);
    1760                 : 
    1761               0 :   if(mIsDetached || otherRange->IsDetached())
    1762               0 :     return NS_ERROR_DOM_INVALID_STATE_ERR;
    1763               0 :   if (!mIsPositioned || !otherRange->IsPositioned())
    1764               0 :     return NS_ERROR_NOT_INITIALIZED;
    1765                 : 
    1766                 :   nsINode *ourNode, *otherNode;
    1767                 :   PRInt32 ourOffset, otherOffset;
    1768                 : 
    1769               0 :   switch (aHow) {
    1770                 :     case nsIDOMRange::START_TO_START:
    1771               0 :       ourNode = mStartParent;
    1772               0 :       ourOffset = mStartOffset;
    1773               0 :       otherNode = otherRange->GetStartParent();
    1774               0 :       otherOffset = otherRange->StartOffset();
    1775               0 :       break;
    1776                 :     case nsIDOMRange::START_TO_END:
    1777               0 :       ourNode = mEndParent;
    1778               0 :       ourOffset = mEndOffset;
    1779               0 :       otherNode = otherRange->GetStartParent();
    1780               0 :       otherOffset = otherRange->StartOffset();
    1781               0 :       break;
    1782                 :     case nsIDOMRange::END_TO_START:
    1783               0 :       ourNode = mStartParent;
    1784               0 :       ourOffset = mStartOffset;
    1785               0 :       otherNode = otherRange->GetEndParent();
    1786               0 :       otherOffset = otherRange->EndOffset();
    1787               0 :       break;
    1788                 :     case nsIDOMRange::END_TO_END:
    1789               0 :       ourNode = mEndParent;
    1790               0 :       ourOffset = mEndOffset;
    1791               0 :       otherNode = otherRange->GetEndParent();
    1792               0 :       otherOffset = otherRange->EndOffset();
    1793               0 :       break;
    1794                 :     default:
    1795                 :       // We were passed an illegal value
    1796               0 :       return NS_ERROR_ILLEGAL_VALUE;
    1797                 :   }
    1798                 : 
    1799               0 :   if (mRoot != otherRange->GetRoot())
    1800               0 :     return NS_ERROR_DOM_WRONG_DOCUMENT_ERR;
    1801                 : 
    1802                 :   *aCmpRet = nsContentUtils::ComparePoints(ourNode, ourOffset,
    1803               0 :                                            otherNode, otherOffset);
    1804                 : 
    1805               0 :   return NS_OK;
    1806                 : }
    1807                 : 
    1808                 : /* static */ nsresult
    1809              12 : nsRange::CloneParentsBetween(nsIDOMNode *aAncestor,
    1810                 :                              nsIDOMNode *aNode,
    1811                 :                              nsIDOMNode **aClosestAncestor,
    1812                 :                              nsIDOMNode **aFarthestAncestor)
    1813                 : {
    1814              12 :   NS_ENSURE_ARG_POINTER((aAncestor && aNode && aClosestAncestor && aFarthestAncestor));
    1815                 : 
    1816              12 :   *aClosestAncestor  = nsnull;
    1817              12 :   *aFarthestAncestor = nsnull;
    1818                 : 
    1819              12 :   if (aAncestor == aNode)
    1820               5 :     return NS_OK;
    1821                 : 
    1822              14 :   nsCOMPtr<nsIDOMNode> parent, firstParent, lastParent;
    1823                 : 
    1824               7 :   nsresult res = aNode->GetParentNode(getter_AddRefs(parent));
    1825                 : 
    1826              14 :   while(parent && parent != aAncestor)
    1827                 :   {
    1828               0 :     nsCOMPtr<nsIDOMNode> clone, tmpNode;
    1829                 : 
    1830               0 :     res = parent->CloneNode(false, 1, getter_AddRefs(clone));
    1831                 : 
    1832               0 :     if (NS_FAILED(res)) return res;
    1833               0 :     if (!clone)         return NS_ERROR_FAILURE;
    1834                 : 
    1835               0 :     if (! firstParent)
    1836               0 :       firstParent = lastParent = clone;
    1837                 :     else
    1838                 :     {
    1839               0 :       res = clone->AppendChild(lastParent, getter_AddRefs(tmpNode));
    1840                 : 
    1841               0 :       if (NS_FAILED(res)) return res;
    1842                 : 
    1843               0 :       lastParent = clone;
    1844                 :     }
    1845                 : 
    1846               0 :     tmpNode = parent;
    1847               0 :     res = tmpNode->GetParentNode(getter_AddRefs(parent));
    1848                 :   }
    1849                 : 
    1850               7 :   *aClosestAncestor  = firstParent;
    1851               7 :   NS_IF_ADDREF(*aClosestAncestor);
    1852                 : 
    1853               7 :   *aFarthestAncestor = lastParent;
    1854               7 :   NS_IF_ADDREF(*aFarthestAncestor);
    1855                 : 
    1856               7 :   return NS_OK;
    1857                 : }
    1858                 : 
    1859                 : NS_IMETHODIMP
    1860               0 : nsRange::CloneContents(nsIDOMDocumentFragment** aReturn)
    1861                 : {
    1862               0 :   if (IsDetached())
    1863               0 :     return NS_ERROR_DOM_INVALID_STATE_ERR;
    1864                 : 
    1865                 :   nsresult res;
    1866               0 :   nsCOMPtr<nsIDOMNode> commonAncestor;
    1867               0 :   res = GetCommonAncestorContainer(getter_AddRefs(commonAncestor));
    1868               0 :   if (NS_FAILED(res)) return res;
    1869                 : 
    1870                 :   nsCOMPtr<nsIDOMDocument> document =
    1871               0 :     do_QueryInterface(mStartParent->OwnerDoc());
    1872               0 :   NS_ASSERTION(document, "CloneContents needs a document to continue.");
    1873               0 :   if (!document) return NS_ERROR_FAILURE;
    1874                 : 
    1875                 :   // Create a new document fragment in the context of this document,
    1876                 :   // which might be null
    1877                 : 
    1878               0 :   nsCOMPtr<nsIDOMDocumentFragment> clonedFrag;
    1879                 : 
    1880               0 :   nsCOMPtr<nsIDocument> doc(do_QueryInterface(document));
    1881                 : 
    1882               0 :   res = NS_NewDocumentFragment(getter_AddRefs(clonedFrag),
    1883               0 :                                doc->NodeInfoManager());
    1884               0 :   if (NS_FAILED(res)) return res;
    1885                 : 
    1886               0 :   nsCOMPtr<nsIDOMNode> commonCloneAncestor(do_QueryInterface(clonedFrag));
    1887               0 :   if (!commonCloneAncestor) return NS_ERROR_FAILURE;
    1888                 : 
    1889                 :   // Create and initialize a subtree iterator that will give
    1890                 :   // us all the subtrees within the range.
    1891                 : 
    1892               0 :   RangeSubtreeIterator iter;
    1893                 : 
    1894               0 :   res = iter.Init(this);
    1895               0 :   if (NS_FAILED(res)) return res;
    1896                 : 
    1897               0 :   if (iter.IsDone())
    1898                 :   {
    1899                 :     // There's nothing to add to the doc frag, we must be done!
    1900                 : 
    1901               0 :     *aReturn = clonedFrag;
    1902               0 :     NS_IF_ADDREF(*aReturn);
    1903               0 :     return NS_OK;
    1904                 :   }
    1905                 : 
    1906               0 :   iter.First();
    1907                 : 
    1908                 :   // With the exception of text nodes that contain one of the range
    1909                 :   // end points and elements which don't have any content selected the subtree
    1910                 :   // iterator should only give us back subtrees that are completely contained
    1911                 :   // between the range's end points.
    1912                 :   //
    1913                 :   // Unfortunately these subtrees don't contain the parent hierarchy/context
    1914                 :   // that the Range spec requires us to return. This loop clones the
    1915                 :   // parent hierarchy, adds a cloned version of the subtree, to it, then
    1916                 :   // correctly places this new subtree into the doc fragment.
    1917                 : 
    1918               0 :   while (!iter.IsDone())
    1919                 :   {
    1920               0 :     nsCOMPtr<nsIDOMNode> node(iter.GetCurrentNode());
    1921               0 :     nsCOMPtr<nsINode> iNode = do_QueryInterface(node);
    1922               0 :     bool deepClone = !iNode->IsElement() ||
    1923               0 :                        (!(iNode == mEndParent && mEndOffset == 0) &&
    1924               0 :                         !(iNode == mStartParent &&
    1925                 :                           mStartOffset ==
    1926               0 :                             PRInt32(iNode->AsElement()->GetChildCount())));
    1927                 : 
    1928                 :     // Clone the current subtree!
    1929                 : 
    1930               0 :     nsCOMPtr<nsIDOMNode> clone;
    1931               0 :     res = node->CloneNode(deepClone, 1, getter_AddRefs(clone));
    1932               0 :     if (NS_FAILED(res)) return res;
    1933                 : 
    1934                 :     // If it's CharacterData, make sure we only clone what
    1935                 :     // is in the range.
    1936                 :     //
    1937                 :     // XXX_kin: We need to also handle ProcessingInstruction
    1938                 :     // XXX_kin: according to the spec.
    1939                 : 
    1940               0 :     nsCOMPtr<nsIDOMCharacterData> charData(do_QueryInterface(clone));
    1941                 : 
    1942               0 :     if (charData)
    1943                 :     {
    1944               0 :       if (iNode == mEndParent)
    1945                 :       {
    1946                 :         // We only need the data before mEndOffset, so get rid of any
    1947                 :         // data after it.
    1948                 : 
    1949               0 :         PRUint32 dataLength = 0;
    1950               0 :         res = charData->GetLength(&dataLength);
    1951               0 :         if (NS_FAILED(res)) return res;
    1952                 : 
    1953               0 :         if (dataLength > (PRUint32)mEndOffset)
    1954                 :         {
    1955               0 :           res = charData->DeleteData(mEndOffset, dataLength - mEndOffset);
    1956               0 :           if (NS_FAILED(res)) return res;
    1957                 :         }
    1958                 :       }       
    1959                 : 
    1960               0 :       if (iNode == mStartParent)
    1961                 :       {
    1962                 :         // We don't need any data before mStartOffset, so just
    1963                 :         // delete it!
    1964                 : 
    1965               0 :         if (mStartOffset > 0)
    1966                 :         {
    1967               0 :           res = charData->DeleteData(0, mStartOffset);
    1968               0 :           if (NS_FAILED(res)) return res;
    1969                 :         }
    1970                 :       }
    1971                 :     }
    1972                 : 
    1973                 :     // Clone the parent hierarchy between commonAncestor and node.
    1974                 : 
    1975               0 :     nsCOMPtr<nsIDOMNode> closestAncestor, farthestAncestor;
    1976                 : 
    1977                 :     res = CloneParentsBetween(commonAncestor, node,
    1978               0 :                               getter_AddRefs(closestAncestor),
    1979               0 :                               getter_AddRefs(farthestAncestor));
    1980                 : 
    1981               0 :     if (NS_FAILED(res)) return res;
    1982                 : 
    1983                 :     // Hook the parent hierarchy/context of the subtree into the clone tree.
    1984                 : 
    1985               0 :     nsCOMPtr<nsIDOMNode> tmpNode;
    1986                 : 
    1987               0 :     if (farthestAncestor)
    1988                 :     {
    1989               0 :       res = commonCloneAncestor->AppendChild(farthestAncestor,
    1990               0 :                                              getter_AddRefs(tmpNode));
    1991                 : 
    1992               0 :       if (NS_FAILED(res)) return res;
    1993                 :     }
    1994                 : 
    1995                 :     // Place the cloned subtree into the cloned doc frag tree!
    1996                 : 
    1997               0 :     if (closestAncestor)
    1998                 :     {
    1999                 :       // Append the subtree under closestAncestor since it is the
    2000                 :       // immediate parent of the subtree.
    2001                 : 
    2002               0 :       res = closestAncestor->AppendChild(clone, getter_AddRefs(tmpNode));
    2003                 :     }
    2004                 :     else
    2005                 :     {
    2006                 :       // If we get here, there is no missing parent hierarchy between 
    2007                 :       // commonAncestor and node, so just append clone to commonCloneAncestor.
    2008                 : 
    2009               0 :       res = commonCloneAncestor->AppendChild(clone, getter_AddRefs(tmpNode));
    2010                 :     }
    2011               0 :     if (NS_FAILED(res)) return res;
    2012                 : 
    2013                 :     // Get the next subtree to be processed. The idea here is to setup
    2014                 :     // the parameters for the next iteration of the loop.
    2015                 : 
    2016               0 :     iter.Next();
    2017                 : 
    2018               0 :     if (iter.IsDone())
    2019                 :       break; // We must be done!
    2020                 : 
    2021               0 :     nsCOMPtr<nsIDOMNode> nextNode(iter.GetCurrentNode());
    2022               0 :     if (!nextNode) return NS_ERROR_FAILURE;
    2023                 : 
    2024                 :     // Get node and nextNode's common parent.
    2025               0 :     nsContentUtils::GetCommonAncestor(node, nextNode, getter_AddRefs(commonAncestor));
    2026                 : 
    2027               0 :     if (!commonAncestor)
    2028               0 :       return NS_ERROR_FAILURE;
    2029                 : 
    2030                 :     // Find the equivalent of commonAncestor in the cloned tree!
    2031                 : 
    2032               0 :     while (node && node != commonAncestor)
    2033                 :     {
    2034               0 :       tmpNode = node;
    2035               0 :       res = tmpNode->GetParentNode(getter_AddRefs(node));
    2036               0 :       if (NS_FAILED(res)) return res;
    2037               0 :       if (!node) return NS_ERROR_FAILURE;
    2038                 : 
    2039               0 :       tmpNode = clone;
    2040               0 :       res = tmpNode->GetParentNode(getter_AddRefs(clone));
    2041               0 :       if (NS_FAILED(res)) return res;
    2042               0 :       if (!clone) return NS_ERROR_FAILURE;
    2043                 :     }
    2044                 : 
    2045               0 :     commonCloneAncestor = clone;
    2046                 :   }
    2047                 : 
    2048               0 :   *aReturn = clonedFrag;
    2049               0 :   NS_IF_ADDREF(*aReturn);
    2050                 : 
    2051               0 :   return NS_OK;
    2052                 : }
    2053                 : 
    2054                 : nsresult
    2055               0 : nsRange::CloneRange(nsRange** aReturn) const
    2056                 : {
    2057               0 :   if(mIsDetached)
    2058               0 :     return NS_ERROR_DOM_INVALID_STATE_ERR;
    2059                 : 
    2060               0 :   if (aReturn == 0)
    2061               0 :     return NS_ERROR_NULL_POINTER;
    2062                 : 
    2063               0 :   nsRefPtr<nsRange> range = new nsRange();
    2064                 : 
    2065               0 :   range->SetMaySpanAnonymousSubtrees(mMaySpanAnonymousSubtrees);
    2066                 : 
    2067               0 :   range->DoSetRange(mStartParent, mStartOffset, mEndParent, mEndOffset, mRoot);
    2068                 : 
    2069               0 :   range.forget(aReturn);
    2070                 : 
    2071               0 :   return NS_OK;
    2072                 : }
    2073                 : 
    2074                 : NS_IMETHODIMP
    2075               0 : nsRange::CloneRange(nsIDOMRange** aReturn)
    2076                 : {
    2077               0 :   nsRefPtr<nsRange> range;
    2078               0 :   nsresult rv = CloneRange(getter_AddRefs(range));
    2079               0 :   range.forget(aReturn);
    2080               0 :   return rv;
    2081                 : }
    2082                 : 
    2083                 : NS_IMETHODIMP
    2084               0 : nsRange::InsertNode(nsIDOMNode* aN)
    2085                 : {
    2086               0 :   VALIDATE_ACCESS(aN);
    2087                 :   
    2088                 :   nsresult res;
    2089                 :   PRInt32 tStartOffset;
    2090               0 :   this->GetStartOffset(&tStartOffset);
    2091                 : 
    2092               0 :   nsCOMPtr<nsIDOMNode> tStartContainer;
    2093               0 :   res = this->GetStartContainer(getter_AddRefs(tStartContainer));
    2094               0 :   if(NS_FAILED(res)) return res;
    2095                 : 
    2096               0 :   nsCOMPtr<nsIDOMText> startTextNode(do_QueryInterface(tStartContainer));
    2097               0 :   if (startTextNode)
    2098                 :   {
    2099               0 :     nsCOMPtr<nsIDOMNode> tSCParentNode;
    2100               0 :     res = tStartContainer->GetParentNode(getter_AddRefs(tSCParentNode));
    2101               0 :     if(NS_FAILED(res)) return res;
    2102               0 :     NS_ENSURE_STATE(tSCParentNode);
    2103                 : 
    2104                 :     PRInt32 tEndOffset;
    2105               0 :     GetEndOffset(&tEndOffset);
    2106                 : 
    2107               0 :     nsCOMPtr<nsIDOMNode> tEndContainer;
    2108               0 :     res = this->GetEndContainer(getter_AddRefs(tEndContainer));
    2109               0 :     if(NS_FAILED(res)) return res;
    2110                 : 
    2111               0 :     nsCOMPtr<nsIDOMText> secondPart;
    2112               0 :     res = startTextNode->SplitText(tStartOffset, getter_AddRefs(secondPart));
    2113               0 :     if (NS_FAILED(res)) return res;
    2114                 : 
    2115               0 :     nsCOMPtr<nsIDOMNode> tResultNode;
    2116               0 :     res = tSCParentNode->InsertBefore(aN, secondPart, getter_AddRefs(tResultNode));
    2117               0 :     if (NS_FAILED(res)) return res;
    2118                 : 
    2119               0 :     if (tEndContainer == tStartContainer && tEndOffset != tStartOffset)
    2120               0 :       res = SetEnd(secondPart, tEndOffset - tStartOffset);
    2121                 : 
    2122               0 :     return res;
    2123                 :   }  
    2124                 : 
    2125               0 :   nsCOMPtr<nsIDOMNodeList>tChildList;
    2126               0 :   res = tStartContainer->GetChildNodes(getter_AddRefs(tChildList));
    2127               0 :   if(NS_FAILED(res)) return res;
    2128                 :   PRUint32 tChildListLength;
    2129               0 :   res = tChildList->GetLength(&tChildListLength);
    2130               0 :   if(NS_FAILED(res)) return res;
    2131                 : 
    2132                 :   // find the insertion point in the DOM and insert the Node
    2133               0 :   nsCOMPtr<nsIDOMNode>tChildNode;
    2134               0 :   res = tChildList->Item(tStartOffset, getter_AddRefs(tChildNode));
    2135               0 :   if(NS_FAILED(res)) return res;
    2136                 :   
    2137               0 :   nsCOMPtr<nsIDOMNode> tResultNode;
    2138               0 :   return tStartContainer->InsertBefore(aN, tChildNode, getter_AddRefs(tResultNode));
    2139                 : }
    2140                 : 
    2141                 : NS_IMETHODIMP
    2142               0 : nsRange::SurroundContents(nsIDOMNode* aNewParent)
    2143                 : {
    2144               0 :   VALIDATE_ACCESS(aNewParent);
    2145                 : 
    2146               0 :   NS_ENSURE_TRUE(mRoot, NS_ERROR_DOM_INVALID_STATE_ERR);
    2147                 :   // INVALID_STATE_ERROR: Raised if the Range partially selects a non-text
    2148                 :   // node.
    2149               0 :   if (mStartParent != mEndParent) {
    2150               0 :     bool startIsText = mStartParent->IsNodeOfType(nsINode::eTEXT);
    2151               0 :     bool endIsText = mEndParent->IsNodeOfType(nsINode::eTEXT);
    2152               0 :     nsINode* startGrandParent = mStartParent->GetNodeParent();
    2153               0 :     nsINode* endGrandParent = mEndParent->GetNodeParent();
    2154               0 :     NS_ENSURE_TRUE((startIsText && endIsText &&
    2155                 :                     startGrandParent &&
    2156                 :                     startGrandParent == endGrandParent) ||
    2157                 :                    (startIsText &&
    2158                 :                     startGrandParent &&
    2159                 :                     startGrandParent == mEndParent) ||
    2160                 :                    (endIsText &&
    2161                 :                     endGrandParent &&
    2162                 :                     endGrandParent == mStartParent),
    2163                 :                    NS_ERROR_DOM_INVALID_STATE_ERR);
    2164                 :   }
    2165                 : 
    2166                 :   // Extract the contents within the range.
    2167                 : 
    2168               0 :   nsCOMPtr<nsIDOMDocumentFragment> docFrag;
    2169                 : 
    2170               0 :   nsresult res = ExtractContents(getter_AddRefs(docFrag));
    2171                 : 
    2172               0 :   if (NS_FAILED(res)) return res;
    2173               0 :   if (!docFrag) return NS_ERROR_FAILURE;
    2174                 : 
    2175                 :   // Spec says we need to remove all of aNewParent's
    2176                 :   // children prior to insertion.
    2177                 : 
    2178               0 :   nsCOMPtr<nsIDOMNodeList> children;
    2179               0 :   res = aNewParent->GetChildNodes(getter_AddRefs(children));
    2180                 : 
    2181               0 :   if (NS_FAILED(res)) return res;
    2182               0 :   if (!children) return NS_ERROR_FAILURE;
    2183                 : 
    2184               0 :   PRUint32 numChildren = 0;
    2185               0 :   res = children->GetLength(&numChildren);
    2186               0 :   if (NS_FAILED(res)) return res;
    2187                 : 
    2188               0 :   nsCOMPtr<nsIDOMNode> tmpNode;
    2189                 : 
    2190               0 :   while (numChildren)
    2191                 :   {
    2192               0 :     nsCOMPtr<nsIDOMNode> child;
    2193               0 :     res = children->Item(--numChildren, getter_AddRefs(child));
    2194                 : 
    2195               0 :     if (NS_FAILED(res)) return res;
    2196               0 :     if (!child) return NS_ERROR_FAILURE;
    2197                 : 
    2198               0 :     res = aNewParent->RemoveChild(child, getter_AddRefs(tmpNode));
    2199               0 :     if (NS_FAILED(res)) return res;
    2200                 :   }
    2201                 : 
    2202                 :   // Insert aNewParent at the range's start point.
    2203                 : 
    2204               0 :   res = InsertNode(aNewParent);
    2205               0 :   if (NS_FAILED(res)) return res;
    2206                 : 
    2207                 :   // Append the content we extracted under aNewParent.
    2208                 : 
    2209               0 :   res = aNewParent->AppendChild(docFrag, getter_AddRefs(tmpNode));
    2210               0 :   if (NS_FAILED(res)) return res;
    2211                 : 
    2212                 :   // Select aNewParent, and its contents.
    2213                 : 
    2214               0 :   return SelectNode(aNewParent);
    2215                 : }
    2216                 : 
    2217                 : NS_IMETHODIMP
    2218               0 : nsRange::ToString(nsAString& aReturn)
    2219                 : { 
    2220               0 :   if(mIsDetached)
    2221               0 :     return NS_ERROR_DOM_INVALID_STATE_ERR;
    2222                 : 
    2223                 :   // clear the string
    2224               0 :   aReturn.Truncate();
    2225                 :   
    2226                 :   // If we're unpositioned, return the empty string
    2227               0 :   if (!mIsPositioned) {
    2228               0 :     return NS_OK;
    2229                 :   }
    2230                 : 
    2231                 : #ifdef DEBUG_range
    2232                 :       printf("Range dump: -----------------------\n");
    2233                 : #endif /* DEBUG */
    2234                 :     
    2235                 :   // effeciency hack for simple case
    2236               0 :   if (mStartParent == mEndParent)
    2237                 :   {
    2238               0 :     nsCOMPtr<nsIDOMText> textNode( do_QueryInterface(mStartParent) );
    2239                 :     
    2240               0 :     if (textNode)
    2241                 :     {
    2242                 : #ifdef DEBUG_range
    2243                 :       // If debug, dump it:
    2244                 :       nsCOMPtr<nsIContent> cN (do_QueryInterface(mStartParent));
    2245                 :       if (cN) cN->List(stdout);
    2246                 :       printf("End Range dump: -----------------------\n");
    2247                 : #endif /* DEBUG */
    2248                 : 
    2249                 :       // grab the text
    2250               0 :       if (NS_FAILED(textNode->SubstringData(mStartOffset,mEndOffset-mStartOffset,aReturn)))
    2251               0 :         return NS_ERROR_UNEXPECTED;
    2252               0 :       return NS_OK;
    2253                 :     }
    2254                 :   } 
    2255                 :   
    2256                 :   /* complex case: mStartParent != mEndParent, or mStartParent not a text node
    2257                 :      revisit - there are potential optimizations here and also tradeoffs.
    2258                 :   */
    2259                 : 
    2260               0 :   nsCOMPtr<nsIContentIterator> iter;
    2261               0 :   nsresult rv = NS_NewContentIterator(getter_AddRefs(iter));
    2262               0 :   NS_ENSURE_SUCCESS(rv, rv);
    2263               0 :   rv = iter->Init(this);
    2264               0 :   NS_ENSURE_SUCCESS(rv, rv);
    2265                 :   
    2266               0 :   nsString tempString;
    2267                 :  
    2268                 :   // loop through the content iterator, which returns nodes in the range in 
    2269                 :   // close tag order, and grab the text from any text node
    2270               0 :   while (!iter->IsDone())
    2271                 :   {
    2272               0 :     nsINode *n = iter->GetCurrentNode();
    2273                 : 
    2274                 : #ifdef DEBUG_range
    2275                 :     // If debug, dump it:
    2276                 :     n->List(stdout);
    2277                 : #endif /* DEBUG */
    2278               0 :     nsCOMPtr<nsIDOMText> textNode(do_QueryInterface(n));
    2279               0 :     if (textNode) // if it's a text node, get the text
    2280                 :     {
    2281               0 :       if (n == mStartParent) // only include text past start offset
    2282                 :       {
    2283                 :         PRUint32 strLength;
    2284               0 :         textNode->GetLength(&strLength);
    2285               0 :         textNode->SubstringData(mStartOffset,strLength-mStartOffset,tempString);
    2286               0 :         aReturn += tempString;
    2287                 :       }
    2288               0 :       else if (n == mEndParent)  // only include text before end offset
    2289                 :       {
    2290               0 :         textNode->SubstringData(0,mEndOffset,tempString);
    2291               0 :         aReturn += tempString;
    2292                 :       }
    2293                 :       else  // grab the whole kit-n-kaboodle
    2294                 :       {
    2295               0 :         textNode->GetData(tempString);
    2296               0 :         aReturn += tempString;
    2297                 :       }
    2298                 :     }
    2299                 : 
    2300               0 :     iter->Next();
    2301                 :   }
    2302                 : 
    2303                 : #ifdef DEBUG_range
    2304                 :   printf("End Range dump: -----------------------\n");
    2305                 : #endif /* DEBUG */
    2306               0 :   return NS_OK;
    2307                 : }
    2308                 : 
    2309                 : 
    2310                 : 
    2311                 : NS_IMETHODIMP
    2312               9 : nsRange::Detach()
    2313                 : {
    2314               9 :   if(mIsDetached)
    2315               0 :     return NS_ERROR_DOM_INVALID_STATE_ERR;
    2316                 : 
    2317               9 :   if (IsInSelection()) {
    2318               0 :     ::InvalidateAllFrames(GetRegisteredCommonAncestor());
    2319                 :   }
    2320                 : 
    2321               9 :   mIsDetached = true;
    2322                 : 
    2323               9 :   DoSetRange(nsnull, 0, nsnull, 0, nsnull);
    2324                 :   
    2325               9 :   return NS_OK;
    2326                 : }
    2327                 : 
    2328                 : NS_IMETHODIMP    
    2329               0 : nsRange::CreateContextualFragment(const nsAString& aFragment,
    2330                 :                                   nsIDOMDocumentFragment** aReturn)
    2331                 : {
    2332               0 :   if (mIsPositioned) {
    2333                 :     return nsContentUtils::CreateContextualFragment(mStartParent, aFragment,
    2334               0 :                                                     false, aReturn);
    2335                 :   }
    2336               0 :   return NS_ERROR_FAILURE;
    2337                 : }
    2338                 : 
    2339               0 : static void ExtractRectFromOffset(nsIFrame* aFrame,
    2340                 :                                   const nsIFrame* aRelativeTo, 
    2341                 :                                   const PRInt32 aOffset, nsRect* aR, bool aKeepLeft)
    2342                 : {
    2343               0 :   nsPoint point;
    2344               0 :   aFrame->GetPointFromOffset(aOffset, &point);
    2345                 : 
    2346               0 :   point += aFrame->GetOffsetTo(aRelativeTo);
    2347                 : 
    2348                 :   //given a point.x, extract left or right portion of rect aR
    2349                 :   //point.x has to be within this rect
    2350               0 :   NS_ASSERTION(aR->x <= point.x && point.x <= aR->XMost(),
    2351                 :                    "point.x should not be outside of rect r");
    2352                 : 
    2353               0 :   if (aKeepLeft) {
    2354               0 :     aR->width = point.x - aR->x;
    2355                 :   } else {
    2356               0 :     aR->width = aR->XMost() - point.x;
    2357               0 :     aR->x = point.x;
    2358                 :   }
    2359               0 : }
    2360                 : 
    2361               0 : static nsresult GetPartialTextRect(nsLayoutUtils::RectCallback* aCallback,
    2362                 :                                    nsIContent* aContent, PRInt32 aStartOffset, PRInt32 aEndOffset)
    2363                 : {
    2364               0 :   nsIFrame* frame = aContent->GetPrimaryFrame();
    2365               0 :   if (frame && frame->GetType() == nsGkAtoms::textFrame) {
    2366               0 :     nsTextFrame* textFrame = static_cast<nsTextFrame*>(frame);
    2367               0 :     nsIFrame* relativeTo = nsLayoutUtils::GetContainingBlockForClientRect(textFrame);
    2368               0 :     for (nsTextFrame* f = textFrame; f; f = static_cast<nsTextFrame*>(f->GetNextContinuation())) {
    2369               0 :       PRInt32 fstart = f->GetContentOffset(), fend = f->GetContentEnd();
    2370               0 :       if (fend <= aStartOffset || fstart >= aEndOffset)
    2371               0 :         continue;
    2372                 : 
    2373                 :       // overlapping with the offset we want
    2374               0 :       f->EnsureTextRun(nsTextFrame::eInflated);
    2375               0 :       NS_ENSURE_TRUE(f->GetTextRun(nsTextFrame::eInflated), NS_ERROR_OUT_OF_MEMORY);
    2376               0 :       bool rtl = f->GetTextRun(nsTextFrame::eInflated)->IsRightToLeft();
    2377               0 :       nsRect r(f->GetOffsetTo(relativeTo), f->GetSize());
    2378               0 :       if (fstart < aStartOffset) {
    2379                 :         // aStartOffset is within this frame
    2380               0 :         ExtractRectFromOffset(f, relativeTo, aStartOffset, &r, rtl);
    2381                 :       }
    2382               0 :       if (fend > aEndOffset) {
    2383                 :         // aEndOffset is in the middle of this frame
    2384               0 :         ExtractRectFromOffset(f, relativeTo, aEndOffset, &r, !rtl);
    2385                 :       }
    2386               0 :       aCallback->AddRect(r);
    2387                 :     }
    2388                 :   }
    2389               0 :   return NS_OK;
    2390                 : }
    2391                 : 
    2392               0 : static void CollectClientRects(nsLayoutUtils::RectCallback* aCollector, 
    2393                 :                                nsRange* aRange,
    2394                 :                                nsINode* aStartParent, PRInt32 aStartOffset,
    2395                 :                                nsINode* aEndParent, PRInt32 aEndOffset)
    2396                 : {
    2397                 :   // Hold strong pointers across the flush
    2398               0 :   nsCOMPtr<nsIDOMNode> startContainer = do_QueryInterface(aStartParent);
    2399               0 :   nsCOMPtr<nsIDOMNode> endContainer = do_QueryInterface(aEndParent);
    2400                 : 
    2401                 :   // Flush out layout so our frames are up to date.
    2402               0 :   if (!aStartParent->IsInDoc()) {
    2403                 :     return;
    2404                 :   }
    2405                 : 
    2406               0 :   aStartParent->GetCurrentDoc()->FlushPendingNotifications(Flush_Layout);
    2407                 : 
    2408                 :   // Recheck whether we're still in the document
    2409               0 :   if (!aStartParent->IsInDoc()) {
    2410                 :     return;
    2411                 :   }
    2412                 : 
    2413               0 :   RangeSubtreeIterator iter;
    2414                 : 
    2415               0 :   nsresult rv = iter.Init(aRange);
    2416               0 :   if (NS_FAILED(rv)) return;
    2417                 : 
    2418               0 :   if (iter.IsDone()) {
    2419                 :     // the range is collapsed, only continue if the cursor is in a text node
    2420               0 :     nsCOMPtr<nsIContent> content = do_QueryInterface(aStartParent);
    2421               0 :     if (content && content->IsNodeOfType(nsINode::eTEXT)) {
    2422               0 :       nsIFrame* frame = content->GetPrimaryFrame();
    2423               0 :       if (frame && frame->GetType() == nsGkAtoms::textFrame) {
    2424               0 :         nsTextFrame* textFrame = static_cast<nsTextFrame*>(frame);
    2425                 :         PRInt32 outOffset;
    2426                 :         nsIFrame* outFrame;
    2427                 :         textFrame->GetChildFrameContainingOffset(aStartOffset, false, 
    2428               0 :           &outOffset, &outFrame);
    2429               0 :         if (outFrame) {
    2430                 :            nsIFrame* relativeTo = 
    2431               0 :              nsLayoutUtils::GetContainingBlockForClientRect(outFrame);
    2432               0 :            nsRect r(outFrame->GetOffsetTo(relativeTo), outFrame->GetSize());
    2433               0 :            ExtractRectFromOffset(outFrame, relativeTo, aStartOffset, &r, false);
    2434               0 :            r.width = 0;
    2435               0 :            aCollector->AddRect(r);
    2436                 :         }
    2437                 :       }
    2438                 :     }
    2439                 :     return;
    2440                 :   }
    2441                 : 
    2442               0 :   do {
    2443               0 :     nsCOMPtr<nsIDOMNode> node(iter.GetCurrentNode());
    2444               0 :     iter.Next();
    2445               0 :     nsCOMPtr<nsIContent> content = do_QueryInterface(node);
    2446               0 :     if (!content)
    2447               0 :       continue;
    2448               0 :     if (content->IsNodeOfType(nsINode::eTEXT)) {
    2449               0 :        if (node == startContainer) {
    2450               0 :          PRInt32 offset = startContainer == endContainer ? 
    2451               0 :            aEndOffset : content->GetText()->GetLength();
    2452               0 :          GetPartialTextRect(aCollector, content, aStartOffset, offset);
    2453               0 :          continue;
    2454               0 :        } else if (node == endContainer) {
    2455               0 :          GetPartialTextRect(aCollector, content, 0, aEndOffset);
    2456               0 :          continue;
    2457                 :        }
    2458                 :     }
    2459                 : 
    2460               0 :     nsIFrame* frame = content->GetPrimaryFrame();
    2461               0 :     if (frame) {
    2462                 :       nsLayoutUtils::GetAllInFlowRects(frame,
    2463               0 :         nsLayoutUtils::GetContainingBlockForClientRect(frame), aCollector);
    2464                 :     }
    2465               0 :   } while (!iter.IsDone());
    2466                 : }
    2467                 : 
    2468                 : NS_IMETHODIMP
    2469               0 : nsRange::GetBoundingClientRect(nsIDOMClientRect** aResult)
    2470                 : {
    2471               0 :   *aResult = nsnull;
    2472                 : 
    2473                 :   // Weak ref, since we addref it below
    2474               0 :   nsClientRect* rect = new nsClientRect();
    2475               0 :   if (!rect)
    2476               0 :     return NS_ERROR_OUT_OF_MEMORY;
    2477                 : 
    2478               0 :   NS_ADDREF(*aResult = rect);
    2479                 : 
    2480               0 :   if (!mStartParent)
    2481               0 :     return NS_OK;
    2482                 : 
    2483               0 :   nsLayoutUtils::RectAccumulator accumulator;
    2484                 :   
    2485                 :   CollectClientRects(&accumulator, this, mStartParent, mStartOffset, 
    2486               0 :     mEndParent, mEndOffset);
    2487                 : 
    2488               0 :   nsRect r = accumulator.mResultRect.IsEmpty() ? accumulator.mFirstRect : 
    2489               0 :     accumulator.mResultRect;
    2490               0 :   rect->SetLayoutRect(r);
    2491               0 :   return NS_OK;
    2492                 : }
    2493                 : 
    2494                 : NS_IMETHODIMP
    2495               0 : nsRange::GetClientRects(nsIDOMClientRectList** aResult)
    2496                 : {
    2497               0 :   *aResult = nsnull;
    2498                 : 
    2499               0 :   if (!mStartParent)
    2500               0 :     return NS_OK;
    2501                 : 
    2502                 :   nsRefPtr<nsClientRectList> rectList =
    2503               0 :     new nsClientRectList(static_cast<nsIDOMRange*>(this));
    2504               0 :   if (!rectList)
    2505               0 :     return NS_ERROR_OUT_OF_MEMORY;
    2506                 : 
    2507               0 :   nsLayoutUtils::RectListBuilder builder(rectList);
    2508                 : 
    2509                 :   CollectClientRects(&builder, this, mStartParent, mStartOffset, 
    2510               0 :     mEndParent, mEndOffset);
    2511                 : 
    2512               0 :   if (NS_FAILED(builder.mRV))
    2513               0 :     return builder.mRV;
    2514               0 :   rectList.forget(aResult);
    2515               0 :   return NS_OK;
    2516                 : }
    2517                 : 
    2518                 : NS_IMETHODIMP
    2519               0 : nsRange::GetUsedFontFaces(nsIDOMFontFaceList** aResult)
    2520                 : {
    2521               0 :   *aResult = nsnull;
    2522                 : 
    2523               0 :   NS_ENSURE_TRUE(mStartParent, NS_ERROR_UNEXPECTED);
    2524                 : 
    2525               0 :   nsCOMPtr<nsIDOMNode> startContainer = do_QueryInterface(mStartParent);
    2526               0 :   nsCOMPtr<nsIDOMNode> endContainer = do_QueryInterface(mEndParent);
    2527                 : 
    2528                 :   // Flush out layout so our frames are up to date.
    2529               0 :   nsIDocument* doc = mStartParent->OwnerDoc();
    2530               0 :   NS_ENSURE_TRUE(doc, NS_ERROR_UNEXPECTED);
    2531               0 :   doc->FlushPendingNotifications(Flush_Frames);
    2532                 : 
    2533                 :   // Recheck whether we're still in the document
    2534               0 :   NS_ENSURE_TRUE(mStartParent->IsInDoc(), NS_ERROR_UNEXPECTED);
    2535                 : 
    2536               0 :   nsRefPtr<nsFontFaceList> fontFaceList = new nsFontFaceList();
    2537                 : 
    2538               0 :   RangeSubtreeIterator iter;
    2539               0 :   nsresult rv = iter.Init(this);
    2540               0 :   NS_ENSURE_SUCCESS(rv, rv);
    2541                 : 
    2542               0 :   while (!iter.IsDone()) {
    2543                 :     // only collect anything if the range is not collapsed
    2544               0 :     nsCOMPtr<nsIDOMNode> node(iter.GetCurrentNode());
    2545               0 :     iter.Next();
    2546                 : 
    2547               0 :     nsCOMPtr<nsIContent> content = do_QueryInterface(node);
    2548               0 :     if (!content) {
    2549               0 :       continue;
    2550                 :     }
    2551               0 :     nsIFrame* frame = content->GetPrimaryFrame();
    2552               0 :     if (!frame) {
    2553               0 :       continue;
    2554                 :     }
    2555                 : 
    2556               0 :     if (content->IsNodeOfType(nsINode::eTEXT)) {
    2557               0 :        if (node == startContainer) {
    2558               0 :          PRInt32 offset = startContainer == endContainer ? 
    2559               0 :            mEndOffset : content->GetText()->GetLength();
    2560                 :          nsLayoutUtils::GetFontFacesForText(frame, mStartOffset, offset,
    2561               0 :                                             true, fontFaceList);
    2562               0 :          continue;
    2563                 :        }
    2564               0 :        if (node == endContainer) {
    2565                 :          nsLayoutUtils::GetFontFacesForText(frame, 0, mEndOffset,
    2566               0 :                                             true, fontFaceList);
    2567               0 :          continue;
    2568                 :        }
    2569                 :     }
    2570                 : 
    2571               0 :     nsLayoutUtils::GetFontFacesForFrames(frame, fontFaceList);
    2572                 :   }
    2573                 : 
    2574               0 :   fontFaceList.forget(aResult);
    2575               0 :   return NS_OK;
    2576                 : }
    2577                 : 
    2578                 : nsINode*
    2579               0 : nsRange::GetRegisteredCommonAncestor()
    2580                 : {
    2581               0 :   NS_ASSERTION(IsInSelection(),
    2582                 :                "GetRegisteredCommonAncestor only valid for range in selection");
    2583               0 :   nsINode* ancestor = GetNextRangeCommonAncestor(mStartParent);
    2584               0 :   while (ancestor) {
    2585                 :     RangeHashTable* ranges =
    2586               0 :       static_cast<RangeHashTable*>(ancestor->GetProperty(nsGkAtoms::range));
    2587               0 :     if (ranges->GetEntry(this)) {
    2588               0 :       break;
    2589                 :     }
    2590               0 :     ancestor = GetNextRangeCommonAncestor(ancestor->GetNodeParent());
    2591                 :   }
    2592               0 :   NS_ASSERTION(ancestor, "can't find common ancestor for selected range");
    2593               0 :   return ancestor;
    2594                 : }
    2595                 : 
    2596                 : /* static */ bool nsRange::AutoInvalidateSelection::mIsNested;
    2597                 : 
    2598             142 : nsRange::AutoInvalidateSelection::~AutoInvalidateSelection()
    2599                 : {
    2600              71 :   NS_ASSERTION(mWasInSelection == mRange->IsInSelection(),
    2601                 :                "Range got unselected in AutoInvalidateSelection block");
    2602              71 :   if (!mCommonAncestor) {
    2603                 :     return;
    2604                 :   }
    2605               0 :   mIsNested = false;
    2606               0 :   ::InvalidateAllFrames(mCommonAncestor);
    2607               0 :   nsINode* commonAncestor = mRange->GetRegisteredCommonAncestor();
    2608               0 :   if (commonAncestor != mCommonAncestor) {
    2609               0 :     ::InvalidateAllFrames(commonAncestor);
    2610                 :   }
    2611            4463 : }

Generated by: LCOV version 1.7