Bug 489306 - overflowed content doesn't expose child text accessibles, r=marcoz, davidb, a=beltzner
authorAlexander Surkov <surkov.alexander@gmail.com>
Wed, 06 May 2009 11:23:58 +0800
changeset 25091 fe1a4c1e4fa0d3fac97de1785956724c63b44339
parent 25090 38c2817eba84d7ad8b1a9af82cba18693a1a2213
child 25092 8fdd47a7ad89f4395c09a5f40f7362fd4e62c189
push id1351
push usersurkov.alexander@gmail.com
push dateWed, 06 May 2009 02:24:36 +0000
reviewersmarcoz, davidb, beltzner
bugs489306
milestone1.9.1b5pre
Bug 489306 - overflowed content doesn't expose child text accessibles, r=marcoz, davidb, a=beltzner
accessible/src/base/nsAccessibleTreeWalker.cpp
accessible/src/base/nsAccessibleTreeWalker.h
accessible/tests/mochitest/Makefile.in
accessible/tests/mochitest/common.js
accessible/tests/mochitest/test_elm_txtcntnr.html
--- a/accessible/src/base/nsAccessibleTreeWalker.cpp
+++ b/accessible/src/base/nsAccessibleTreeWalker.cpp
@@ -71,17 +71,16 @@ nsAccessibleTreeWalker::~nsAccessibleTre
 
 void nsAccessibleTreeWalker::GetKids(nsIDOMNode *aParentNode)
 {
   nsCOMPtr<nsIContent> parentContent(do_QueryInterface(aParentNode));
   if (!parentContent || !parentContent->IsNodeOfType(nsINode::eHTML)) {
     mState.frame = nsnull;  // Don't walk frames in non-HTML content, just walk the DOM.
   }
 
-  PushState();
   UpdateFrame(PR_TRUE);
 
   // Walk frames? UpdateFrame() sets this when it sees anonymous frames
   if (mState.siblingIndex == eSiblingsWalkFrames) {
     return;
   }
 
   // Walk anonymous content? Not currently used for HTML -- anonymous content there uses frame walking
@@ -205,16 +204,18 @@ NS_IMETHODIMP nsAccessibleTreeWalker::Ge
 NS_IMETHODIMP nsAccessibleTreeWalker::GetFirstChild()
 {
   mState.accessible = nsnull;
   if (mState.isHidden || !mState.domNode) {
     return NS_ERROR_FAILURE;
   }
 
   nsCOMPtr<nsIDOMNode> parent(mState.domNode);
+
+  PushState();
   GetKids(parent); // Side effects change our state (mState)
 
   // Recursive loop: depth first search for first accessible child
   while (mState.domNode) {
     if ((mState.domNode != parent && GetAccessible()) || NS_SUCCEEDED(GetFirstChild()))
       return NS_OK;
     UpdateFrame(PR_FALSE);
     GetNextDOMNode();
--- a/accessible/src/base/nsAccessibleTreeWalker.h
+++ b/accessible/src/base/nsAccessibleTreeWalker.h
@@ -68,30 +68,71 @@ struct WalkState {
   */
 
 class nsAccessibleTreeWalker {
 public:
   nsAccessibleTreeWalker(nsIWeakReference* aShell, nsIDOMNode* aContent, 
     PRBool mWalkAnonymousContent);
   virtual ~nsAccessibleTreeWalker();
 
+  /**
+   * Moves current state to point to the next child accessible.
+   */
   NS_IMETHOD GetNextSibling();
+
+  /**
+   * Moves current state to point to the first child accessible.
+   */
   NS_IMETHOD GetFirstChild();
 
+  /**
+   * Current state. Used to initialize a11y tree walker and to get an accessible
+   * current state points to.
+   */
   WalkState mState;
 
 protected:
+
+  /**
+   * Return true if currently navigated node/frame is accessible.
+   */
   PRBool GetAccessible();
+
+  /**
+   * Prepares current state to navigate through children of node/frame.
+   */
   void GetKids(nsIDOMNode *aParent);
 
+  /**
+   * Clears the current state.
+   */
   void ClearState();
+
+  /**
+   * Push current state on top of stack. State stack is used to navigate down to
+   * DOM/frame subtree duiring searching of accessible children.
+   */
   NS_IMETHOD PushState();
+
+  /**
+   * Pop state from stack and makes it current.
+   */
   NS_IMETHOD PopState();
 
+  /**
+   * Change current state so that its frame is changed to next frame.
+   *
+   * @param  aTryFirstChild  [in] points whether we should move to child or
+   *                         sibling frame
+   */
   void UpdateFrame(PRBool aTryFirstChild);
+
+  /**
+   * Change current state so that its node is changed to next node.
+   */
   void GetNextDOMNode();
 
   nsCOMPtr<nsIWeakReference> mWeakShell;
   nsCOMPtr<nsIAccessibilityService> mAccService;
   PRBool mWalkAnonContent;
 };
 
 #endif 
--- a/accessible/tests/mochitest/Makefile.in
+++ b/accessible/tests/mochitest/Makefile.in
@@ -62,16 +62,17 @@ include $(topsrcdir)/config/rules.mk
 		test_aria_activedescendant.html \
 		test_aria_role_article.html \
 		test_aria_role_equation.html \
  		test_aria_token_attrs.html \
 		$(warning test_bug368835.xul temporarily disabled) \
 		test_bug420863.html \
 		$(warning	test_childAtPoint.xul temporarily disabled) \
 		test_cssattrs.html \
+		test_elm_txtcntnr.html \
 		test_events_caretmove.html \
 		test_events_mutation.html \
 		$(warning test_groupattrs.xul temporarily disabled) \
 	$(warning test_table_indexes.html temporarily disabled) \
  		test_nsHyperTextAcc_roles.html \
 		test_nsIAccessible_actions.html \
 		$(warning test_nsIAccessible_actions.xul temporarily disabled) \
 		test_nsIAccessible_applicationAccessible.html \
--- a/accessible/tests/mochitest/common.js
+++ b/accessible/tests/mochitest/common.js
@@ -242,16 +242,47 @@ function getAccessible(aAccOrElmOrID, aI
  * Return true if the given identifier has an accessible.
  */
 function isAccessible(aAccOrElmOrID)
 {
   return getAccessible(aAccOrElmOrID, null, null, true) ? true : false;
 }
 
 /**
+ * Compare expected and actual accessibles trees.
+ */
+function testAccessibleTree(aAccOrElmOrID, aAccTree)
+{
+  var acc = getAccessible(aAccOrElmOrID);
+  if (!acc)
+    return;
+
+  for (var prop in aAccTree) {
+    var msg = "Wrong value of property '" + prop + "'.";
+    if (prop == "role")
+      is(roleToString(acc[prop]), roleToString(aAccTree[prop]), msg);
+    else if (prop != "children")
+      is(acc[prop], aAccTree[prop], msg);
+  }
+
+  if ("children" in aAccTree) {
+    var children = acc.children;
+    is(aAccTree.children.length, children.length,
+       "Different amount of expected children.");
+
+    if (aAccTree.children.length == children.length) { 
+      for (var i = 0; i < children.length; i++) {
+        var child = children.queryElementAt(i, nsIAccessible);
+        testAccessibleTree(child, aAccTree.children[i]);
+      }
+    }
+  }
+}
+
+/**
  * Convert role to human readable string.
  */
 function roleToString(aRole)
 {
   return gAccRetrieval.getStringRole(aRole);
 }
 
 /**
new file mode 100644
--- /dev/null
+++ b/accessible/tests/mochitest/test_elm_txtcntnr.html
@@ -0,0 +1,57 @@
+<!DOCTYPE html>
+<html>
+
+<head>
+  <title>HTML text containers tests</title>
+  <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css" />
+
+  <script type="application/javascript"
+          src="chrome://mochikit/content/MochiKit/packed.js"></script>
+  <script type="application/javascript"
+          src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+
+  <script type="application/javascript"
+          src="chrome://mochikit/content/a11y/accessible/common.js"></script>
+  <script type="application/javascript"
+          src="chrome://mochikit/content/a11y/accessible/role.js"></script>
+
+  <script type="application/javascript">
+    function doTest()
+    {
+      var accTree = {
+        role: ROLE_SECTION,
+        children: [
+          { // text child
+            role: ROLE_TEXT_LEAF
+          }
+        ]
+      };
+
+      testAccessibleTree("c1", accTree);
+      testAccessibleTree("c2", accTree);
+
+      SimpleTest.finish();
+    }
+
+    SimpleTest.waitForExplicitFinish();
+    addLoadEvent(doTest);
+  </script>
+</head>
+<body>
+
+  <a target="_blank"
+     title="overflowed content doesn't expose child text accessibles"
+     href="https://bugzilla.mozilla.org/show_bug.cgi?id=489306">Mozilla Bug 489306</a>
+  <p id="display"></p>
+  <div id="content" style="display: none"></div>
+  <pre id="test">
+  </pre>
+
+  <div id="c1" style="width: 100px; height: 100px; overflow: auto;">
+    1hellohello 2hellohello 3hellohello 4hellohello 5hellohello 6hellohello 7hellohello
+  </div>
+  <div id="c2">
+    1hellohello 2hellohello 3hellohello 4hellohello 5hellohello 6hellohello 7hellohello
+  </div>
+</body>
+</html>