Bug 896326 - Accessibility may return empty lines where there are embedded objects, r=tbsaunde
authorAlexander Surkov <surkov.alexander@gmail.com>
Fri, 26 Jul 2013 10:41:25 -0400
changeset 140150 0f8523d1dfe93930c76667f895f75f0b0b133132
parent 140149 9a39f63704fa62d91de4112b8430929a0bcdb323
child 140151 8a6e3d2291836f26b0787f554be3d989b686ceec
push id25016
push userryanvm@gmail.com
push dateSat, 27 Jul 2013 02:25:56 +0000
treeherdermozilla-central@fb48c7d58b8b [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerstbsaunde
bugs896326
milestone25.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 896326 - Accessibility may return empty lines where there are embedded objects, r=tbsaunde
accessible/src/generic/HyperTextAccessible.cpp
accessible/tests/mochitest/common.js
accessible/tests/mochitest/text/test_atcaretoffset.html
accessible/tests/mochitest/text/test_lineboundary.html
--- a/accessible/src/generic/HyperTextAccessible.cpp
+++ b/accessible/src/generic/HyperTextAccessible.cpp
@@ -713,43 +713,29 @@ HyperTextAccessible::GetRelativeOffset(n
     rv = RenderedToContentOffset(frame, aFromOffset, &contentOffset);
     NS_ENSURE_SUCCESS(rv, -1);
   }
 
   nsPeekOffsetStruct pos(aAmount, aDirection, contentOffset,
                          0, kIsJumpLinesOk, kIsScrollViewAStop, kIsKeyboardSelect, kIsVisualBidi,
                          aWordMovementType);
   rv = aFromFrame->PeekOffset(&pos);
-  if (NS_FAILED(rv)) {
-    pos.mResultContent = aFromFrame->GetContent();
-    if (aDirection == eDirPrevious) {
-      // Use passed-in frame as starting point in failure case for now,
-      // this is a hack to deal with starting on a list bullet frame,
-      // which fails in PeekOffset() because the line iterator doesn't see it.
-      // XXX Need to look at our overall handling of list bullets, which are an odd case
-      int32_t endOffsetUnused;
-      aFromFrame->GetOffsets(pos.mContentOffset, endOffsetUnused);
-    }
-    else {
-      // XXX: PeekOffset fails on a last frame in the document for
-      // eSelectLine/eDirNext. DOM selection (up/down arrowing processing) has
-      // similar code to handle this case. One day it should be incorporated
-      // into PeekOffset.
-      int32_t startOffsetUnused;
-      aFromFrame->GetOffsets(startOffsetUnused, pos.mContentOffset);
-    }
+
+  // PeekOffset fails on last/first lines of the text in certain cases.
+  if (NS_FAILED(rv) && aAmount == eSelectLine) {
+    pos.mAmount = (aDirection == eDirNext) ? eSelectEndLine : eSelectBeginLine;
+    aFromFrame->PeekOffset(&pos);
   }
-
-  // Turn the resulting node and offset into a hyperTextOffset
-  int32_t hyperTextOffset;
   if (!pos.mResultContent)
     return -1;
 
+  // Turn the resulting node and offset into a hyperTextOffset
   // If finalAccessible is nullptr, then DOMPointToHypertextOffset() searched
   // through the hypertext children without finding the node/offset position.
+  int32_t hyperTextOffset;
   Accessible* finalAccessible =
     DOMPointToHypertextOffset(pos.mResultContent, pos.mContentOffset,
                               &hyperTextOffset, aDirection == eDirNext);
 
   if (!finalAccessible && aDirection == eDirPrevious) {
     // If we reached the end during search, this means we didn't find the DOM point
     // and we're actually at the start of the paragraph
     hyperTextOffset = 0;
--- a/accessible/tests/mochitest/common.js
+++ b/accessible/tests/mochitest/common.js
@@ -153,28 +153,28 @@ function isObject(aObj, aExpectedObj, aM
 }
 
 ////////////////////////////////////////////////////////////////////////////////
 // Helpers for getting DOM node/accessible
 
 /**
  * Return the DOM node by identifier (may be accessible, DOM node or ID).
  */
-function getNode(aAccOrNodeOrID)
+function getNode(aAccOrNodeOrID, aDocument)
 {
   if (!aAccOrNodeOrID)
     return null;
 
   if (aAccOrNodeOrID instanceof nsIDOMNode)
     return aAccOrNodeOrID;
 
   if (aAccOrNodeOrID instanceof nsIAccessible)
     return aAccOrNodeOrID.DOMNode;
 
-  node = document.getElementById(aAccOrNodeOrID);
+  node = (aDocument || document).getElementById(aAccOrNodeOrID);
   if (!node) {
     ok(false, "Can't get DOM element for " + aAccOrNodeOrID);
     return null;
   }
 
   return node;
 }
 
--- a/accessible/tests/mochitest/text/test_atcaretoffset.html
+++ b/accessible/tests/mochitest/text/test_atcaretoffset.html
@@ -110,17 +110,17 @@
 
       // __a__w__o__r__d__\n
       //  0  1  2  3  4  5
       // __t__w__o__ (soft line break)
       //  6  7  8  9
       // __w__o__r__d__s
       // 10 11 12 13 14 15
 
-      traverseTextByLines(gQueue, "textarea", 
+      traverseTextByLines(gQueue, "textarea",
                           [ [ "aword", "\n", 0, 5 ],
                             [ "two ", "", 6, 10 ],
                             [ "words", "", 10, 15 ]] );
 
       traverseTextByLines(gQueue, "ta_wrapped", 
                           [ [ "hi ", "", 0, 3 ],
                             [ "hello", "", 3, 8 ],
                             [ " my ", "", 8, 12 ],
--- a/accessible/tests/mochitest/text/test_lineboundary.html
+++ b/accessible/tests/mochitest/text/test_lineboundary.html
@@ -12,17 +12,18 @@
           src="../text.js"></script>
   <script type="application/javascript">
     function doTest()
     {
       //////////////////////////////////////////////////////////////////////////
       // __h__e__l__l__o__ __m__y__ __f__r__i__e__n__d__
       //  0  1  2  3  4  5  6  7  8  9 10 11 12 13 14 15
 
-      var IDs = [ "input", "div", "editable", "textarea" ];
+      var IDs = [ "input", "div", "editable", "textarea",
+                  getNode("ta", getNode("ta_cntr").contentDocument) ];
 
       testTextBeforeOffset(IDs, BOUNDARY_LINE_START,
                            [ [ 0, 15, "", 0, 0 ] ]);
       testTextBeforeOffset(IDs, BOUNDARY_LINE_END,
                            [ [ 0, 15, "", 0, 0 ] ]);
 
       testTextAtOffset(IDs, BOUNDARY_LINE_START,
                        [ [ 0, 15, "hello my friend", 0, 15 ] ]);
@@ -71,16 +72,36 @@
                             [ 8, 8, "two words\n", 9, 19 ],
                             [ 9, 19, "", 19, 19 ]]);
       testTextAfterOffset(IDs, BOUNDARY_LINE_END,
                           [ [ 0, 7, "\n", 7, 8 ],
                             [ 8, 8, "\ntwo words", 8, 18 ],
                             [ 9, 18, "\n", 18, 19 ],
                             [ 19, 19, "", 19, 19 ]]);
 
+      //////////////////////////////////////////////////////////////////////////
+      // a * b (* is embedded char for link)
+      testTextBeforeOffset([ getAccessible("ht_1").firstChild ], BOUNDARY_LINE_START,
+                           [ [ 0, 5, "", 0, 0 ] ]);
+
+      testTextBeforeOffset([ getAccessible("ht_1").firstChild ], BOUNDARY_LINE_END,
+                           [ [ 0, 5, "", 0, 0 ] ]);
+
+      testTextAtOffset([ getAccessible("ht_1").firstChild ], BOUNDARY_LINE_START,
+                       [ [ 0, 5, "a " + kEmbedChar + " c", 0, 5 ] ]);
+
+      testTextAtOffset([ getAccessible("ht_1").firstChild ], BOUNDARY_LINE_END,
+                       [ [ 0, 5, "a " + kEmbedChar + " c", 0, 5 ] ]);
+
+      testTextAfterOffset([ getAccessible("ht_1").firstChild ], BOUNDARY_LINE_START,
+                          [ [ 0, 5, "", 5, 5 ] ]);
+
+      testTextAfterOffset([ getAccessible("ht_1").firstChild ], BOUNDARY_LINE_END,
+                          [ [ 0, 5, "", 5, 5 ] ]);
+                           
       SimpleTest.finish();
     }
 
     SimpleTest.waitForExplicitFinish();
     addA11yLoadEvent(doTest);
   </script>
 </head>
 <body>
@@ -105,16 +126,18 @@
   <div id="content" style="display: none"></div>
   <pre id="test">
   </pre>
 
   <input id="input" value="hello my friend"/>
   <div id="div">hello my friend</div>
   <div id="editable" contenteditable="true">hello my friend</div>
   <textarea id="textarea">hello my friend</textarea>
+  <iframe id="ta_cntr"
+          src="data:text/html,<html><body><textarea id='ta'>hello my friend</textarea></body></html>"></iframe>
 
   <pre>
     <div id="ml_div">oneword
 
 two words
 </div>
   <div id="ml_divbr">oneword<br/><br/>two words<br/></div>
   <div id="ml_editable" contenteditable="true">oneword
@@ -122,10 +145,12 @@ two words
 two words
 </div>
   <div id="ml_editablebr" contenteditable="true">oneword<br/><br/>two words<br/></div>
   <textarea id="ml_textarea" cols="300">oneword
 
 two words
 </textarea>
   </pre>
+
+  <iframe id="ht_1" src="data:text/html,<html><body>a <a href=''>b</a> c</body></html>"></iframe>
 </body>
 </html>