From 4bb31ec532bac06b6b84b24c246795ee4782f3ee Mon Sep 17 00:00:00 2001 From: Alexander Surkov Date: Fri, 28 Dec 2012 17:15:02 +0900 Subject: [PATCH] Bug 814836 - element messes up screen readers, r=tbsaunde, sr=roc --- accessible/public/nsIAccessibleProvider.idl | 4 +- accessible/src/base/AccTypes.h | 2 +- .../src/base/nsAccessibilityService.cpp | 112 +++++++++++------- accessible/src/base/nsAccessibilityService.h | 14 +-- accessible/src/generic/Accessible.cpp | 1 + accessible/src/generic/Accessible.h | 2 +- accessible/src/mac/AccessibleWrap.mm | 4 +- accessible/src/xul/XULTabAccessible.cpp | 4 +- accessible/src/xul/XULTabAccessible.h | 6 +- .../mochitest/states/test_visibility.xul | 1 - .../tests/mochitest/treeupdate/Makefile.in | 1 + .../tests/mochitest/treeupdate/test_deck.xul | 109 +++++++++++++++++ layout/xul/base/src/nsDeckFrame.cpp | 12 ++ toolkit/content/widgets/tabbox.xml | 2 +- 14 files changed, 211 insertions(+), 63 deletions(-) create mode 100644 accessible/tests/mochitest/treeupdate/test_deck.xul diff --git a/accessible/public/nsIAccessibleProvider.idl b/accessible/public/nsIAccessibleProvider.idl index a854fba8b0d..d95054f4b93 100644 --- a/accessible/public/nsIAccessibleProvider.idl +++ b/accessible/public/nsIAccessibleProvider.idl @@ -62,8 +62,8 @@ interface nsIAccessibleProvider : nsISupports const long XULTab = 0x00001017; /** Used for XUL tabs element, a container for tab elements */ const long XULTabs = 0x00001018; - /** Used for XUL deck frame */ - const long XULDeck = 0x00001019; + /** Used for XUL tabpanels element */ + const long XULTabpanels = 0x00001019; const long XULText = 0x0000101A; const long XULTextBox = 0x0000101B; diff --git a/accessible/src/base/AccTypes.h b/accessible/src/base/AccTypes.h index e707a350ee7..2f5886fbe44 100644 --- a/accessible/src/base/AccTypes.h +++ b/accessible/src/base/AccTypes.h @@ -52,7 +52,7 @@ enum AccType { eMenuPopupType, eProgressType, eRootType, - eXULDeckType, + eXULTabpanelsType, eXULTreeType, eLastAccType = eXULTreeType diff --git a/accessible/src/base/nsAccessibilityService.cpp b/accessible/src/base/nsAccessibilityService.cpp index 44cea801c71..42cf653f54d 100644 --- a/accessible/src/base/nsAccessibilityService.cpp +++ b/accessible/src/base/nsAccessibilityService.cpp @@ -60,6 +60,7 @@ #include "mozilla/Preferences.h" #include "mozilla/Services.h" #include "mozilla/Util.h" +#include "nsDeckFrame.h" #ifdef MOZ_XUL #include "XULAlertAccessible.h" @@ -254,6 +255,47 @@ nsAccessibilityService::CreatePluginAccessible(nsObjectFrame* aFrame, return nullptr; } +void +nsAccessibilityService::DeckPanelSwitched(nsIPresShell* aPresShell, + nsIContent* aDeckNode, + nsIFrame* aPrevBoxFrame, + nsIFrame* aCurrentBoxFrame) +{ + // Ignore tabpanels elements (a deck having an accessible) since their + // children are accessible not depending on selected tab. + DocAccessible* document = GetDocAccessible(aPresShell); + if (!document || document->HasAccessible(aDeckNode)) + return; + + if (aPrevBoxFrame) { + nsIContent* panelNode = aPrevBoxFrame->GetContent(); +#ifdef A11Y_LOG + if (logging::IsEnabled(logging::eTree)) { + logging::MsgBegin("TREE", "deck panel unselected"); + logging::Node("container", panelNode); + logging::Node("content", aDeckNode); + logging::MsgEnd(); + } +#endif + + document->ContentRemoved(aDeckNode, panelNode); + } + + if (aCurrentBoxFrame) { + nsIContent* panelNode = aCurrentBoxFrame->GetContent(); +#ifdef A11Y_LOG + if (logging::IsEnabled(logging::eTree)) { + logging::MsgBegin("TREE", "deck panel selected"); + logging::Node("container", panelNode); + logging::Node("content", aDeckNode); + logging::MsgEnd(); + } +#endif + + document->ContentInserted(aDeckNode, panelNode, panelNode->GetNextSibling()); + } +} + void nsAccessibilityService::ContentRangeInserted(nsIPresShell* aPresShell, nsIContent* aContainer, @@ -843,28 +885,43 @@ nsAccessibilityService::GetOrCreateAccessible(nsINode* aNode, } } - if (!newAcc) { + // Accessible XBL types and deck stuff are used in XUL only currently. + if (!newAcc && content->IsXUL()) { + // No accessible for not selected deck panel and its children. + if (!aContext->IsXULTabpanels()) { + nsDeckFrame* deckFrame = do_QueryFrame(frame->GetParent()); + if (deckFrame && deckFrame->GetSelectedBox() != frame) { + if (aIsSubtreeHidden) + *aIsSubtreeHidden = true; + + return nullptr; + } + } + // Elements may implement nsIAccessibleProvider via XBL. This allows them to // say what kind of accessible to create. newAcc = CreateAccessibleByType(content, document); + + // Any XUL box can be used as tabpanel, make sure we create a proper + // accessible for it. + if (!newAcc && aContext->IsXULTabpanels() && + content->GetParent() == aContext->GetContent()) { + nsIAtom* frameType = frame->GetType(); + if (frameType == nsGkAtoms::boxFrame || + frameType == nsGkAtoms::scrollFrame) { + newAcc = new XULTabpanelAccessible(content, document); + } + } } if (!newAcc) { - // xul:deck does not have XBL and nsIFrame::CreateAccessible() is only called - // on HTML elements - nsIAtom* tag = content->Tag(); - if ((tag == nsGkAtoms::deck) || (tag == nsGkAtoms::tabpanels)) { - newAcc = new XULDeckAccessible(content, document); - } else if (content->IsSVG(nsGkAtoms::svg)) { + if (content->IsSVG(nsGkAtoms::svg)) { newAcc = new EnumRoleAccessible(content, document, roles::DIAGRAM); } else if (content->IsMathML(nsGkAtoms::math)) { newAcc = new EnumRoleAccessible(content, document, roles::EQUATION); } } - if (!newAcc) - newAcc = CreateAccessibleForDeckChild(frame, content, document); - // If no accessible, see if we need to create a generic accessible because // of some property that makes this object interesting // We don't do this for , , , etc. which @@ -1011,8 +1068,8 @@ nsAccessibilityService::CreateAccessibleByType(nsIContent* aContent, accessible = new XULComboboxAccessible(aContent, aDoc); break; - case nsIAccessibleProvider::XULDeck: - accessible = new XULDeckAccessible(aContent, aDoc); + case nsIAccessibleProvider::XULTabpanels: + accessible = new XULTabpanelsAccessible(aContent, aDoc); break; case nsIAccessibleProvider::XULDropmarker: @@ -1480,37 +1537,6 @@ NS_GetAccessibilityService(nsIAccessibilityService** aResult) //////////////////////////////////////////////////////////////////////////////// // nsAccessibilityService private (DON'T put methods here) -already_AddRefed -nsAccessibilityService::CreateAccessibleForDeckChild(nsIFrame* aFrame, - nsIContent* aContent, - DocAccessible* aDoc) -{ - if (aFrame->GetType() == nsGkAtoms::boxFrame || - aFrame->GetType() == nsGkAtoms::scrollFrame) { - - nsIFrame* parentFrame = aFrame->GetParent(); - if (parentFrame && parentFrame->GetType() == nsGkAtoms::deckFrame) { - // If deck frame is for xul:tabpanels element then the given node has - // tabpanel accessible. - nsIContent* parentContent = parentFrame->GetContent(); -#ifdef MOZ_XUL - if (parentContent->NodeInfo()->Equals(nsGkAtoms::tabpanels, - kNameSpaceID_XUL)) { - Accessible* accessible = new XULTabpanelAccessible(aContent, aDoc); - NS_ADDREF(accessible); - return accessible; - } -#endif - Accessible* accessible = new EnumRoleAccessible(aContent, aDoc, - roles::PROPERTYPAGE); - NS_ADDREF(accessible); - return accessible; - } - } - - return nullptr; -} - #ifdef MOZ_XUL already_AddRefed nsAccessibilityService::CreateAccessibleForXULTree(nsIContent* aContent, diff --git a/accessible/src/base/nsAccessibilityService.h b/accessible/src/base/nsAccessibilityService.h index d30bca016c1..dbdf66f53d1 100644 --- a/accessible/src/base/nsAccessibilityService.h +++ b/accessible/src/base/nsAccessibilityService.h @@ -64,6 +64,13 @@ public: virtual Accessible* AddNativeRootAccessible(void* aAtkAccessible); virtual void RemoveNativeRootAccessible(Accessible* aRootAccessible); + /** + * Notification used to update the accessible tree when deck panel is + * switched. + */ + void DeckPanelSwitched(nsIPresShell* aPresShell, nsIContent* aDeckNode, + nsIFrame* aPrevBoxFrame, nsIFrame* aCurrentBoxFrame); + /** * Notification used to update the accessible tree when new content is * inserted. @@ -173,13 +180,6 @@ private: CreateAccessibleByFrameType(nsIFrame* aFrame, nsIContent* aContent, Accessible* aContext); - /** - * Create accessible if parent is a deck frame. - */ - already_AddRefed - CreateAccessibleForDeckChild(nsIFrame* aFrame, nsIContent* aContent, - DocAccessible* aDoc); - #ifdef MOZ_XUL /** * Create accessible for XUL tree element. diff --git a/accessible/src/generic/Accessible.cpp b/accessible/src/generic/Accessible.cpp index f8aedc4197f..f0090458bca 100644 --- a/accessible/src/generic/Accessible.cpp +++ b/accessible/src/generic/Accessible.cpp @@ -612,6 +612,7 @@ Accessible::VisibilityState() deckFrame->GetContent()->Tag() == nsGkAtoms::tabpanels) return states::OFFSCREEN; + NS_NOTREACHED("Children of not selected deck panel are not accessible."); return states::INVISIBLE; } diff --git a/accessible/src/generic/Accessible.h b/accessible/src/generic/Accessible.h index 9eb2e62ab4f..007b345bb6e 100644 --- a/accessible/src/generic/Accessible.h +++ b/accessible/src/generic/Accessible.h @@ -520,7 +520,7 @@ public: bool IsTextLeaf() const { return mType == eTextLeafType; } TextLeafAccessible* AsTextLeaf(); - bool IsXULDeck() const { return mType == eXULDeckType; } + bool IsXULTabpanels() const { return mType == eXULTabpanelsType; } bool IsXULTree() const { return mType == eXULTreeType; } XULTreeAccessible* AsXULTree(); diff --git a/accessible/src/mac/AccessibleWrap.mm b/accessible/src/mac/AccessibleWrap.mm index b02c8d7bac8..87b53380ae8 100644 --- a/accessible/src/mac/AccessibleWrap.mm +++ b/accessible/src/mac/AccessibleWrap.mm @@ -60,9 +60,9 @@ AccessibleWrap::GetNativeType () { NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NIL; - if (IsXULDeck()) + if (IsXULTabpanels()) return [mozPaneAccessible class]; - + roles::Role role = Role(); switch (role) { case roles::PUSHBUTTON: diff --git a/accessible/src/xul/XULTabAccessible.cpp b/accessible/src/xul/XULTabAccessible.cpp index e46a447ed8a..7f15827de3f 100644 --- a/accessible/src/xul/XULTabAccessible.cpp +++ b/accessible/src/xul/XULTabAccessible.cpp @@ -163,11 +163,11 @@ XULTabsAccessible::NativeName(nsString& aName) //////////////////////////////////////////////////////////////////////////////// -// XULDeckAccessible +// XULTabpanelsAccessible //////////////////////////////////////////////////////////////////////////////// role -XULDeckAccessible::NativeRole() +XULTabpanelsAccessible::NativeRole() { return roles::PANE; } diff --git a/accessible/src/xul/XULTabAccessible.h b/accessible/src/xul/XULTabAccessible.h index 260035bf797..b8fe6ecee09 100644 --- a/accessible/src/xul/XULTabAccessible.h +++ b/accessible/src/xul/XULTabAccessible.h @@ -62,12 +62,12 @@ protected: /** * A container of tab panels, xul:tabpanels element. */ -class XULDeckAccessible : public AccessibleWrap +class XULTabpanelsAccessible : public AccessibleWrap { public: - XULDeckAccessible(nsIContent* aContent, DocAccessible* aDoc) : + XULTabpanelsAccessible(nsIContent* aContent, DocAccessible* aDoc) : AccessibleWrap(aContent, aDoc) - { mType = eXULDeckType; } + { mType = eXULTabpanelsType; } // Accessible virtual a11y::role NativeRole(); diff --git a/accessible/tests/mochitest/states/test_visibility.xul b/accessible/tests/mochitest/states/test_visibility.xul index 5978ddb9b7f..3f999113172 100644 --- a/accessible/tests/mochitest/states/test_visibility.xul +++ b/accessible/tests/mochitest/states/test_visibility.xul @@ -20,7 +20,6 @@ + + + + + + + + + + + Mozilla Bug 814836 + + +

+ +
+      
+ + + + + + This is the first page + +