editor/libeditor/base/nsSelectionState.cpp

Sat, 03 Jan 2015 20:18:00 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Sat, 03 Jan 2015 20:18:00 +0100
branch
TOR_BUG_3246
changeset 7
129ffea94266
permissions
-rw-r--r--

Conditionally enable double key logic according to:
private browsing mode or privacy.thirdparty.isolate preference and
implement in GetCookieStringCommon and FindCookie where it counts...
With some reservations of how to convince FindCookie users to test
condition and pass a nullptr when disabling double key logic.

     1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
     2 /* This Source Code Form is subject to the terms of the Mozilla Public
     3  * License, v. 2.0. If a copy of the MPL was not distributed with this
     4  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     6 #include "mozilla/Assertions.h"         // for MOZ_ASSERT, etc
     7 #include "mozilla/dom/Selection.h"      // for Selection
     8 #include "nsAString.h"                  // for nsAString_internal::Length
     9 #include "nsAutoPtr.h"                  // for nsRefPtr, getter_AddRefs, etc
    10 #include "nsCycleCollectionParticipant.h"
    11 #include "nsDebug.h"                    // for NS_ENSURE_TRUE, etc
    12 #include "nsEditor.h"                   // for nsEditor
    13 #include "nsEditorUtils.h"              // for nsEditorUtils
    14 #include "nsError.h"                    // for NS_OK, etc
    15 #include "nsIDOMCharacterData.h"        // for nsIDOMCharacterData
    16 #include "nsIDOMNode.h"                 // for nsIDOMNode
    17 #include "nsIDOMRange.h"                // for nsIDOMRange, etc
    18 #include "nsISelection.h"               // for nsISelection
    19 #include "nsISupportsImpl.h"            // for nsRange::Release
    20 #include "nsRange.h"                    // for nsRange
    21 #include "nsSelectionState.h"
    23 using namespace mozilla;
    24 using namespace mozilla::dom;
    26 /***************************************************************************
    27  * class for recording selection info.  stores selection as collection of
    28  * { {startnode, startoffset} , {endnode, endoffset} } tuples.  Can't store
    29  * ranges since dom gravity will possibly change the ranges.
    30  */
    31 nsSelectionState::nsSelectionState() : mArray(){}
    33 nsSelectionState::~nsSelectionState() 
    34 {
    35   MakeEmpty();
    36 }
    38 void
    39 nsSelectionState::DoTraverse(nsCycleCollectionTraversalCallback &cb)
    40 {
    41   for (uint32_t i = 0, iEnd = mArray.Length(); i < iEnd; ++i)
    42   {
    43     nsRangeStore* item = mArray[i];
    44     NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb,
    45                                        "selection state mArray[i].startNode");
    46     cb.NoteXPCOMChild(item->startNode);
    47     NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb,
    48                                        "selection state mArray[i].endNode");
    49     cb.NoteXPCOMChild(item->endNode);
    50   }
    51 }
    53 void
    54 nsSelectionState::SaveSelection(Selection* aSel)
    55 {
    56   MOZ_ASSERT(aSel);
    57   int32_t arrayCount = mArray.Length();
    58   int32_t rangeCount = aSel->GetRangeCount();
    60   // if we need more items in the array, new them
    61   if (arrayCount < rangeCount) {
    62     for (int32_t i = arrayCount; i < rangeCount; i++) {
    63       mArray.AppendElement();
    64       mArray[i] = new nsRangeStore();
    65     }
    66   } else if (arrayCount > rangeCount) {
    67     // else if we have too many, delete them
    68     for (int32_t i = arrayCount - 1; i >= rangeCount; i--) {
    69       mArray.RemoveElementAt(i);
    70     }
    71   }
    73   // now store the selection ranges
    74   for (int32_t i = 0; i < rangeCount; i++) {
    75     mArray[i]->StoreRange(aSel->GetRangeAt(i));
    76   }
    77 }
    79 nsresult  
    80 nsSelectionState::RestoreSelection(nsISelection *aSel)
    81 {
    82   NS_ENSURE_TRUE(aSel, NS_ERROR_NULL_POINTER);
    83   nsresult res;
    84   uint32_t i, arrayCount = mArray.Length();
    86   // clear out selection
    87   aSel->RemoveAllRanges();
    89   // set the selection ranges anew
    90   for (i=0; i<arrayCount; i++)
    91   {
    92     nsRefPtr<nsRange> range;
    93     mArray[i]->GetRange(getter_AddRefs(range));
    94     NS_ENSURE_TRUE(range, NS_ERROR_UNEXPECTED);
    96     res = aSel->AddRange(range);
    97     if(NS_FAILED(res)) return res;
    99   }
   100   return NS_OK;
   101 }
   103 bool
   104 nsSelectionState::IsCollapsed()
   105 {
   106   if (1 != mArray.Length()) return false;
   107   nsRefPtr<nsRange> range;
   108   mArray[0]->GetRange(getter_AddRefs(range));
   109   NS_ENSURE_TRUE(range, false);
   110   bool bIsCollapsed = false;
   111   range->GetCollapsed(&bIsCollapsed);
   112   return bIsCollapsed;
   113 }
   115 bool
   116 nsSelectionState::IsEqual(nsSelectionState *aSelState)
   117 {
   118   NS_ENSURE_TRUE(aSelState, false);
   119   uint32_t i, myCount = mArray.Length(), itsCount = aSelState->mArray.Length();
   120   if (myCount != itsCount) return false;
   121   if (myCount < 1) return false;
   123   for (i=0; i<myCount; i++)
   124   {
   125     nsRefPtr<nsRange> myRange, itsRange;
   126     mArray[i]->GetRange(getter_AddRefs(myRange));
   127     aSelState->mArray[i]->GetRange(getter_AddRefs(itsRange));
   128     NS_ENSURE_TRUE(myRange && itsRange, false);
   130     int16_t compResult;
   131     nsresult rv;
   132     rv = myRange->CompareBoundaryPoints(nsIDOMRange::START_TO_START, itsRange, &compResult);
   133     if (NS_FAILED(rv) || compResult) return false;
   134     rv = myRange->CompareBoundaryPoints(nsIDOMRange::END_TO_END, itsRange, &compResult);
   135     if (NS_FAILED(rv) || compResult) return false;
   136   }
   137   // if we got here, they are equal
   138   return true;
   139 }
   141 void     
   142 nsSelectionState::MakeEmpty()
   143 {
   144   // free any items in the array
   145   mArray.Clear();
   146 }
   148 bool     
   149 nsSelectionState::IsEmpty()
   150 {
   151   return mArray.IsEmpty();
   152 }
   154 /***************************************************************************
   155  * nsRangeUpdater:  class for updating nsIDOMRanges in response to editor actions.
   156  */
   158 nsRangeUpdater::nsRangeUpdater() : mArray(), mLock(false) {}
   160 nsRangeUpdater::~nsRangeUpdater()
   161 {
   162   // nothing to do, we don't own the items in our array.
   163 }
   165 void 
   166 nsRangeUpdater::RegisterRangeItem(nsRangeStore *aRangeItem)
   167 {
   168   if (!aRangeItem) return;
   169   if (mArray.Contains(aRangeItem))
   170   {
   171     NS_ERROR("tried to register an already registered range");
   172     return;  // don't register it again.  It would get doubly adjusted.
   173   }
   174   mArray.AppendElement(aRangeItem);
   175 }
   177 void 
   178 nsRangeUpdater::DropRangeItem(nsRangeStore *aRangeItem)
   179 {
   180   if (!aRangeItem) return;
   181   mArray.RemoveElement(aRangeItem);
   182 }
   184 nsresult 
   185 nsRangeUpdater::RegisterSelectionState(nsSelectionState &aSelState)
   186 {
   187   uint32_t i, theCount = aSelState.mArray.Length();
   188   if (theCount < 1) return NS_ERROR_FAILURE;
   190   for (i=0; i<theCount; i++)
   191   {
   192     RegisterRangeItem(aSelState.mArray[i]);
   193   }
   195   return NS_OK;
   196 }
   198 nsresult 
   199 nsRangeUpdater::DropSelectionState(nsSelectionState &aSelState)
   200 {
   201   uint32_t i, theCount = aSelState.mArray.Length();
   202   if (theCount < 1) return NS_ERROR_FAILURE;
   204   for (i=0; i<theCount; i++)
   205   {
   206     DropRangeItem(aSelState.mArray[i]);
   207   }
   209   return NS_OK;
   210 }
   212 // gravity methods:
   214 nsresult
   215 nsRangeUpdater::SelAdjCreateNode(nsIDOMNode *aParent, int32_t aPosition)
   216 {
   217   if (mLock) return NS_OK;  // lock set by Will/DidReplaceParent, etc...
   218   NS_ENSURE_TRUE(aParent, NS_ERROR_NULL_POINTER);
   219   uint32_t i, count = mArray.Length();
   220   if (!count) {
   221     return NS_OK;
   222   }
   224   nsRangeStore *item;
   226   for (i=0; i<count; i++)
   227   {
   228     item = mArray[i];
   229     NS_ENSURE_TRUE(item, NS_ERROR_NULL_POINTER);
   231     if ((item->startNode.get() == aParent) && (item->startOffset > aPosition))
   232       item->startOffset++;
   233     if ((item->endNode.get() == aParent) && (item->endOffset > aPosition))
   234       item->endOffset++;
   235   }
   236   return NS_OK;
   237 }
   239 nsresult
   240 nsRangeUpdater::SelAdjInsertNode(nsIDOMNode *aParent, int32_t aPosition)
   241 {
   242   return SelAdjCreateNode(aParent, aPosition);
   243 }
   245 void
   246 nsRangeUpdater::SelAdjDeleteNode(nsIDOMNode *aNode)
   247 {
   248   if (mLock) {
   249     // lock set by Will/DidReplaceParent, etc...
   250     return;
   251   }
   252   MOZ_ASSERT(aNode);
   253   uint32_t i, count = mArray.Length();
   254   if (!count) {
   255     return;
   256   }
   258   int32_t offset = 0;
   259   nsCOMPtr<nsIDOMNode> parent = nsEditor::GetNodeLocation(aNode, &offset);
   261   // check for range endpoints that are after aNode and in the same parent
   262   nsRangeStore *item;
   263   for (i=0; i<count; i++)
   264   {
   265     item = mArray[i];
   266     MOZ_ASSERT(item);
   268     if ((item->startNode.get() == parent) && (item->startOffset > offset))
   269       item->startOffset--;
   270     if ((item->endNode.get() == parent) && (item->endOffset > offset))
   271       item->endOffset--;
   273     // check for range endpoints that are in aNode
   274     if (item->startNode == aNode)
   275     {
   276       item->startNode   = parent;
   277       item->startOffset = offset;
   278     }
   279     if (item->endNode == aNode)
   280     {
   281       item->endNode   = parent;
   282       item->endOffset = offset;
   283     }
   285     // check for range endpoints that are in descendants of aNode
   286     nsCOMPtr<nsIDOMNode> oldStart;
   287     if (nsEditorUtils::IsDescendantOf(item->startNode, aNode))
   288     {
   289       oldStart = item->startNode;  // save for efficiency hack below.
   290       item->startNode   = parent;
   291       item->startOffset = offset;
   292     }
   294     // avoid having to call IsDescendantOf() for common case of range startnode == range endnode.
   295     if ((item->endNode == oldStart) || nsEditorUtils::IsDescendantOf(item->endNode, aNode))
   296     {
   297       item->endNode   = parent;
   298       item->endOffset = offset;
   299     }
   300   }
   301 }
   304 nsresult
   305 nsRangeUpdater::SelAdjSplitNode(nsIDOMNode *aOldRightNode, int32_t aOffset, nsIDOMNode *aNewLeftNode)
   306 {
   307   if (mLock) return NS_OK;  // lock set by Will/DidReplaceParent, etc...
   308   NS_ENSURE_TRUE(aOldRightNode && aNewLeftNode, NS_ERROR_NULL_POINTER);
   309   uint32_t i, count = mArray.Length();
   310   if (!count) {
   311     return NS_OK;
   312   }
   314   int32_t offset;
   315   nsCOMPtr<nsIDOMNode> parent = nsEditor::GetNodeLocation(aOldRightNode, &offset);
   317   // first part is same as inserting aNewLeftnode
   318   nsresult result = SelAdjInsertNode(parent,offset-1);
   319   NS_ENSURE_SUCCESS(result, result);
   321   // next step is to check for range enpoints inside aOldRightNode
   322   nsRangeStore *item;
   324   for (i=0; i<count; i++)
   325   {
   326     item = mArray[i];
   327     NS_ENSURE_TRUE(item, NS_ERROR_NULL_POINTER);
   329     if (item->startNode.get() == aOldRightNode)
   330     {
   331       if (item->startOffset > aOffset)
   332       {
   333         item->startOffset -= aOffset;
   334       }
   335       else
   336       {
   337         item->startNode = aNewLeftNode;
   338       }
   339     }
   340     if (item->endNode.get() == aOldRightNode)
   341     {
   342       if (item->endOffset > aOffset)
   343       {
   344         item->endOffset -= aOffset;
   345       }
   346       else
   347       {
   348         item->endNode = aNewLeftNode;
   349       }
   350     }
   351   }
   352   return NS_OK;
   353 }
   356 nsresult
   357 nsRangeUpdater::SelAdjJoinNodes(nsIDOMNode *aLeftNode, 
   358                                   nsIDOMNode *aRightNode, 
   359                                   nsIDOMNode *aParent, 
   360                                   int32_t aOffset,
   361                                   int32_t aOldLeftNodeLength)
   362 {
   363   if (mLock) return NS_OK;  // lock set by Will/DidReplaceParent, etc...
   364   NS_ENSURE_TRUE(aLeftNode && aRightNode && aParent, NS_ERROR_NULL_POINTER);
   365   uint32_t i, count = mArray.Length();
   366   if (!count) {
   367     return NS_OK;
   368   }
   370   nsRangeStore *item;
   372   for (i=0; i<count; i++)
   373   {
   374     item = mArray[i];
   375     NS_ENSURE_TRUE(item, NS_ERROR_NULL_POINTER);
   377     if (item->startNode.get() == aParent)
   378     {
   379       // adjust start point in aParent
   380       if (item->startOffset > aOffset)
   381       {
   382         item->startOffset--;
   383       }
   384       else if (item->startOffset == aOffset)
   385       {
   386         // join keeps right hand node
   387         item->startNode = aRightNode;
   388         item->startOffset = aOldLeftNodeLength;
   389       }
   390     }
   391     else if (item->startNode.get() == aRightNode)
   392     {
   393       // adjust start point in aRightNode
   394       item->startOffset += aOldLeftNodeLength;
   395     }
   396     else if (item->startNode.get() == aLeftNode)
   397     {
   398       // adjust start point in aLeftNode
   399       item->startNode = aRightNode;
   400     }
   402     if (item->endNode.get() == aParent)
   403     {
   404       // adjust end point in aParent
   405       if (item->endOffset > aOffset)
   406       {
   407         item->endOffset--;
   408       }
   409       else if (item->endOffset == aOffset)
   410       {
   411         // join keeps right hand node
   412         item->endNode = aRightNode;
   413         item->endOffset = aOldLeftNodeLength;
   414       }
   415     }
   416     else if (item->endNode.get() == aRightNode)
   417     {
   418       // adjust end point in aRightNode
   419        item->endOffset += aOldLeftNodeLength;
   420     }
   421     else if (item->endNode.get() == aLeftNode)
   422     {
   423       // adjust end point in aLeftNode
   424       item->endNode = aRightNode;
   425     }
   426   }
   428   return NS_OK;
   429 }
   432 nsresult
   433 nsRangeUpdater::SelAdjInsertText(nsIDOMCharacterData *aTextNode, int32_t aOffset, const nsAString &aString)
   434 {
   435   if (mLock) return NS_OK;  // lock set by Will/DidReplaceParent, etc...
   437   uint32_t count = mArray.Length();
   438   if (!count) {
   439     return NS_OK;
   440   }
   441   nsCOMPtr<nsIDOMNode> node(do_QueryInterface(aTextNode));
   442   NS_ENSURE_TRUE(node, NS_ERROR_NULL_POINTER);
   444   uint32_t len=aString.Length(), i;
   445   nsRangeStore *item;
   446   for (i=0; i<count; i++)
   447   {
   448     item = mArray[i];
   449     NS_ENSURE_TRUE(item, NS_ERROR_NULL_POINTER);
   451     if ((item->startNode.get() == node) && (item->startOffset > aOffset))
   452       item->startOffset += len;
   453     if ((item->endNode.get() == node) && (item->endOffset > aOffset))
   454       item->endOffset += len;
   455   }
   456   return NS_OK;
   457 }
   460 nsresult
   461 nsRangeUpdater::SelAdjDeleteText(nsIDOMCharacterData *aTextNode, int32_t aOffset, int32_t aLength)
   462 {
   463   if (mLock) return NS_OK;  // lock set by Will/DidReplaceParent, etc...
   465   uint32_t i, count = mArray.Length();
   466   if (!count) {
   467     return NS_OK;
   468   }
   469   nsRangeStore *item;
   470   nsCOMPtr<nsIDOMNode> node(do_QueryInterface(aTextNode));
   471   NS_ENSURE_TRUE(node, NS_ERROR_NULL_POINTER);
   473   for (i=0; i<count; i++)
   474   {
   475     item = mArray[i];
   476     NS_ENSURE_TRUE(item, NS_ERROR_NULL_POINTER);
   478     if ((item->startNode.get() == node) && (item->startOffset > aOffset))
   479     {
   480       item->startOffset -= aLength;
   481       if (item->startOffset < 0) item->startOffset = 0;
   482     }
   483     if ((item->endNode.get() == node) && (item->endOffset > aOffset))
   484     {
   485       item->endOffset -= aLength;
   486       if (item->endOffset < 0) item->endOffset = 0;
   487     }
   488   }
   489   return NS_OK;
   490 }
   493 nsresult
   494 nsRangeUpdater::WillReplaceContainer()
   495 {
   496   if (mLock) return NS_ERROR_UNEXPECTED;  
   497   mLock = true;
   498   return NS_OK;
   499 }
   502 nsresult
   503 nsRangeUpdater::DidReplaceContainer(nsIDOMNode *aOriginalNode, nsIDOMNode *aNewNode)
   504 {
   505   NS_ENSURE_TRUE(mLock, NS_ERROR_UNEXPECTED);  
   506   mLock = false;
   508   NS_ENSURE_TRUE(aOriginalNode && aNewNode, NS_ERROR_NULL_POINTER);
   509   uint32_t i, count = mArray.Length();
   510   if (!count) {
   511     return NS_OK;
   512   }
   514   nsRangeStore *item;
   516   for (i=0; i<count; i++)
   517   {
   518     item = mArray[i];
   519     NS_ENSURE_TRUE(item, NS_ERROR_NULL_POINTER);
   521     if (item->startNode.get() == aOriginalNode)
   522       item->startNode = aNewNode;
   523     if (item->endNode.get() == aOriginalNode)
   524       item->endNode = aNewNode;
   525   }
   526   return NS_OK;
   527 }
   530 nsresult
   531 nsRangeUpdater::WillRemoveContainer()
   532 {
   533   if (mLock) return NS_ERROR_UNEXPECTED;  
   534   mLock = true;
   535   return NS_OK;
   536 }
   539 nsresult
   540 nsRangeUpdater::DidRemoveContainer(nsIDOMNode *aNode, nsIDOMNode *aParent, int32_t aOffset, uint32_t aNodeOrigLen)
   541 {
   542   NS_ENSURE_TRUE(mLock, NS_ERROR_UNEXPECTED);  
   543   mLock = false;
   545   NS_ENSURE_TRUE(aNode && aParent, NS_ERROR_NULL_POINTER);
   546   uint32_t i, count = mArray.Length();
   547   if (!count) {
   548     return NS_OK;
   549   }
   551   nsRangeStore *item;
   553   for (i=0; i<count; i++)
   554   {
   555     item = mArray[i];
   556     NS_ENSURE_TRUE(item, NS_ERROR_NULL_POINTER);
   558     if (item->startNode.get() == aNode)
   559     {
   560       item->startNode = aParent;
   561       item->startOffset += aOffset;
   562     }
   563     else if ((item->startNode.get() == aParent) && (item->startOffset > aOffset))
   564       item->startOffset += (int32_t)aNodeOrigLen-1;
   566     if (item->endNode.get() == aNode)
   567     {
   568       item->endNode = aParent;
   569       item->endOffset += aOffset;
   570     }
   571     else if ((item->endNode.get() == aParent) && (item->endOffset > aOffset))
   572       item->endOffset += (int32_t)aNodeOrigLen-1;
   573   }
   574   return NS_OK;
   575 }
   578 nsresult
   579 nsRangeUpdater::WillInsertContainer()
   580 {
   581   if (mLock) return NS_ERROR_UNEXPECTED;  
   582   mLock = true;
   583   return NS_OK;
   584 }
   587 nsresult
   588 nsRangeUpdater::DidInsertContainer()
   589 {
   590   NS_ENSURE_TRUE(mLock, NS_ERROR_UNEXPECTED);  
   591   mLock = false;
   592   return NS_OK;
   593 }
   596 void
   597 nsRangeUpdater::WillMoveNode()
   598 {
   599   mLock = true;
   600 }
   603 void
   604 nsRangeUpdater::DidMoveNode(nsINode* aOldParent, int32_t aOldOffset,
   605                             nsINode* aNewParent, int32_t aNewOffset)
   606 {
   607   MOZ_ASSERT(aOldParent);
   608   MOZ_ASSERT(aNewParent);
   609   NS_ENSURE_TRUE_VOID(mLock);
   610   mLock = false;
   612   nsIDOMNode* oldParent = aOldParent->AsDOMNode();
   613   nsIDOMNode* newParent = aNewParent->AsDOMNode();
   615   for (uint32_t i = 0, count = mArray.Length(); i < count; ++i) {
   616     nsRangeStore* item = mArray[i];
   617     NS_ENSURE_TRUE_VOID(item);
   619     // like a delete in aOldParent
   620     if (item->startNode == oldParent && item->startOffset > aOldOffset) {
   621       item->startOffset--;
   622     }
   623     if (item->endNode == oldParent && item->endOffset > aOldOffset) {
   624       item->endOffset--;
   625     }
   627     // and like an insert in aNewParent
   628     if (item->startNode == newParent && item->startOffset > aNewOffset) {
   629       item->startOffset++;
   630     }
   631     if (item->endNode == newParent && item->endOffset > aNewOffset) {
   632       item->endOffset++;
   633     }
   634   }
   635 }
   639 /***************************************************************************
   640  * helper class for nsSelectionState.  nsRangeStore stores range endpoints.
   641  */
   643   // DEBUG: int32_t nsRangeStore::n = 0;
   645 nsRangeStore::nsRangeStore() 
   646 { 
   647   // DEBUG: n++;  printf("range store alloc count=%d\n", n); 
   648 }
   649 nsRangeStore::~nsRangeStore()
   650 {
   651   // DEBUG: n--;  printf("range store alloc count=%d\n", n); 
   652 }
   654 nsresult nsRangeStore::StoreRange(nsIDOMRange *aRange)
   655 {
   656   NS_ENSURE_TRUE(aRange, NS_ERROR_NULL_POINTER);
   657   aRange->GetStartContainer(getter_AddRefs(startNode));
   658   aRange->GetEndContainer(getter_AddRefs(endNode));
   659   aRange->GetStartOffset(&startOffset);
   660   aRange->GetEndOffset(&endOffset);
   661   return NS_OK;
   662 }
   664 nsresult nsRangeStore::GetRange(nsRange** outRange)
   665 {
   666   return nsRange::CreateRange(startNode, startOffset, endNode, endOffset,
   667                               outRange);
   668 }

mercurial