diff --git a/accessible/src/base/FocusManager.cpp b/accessible/src/base/FocusManager.cpp index 45921505885..914bf7cfbd7 100644 --- a/accessible/src/base/FocusManager.cpp +++ b/accessible/src/base/FocusManager.cpp @@ -7,9 +7,11 @@ #include "Accessible-inl.h" #include "AccIterator.h" #include "DocAccessible-inl.h" +#include "HTMLImageMapAccessible.h" #include "nsAccessibilityService.h" #include "nsAccUtils.h" #include "nsEventShell.h" +#include "nsImageFrame.h" #include "Role.h" #include "nsEventStateManager.h" @@ -37,7 +39,7 @@ FocusManager::FocusedAccessible() const if (focusedNode) { DocAccessible* doc = GetAccService()->GetDocAccessible(focusedNode->OwnerDoc()); - return doc ? doc->GetAccessibleOrContainer(focusedNode) : nullptr; + return doc ? GetFocusableAccessibleFor(focusedNode, doc) : nullptr; } return nullptr; @@ -61,7 +63,7 @@ FocusManager::IsFocused(const Accessible* aAccessible) const DocAccessible* doc = GetAccService()->GetDocAccessible(focusedNode->OwnerDoc()); return aAccessible == - (doc ? doc->GetAccessibleOrContainer(focusedNode) : nullptr); + (doc ? GetFocusableAccessibleFor(focusedNode, doc) : nullptr); } } return false; @@ -241,12 +243,15 @@ FocusManager::ProcessDOMFocus(nsINode* aTarget) DocAccessible* document = GetAccService()->GetDocAccessible(aTarget->OwnerDoc()); - Accessible* target = document->GetAccessibleOrContainer(aTarget); + Accessible* target = GetFocusableAccessibleFor(aTarget, document); if (target && document) { // Check if still focused. Otherwise we can end up with storing the active // item for control that isn't focused anymore. - Accessible* DOMFocus = - document->GetAccessibleOrContainer(FocusedDOMNode()); + nsINode* focusedNode = FocusedDOMNode(); + if (!focusedNode) + return; + + Accessible* DOMFocus = GetFocusableAccessibleFor(focusedNode, document); if (target != DOMFocus) return; @@ -274,8 +279,11 @@ FocusManager::ProcessFocusEvent(AccEvent* aEvent) // Check if still focused. Otherwise we can end up with storing the active // item for control that isn't focused anymore. DocAccessible* document = aEvent->GetDocAccessible(); - Accessible* DOMFocus = document->GetAccessibleOrContainer(FocusedDOMNode()); + nsINode* focusedNode = FocusedDOMNode(); + if (!focusedNode) + return; + Accessible* DOMFocus = GetFocusableAccessibleFor(focusedNode, document); if (target != DOMFocus) return; @@ -394,3 +402,28 @@ FocusManager::FocusedDOMDocument() const nsINode* focusedNode = FocusedDOMNode(); return focusedNode ? focusedNode->OwnerDoc() : nullptr; } + +Accessible* +FocusManager::GetFocusableAccessibleFor(nsINode* aNode, + DocAccessible* aDoc) const +{ + if (!aNode->IsContent() || !aNode->AsContent()->IsHTML(nsGkAtoms::area)) + return aDoc->GetAccessibleOrContainer(aNode); + + // XXX Bug 135040, incorrect when multiple images use the same map. + nsIFrame* frame = aNode->AsContent()->GetPrimaryFrame(); + nsImageFrame* imageFrame = do_QueryFrame(frame); + if (imageFrame) { + Accessible* parent = aDoc->GetAccessible(imageFrame->GetContent()); + if (parent) { + Accessible* area = + parent->AsImageMap()->GetChildAccessibleFor(aNode); + if (area) + return area; + + return nullptr; + } + } + + return aDoc->GetAccessibleOrContainer(aNode); +} diff --git a/accessible/src/base/FocusManager.h b/accessible/src/base/FocusManager.h index ccbbd9e9ee3..c6790a0933d 100644 --- a/accessible/src/base/FocusManager.h +++ b/accessible/src/base/FocusManager.h @@ -123,6 +123,12 @@ private: */ nsIDocument* FocusedDOMDocument() const; + /** + * Return accessible for a focusable node. + */ + Accessible* GetFocusableAccessibleFor(nsINode* aNode, + DocAccessible* aDoc) const; + private: nsRefPtr mActiveItem; nsRefPtr mActiveARIAMenubar; diff --git a/accessible/src/html/HTMLImageMapAccessible.cpp b/accessible/src/html/HTMLImageMapAccessible.cpp index cfe05409dac..4b060b38006 100644 --- a/accessible/src/html/HTMLImageMapAccessible.cpp +++ b/accessible/src/html/HTMLImageMapAccessible.cpp @@ -133,6 +133,19 @@ HTMLImageMapAccessible::UpdateChildAreas(bool aDoFireEvents) mDoc->FireDelayedEvent(reorderEvent); } +Accessible* +HTMLImageMapAccessible::GetChildAccessibleFor(const nsINode* aNode) const +{ + uint32_t length = mChildren.Length(); + for (uint32_t i = 0; i < length; i++) { + Accessible* area = mChildren[i]; + if (area->GetContent() == aNode) + return area; + } + + return nullptr; +} + //////////////////////////////////////////////////////////////////////////////// // HTMLImageMapAccessible: Accessible protected diff --git a/accessible/src/html/HTMLImageMapAccessible.h b/accessible/src/html/HTMLImageMapAccessible.h index 5ed9fe80eff..89c72b12fed 100644 --- a/accessible/src/html/HTMLImageMapAccessible.h +++ b/accessible/src/html/HTMLImageMapAccessible.h @@ -38,6 +38,11 @@ public: */ void UpdateChildAreas(bool aDoFireEvents = true); + /** + * Return accessible of child node. + */ + Accessible* GetChildAccessibleFor(const nsINode* aNode) const; + protected: // Accessible diff --git a/accessible/tests/mochitest/events/test_focus_general.html b/accessible/tests/mochitest/events/test_focus_general.html index e1a09c61495..e881a5a4f80 100644 --- a/accessible/tests/mochitest/events/test_focus_general.html +++ b/accessible/tests/mochitest/events/test_focus_general.html @@ -44,6 +44,16 @@ } } + function imageMapChecker(aID) + { + var node = getNode(aID); + this.type = EVENT_FOCUS; + this.match = function imageMapChecker_match(aEvent) + { + return aEvent.DOMNode == node; + } + } + function topMenuChecker() { this.type = EVENT_FOCUS; @@ -115,6 +125,9 @@ gQueue.push(new synthShiftTab("link", new focusChecker("link"))); } // ! SEAMONKEY + gQueue.push(new synthFocus("a", new imageMapChecker("a"))); + gQueue.push(new synthFocus("b", new imageMapChecker("b"))); + gQueue.invoke(); // Will call SimpleTest.finish(); } @@ -139,6 +152,11 @@ title="Rework accessible focus handling"> Mozilla Bug 673958 + + Mozilla Bug 961696 +

@@ -150,6 +168,12 @@
   link
   
 
+  
+    
+    
+  
+  
+