Bug 771994 - Make nsRangeStore refcounted; r=ehsan
authorAryeh Gregor <ayg@aryeh.name>
Fri, 13 Jul 2012 09:31:15 +0300
changeset 99162 a67b71ac0ba7d9cfbfb3041fc76aa9f9973fb48a
parent 99161 6a5d9afb58e59b6c72c5cc8f66ca2d91078b4a66
child 99163 a2d40b91eea9262dd138daace1569c28fdd6a846
child 99168 7e78cbe9ea946ed6caaf379ee3af46d37b0ea89d
push id23105
push useremorley@mozilla.com
push dateFri, 13 Jul 2012 12:23:43 +0000
treeherdermozilla-central@a2d40b91eea9 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersehsan
bugs771994
milestone16.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 771994 - Make nsRangeStore refcounted; r=ehsan
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
@@ -24,23 +24,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();
@@ -48,16 +48,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--)
     {
@@ -66,17 +67,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)
 {
@@ -86,32 +87,32 @@ nsSelectionState::RestoreSelection(nsISe
 
   // clear out selection
   aSel->RemoveAllRanges();
   
   // set the selection ranges anew
   for (i=0; i<arrayCount; i++)
   {
     nsRefPtr<nsRange> range;
-    mArray[i].GetRange(getter_AddRefs(range));
+    mArray[i]->GetRange(getter_AddRefs(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;
   nsRefPtr<nsRange> range;
-  mArray[0].GetRange(getter_AddRefs(range));
+  mArray[0]->GetRange(getter_AddRefs(range));
   NS_ENSURE_TRUE(range, false);
   bool bIsCollapsed = false;
   range->GetCollapsed(&bIsCollapsed);
   return bIsCollapsed;
 }
 
 bool
 nsSelectionState::IsEqual(nsSelectionState *aSelState)
@@ -119,18 +120,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++)
   {
     nsRefPtr<nsRange> myRange, itsRange;
-    mArray[i].GetRange(getter_AddRefs(myRange));
-    aSelState->mArray[i].GetRange(getter_AddRefs(itsRange));
+    mArray[i]->GetRange(getter_AddRefs(myRange));
+    aSelState->mArray[i]->GetRange(getter_AddRefs(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;
@@ -185,31 +186,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
@@ -25,16 +25,18 @@ class nsRange;
 
 // first a helper struct for saving/setting ranges
 struct nsRangeStore 
 {
   nsRangeStore();
   ~nsRangeStore();
   nsresult StoreRange(nsIDOMRange *aRange);
   nsresult GetRange(nsRange** outRange);
+
+  NS_INLINE_DECL_REFCOUNTING(nsRangeStore)
         
   nsCOMPtr<nsIDOMNode> startNode;
   PRInt32              startOffset;
   nsCOMPtr<nsIDOMNode> endNode;
   PRInt32              endOffset;
   // DEBUG:   static PRInt32 n;
 };
 
@@ -50,17 +52,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:    
   
@@ -94,51 +96,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
@@ -179,16 +179,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
@@ -282,27 +283,27 @@ nsHTMLEditRules::BeforeEdit(nsEditor::Op
     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
@@ -356,17 +357,17 @@ nsHTMLEditRules::AfterEdit(nsEditor::Ope
   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 = mHTMLEditor->GetDOMDocument();
       NS_ENSURE_TRUE(doc, NS_ERROR_NOT_INITIALIZED);
       nsCOMPtr<nsIHTMLDocument> htmlDoc = do_QueryInterface(doc);
       NS_ENSURE_TRUE(htmlDoc, NS_ERROR_FAILURE);
       if (htmlDoc->GetEditingState() == nsIHTMLDocument::eContentEditable) {
@@ -448,21 +449,23 @@ nsHTMLEditRules::AfterEditInner(nsEditor
         (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;
@@ -489,17 +492,18 @@ nsHTMLEditRules::AfterEditInner(nsEditor
       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
@@ -5567,43 +5571,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);
       nsRefPtr<nsRange> range;
       nsresult res2 = item->GetRange(getter_AddRefs(range));
       opRange = range;
       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;
--- a/editor/libeditor/html/nsHTMLEditRules.h
+++ b/editor/libeditor/html/nsHTMLEditRules.h
@@ -288,14 +288,14 @@ protected:
   bool                    mListenerEnabled;
   bool                    mReturnInEmptyLIKillsList;
   bool                    mDidDeleteSelection;
   bool                    mDidRangedDelete;
   bool                    mRestoreContentEditableCount;
   nsRefPtr<nsRange>       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__