Bug 771994 - Make nsRangeStore refcounted; r=ehsan,a=lsblakk
authorAryeh Gregor <ayg@aryeh.name>
Fri, 13 Jul 2012 09:31:15 +0300
changeset 81958 b082369c036a8b1474a2de48420c72376c0c0894
parent 81957 4d94b20d0322196da62c6dfd5f464fa1b3726936
child 81959 b696066d7c63e39773b65adb386521b9f12ef764
push id247
push userayg@aryeh.name
push dateFri, 17 Aug 2012 11:39:38 +0000
reviewersehsan, lsblakk
bugs771994
milestone10.0.7esrpre
Bug 771994 - Make nsRangeStore refcounted; r=ehsan,a=lsblakk
editor/libeditor/base/nsSelectionState.cpp
editor/libeditor/base/nsSelectionState.h
editor/libeditor/html/nsHTMLEditRules.cpp
editor/libeditor/html/nsHTMLEditRules.h
--- a/editor/libeditor/base/nsSelectionState.cpp
+++ b/editor/libeditor/base/nsSelectionState.cpp
@@ -56,23 +56,23 @@ nsSelectionState::~nsSelectionState()
   MakeEmpty();
 }
 
 void
 nsSelectionState::DoTraverse(nsCycleCollectionTraversalCallback &cb)
 {
   for (PRUint32 i = 0, iEnd = mArray.Length(); i < iEnd; ++i)
   {
-    nsRangeStore &item = mArray[i];
+    nsRangeStore* item = mArray[i];
     NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb,
                                        "selection state mArray[i].startNode");
-    cb.NoteXPCOMChild(item.startNode);
+    cb.NoteXPCOMChild(item->startNode);
     NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb,
                                        "selection state mArray[i].endNode");
-    cb.NoteXPCOMChild(item.endNode);
+    cb.NoteXPCOMChild(item->endNode);
   }
 }
 
 nsresult  
 nsSelectionState::SaveSelection(nsISelection *aSel)
 {
   NS_ENSURE_TRUE(aSel, NS_ERROR_NULL_POINTER);
   PRInt32 i,rangeCount, arrayCount = mArray.Length();
@@ -80,16 +80,17 @@ nsSelectionState::SaveSelection(nsISelec
   
   // if we need more items in the array, new them
   if (arrayCount<rangeCount)
   {
     PRInt32 count = rangeCount-arrayCount;
     for (i=0; i<count; i++)
     {
       mArray.AppendElement();
+      mArray[i] = new nsRangeStore();
     }
   }
   
   // else if we have too many, delete them
   else if (arrayCount>rangeCount)
   {
     for (i = arrayCount-1; i >= rangeCount; i--)
     {
@@ -98,17 +99,17 @@ nsSelectionState::SaveSelection(nsISelec
   }
   
   // now store the selection ranges
   nsresult res = NS_OK;
   for (i=0; i<rangeCount; i++)
   {
     nsCOMPtr<nsIDOMRange> range;
     res = aSel->GetRangeAt(i, getter_AddRefs(range));
-    mArray[i].StoreRange(range);
+    mArray[i]->StoreRange(range);
   }
   
   return res;
 }
 
 nsresult  
 nsSelectionState::RestoreSelection(nsISelection *aSel)
 {
@@ -118,32 +119,32 @@ nsSelectionState::RestoreSelection(nsISe
 
   // clear out selection
   aSel->RemoveAllRanges();
   
   // set the selection ranges anew
   for (i=0; i<arrayCount; i++)
   {
     nsCOMPtr<nsIDOMRange> range;
-    mArray[i].GetRange(address_of(range));
+    mArray[i]->GetRange(address_of(range));
     NS_ENSURE_TRUE(range, NS_ERROR_UNEXPECTED);
    
     res = aSel->AddRange(range);
     if(NS_FAILED(res)) return res;
 
   }
   return NS_OK;
 }
 
 bool
 nsSelectionState::IsCollapsed()
 {
   if (1 != mArray.Length()) return false;
   nsCOMPtr<nsIDOMRange> range;
-  mArray[0].GetRange(address_of(range));
+  mArray[0]->GetRange(address_of(range));
   NS_ENSURE_TRUE(range, false);
   bool bIsCollapsed = false;
   range->GetCollapsed(&bIsCollapsed);
   return bIsCollapsed;
 }
 
 bool
 nsSelectionState::IsEqual(nsSelectionState *aSelState)
@@ -151,18 +152,18 @@ nsSelectionState::IsEqual(nsSelectionSta
   NS_ENSURE_TRUE(aSelState, false);
   PRUint32 i, myCount = mArray.Length(), itsCount = aSelState->mArray.Length();
   if (myCount != itsCount) return false;
   if (myCount < 1) return false;
 
   for (i=0; i<myCount; i++)
   {
     nsCOMPtr<nsIDOMRange> myRange, itsRange;
-    mArray[i].GetRange(address_of(myRange));
-    aSelState->mArray[i].GetRange(address_of(itsRange));
+    mArray[i]->GetRange(address_of(myRange));
+    aSelState->mArray[i]->GetRange(address_of(itsRange));
     NS_ENSURE_TRUE(myRange && itsRange, false);
   
     PRInt16 compResult;
     nsresult rv;
     rv = myRange->CompareBoundaryPoints(nsIDOMRange::START_TO_START, itsRange, &compResult);
     if (NS_FAILED(rv) || compResult) return false;
     rv = myRange->CompareBoundaryPoints(nsIDOMRange::END_TO_END, itsRange, &compResult);
     if (NS_FAILED(rv) || compResult) return false;
@@ -217,31 +218,31 @@ nsRangeUpdater::DropRangeItem(nsRangeSto
 nsresult 
 nsRangeUpdater::RegisterSelectionState(nsSelectionState &aSelState)
 {
   PRUint32 i, theCount = aSelState.mArray.Length();
   if (theCount < 1) return NS_ERROR_FAILURE;
 
   for (i=0; i<theCount; i++)
   {
-    RegisterRangeItem(&aSelState.mArray[i]);
+    RegisterRangeItem(aSelState.mArray[i]);
   }
 
   return NS_OK;
 }
 
 nsresult 
 nsRangeUpdater::DropSelectionState(nsSelectionState &aSelState)
 {
   PRUint32 i, theCount = aSelState.mArray.Length();
   if (theCount < 1) return NS_ERROR_FAILURE;
 
   for (i=0; i<theCount; i++)
   {
-    DropRangeItem(&aSelState.mArray[i]);
+    DropRangeItem(aSelState.mArray[i]);
   }
 
   return NS_OK;
 }
 
 // gravity methods:
 
 nsresult
--- a/editor/libeditor/base/nsSelectionState.h
+++ b/editor/libeditor/base/nsSelectionState.h
@@ -38,16 +38,17 @@
 #ifndef __selectionstate_h__
 #define __selectionstate_h__
 
 #include "nsCOMPtr.h"
 #include "nsTArray.h"
 #include "nsIDOMNode.h"
 #include "nsIDOMRange.h"
 #include "nsCycleCollectionParticipant.h"
+#include "nsAutoPtr.h" // for nsRefPtr
 
 class nsIDOMCharacterData;
 class nsISelection;
 
 /***************************************************************************
  * class for recording selection info.  stores selection as collection of
  * { {startnode, startoffset} , {endnode, endoffset} } tuples.  Can't store
  * ranges since dom gravity will possibly change the ranges.
@@ -55,16 +56,18 @@ class nsISelection;
 
 // first a helper struct for saving/setting ranges
 struct nsRangeStore 
 {
   nsRangeStore();
   ~nsRangeStore();
   nsresult StoreRange(nsIDOMRange *aRange);
   nsresult GetRange(nsCOMPtr<nsIDOMRange> *outRange);
+
+  NS_INLINE_DECL_REFCOUNTING(nsRangeStore)
         
   nsCOMPtr<nsIDOMNode> startNode;
   PRInt32              startOffset;
   nsCOMPtr<nsIDOMNode> endNode;
   PRInt32              endOffset;
   // DEBUG:   static PRInt32 n;
 };
 
@@ -80,17 +83,17 @@ class nsSelectionState
   
     nsresult SaveSelection(nsISelection *aSel);
     nsresult RestoreSelection(nsISelection *aSel);
     bool     IsCollapsed();
     bool     IsEqual(nsSelectionState *aSelState);
     void     MakeEmpty();
     bool     IsEmpty();
   protected:    
-    nsTArray<nsRangeStore> mArray;
+    nsTArray<nsRefPtr<nsRangeStore> > mArray;
     
     friend class nsRangeUpdater;
 };
 
 class nsRangeUpdater
 {
   public:    
   
@@ -124,51 +127,52 @@ class nsRangeUpdater
     nsresult DidReplaceContainer(nsIDOMNode *aOriginalNode, nsIDOMNode *aNewNode);
     nsresult WillRemoveContainer();
     nsresult DidRemoveContainer(nsIDOMNode *aNode, nsIDOMNode *aParent, PRInt32 aOffset, PRUint32 aNodeOrigLen);
     nsresult WillInsertContainer();
     nsresult DidInsertContainer();
     nsresult WillMoveNode();
     nsresult DidMoveNode(nsIDOMNode *aOldParent, PRInt32 aOldOffset, nsIDOMNode *aNewParent, PRInt32 aNewOffset);
   protected:    
-    nsTArray<nsRangeStore*> mArray;
+    nsTArray<nsRefPtr<nsRangeStore> > mArray;
     bool mLock;
 };
 
 
 /***************************************************************************
  * helper class for using nsSelectionState.  stack based class for doing
  * preservation of dom points across editor actions
  */
 
 class NS_STACK_CLASS nsAutoTrackDOMPoint
 {
   private:
     nsRangeUpdater &mRU;
     nsCOMPtr<nsIDOMNode> *mNode;
     PRInt32 *mOffset;
-    nsRangeStore mRangeItem;
+    nsRefPtr<nsRangeStore> mRangeItem;
   public:
     nsAutoTrackDOMPoint(nsRangeUpdater &aRangeUpdater, nsCOMPtr<nsIDOMNode> *aNode, PRInt32 *aOffset) :
     mRU(aRangeUpdater)
     ,mNode(aNode)
     ,mOffset(aOffset)
     {
-      mRangeItem.startNode = *mNode;
-      mRangeItem.endNode = *mNode;
-      mRangeItem.startOffset = *mOffset;
-      mRangeItem.endOffset = *mOffset;
-      mRU.RegisterRangeItem(&mRangeItem);
+      mRangeItem = new nsRangeStore();
+      mRangeItem->startNode = *mNode;
+      mRangeItem->endNode = *mNode;
+      mRangeItem->startOffset = *mOffset;
+      mRangeItem->endOffset = *mOffset;
+      mRU.RegisterRangeItem(mRangeItem);
     }
     
     ~nsAutoTrackDOMPoint()
     {
-      mRU.DropRangeItem(&mRangeItem);
-      *mNode  = mRangeItem.startNode;
-      *mOffset = mRangeItem.startOffset;
+      mRU.DropRangeItem(mRangeItem);
+      *mNode  = mRangeItem->startNode;
+      *mOffset = mRangeItem->startOffset;
     }
 };
 
 
 
 /***************************************************************************
  * another helper class for nsSelectionState.  stack based class for doing
  * Will/DidReplaceContainer()
--- a/editor/libeditor/html/nsHTMLEditRules.cpp
+++ b/editor/libeditor/html/nsHTMLEditRules.cpp
@@ -200,16 +200,17 @@ mDocChangeRange(nsnull)
   mCachedStyles[11] = StyleCache(nsEditProperty::samp, EmptyString(), EmptyString());
   mCachedStyles[12] = StyleCache(nsEditProperty::var, EmptyString(), EmptyString());
   mCachedStyles[13] = StyleCache(nsEditProperty::cite, EmptyString(), EmptyString());
   mCachedStyles[14] = StyleCache(nsEditProperty::abbr, EmptyString(), EmptyString());
   mCachedStyles[15] = StyleCache(nsEditProperty::acronym, EmptyString(), EmptyString());
   mCachedStyles[16] = StyleCache(nsEditProperty::cssBackgroundColor, EmptyString(), EmptyString());
   mCachedStyles[17] = StyleCache(nsEditProperty::sub, EmptyString(), EmptyString());
   mCachedStyles[18] = StyleCache(nsEditProperty::sup, EmptyString(), EmptyString());
+  mRangeItem = new nsRangeStore();
 }
 
 nsHTMLEditRules::~nsHTMLEditRules()
 {
   // remove ourselves as a listener to edit actions
   // In some cases, we have already been removed by 
   // ~nsHTMLEditor, in which case we will get a null pointer here
   // which we ignore.  But this allows us to add the ability to
@@ -304,27 +305,27 @@ nsHTMLEditRules::BeforeEdit(PRInt32 acti
     nsresult res = mHTMLEditor->GetSelection(getter_AddRefs(selection));
     NS_ENSURE_SUCCESS(res, res);
   
     // get the selection start location
     nsCOMPtr<nsIDOMNode> selStartNode, selEndNode;
     PRInt32 selOffset;
     res = mHTMLEditor->GetStartNodeAndOffset(selection, getter_AddRefs(selStartNode), &selOffset);
     NS_ENSURE_SUCCESS(res, res);
-    mRangeItem.startNode = selStartNode;
-    mRangeItem.startOffset = selOffset;
+    mRangeItem->startNode = selStartNode;
+    mRangeItem->startOffset = selOffset;
 
     // get the selection end location
     res = mHTMLEditor->GetEndNodeAndOffset(selection, getter_AddRefs(selEndNode), &selOffset);
     NS_ENSURE_SUCCESS(res, res);
-    mRangeItem.endNode = selEndNode;
-    mRangeItem.endOffset = selOffset;
+    mRangeItem->endNode = selEndNode;
+    mRangeItem->endOffset = selOffset;
 
     // register this range with range updater to track this as we perturb the doc
-    (mHTMLEditor->mRangeUpdater).RegisterRangeItem(&mRangeItem);
+    (mHTMLEditor->mRangeUpdater).RegisterRangeItem(mRangeItem);
 
     // clear deletion state bool
     mDidDeleteSelection = false;
     
     // clear out mDocChangeRange and mUtilRange
     if(mDocChangeRange)
     {
       // clear out our accounting of what changed
@@ -381,17 +382,17 @@ nsHTMLEditRules::AfterEdit(PRInt32 actio
   NS_PRECONDITION(mActionNesting>0, "bad action nesting!");
   nsresult res = NS_OK;
   if (!--mActionNesting)
   {
     // do all the tricky stuff
     res = AfterEditInner(action, aDirection);
 
     // free up selectionState range item
-    (mHTMLEditor->mRangeUpdater).DropRangeItem(&mRangeItem);
+    (mHTMLEditor->mRangeUpdater).DropRangeItem(mRangeItem);
 
     // Reset the contenteditable count to its previous value
     if (mRestoreContentEditableCount) {
       nsCOMPtr<nsIDOMDocument> doc;
       res = mHTMLEditor->GetDocument(getter_AddRefs(doc));
       NS_ENSURE_SUCCESS(res, res);
       nsCOMPtr<nsIHTMLDocument> htmlDoc = do_QueryInterface(doc);
       NS_ENSURE_TRUE(htmlDoc, NS_ERROR_FAILURE);
@@ -473,21 +474,23 @@ nsHTMLEditRules::AfterEditInner(PRInt32 
         (action == nsEditor::kOpInsertBreak) || 
         (action == nsHTMLEditor::kOpHTMLPaste ||
         (action == nsHTMLEditor::kOpLoadHTML)))
     {
       res = AdjustWhitespace(selection);
       NS_ENSURE_SUCCESS(res, res);
       
       // also do this for original selection endpoints. 
-      nsWSRunObject(mHTMLEditor, mRangeItem.startNode, mRangeItem.startOffset).AdjustWhitespace();
+      nsWSRunObject(mHTMLEditor, mRangeItem->startNode,
+                    mRangeItem->startOffset).AdjustWhitespace();
       // we only need to handle old selection endpoint if it was different from start
-      if ((mRangeItem.startNode != mRangeItem.endNode) || (mRangeItem.startOffset != mRangeItem.endOffset))
-      {
-        nsWSRunObject(mHTMLEditor, mRangeItem.endNode, mRangeItem.endOffset).AdjustWhitespace();
+      if (mRangeItem->startNode != mRangeItem->endNode ||
+          mRangeItem->startOffset != mRangeItem->endOffset) {
+        nsWSRunObject(mHTMLEditor, mRangeItem->endNode,
+                      mRangeItem->endOffset).AdjustWhitespace();
       }
     }
     
     // if we created a new block, make sure selection lands in it
     if (mNewBlock)
     {
       res = PinSelectionToNewBlock(selection);
       mNewBlock = 0;
@@ -515,17 +518,18 @@ nsHTMLEditRules::AfterEditInner(PRInt32 
       res = ReapplyCachedStyles();
       NS_ENSURE_SUCCESS(res, res);
       res = ClearCachedStyles();
       NS_ENSURE_SUCCESS(res, res);
     }    
   }
 
   res = mHTMLEditor->HandleInlineSpellCheck(action, selection, 
-                                            mRangeItem.startNode, mRangeItem.startOffset,
+                                            mRangeItem->startNode,
+                                            mRangeItem->startOffset,
                                             rangeStartParent, rangeStartOffset,
                                             rangeEndParent, rangeEndOffset);
   NS_ENSURE_SUCCESS(res, res);
 
   // detect empty doc
   res = CreateBogusNodeIfNeeded(selection);
   
   // adjust selection HINT if needed
@@ -5866,43 +5870,43 @@ nsHTMLEditRules::GetNodesForOperation(ns
 
   nsresult res = NS_OK;
   
   // bust up any inlines that cross our range endpoints,
   // but only if we are allowed to touch content.
   
   if (!aDontTouchContent)
   {
-    nsAutoTArray<nsRangeStore, 16> rangeItemArray;
+    nsTArray<nsRefPtr<nsRangeStore> > rangeItemArray;
     if (!rangeItemArray.AppendElements(rangeCount)) {
       return NS_ERROR_OUT_OF_MEMORY;
     }
 
     NS_ASSERTION(static_cast<PRUint32>(rangeCount) == rangeItemArray.Length(),
                  "How did that happen?");
 
     // first register ranges for special editor gravity
     for (i = 0; i < rangeCount; i++)
     {
       opRange = inArrayOfRanges[0];
-      nsRangeStore *item = rangeItemArray.Elements() + i;
-      item->StoreRange(opRange);
-      mHTMLEditor->mRangeUpdater.RegisterRangeItem(item);
+      rangeItemArray[i] = new nsRangeStore();
+      rangeItemArray[i]->StoreRange(opRange);
+      mHTMLEditor->mRangeUpdater.RegisterRangeItem(rangeItemArray[i]);
       inArrayOfRanges.RemoveObjectAt(0);
     }    
     // now bust up inlines.  Safe to start at rangeCount-1, since we
     // asserted we have enough items above.
     for (i = rangeCount-1; i >= 0 && NS_SUCCEEDED(res); i--)
     {
-      res = BustUpInlinesAtRangeEndpoints(rangeItemArray[i]);
+      res = BustUpInlinesAtRangeEndpoints(*rangeItemArray[i]);
     } 
     // then unregister the ranges
     for (i = 0; i < rangeCount; i++)
     {
-      nsRangeStore *item = rangeItemArray.Elements() + i;
+      nsRangeStore* item = rangeItemArray[i];
       mHTMLEditor->mRangeUpdater.DropRangeItem(item);
       nsresult res2 = item->GetRange(address_of(opRange));
       if (NS_FAILED(res2) && NS_SUCCEEDED(res)) {
         // Remember the failure, but keep going so we make sure to unregister
         // all our range items.
         res = res2;
       }
       inArrayOfRanges.AppendObject(opRange);
--- a/editor/libeditor/html/nsHTMLEditRules.h
+++ b/editor/libeditor/html/nsHTMLEditRules.h
@@ -309,14 +309,14 @@ protected:
   bool                    mListenerEnabled;
   bool                    mReturnInEmptyLIKillsList;
   bool                    mDidDeleteSelection;
   bool                    mDidRangedDelete;
   bool                    mRestoreContentEditableCount;
   nsCOMPtr<nsIDOMRange>   mUtilRange;
   PRUint32                mJoinOffset;  // need to remember an int across willJoin/didJoin...
   nsCOMPtr<nsIDOMNode>    mNewBlock;
-  nsRangeStore            mRangeItem;
+  nsRefPtr<nsRangeStore>  mRangeItem;
   StyleCache              mCachedStyles[SIZE_STYLE_TABLE];
 };
 
 #endif //nsHTMLEditRules_h__