Bug 1408227 - part 3: Redesign WSRunObject::FindRun() with EditorRawDOMPoint r?m_kato draft
authorMasayuki Nakano <masayuki@d-toybox.com>
Tue, 21 Nov 2017 19:03:03 +0900
changeset 706047 2e884a311bfb092f494c4ecb09400af5f0e2966e
parent 706046 14c9611fa71a4145720a1ac0f2148d88b6725e60
child 706048 2d87c6f80e5088e7ba056296016abde958d405e7
push id91674
push usermasayuki@d-toybox.com
push dateFri, 01 Dec 2017 02:38:11 +0000
reviewersm_kato
bugs1408227
milestone59.0a1
Bug 1408227 - part 3: Redesign WSRunObject::FindRun() with EditorRawDOMPoint r?m_kato WSRunObject::FindRun() finds the nearest run from aPoint to specified direction. So, it uses nsContentUtils::ComparePoints() a lot. Therefore, it should use an overload which takes RawRangeBoundary. Although, it's not optimized for RawRangeBoundary, but if it'd be optimized, this method becomes faster. And this patch renames it to FindNearestRun(). MozReview-Commit-ID: 2NkR5E1st6d
editor/libeditor/WSRunObject.cpp
editor/libeditor/WSRunObject.h
--- a/editor/libeditor/WSRunObject.cpp
+++ b/editor/libeditor/WSRunObject.cpp
@@ -175,21 +175,18 @@ WSRunObject::InsertBreak(Selection& aSel
   if (NS_WARN_IF(!aPointToInsert.IsSet())) {
     return nullptr;
   }
 
   // MOOSE: for now, we always assume non-PRE formatting.  Fix this later.
   // meanwhile, the pre case is handled in WillInsertText in
   // HTMLEditRules.cpp
 
-  WSFragment *beforeRun, *afterRun;
-  FindRun(aPointToInsert.Container(), aPointToInsert.Offset(),
-          &beforeRun, false);
-  FindRun(aPointToInsert.Container(), aPointToInsert.Offset(),
-          &afterRun, true);
+  WSFragment* beforeRun = FindNearestRun(aPointToInsert, false);
+  WSFragment* afterRun = FindNearestRun(aPointToInsert, true);
 
   EditorDOMPoint pointToInsert(aPointToInsert);
   {
     // Some scoping for AutoTrackDOMPoint.  This will track our insertion
     // point while we tweak any surrounding whitespace
     AutoTrackDOMPoint tracker(mHTMLEditor->mRangeUpdater, &pointToInsert);
 
     // Handle any changes needed to ws run after inserted br
@@ -268,25 +265,21 @@ WSRunObject::InsertText(nsIDocument& aDo
 
   if (aStringToInsert.IsEmpty()) {
     if (aPointAfterInsertedString) {
       *aPointAfterInsertedString = aPointToInsert;
     }
     return NS_OK;
   }
 
+  WSFragment* beforeRun = FindNearestRun(aPointToInsert, false);
+  WSFragment* afterRun = FindNearestRun(aPointToInsert, true);
+
   EditorDOMPoint pointToInsert(aPointToInsert);
   nsAutoString theString(aStringToInsert);
-
-  WSFragment *beforeRun, *afterRun;
-  FindRun(pointToInsert.Container(), pointToInsert.Offset(),
-          &beforeRun, false);
-  FindRun(pointToInsert.Container(), pointToInsert.Offset(),
-          &afterRun, true);
-
   {
     // Some scoping for AutoTrackDOMPoint.  This will track our insertion
     // point while we tweak any surrounding whitespace
     AutoTrackDOMPoint tracker(mHTMLEditor->mRangeUpdater, &pointToInsert);
 
     // Handle any changes needed to ws run after inserted text
     if (!afterRun || afterRun->mType & WSType::trailingWS) {
       // Don't need to do anything.  Just insert text.  ws won't change.
@@ -505,18 +498,17 @@ WSRunObject::PriorVisibleNode(nsINode* a
                               int32_t* outVisOffset,
                               WSType* outType)
 {
   // Find first visible thing before the point.  Position
   // outVisNode/outVisOffset just _after_ that thing.  If we don't find
   // anything return start of ws.
   MOZ_ASSERT(aNode && outVisNode && outVisOffset && outType);
 
-  WSFragment* run;
-  FindRun(aNode, aOffset, &run, false);
+  WSFragment* run = FindNearestRun(EditorRawDOMPoint(aNode, aOffset), false);
 
   // Is there a visible run there or earlier?
   for (; run; run = run->mLeft) {
     if (run->mType == WSType::normalWS) {
       WSPoint point = GetCharBefore(aNode, aOffset);
       // When it's a non-empty text node, return it.
       if (point.mTextNode && point.mTextNode->Length()) {
         *outVisNode = point.mTextNode;
@@ -547,18 +539,17 @@ WSRunObject::NextVisibleNode(nsINode* aN
                              int32_t* outVisOffset,
                              WSType* outType)
 {
   // Find first visible thing after the point.  Position
   // outVisNode/outVisOffset just _before_ that thing.  If we don't find
   // anything return end of ws.
   MOZ_ASSERT(aNode && outVisNode && outVisOffset && outType);
 
-  WSFragment* run;
-  FindRun(aNode, aOffset, &run, true);
+  WSFragment* run = FindNearestRun(EditorRawDOMPoint(aNode, aOffset), true);
 
   // Is there a visible run there or later?
   for (; run; run = run->mRight) {
     if (run->mType == WSType::normalWS) {
       WSPoint point = GetCharAfter(aNode, aOffset);
       // When it's a non-empty text node, return it.
       if (point.mTextNode && point.mTextNode->Length()) {
         *outVisNode = point.mTextNode;
@@ -1188,19 +1179,18 @@ WSRunObject::PrepareToDeleteRangePriv(WS
   // intervening content is deleted.  It's overly agressive right
   // now.  There might be a block boundary remaining between them after
   // the deletion, in which case these adjstments are unneeded (though
   // I don't think they can ever be harmful?)
 
   NS_ENSURE_TRUE(aEndObject, NS_ERROR_NULL_POINTER);
 
   // get the runs before and after selection
-  WSFragment *beforeRun, *afterRun;
-  FindRun(mNode, mOffset, &beforeRun, false);
-  aEndObject->FindRun(aEndObject->mNode, aEndObject->mOffset, &afterRun, true);
+  WSFragment* beforeRun = FindNearestRun(Point(), false);
+  WSFragment* afterRun = aEndObject->FindNearestRun(aEndObject->Point(), true);
 
   // trim after run of any leading ws
   if (afterRun && (afterRun->mType & WSType::leadingWS)) {
     nsresult rv =
       aEndObject->DeleteChars(aEndObject->mNode, aEndObject->mOffset,
                               afterRun->mEndNode, afterRun->mEndOffset);
     NS_ENSURE_SUCCESS(rv, rv);
   }
@@ -1248,19 +1238,18 @@ WSRunObject::PrepareToDeleteRangePriv(WS
 nsresult
 WSRunObject::PrepareToSplitAcrossBlocksPriv()
 {
   // used to prepare ws to be split across two blocks.  The main issue
   // here is make sure normalWS doesn't end up becoming non-significant
   // leading or trailing ws after the split.
 
   // get the runs before and after selection
-  WSFragment *beforeRun, *afterRun;
-  FindRun(mNode, mOffset, &beforeRun, false);
-  FindRun(mNode, mOffset, &afterRun, true);
+  WSFragment* beforeRun = FindNearestRun(Point(), false);
+  WSFragment* afterRun = FindNearestRun(Point(), true);
 
   // adjust normal ws in afterRun if needed
   if (afterRun && afterRun->mType == WSType::normalWS) {
     // make sure leading char of following ws is an nbsp, so that it will show up
     WSPoint point = GetCharAfter(mNode, mOffset);
     if (point.mTextNode && nsCRT::IsAsciiSpace(point.mChar)) {
       nsresult rv = ConvertToNBSP(point);
       NS_ENSURE_SUCCESS(rv, rv);
@@ -1547,65 +1536,53 @@ WSRunObject::GetAsciiWSBounds(int16_t aD
   }
 
   startNode.forget(outStartNode);
   *outStartOffset = startOffset;
   endNode.forget(outEndNode);
   *outEndOffset = endOffset;
 }
 
-/**
- * Given a dompoint, find the ws run that is before or after it, as caller
- * needs
- */
-void
-WSRunObject::FindRun(nsINode* aNode,
-                     int32_t aOffset,
-                     WSFragment** outRun,
-                     bool after)
+WSRunObject::WSFragment*
+WSRunObject::FindNearestRun(const EditorRawDOMPoint& aPoint,
+                            bool aForward)
 {
-  MOZ_ASSERT(aNode && outRun);
-  *outRun = nullptr;
+  MOZ_ASSERT(aPoint.IsSetAndValid());
 
   for (WSFragment* run = mStartRun; run; run = run->mRight) {
-    int32_t comp = run->mStartNode ? nsContentUtils::ComparePoints(aNode,
-        aOffset, run->mStartNode, run->mStartOffset) : -1;
+    int32_t comp = run->mStartNode ?
+      nsContentUtils::ComparePoints(aPoint, run->StartPoint()) : -1;
     if (comp <= 0) {
-      if (after) {
-        *outRun = run;
-      } else {
-        // before
-        *outRun = nullptr;
-      }
-      return;
+      // aPoint equals or before start of the run.  Return the run if we're
+      // scanning forward, otherwise, nullptr.
+      return aForward ? run : nullptr;
     }
-    comp = run->mEndNode ? nsContentUtils::ComparePoints(aNode, aOffset,
-        run->mEndNode, run->mEndOffset) : -1;
+
+    comp = run->mEndNode ?
+      nsContentUtils::ComparePoints(aPoint, run->EndPoint()) : -1;
     if (comp < 0) {
-      *outRun = run;
-      return;
-    } else if (!comp) {
-      if (after) {
-        *outRun = run->mRight;
-      } else {
-        // before
-        *outRun = run;
-      }
-      return;
+      // If aPoint is in the run, return the run.
+      return run;
     }
+
+    if (!comp) {
+      // If aPoint is at end of the run, return next run if we're scanning
+      // forward, otherwise, return the run.
+      return aForward ? run->mRight : run;
+    }
+
     if (!run->mRight) {
-      if (after) {
-        *outRun = nullptr;
-      } else {
-        // before
-        *outRun = run;
-      }
-      return;
+      // If the run is the last run and aPoint is after end of the last run,
+      // return nullptr if we're scanning forward, otherwise, return this
+      // last run.
+      return aForward ? nullptr : run;
     }
   }
+
+  return nullptr;
 }
 
 char16_t
 WSRunObject::GetCharAt(Text* aTextNode,
                        int32_t aOffset)
 {
   // return 0 if we can't get a char, for whatever reason
   NS_ENSURE_TRUE(aTextNode, 0);
--- a/editor/libeditor/WSRunObject.h
+++ b/editor/libeditor/WSRunObject.h
@@ -312,16 +312,25 @@ protected:
     WSFragment *mLeft, *mRight;
 
     WSFragment()
       : mStartOffset(0)
       , mEndOffset(0)
       , mLeft(nullptr)
       , mRight(nullptr)
     {}
+
+    EditorRawDOMPoint StartPoint() const
+    {
+      return EditorRawDOMPoint(mStartNode, mStartOffset);
+    }
+    EditorRawDOMPoint EndPoint() const
+    {
+      return EditorRawDOMPoint(mEndNode, mEndOffset);
+    }
   };
 
   // A WSPoint struct represents a unique location within the ws run.  It is
   // always within a textnode that is one of the nodes stored in the list
   // in the wsRunObject.  For convenience, the character at that point is also
   // stored in the struct.
   struct MOZ_STACK_CLASS WSPoint final
   {
@@ -367,30 +376,65 @@ protected:
   WSPoint GetCharAfter(nsINode* aNode, int32_t aOffset);
   WSPoint GetCharBefore(nsINode* aNode, int32_t aOffset);
   WSPoint GetCharAfter(const WSPoint& aPoint);
   WSPoint GetCharBefore(const WSPoint& aPoint);
   nsresult ConvertToNBSP(WSPoint aPoint);
   void GetAsciiWSBounds(int16_t aDir, nsINode* aNode, int32_t aOffset,
                         dom::Text** outStartNode, int32_t* outStartOffset,
                         dom::Text** outEndNode, int32_t* outEndOffset);
-  void FindRun(nsINode* aNode, int32_t aOffset, WSFragment** outRun,
-               bool after);
+
+  /**
+   * FindNearestRun() looks for a WSFragment which is closest to specified
+   * direction from aPoint.
+   *
+   * @param aPoint      The point to start to look for.
+   * @param aForward    true if caller needs to look for a WSFragment after the
+   *                    point in the DOM tree.  Otherwise, i.e., before the
+   *                    point, false.
+   * @return            Found WSFragment instance.
+   *                    If aForward is true and:
+   *                      if aPoint is end of a run, returns next run.
+   *                      if aPoint is start of a run, returns the run.
+   *                      if aPoint is before the first run, returns the first
+   *                      run.
+   *                      If aPoint is after the last run, returns nullptr.
+   *                    If aForward is false and:
+   *                      if aPoint is end of a run, returns the run.
+   *                      if aPoint is start of a run, returns its next run.
+   *                      if aPoint is before the first run, returns nullptr.
+   *                      if aPoint is after the last run, returns the last run.
+   */
+  WSFragment* FindNearestRun(const EditorRawDOMPoint& aPoint, bool aForward);
+
   char16_t GetCharAt(dom::Text* aTextNode, int32_t aOffset);
   WSPoint GetWSPointAfter(nsINode* aNode, int32_t aOffset);
   WSPoint GetWSPointBefore(nsINode* aNode, int32_t aOffset);
   nsresult CheckTrailingNBSPOfRun(WSFragment *aRun);
   nsresult CheckTrailingNBSP(WSFragment* aRun, nsINode* aNode,
                              int32_t aOffset);
   nsresult CheckLeadingNBSP(WSFragment* aRun, nsINode* aNode,
                             int32_t aOffset);
 
   nsresult Scrub();
   bool IsBlockNode(nsINode* aNode);
 
+  EditorRawDOMPoint Point() const
+  {
+    return EditorRawDOMPoint(mNode, mOffset);
+  }
+  EditorRawDOMPoint StartPoint() const
+  {
+    return EditorRawDOMPoint(mStartNode, mStartOffset);
+  }
+  EditorRawDOMPoint EndPoint() const
+  {
+    return EditorRawDOMPoint(mEndNode, mEndOffset);
+  }
+
   // The node passed to our constructor.
   nsCOMPtr<nsINode> mNode;
   // The offset passed to our contructor.
   int32_t mOffset;
   // Together, the above represent the point at which we are building up ws info.
 
   // true if we are in preformatted whitespace context.
   bool mPRE;