diff --git a/accessible/base/HTMLMarkupMap.h b/accessible/base/HTMLMarkupMap.h index 3dd2f34bd538..d85f4accf04c 100644 --- a/accessible/base/HTMLMarkupMap.h +++ b/accessible/base/HTMLMarkupMap.h @@ -8,6 +8,12 @@ MARKUPMAP( a, [](Element* aElement, LocalAccessible* aContext) -> LocalAccessible* { + // An anchor element without an href attribute and without a click + // listener should be a generic. + if (!aElement->HasAttr(nsGkAtoms::href) && + !nsCoreUtils::HasClickListener(aElement)) { + return new HyperTextAccessibleWrap(aElement, aContext->Document()); + } // Only some roles truly enjoy life as HTMLLinkAccessibles, for // details see closed bug 494807. const nsRoleMapEntry* roleMapEntry = aria::GetRoleMap(aElement); @@ -18,7 +24,7 @@ MARKUPMAP( return new HTMLLinkAccessible(aElement, aContext->Document()); }, - roles::LINK) + 0) MARKUPMAP(abbr, New_HyperText, 0) diff --git a/accessible/base/nsAccessibilityService.cpp b/accessible/base/nsAccessibilityService.cpp index 79797feae9ed..37082a605914 100644 --- a/accessible/base/nsAccessibilityService.cpp +++ b/accessible/base/nsAccessibilityService.cpp @@ -442,17 +442,33 @@ nsAccessibilityService::ListenersChanged(nsIArray* aEventChanges) { content == document->DocumentNode()->GetRootElement())) { acc = document; } + if (!acc && content->IsElement() && + content->AsElement()->IsHTMLElement(nsGkAtoms::area)) { + // For area accessibles, we have to recreate the entire image map, + // since the image map accessible manages the tree itself. The click + // listener change may require us to update the role for the + // accessible associated with the area element. + LocalAccessible* areaAcc = + document->GetAccessibleEvenIfNotInMap(content); + if (areaAcc && areaAcc->LocalParent()) { + document->RecreateAccessible(areaAcc->LocalParent()->GetContent()); + } + } if (!acc && nsCoreUtils::HasClickListener(content)) { // Create an accessible for a inaccessible element having click event // handler. document->ContentInserted(content, content->GetNextSibling()); } else if (acc) { - if (acc->IsHTMLLink() && !acc->AsHTMLLink()->IsLinked()) { - // Notify of a LINKED state change if an HTML link gets a click - // listener but does not have an href attribute. - RefPtr linkedChangeEvent = - new AccStateChangeEvent(acc, states::LINKED); - document->FireDelayedEvent(linkedChangeEvent); + if ((acc->IsHTMLLink() && !acc->AsHTMLLink()->IsLinked()) || + (content->IsElement() && + content->AsElement()->IsHTMLElement(nsGkAtoms::a) && + !acc->IsHTMLLink())) { + // An HTML link without an href attribute should have a generic + // role, unless it has a click listener. Since we might have gained + // or lost a click listener here, recreate the accessible so that we + // can create the correct type of accessible. If it was a link, it + // may no longer be one. If it wasn't, it may become one. + document->RecreateAccessible(content); } // A click listener change might mean losing or gaining an action. diff --git a/accessible/generic/DocAccessible.cpp b/accessible/generic/DocAccessible.cpp index 51ef54a8794f..d6dff6016834 100644 --- a/accessible/generic/DocAccessible.cpp +++ b/accessible/generic/DocAccessible.cpp @@ -1803,6 +1803,33 @@ bool DocAccessible::UpdateAccessibleOnAttrChange(dom::Element* aElement, return true; } + if (aAttribute == nsGkAtoms::href && + !nsCoreUtils::HasClickListener(aElement)) { + // If the href is added or removed for a or area elements without click + // listeners, we need to recreate the accessible since the role might have + // changed. Without an href or click listener, the accessible must be a + // generic. + if (aElement->IsHTMLElement(nsGkAtoms::a)) { + LocalAccessible* acc = GetAccessible(aElement); + if (!acc) { + return false; + } + if (acc->IsHTMLLink() != aElement->HasAttr(nsGkAtoms::href)) { + RecreateAccessible(aElement); + return true; + } + } else if (aElement->IsHTMLElement(nsGkAtoms::area)) { + // For area accessibles, we have to recreate the entire image map, since + // the image map accessible manages the tree itself. + LocalAccessible* areaAcc = GetAccessibleEvenIfNotInMap(aElement); + if (!areaAcc || !areaAcc->LocalParent()) { + return false; + } + RecreateAccessible(areaAcc->LocalParent()->GetContent()); + return true; + } + } + if (aElement->IsHTMLElement(nsGkAtoms::img) && aAttribute == nsGkAtoms::alt) { // If alt text changes on an img element, we may want to create or remove an // accessible for that img. diff --git a/accessible/html/HTMLImageMapAccessible.cpp b/accessible/html/HTMLImageMapAccessible.cpp index f20974e9cf35..b5f307cb7031 100644 --- a/accessible/html/HTMLImageMapAccessible.cpp +++ b/accessible/html/HTMLImageMapAccessible.cpp @@ -9,6 +9,7 @@ #include "EventTree.h" #include "Role.h" +#include "nsCoreUtils.h" #include "nsIFrame.h" #include "nsImageFrame.h" #include "nsImageMap.h" @@ -105,6 +106,19 @@ HTMLAreaAccessible::HTMLAreaAccessible(nsIContent* aContent, //////////////////////////////////////////////////////////////////////////////// // HTMLAreaAccessible: LocalAccessible +role HTMLAreaAccessible::NativeRole() const { + // A link element without an href attribute and without a click listener + // should be reported as a generic. + if (mContent->IsElement()) { + dom::Element* element = mContent->AsElement(); + if (!element->HasAttr(nsGkAtoms::href) && + !nsCoreUtils::HasClickListener(element)) { + return roles::TEXT; + } + } + return HTMLLinkAccessible::NativeRole(); +} + ENameValueFlag HTMLAreaAccessible::NativeName(nsString& aName) const { ENameValueFlag nameFlag = LocalAccessible::NativeName(aName); if (!aName.IsEmpty()) return nameFlag; diff --git a/accessible/html/HTMLImageMapAccessible.h b/accessible/html/HTMLImageMapAccessible.h index 2dc1779ddd7a..15c56b44dede 100644 --- a/accessible/html/HTMLImageMapAccessible.h +++ b/accessible/html/HTMLImageMapAccessible.h @@ -61,6 +61,9 @@ class HTMLAreaAccessible final : public HTMLLinkAccessible { return false; } + // LocalAccessible + virtual role NativeRole() const override; + protected: // LocalAccessible virtual ENameValueFlag NativeName(nsString& aName) const override; diff --git a/accessible/tests/browser/e10s/browser_caching_actions.js b/accessible/tests/browser/e10s/browser_caching_actions.js index 8bf3542a0373..1407f3786218 100644 --- a/accessible/tests/browser/e10s/browser_caching_actions.js +++ b/accessible/tests/browser/e10s/browser_caching_actions.js @@ -92,6 +92,10 @@ addAccessibleTask( src="http://example.com/a11y/accessible/tests/mochitest/moz.png"> + + + +