bug 428248 - Implement tests for nsIAccessibleHyperText interface r=Alexander Surkov (surkov.alexander@gmail.com) a1.9=beltzner
authormarco.zehe@googlemail.com
Fri, 11 Apr 2008 00:22:32 -0700
changeset 14209 02aaeeccd9798ec6e677ed2460b9a84f433bfb0c
parent 14208 0a8fa3ff172c34338b088d1eb35b8fe53bc9d78a
child 14210 82cebd3193dcde46d8dbbf8b9f142d11603c18f2
push idunknown
push userunknown
push dateunknown
reviewersAlexander
bugs428248
milestone1.9pre
bug 428248 - Implement tests for nsIAccessibleHyperText interface r=Alexander Surkov (surkov.alexander@gmail.com) a1.9=beltzner
accessible/public/nsIAccessibleHyperText.idl
accessible/src/atk/nsAccessibleWrap.cpp
accessible/src/atk/nsMaiInterfaceHypertext.cpp
accessible/src/html/nsHyperTextAccessible.cpp
accessible/src/msaa/CAccessibleHypertext.cpp
accessible/tests/mochitest/Makefile.in
accessible/tests/mochitest/test_nsIAccessibleHyperText.html
--- a/accessible/public/nsIAccessibleHyperText.idl
+++ b/accessible/public/nsIAccessibleHyperText.idl
@@ -37,21 +37,43 @@
  * the provisions above, a recipient may use your version of this file under
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
 #include "nsISupports.idl"
 #include "nsIAccessibleHyperLink.idl"
 
-[scriptable, uuid(dec56474-2887-4d44-9826-1594cfe4a2f4)]
+/**
+ * A cross-platform interface that deals with text which contains hyperlinks.
+ */
+
+[scriptable, uuid(d56bd454-8ff3-4edc-b266-baeada00267b)]
 interface nsIAccessibleHyperText : nsISupports
 {
-  readonly attribute long links;
-
-  nsIAccessibleHyperLink getLink (in long index);
+  /**
+   * Returns the number of links contained within this hypertext object.
+   */
+  readonly attribute long linkCount;
 
   /*
-   * Return the link index at this character index.
-   * Return value of -1 indicates no link at that index.
+   * Returns the link index at the given character index.
+   * Each link is an embedded object representing exactly 1 character within
+   * the hypertext.
+   *
+   * @param charIndex  the 0-based character index.
+   *
+   * @returns long  0-based link's index.
+   * A return value of -1 indicates no link is present at that index.
    */
-  long getLinkIndex (in long charIndex);
+  long getLinkIndex(in long charIndex);
+
+  /**
+   * Retrieves the nsIAccessibleHyperLink object at the given link index.
+   *
+   * @param linkIndex  0-based index of the link that is to be retrieved.
+   * This can be retrieved via getLinkIndex (see above).
+   *
+   * @returns nsIAccessibleHyperLink  Object representing the link properties
+   * or NS_ERROR_INVALID_ARG if there is no link at that index.
+   */
+  nsIAccessibleHyperLink getLink(in long linkIndex);
 };
--- a/accessible/src/atk/nsAccessibleWrap.cpp
+++ b/accessible/src/atk/nsAccessibleWrap.cpp
@@ -868,17 +868,17 @@ getChildCountCB(AtkObject *aAtkObj)
         return 0;
     }
 
     PRInt32 count = 0;
     nsCOMPtr<nsIAccessibleHyperText> hyperText;
     accWrap->QueryInterface(NS_GET_IID(nsIAccessibleHyperText), getter_AddRefs(hyperText));
     if (hyperText) {
         // If HyperText, then number of links matches number of children
-        hyperText->GetLinks(&count);
+        hyperText->GetLinkCount(&count);
     }
     else {
         nsCOMPtr<nsIAccessibleText> accText;
         accWrap->QueryInterface(NS_GET_IID(nsIAccessibleText), getter_AddRefs(accText));
         if (!accText) {    // Accessible text that is not a HyperText has no children
             accWrap->GetChildCount(&count);
         }
     }
--- a/accessible/src/atk/nsMaiInterfaceHypertext.cpp
+++ b/accessible/src/atk/nsMaiInterfaceHypertext.cpp
@@ -87,17 +87,17 @@ getLinkCountCB(AtkHypertext *aText)
         return -1;
 
     nsCOMPtr<nsIAccessibleHyperText> hyperText;
     accWrap->QueryInterface(NS_GET_IID(nsIAccessibleHyperText),
                             getter_AddRefs(hyperText));
     NS_ENSURE_TRUE(hyperText, -1);
 
     PRInt32 count = -1;
-    nsresult rv = hyperText->GetLinks(&count);
+    nsresult rv = hyperText->GetLinkCount(&count);
     NS_ENSURE_SUCCESS(rv, -1);
 
     return count;
 }
 
 gint
 getLinkIndexCB(AtkHypertext *aText, gint aCharIndex)
 {
--- a/accessible/src/html/nsHyperTextAccessible.cpp
+++ b/accessible/src/html/nsHyperTextAccessible.cpp
@@ -1266,54 +1266,59 @@ nsHyperTextAccessible::GetOffsetAtPoint(
     NS_ENSURE_TRUE(textLength >= 0, NS_ERROR_FAILURE);
     offset += textLength;
   }
 
   return NS_OK; // Not found, will return -1
 }
 
 // ------- nsIAccessibleHyperText ---------------
-NS_IMETHODIMP nsHyperTextAccessible::GetLinks(PRInt32 *aLinks)
+NS_IMETHODIMP
+nsHyperTextAccessible::GetLinkCount(PRInt32 *aLinkCount)
 {
-  *aLinks = 0;
+  NS_ENSURE_ARG_POINTER(aLinkCount);
+  *aLinkCount = 0;
   if (!mDOMNode) {
     return NS_ERROR_FAILURE;
   }
 
   nsCOMPtr<nsIAccessible> accessible;
 
   while (NextChild(accessible)) {
     if (IsEmbeddedObject(accessible)) {
-      ++*aLinks;
+      ++*aLinkCount;
     }
   }
   return NS_OK;
 }
 
 
 NS_IMETHODIMP
-nsHyperTextAccessible::GetLink(PRInt32 aIndex, nsIAccessibleHyperLink **aLink)
+nsHyperTextAccessible::GetLink(PRInt32 aLinkIndex, nsIAccessibleHyperLink **aLink)
 {
   NS_ENSURE_ARG_POINTER(aLink);
   *aLink = nsnull;
 
   if (IsDefunct())
     return NS_ERROR_FAILURE;
 
+  PRInt32 linkIndex = aLinkIndex;
   nsCOMPtr<nsIAccessible> accessible;
   while (NextChild(accessible)) {
-    if (IsEmbeddedObject(accessible) && aIndex-- == 0)
+    if (IsEmbeddedObject(accessible) && linkIndex-- == 0)
       return CallQueryInterface(accessible, aLink);
   }
 
   return NS_ERROR_INVALID_ARG;
 }
 
-NS_IMETHODIMP nsHyperTextAccessible::GetLinkIndex(PRInt32 aCharIndex, PRInt32 *aLinkIndex)
+NS_IMETHODIMP
+nsHyperTextAccessible::GetLinkIndex(PRInt32 aCharIndex, PRInt32 *aLinkIndex)
 {
+  NS_ENSURE_ARG_POINTER(aLinkIndex);
   *aLinkIndex = -1; // API says this magic value means 'not found'
 
   PRInt32 characterCount = 0;
   PRInt32 linkIndex = 0;
   if (!mDOMNode) {
     return NS_ERROR_FAILURE;
   }
 
--- a/accessible/src/msaa/CAccessibleHypertext.cpp
+++ b/accessible/src/msaa/CAccessibleHypertext.cpp
@@ -75,40 +75,40 @@ CAccessibleHypertext::get_nHyperlinks(lo
 __try {
   *aHyperlinkCount = 0;
 
   nsCOMPtr<nsIAccessibleHyperText> hyperAcc(do_QueryInterface(this));
   if (!hyperAcc)
     return E_FAIL;
 
   PRInt32 count = 0;
-  nsresult rv = hyperAcc->GetLinks(&count);
+  nsresult rv = hyperAcc->GetLinkCount(&count);
   if (NS_FAILED(rv))
     return GetHRESULT(rv);
 
   *aHyperlinkCount = count;
   return S_OK;
 
 } __except(nsAccessNodeWrap::FilterA11yExceptions(::GetExceptionCode(), GetExceptionInformation())) { }
   return E_FAIL;
 }
 
 STDMETHODIMP
-CAccessibleHypertext::get_hyperlink(long aIndex,
+CAccessibleHypertext::get_hyperlink(long aLinkIndex,
                                     IAccessibleHyperlink **aHyperlink)
 {
 __try {
   *aHyperlink = NULL;
 
   nsCOMPtr<nsIAccessibleHyperText> hyperAcc(do_QueryInterface(this));
   if (!hyperAcc)
     return E_FAIL;
 
   nsCOMPtr<nsIAccessibleHyperLink> hyperLink;
-  nsresult rv = hyperAcc->GetLink(aIndex, getter_AddRefs(hyperLink));
+  nsresult rv = hyperAcc->GetLink(aLinkIndex, getter_AddRefs(hyperLink));
   if (NS_FAILED(rv))
     return GetHRESULT(rv);
 
   nsCOMPtr<nsIWinAccessNode> winAccessNode(do_QueryInterface(hyperLink));
   if (!winAccessNode)
     return E_FAIL;
 
   void *instancePtr = NULL;
--- a/accessible/tests/mochitest/Makefile.in
+++ b/accessible/tests/mochitest/Makefile.in
@@ -51,12 +51,13 @@ include $(topsrcdir)/config/rules.mk
 		test_groupattrs.xul \
 		test_table_indexes.html \
 		test_nsIAccessibleTable_1.html \
 		test_nsIAccessibleTable_2.html \
 		test_nsIAccessibleTable_3.html \
 		test_nsIAccessibleTable_4.html \
 		test_nsIAccessibleTable_listboxes.xul \
 		test_nsIAccessibleHyperLink.html \
+		test_nsIAccessibleHyperText.html \
 		$(NULL)
 
 libs:: $(_TEST_FILES)
 	$(INSTALL) $(foreach f,$^,"$f") $(DEPTH)/_tests/testing/mochitest/a11y/$(relativesrcdir)
new file mode 100644
--- /dev/null
+++ b/accessible/tests/mochitest/test_nsIAccessibleHyperText.html
@@ -0,0 +1,114 @@
+<!DOCTYPE html>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=428248
+-->
+<head>
+  <title>nsIHyper>TextAccessible chrome 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">
+    var gParagraphAcc;
+
+    function testThis(aID, aCharIndex, aExpectedLinkIndex, aName)
+    {
+      is(gParagraphAcc.getLinkIndex(aCharIndex), aExpectedLinkIndex,
+         "Wrong link index for ID " + aID + "!");
+      var linkAcc;
+      try {
+        linkAcc = gParagraphAcc.getLink(aExpectedLinkIndex);
+      } catch(e) {
+        ok(linkAcc, "No accessible for link " + aID + "!");
+      }
+      // Just test the link's name to make sure we get the right one.
+      is(linkAcc.getAnchor(0).name, aName, "Wrong name for " + aID + "!");
+    }
+
+    function doTest()
+    {
+      var accService = Components.classes["@mozilla.org/accessibleRetrieval;1"].
+                       getService(Components.interfaces.nsIAccessibleRetrieval);
+
+      var paragraphElement = document.getElementById("testParagraph");
+      try {
+        gParagraphAcc = accService.getAccessibleFor(paragraphElement).
+            QueryInterface(Components.interfaces.nsIAccessibleHyperText);
+      } catch(e) {
+        ok(gParagraphAcc, "No interface for the paragraph!");
+      }
+
+      // Test link count
+      is(gParagraphAcc.linkCount, 7, "Wrong link count for paragraph!");
+
+      // normal hyperlink
+      testThis("NormalHyperlink", 14, 0, "Mozilla Foundation");
+
+      // ARIA hyperlink
+      testThis("AriaHyperlink", 28, 1, "Mozilla Foundation Home");
+
+      // ARIA hyperlink with status invalid
+      testThis("InvalidAriaHyperlink", 64, 2, "Invalid link");
+
+      // image map, but not its link children. They are not part of hypertext.
+      testThis("imgmap", 78, 3, "b");
+
+      // empty hyperlink
+      testThis("emptyLink", 93, 4, "");
+
+      // normal hyperlink with embedded span
+      testThis("LinkWithSpan", 119, 5, "Heise Online");
+
+      // Named anchor
+      testThis("namedAnchor", 197, 6, "This should never be of state_linked");
+
+      SimpleTest.finish();
+    }
+
+    SimpleTest.waitForExplicitFinish();
+    addLoadEvent(doTest);
+  </script>
+</head>
+<body>
+
+  <a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=418368">Mozilla Bug 418368</a>
+  <p id="display"></p>
+  <div id="content" style="display: none"></div>
+  <pre id="test">
+  </pre>
+  <p id="testParagraph">  
+    <br>Simple link:<br>
+    <a id="NormalHyperlink" href="http://www.mozilla.org">Mozilla Foundation</a>
+    <br>ARIA link:<br>
+    <span id="AriaHyperlink" role="link"
+           onclick="window.open('http://www.mozilla.org/');"
+           tabindex="0">Mozilla Foundation Home</span>
+    <br>Invalid, non-focusable hyperlink:<br>
+    <span id="InvalidAriaHyperlink" role="link" aria-invalid="true"
+          onclick="window.open('http:/www.mozilla.org/');">Invalid link</span>
+    <br>Image map:<br>
+    <map name="atoz_map">
+      <area href="http://www.bbc.co.uk/radio4/atoz/index.shtml#b"
+            coords="17,0,30,14"
+            alt="b"
+            shape="rect"></area>
+      <area href="http://www.bbc.co.uk/radio4/atoz/index.shtml#a"
+            coords="0,0,13,14"
+            alt="a"
+            shape="rect"></area>
+    </map>
+    <img width="447" id="imgmap"
+         height="15"
+         usemap="#atoz_map"
+         src="http://www.bbc.co.uk/radio4/images/letters.gif"></img>
+    <br>Empty link:<br>
+    <a id="emptyLink" href=""><img src=""></img></a>
+    <br>Link with embedded span<br>
+    <a id="LinkWithSpan" href="http://www.heise.de/"><span lang="de">Heise Online</span></a>
+    <br>Named anchor, must not have "linked" state for it to be exposed correctly:<br>
+    <a id="namedAnchor" name="named_anchor">This should never be of state_linked</a>
+  </p>
+</body>
+</html>