Bug 935375 - Word offsets broken if the next word is an embedded object. r=tbsaunde, a=lsblakk
authorAlexander Surkov <surkov.alexander@gmail.com>
Thu, 19 Dec 2013 09:51:00 -0500
changeset 175411 7a42668c79b014fd8cb74375fbaf7a94bfa6ca70
parent 175410 a1aa4c58f887a378099a9c36d98576fcad3511bf
child 175412 ce854959b0a0358029f6fa42d6645789ecb9a9e5
push id445
push userffxbld
push dateMon, 10 Mar 2014 22:05:19 +0000
treeherdermozilla-release@dc38b741b04e [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerstbsaunde, lsblakk
bugs935375
milestone28.0a2
Bug 935375 - Word offsets broken if the next word is an embedded object. r=tbsaunde, a=lsblakk
accessible/src/generic/HyperTextAccessible.cpp
accessible/tests/mochitest/text/test_wordboundary.html
--- a/accessible/src/generic/HyperTextAccessible.cpp
+++ b/accessible/src/generic/HyperTextAccessible.cpp
@@ -601,56 +601,57 @@ HyperTextAccessible::HypertextOffsetsToD
   return aRange->SetEnd(endPoint.node, endPoint.idx);
 }
 
 int32_t
 HyperTextAccessible::FindOffset(int32_t aOffset, nsDirection aDirection,
                                 nsSelectionAmount aAmount,
                                 EWordMovementType aWordMovementType)
 {
-  // Convert hypertext offset to frame-relative offset.
-  int32_t offsetInFrame = aOffset, notUsedOffset = aOffset;
-  nsRefPtr<Accessible> accAtOffset;
-  nsIFrame* frameAtOffset =
-    GetPosAndText(offsetInFrame, notUsedOffset, nullptr, nullptr,
-                  getter_AddRefs(accAtOffset));
-  if (!frameAtOffset) {
-    if (aOffset == CharacterCount()) {
-      // Asking for start of line, while on last character.
-      if (accAtOffset)
-        frameAtOffset = accAtOffset->GetFrame();
-    }
-    NS_ASSERTION(frameAtOffset, "No start frame for text getting!");
-    if (!frameAtOffset)
+  // Find a leaf accessible frame to start with. PeekOffset wants this.
+  HyperTextAccessible* text = this;
+  Accessible* child = nullptr;
+  int32_t innerOffset = aOffset;
+
+  do {
+    int32_t childIdx = text->GetChildIndexAtOffset(innerOffset);
+    NS_ASSERTION(childIdx != -1, "Bad in offset!");
+    if (childIdx == -1)
       return -1;
 
-    // We're on the last continuation since we're on the last character.
-    frameAtOffset = frameAtOffset->LastContinuation();
+    child = text->GetChildAt(childIdx);
+    innerOffset -= text->GetChildOffset(childIdx);
+
+    text = child->AsHyperText();
+  } while (text);
+
+  nsIFrame* childFrame = child->GetFrame();
+  NS_ENSURE_TRUE(childFrame, -1);
+
+  int32_t innerContentOffset = innerOffset;
+  if (child->IsTextLeaf()) {
+    NS_ASSERTION(childFrame->GetType() == nsGkAtoms::textFrame, "Wrong frame!");
+    RenderedToContentOffset(childFrame, innerOffset, &innerContentOffset);
   }
 
-  // Return hypertext offset of the boundary of the found word.
-  int32_t contentOffset = offsetInFrame;
-  nsIFrame* primaryFrame = accAtOffset->GetFrame();
-  NS_ENSURE_TRUE(primaryFrame, -1);
-
-  nsresult rv = NS_OK;
-  if (primaryFrame->GetType() == nsGkAtoms::textFrame) {
-    rv = RenderedToContentOffset(primaryFrame, offsetInFrame, &contentOffset);
-    NS_ENSURE_SUCCESS(rv, -1);
-  }
+  nsIFrame* frameAtOffset = childFrame;
+  int32_t unusedOffsetInFrame = 0;
+  childFrame->GetChildFrameContainingOffset(innerContentOffset, true,
+                                            &unusedOffsetInFrame,
+                                            &frameAtOffset);
 
   const bool kIsJumpLinesOk = true; // okay to jump lines
   const bool kIsScrollViewAStop = false; // do not stop at scroll views
   const bool kIsKeyboardSelect = true; // is keyboard selection
   const bool kIsVisualBidi = false; // use visual order for bidi text
-  nsPeekOffsetStruct pos(aAmount, aDirection, contentOffset,
+  nsPeekOffsetStruct pos(aAmount, aDirection, innerContentOffset,
                          0, kIsJumpLinesOk, kIsScrollViewAStop,
                          kIsKeyboardSelect, kIsVisualBidi,
                          aWordMovementType);
-  rv = frameAtOffset->PeekOffset(&pos);
+  nsresult rv = frameAtOffset->PeekOffset(&pos);
 
   // PeekOffset fails on last/first lines of the text in certain cases.
   if (NS_FAILED(rv) && aAmount == eSelectLine) {
     pos.mAmount = (aDirection == eDirNext) ? eSelectEndLine : eSelectBeginLine;
     frameAtOffset->PeekOffset(&pos);
   }
   if (!pos.mResultContent)
     return -1;
--- a/accessible/tests/mochitest/text/test_wordboundary.html
+++ b/accessible/tests/mochitest/text/test_wordboundary.html
@@ -217,16 +217,29 @@
       testTextAfterOffset(ids, BOUNDARY_WORD_END,
                            [ [ 0, 7, "\n\ntwo", 7, 12 ],
                              [ 8, 12, " words", 12, 18 ],
                              [ 13, 18, "\n", 18, 19,
                                [ [ 18, "ml_divbr1", kTodo, kTodo, kOk ],
                                  [ 18, "ml_edivbr1", kTodo, kTodo, kOk ] ] ],
                              [ 19, 19, "", 19, 19 ] ]);
 
+      // a <a href="#">b</a>
+      // a *
+      testTextBeforeOffset("cntr_1", BOUNDARY_WORD_START,
+                           [ [ 0, 1, "", 0, 0 ],
+                             [ 2, 3, "a ", 0, 2 ] ]);
+
+      testTextAtOffset("cntr_1", BOUNDARY_WORD_START,
+                       [ [ 0, 1, "a ", 0, 2 ],
+                         [ 2, 3, kEmbedChar, 2, 3 ] ]);
+      testTextAfterOffset("cntr_1", BOUNDARY_WORD_START,
+                           [ [ 0, 1, kEmbedChar, 2, 3 ],
+                             [ 2, 3, "", 3, 3 ] ]);
+
       SimpleTest.finish();
     }
 
     SimpleTest.waitForExplicitFinish();
     addA11yLoadEvent(doTest);
   </script>
 </head>
 <body>
@@ -275,10 +288,11 @@ two words
 </div>
 <div id="ml_edivbr1" contenteditable="true">oneword<br/><br/>two words<br/><br/></div>
 <textarea id="ml_t1" cols="300">oneword
 
 two words
 </textarea>
   </pre>
 
+  <div id="cntr_1">a <a href="#">b</a></div>
 </body>
 </html>