Bug 1286464 part.10 ContentEventHandler::OnQueryTextRectArray() should append same rects for following characters of a line breaker in nsTextFrame r=smaug draft
authorMasayuki Nakano <masayuki@d-toybox.com>
Fri, 05 Aug 2016 14:06:30 +0900
changeset 400166 dca28a6e4661eef3c8a102916c451e0f021bf6d5
parent 400165 3afaca4d6e9f09e2054c4a6bd876635cfef6c58c
child 400167 97653f1ed04a6a03373cd53613d92aba45fbe38b
push id26081
push usermasayuki@d-toybox.com
push dateFri, 12 Aug 2016 17:11:29 +0000
reviewerssmaug
bugs1286464
milestone51.0a1
Bug 1286464 part.10 ContentEventHandler::OnQueryTextRectArray() should append same rects for following characters of a line breaker in nsTextFrame r=smaug If line breakers in a text node works as is, e.g., |white-space: pre;| is specified, we need to handle line breakers in text frames too. This patch handles "\n" in text nodes same as line breakers caused by some elements. MozReview-Commit-ID: JmXesusFxzR
dom/events/ContentEventHandler.cpp
--- a/dom/events/ContentEventHandler.cpp
+++ b/dom/events/ContentEventHandler.cpp
@@ -1588,25 +1588,26 @@ ContentEventHandler::OnQueryTextRectArra
     // get the starting frame rect
     nsRect frameRect(nsPoint(0, 0), firstFrame->GetRect().Size());
     rv = ConvertToRootRelativeOffset(firstFrame, frameRect);
     if (NS_WARN_IF(NS_FAILED(rv))) {
       return rv;
     }
 
     bool startsBetweenLineBreaker = false;
+    nsAutoString chars;
     AutoTArray<nsRect, 16> charRects;
 
-    bool isLineBreaker = ShouldBreakLineBefore(firstContent, mRootContent);
-    if (isLineBreaker) {
+    if (ShouldBreakLineBefore(firstContent, mRootContent)) {
       // TODO: If the frame isn't <br> and there was previous text frame or
       //       <br>, we can set the rect to caret rect at the end.  Currently,
       //       this sets the rect to caret rect at the start of the node.
       FrameRelativeRect brRect = GetLineBreakerRectBefore(firstFrame);
       charRects.AppendElement(brRect.RectRelativeTo(firstFrame));
+      chars.AssignLiteral("\n");
       if (kBRLength > 1 && offset == aEvent->mInput.mOffset && offset) {
         // If the first frame for the previous offset of the query range and
         // the first frame for the start of query range are same, that means
         // the start offset is between the first line breaker (i.e., the range
         // starts between "\r" and "\n").
         rv = SetRangeFromFlatTextOffset(range, aEvent->mInput.mOffset - 1, 1,
                                         lineBreakType, true, nullptr);
         if (NS_WARN_IF(NS_FAILED(rv))) {
@@ -1619,16 +1620,40 @@ ContentEventHandler::OnQueryTextRectArra
     } else {
       rv = firstFrame->GetCharacterRectsInRange(firstFrame.mStartOffsetInNode,
                                                 kEndOffset - offset, charRects);
       if (NS_WARN_IF(NS_FAILED(rv)) || NS_WARN_IF(charRects.IsEmpty())) {
         // XXX: If the node isn't a text node and does not cause a line break,
         //      we need to recompute with new range, but how?
         return rv;
       }
+      // Assign the characters whose rects are computed by the call of
+      // nsTextFrame::GetCharacterRectsInRange().
+      AppendSubString(chars, firstContent, firstFrame.mStartOffsetInNode,
+                      charRects.Length());
+      if (NS_WARN_IF(chars.Length() != charRects.Length())) {
+        return NS_ERROR_UNEXPECTED;
+      }
+      if (kBRLength > 1 && chars[0] == '\n' &&
+          offset == aEvent->mInput.mOffset && offset) {
+        // If start of range starting from previous offset of query range is
+        // same as the start of query range, the query range starts from
+        // between a line breaker (i.e., the range starts between "\r" and
+        // "\n").
+        RefPtr<nsRange> rangeToPrevOffset = new nsRange(mRootContent);
+        rv = SetRangeFromFlatTextOffset(rangeToPrevOffset,
+                                        aEvent->mInput.mOffset - 1, 1,
+                                        lineBreakType, true, nullptr);
+        if (NS_WARN_IF(NS_FAILED(rv))) {
+          return rv;
+        }
+        startsBetweenLineBreaker =
+          range->GetStartParent() == rangeToPrevOffset->GetStartParent() &&
+          range->StartOffset() == rangeToPrevOffset->StartOffset();
+      }
     }
 
     for (size_t i = 0; i < charRects.Length() && offset < kEndOffset; i++) {
       nsRect charRect = charRects[i];
       charRect.x += frameRect.x;
       charRect.y += frameRect.y;
 
       rect = LayoutDeviceIntRect::FromUnknownRect(
@@ -1637,17 +1662,17 @@ ContentEventHandler::OnQueryTextRectArra
       // return non-empty rect.
       EnsureNonEmptyRect(rect);
 
       aEvent->mReply.mRectArray.AppendElement(rect);
       offset++;
 
       // If it's not a line breaker or the line breaker length is same as
       // XP line breaker's, we need to do nothing for current character.
-      if (!isLineBreaker || kBRLength == 1) {
+      if (chars[i] != '\n' || kBRLength == 1) {
         continue;
       }
 
       MOZ_ASSERT(kBRLength == 2);
 
       // If it's already reached the end of query range, we don't need to do
       // anymore.
       if (offset == kEndOffset) {