Bug 652635 - Fallback missing @longdesc to aria-describedby pointing to <a href>, r=surkov, jonas
authorMark Capella <markcapella@twcny.rr.com>
Wed, 11 Apr 2012 15:16:00 +0900
changeset 95144 1a46ebf1b9d521489b0c685719df7ac19a30b080
parent 95143 b44a23917a99aa1a5e32306a42458a0893d24544
child 95145 ced9405748208b7dc216f7b8a6b33799cf634849
push id160
push userlsblakk@mozilla.com
push dateFri, 13 Jul 2012 18:18:57 +0000
treeherdermozilla-release@228ba1a111fc [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerssurkov, jonas
bugs652635
milestone14.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 652635 - Fallback missing @longdesc to aria-describedby pointing to <a href>, r=surkov, jonas
accessible/src/html/Makefile.in
accessible/src/html/nsHTMLImageAccessible.cpp
accessible/src/html/nsHTMLImageAccessible.h
accessible/tests/mochitest/test_nsIAccessibleImage.html
content/html/content/src/nsGenericHTMLElement.h
--- a/accessible/src/html/Makefile.in
+++ b/accessible/src/html/Makefile.in
@@ -70,11 +70,13 @@ EXPORTS = \
 FORCE_STATIC_LIB = 1
 
 include $(topsrcdir)/config/rules.mk
 
 LOCAL_INCLUDES = \
   -I$(srcdir)/../base \
   -I$(srcdir)/../generic \
   -I$(srcdir)/../xpcom \
+  -I$(srcdir)/../../../content/base/src \
+  -I$(srcdir)/../../../content/html/content/src \
   -I$(srcdir)/../../../layout/generic \
   -I$(srcdir)/../../../layout/xul/base/src \
   $(NULL)
--- a/accessible/src/html/nsHTMLImageAccessible.cpp
+++ b/accessible/src/html/nsHTMLImageAccessible.cpp
@@ -35,20 +35,22 @@
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
 #include "nsHTMLImageAccessible.h"
 
 #include "nsAccUtils.h"
 #include "Role.h"
+#include "AccIterator.h"
 #include "States.h"
 
 #include "imgIContainer.h"
 #include "imgIRequest.h"
+#include "nsGenericHTMLElement.h"
 #include "nsIDocument.h"
 #include "nsIImageLoadingContent.h"
 #include "nsILink.h"
 #include "nsIPresShell.h"
 #include "nsIServiceManager.h"
 #include "nsIDOMHTMLImageElement.h"
 #include "nsIDOMDocument.h"
 #include "nsPIDOMWindow.h"
@@ -141,47 +143,50 @@ nsHTMLImageAccessible::ActionCount()
 NS_IMETHODIMP
 nsHTMLImageAccessible::GetActionName(PRUint8 aIndex, nsAString& aName)
 {
   aName.Truncate();
 
   if (IsDefunct())
     return NS_ERROR_FAILURE;
 
-  if (IsValidLongDescIndex(aIndex)) {
+  if (IsLongDescIndex(aIndex) && HasLongDesc()) {
     aName.AssignLiteral("showlongdesc"); 
     return NS_OK;
   }
   return nsLinkableAccessible::GetActionName(aIndex, aName);
 }
 
 NS_IMETHODIMP
 nsHTMLImageAccessible::DoAction(PRUint8 aIndex)
 {
   if (IsDefunct())
     return NS_ERROR_FAILURE;
 
-  if (IsValidLongDescIndex(aIndex)) {
-    //get the long description uri and open in a new window
-    nsCOMPtr<nsIDOMHTMLImageElement> element(do_QueryInterface(mContent));
-    NS_ENSURE_TRUE(element, NS_ERROR_FAILURE);
+  // Get the long description uri and open in a new window.
+  if (!IsLongDescIndex(aIndex))
+    return nsLinkableAccessible::DoAction(aIndex);
 
-    nsAutoString longDesc;
-    nsresult rv = element->GetLongDesc(longDesc);
-    NS_ENSURE_SUCCESS(rv, rv);
+  nsCOMPtr<nsIURI> uri = GetLongDescURI();
+  if (!uri)
+    return NS_ERROR_INVALID_ARG;
 
-    nsIDocument* document = mContent->OwnerDoc();
-    nsCOMPtr<nsPIDOMWindow> piWindow = document->GetWindow();
-    nsCOMPtr<nsIDOMWindow> win = do_QueryInterface(piWindow);
-    NS_ENSURE_TRUE(win, NS_ERROR_FAILURE);
-    nsCOMPtr<nsIDOMWindow> tmp;
-    return win->Open(longDesc, EmptyString(), EmptyString(),
-                     getter_AddRefs(tmp));
-  }
-  return nsLinkableAccessible::DoAction(aIndex);
+  nsCAutoString utf8spec;
+  uri->GetSpec(utf8spec);
+  NS_ConvertUTF8toUTF16 spec(utf8spec);
+
+  nsIDocument* document = mContent->OwnerDoc();
+  nsCOMPtr<nsPIDOMWindow> piWindow = document->GetWindow();
+  nsCOMPtr<nsIDOMWindow> win = do_QueryInterface(piWindow);
+  NS_ENSURE_STATE(win);
+
+  nsCOMPtr<nsIDOMWindow> tmp;
+  return win->Open(spec, EmptyString(), EmptyString(),
+                   getter_AddRefs(tmp));
+
 }
 
 ////////////////////////////////////////////////////////////////////////////////
 // nsIAccessibleImage
 
 NS_IMETHODIMP
 nsHTMLImageAccessible::GetImagePosition(PRUint32 aCoordType,
                                         PRInt32 *aX, PRInt32 *aY)
@@ -217,25 +222,47 @@ nsHTMLImageAccessible::GetAttributesInte
     nsAccUtils::SetAccAttr(aAttributes, nsGkAtoms::src, src);
 
   return NS_OK;
 }
 
 ////////////////////////////////////////////////////////////////////////////////
 // Private methods
 
-bool
-nsHTMLImageAccessible::HasLongDesc()
+already_AddRefed<nsIURI>
+nsHTMLImageAccessible::GetLongDescURI() const
 {
-  if (IsDefunct())
-    return false;
+  if (mContent->HasAttr(kNameSpaceID_None, nsGkAtoms::longdesc)) {
+    nsGenericHTMLElement* element = 
+      nsGenericHTMLElement::FromContent(mContent);
+    if (element) {
+      nsCOMPtr<nsIURI> uri;
+      element->GetURIAttr(nsGkAtoms::longdesc, nsnull, getter_AddRefs(uri));
+      return uri.forget();
+    }
+  }
 
-  return mContent->HasAttr(kNameSpaceID_None, nsGkAtoms::longdesc);
+  nsDocAccessible* document = Document();
+  if (document) {
+    IDRefsIterator iter(document, mContent, nsGkAtoms::aria_describedby);
+    nsIContent* target = nsnull;
+    while (target = iter.NextElem()) {
+      if ((target->IsHTML(nsGkAtoms::a) || target->IsHTML(nsGkAtoms::area)) &&
+          target->HasAttr(kNameSpaceID_None, nsGkAtoms::href)) {
+        nsGenericHTMLElement* element =
+          nsGenericHTMLElement::FromContent(target);
+
+        nsCOMPtr<nsIURI> uri;
+        element->GetURIAttr(nsGkAtoms::href, nsnull, getter_AddRefs(uri));
+        return uri.forget();
+      }
+    }
+  }
+
+  return nsnull;
 }
 
 bool
-nsHTMLImageAccessible::IsValidLongDescIndex(PRUint8 aIndex)
+nsHTMLImageAccessible::IsLongDescIndex(PRUint8 aIndex)
 {
-  if (!HasLongDesc())
-    return false;
-
   return aIndex == nsLinkableAccessible::ActionCount();
 }
+
--- a/accessible/src/html/nsHTMLImageAccessible.h
+++ b/accessible/src/html/nsHTMLImageAccessible.h
@@ -37,16 +37,18 @@
  * ***** END LICENSE BLOCK ***** */
 
 #ifndef _nsHTMLImageAccessible_H_
 #define _nsHTMLImageAccessible_H_
 
 #include "nsBaseWidgetAccessible.h"
 #include "nsIAccessibleImage.h"
 
+class nsGenericHTMLElement;
+
 /* Accessible for supporting images
  * supports:
  * - gets name, role
  * - support basic state
  */
 class nsHTMLImageAccessible : public nsLinkableAccessible,
                               public nsIAccessibleImage
 {
@@ -69,36 +71,47 @@ public:
   virtual PRUint64 NativeState();
   virtual nsresult GetAttributesInternal(nsIPersistentProperties *aAttributes);
 
   // ActionAccessible
   virtual PRUint8 ActionCount();
 
 private:
   /**
-   * Determine if this image accessible has a longdesc attribute.
-   *
-   * @returns  true if the longdesc attribute is present.
+   * Return whether the element has a longdesc URI.
    */
-  bool HasLongDesc();
-  
+  bool HasLongDesc() const
+  {
+    nsCOMPtr<nsIURI> uri = GetLongDescURI();
+    return uri;
+  }
+
+  /**
+   * Return an URI for showlongdesc action if any.
+   */
+  already_AddRefed<nsIURI> GetLongDescURI() const;
+
   /**
    * Used by GetActionName and DoAction to ensure the index for opening the
    * longdesc URL is valid.
    * It is always assumed that the highest possible index opens the longdesc.
+   * This doesn't check that there is actually a longdesc, just that the index
+   * would be correct if there was one.
    *
    * @param aIndex  The 0-based index to be tested.
    *
    * @returns  true if index is valid for longdesc action.
    */
-  bool IsValidLongDescIndex(PRUint8 aIndex);
+  inline bool IsLongDescIndex(PRUint8 aIndex);
+
 };
 
 ////////////////////////////////////////////////////////////////////////////////
 // nsAccessible downcasting method
+
 inline nsHTMLImageAccessible*
 nsAccessible::AsImage()
 {
   return IsImageAccessible() ?
     static_cast<nsHTMLImageAccessible*>(this) : nsnull;
 }
 
 #endif
--- a/accessible/tests/mochitest/test_nsIAccessibleImage.html
+++ b/accessible/tests/mochitest/test_nsIAccessibleImage.html
@@ -123,37 +123,57 @@ https://bugzilla.mozilla.org/show_bug.cg
                89, 38, 2, actionNamesArray);
       
       // Image with click
       actionNamesArray = null;
       actionNamesArray = new Array("click");
       testThis("click", "moz.png",
                89, 38, 1, actionNamesArray);
       
+      // Image with long desc
+      actionNamesArray = null;
+      actionNamesArray = new Array("showlongdesc");
+      testThis("longdesc2", "moz.png",
+               89, 38, 1, actionNamesArray);
+
       SimpleTest.finish();
     }
 
     SimpleTest.waitForExplicitFinish();
     addA11yLoadEvent(doTest);
   </script>
 </head>
 <body>
 
   <a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=429659">Mozilla Bug 429659</a>
+  <a target="_blank"
+    href="https://bugzilla.mozilla.org/show_bug.cgi?id=652635"
+    title="fall back missing @longdesc to aria-describedby pointing to a href">
+     Mozilla Bug 652635
+  </a>
+
   <p id="display"></p>
   <div id="content" style="display: none"></div>
   <pre id="test">
   </pre>
+
   <br>Simple image:<br>
   <img id="nonLinkedImage" src="moz.png"/>
   <br>Linked image:<br>
   <a href="http://www.mozilla.org"><img id="linkedImage" src="moz.png"></a>
   <br>Image with longdesc:<br>
   <img id="longdesc" src="moz.png" longdesc="longdesc_src.html"
        alt="Image of Mozilla logo"/>
   <br>Image with click and longdesc:<br>
   <img id="clickAndLongdesc" src="moz.png" longdesc="longdesc_src.html"
        alt="Another image of Mozilla logo" onclick="alert('Clicked!');"/>
+
+  <br>image described by a link to be treated as longdesc<br>
+  <img id="longdesc2" src="moz.png" aria-describedby="describing_link"
+       alt="Second Image of Mozilla logo"/>
+  <a id="describing_link" href="longdesc_src.html">link to description of image</a>
+
   <br>Image with click:<br>
   <img id="click" src="moz.png"
        alt="A third image of Mozilla logo" onclick="alert('Clicked, too!');"/>
+
 </body>
 </html>
--- a/content/html/content/src/nsGenericHTMLElement.h
+++ b/content/html/content/src/nsGenericHTMLElement.h
@@ -521,16 +521,24 @@ public:
    *
    * @param aAttr      name of attribute.
    * @param aBaseAttr  name of base attribute.
    * @param aResult    result value [out]
    */
   NS_HIDDEN_(nsresult) GetURIAttr(nsIAtom* aAttr, nsIAtom* aBaseAttr, nsAString& aResult);
 
   /**
+   * Gets the absolute URI values of an attribute, by resolving any relative
+   * URIs in the attribute against the baseuri of the element. If a substring
+   * isn't a relative URI, the substring is returned as is. Only works for
+   * attributes in null namespace.
+   */
+  bool GetURIAttr(nsIAtom* aAttr, nsIAtom* aBaseAttr, nsIURI** aURI) const;
+
+  /**
    * Returns the current disabled state of the element.
    */
   virtual bool IsDisabled() const {
     return false;
   }
 
   bool IsHidden() const
   {
@@ -701,24 +709,16 @@ protected:
    * in null namespace.
    *
    * @param aAttr    name of attribute.
    * @param aValue   Double value of attribute.
    */
   NS_HIDDEN_(nsresult) SetDoubleAttr(nsIAtom* aAttr, double aValue);
 
   /**
-   * Helper for GetURIAttr and GetHrefURIForAnchors which returns an
-   * nsIURI in the out param.
-   *
-   * @return true if we had the attr, false otherwise.
-   */
-  NS_HIDDEN_(bool) GetURIAttr(nsIAtom* aAttr, nsIAtom* aBaseAttr, nsIURI** aURI) const;
-
-  /**
    * This method works like GetURIAttr, except that it supports multiple
    * URIs separated by whitespace (one or more U+0020 SPACE characters).
    *
    * Gets the absolute URI values of an attribute, by resolving any relative
    * URIs in the attribute against the baseuri of the element. If a substring
    * isn't a relative URI, the substring is returned as is. Only works for
    * attributes in null namespace.
    *