michael@0: /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: #include "nsAccessibilityService.h" michael@0: michael@0: // NOTE: alphabetically ordered michael@0: #include "ApplicationAccessibleWrap.h" michael@0: #include "ARIAGridAccessibleWrap.h" michael@0: #include "ARIAMap.h" michael@0: #include "DocAccessible-inl.h" michael@0: #include "FocusManager.h" michael@0: #include "HTMLCanvasAccessible.h" michael@0: #include "HTMLElementAccessibles.h" michael@0: #include "HTMLImageMapAccessible.h" michael@0: #include "HTMLLinkAccessible.h" michael@0: #include "HTMLListAccessible.h" michael@0: #include "HTMLSelectAccessible.h" michael@0: #include "HTMLTableAccessibleWrap.h" michael@0: #include "HyperTextAccessibleWrap.h" michael@0: #include "RootAccessible.h" michael@0: #include "nsAccessiblePivot.h" michael@0: #include "nsAccUtils.h" michael@0: #include "nsAttrName.h" michael@0: #include "nsEventShell.h" michael@0: #include "nsIURI.h" michael@0: #include "OuterDocAccessible.h" michael@0: #include "Platform.h" michael@0: #include "Role.h" michael@0: #ifdef MOZ_ACCESSIBILITY_ATK michael@0: #include "RootAccessibleWrap.h" michael@0: #endif michael@0: #include "States.h" michael@0: #include "Statistics.h" michael@0: #include "TextLeafAccessibleWrap.h" michael@0: michael@0: #ifdef MOZ_ACCESSIBILITY_ATK michael@0: #include "AtkSocketAccessible.h" michael@0: #endif michael@0: michael@0: #ifdef XP_WIN michael@0: #include "mozilla/a11y/Compatibility.h" michael@0: #include "HTMLWin32ObjectAccessible.h" michael@0: #include "mozilla/StaticPtr.h" michael@0: #endif michael@0: michael@0: #ifdef A11Y_LOG michael@0: #include "Logging.h" michael@0: #endif michael@0: michael@0: #ifdef MOZ_CRASHREPORTER michael@0: #include "nsExceptionHandler.h" michael@0: #endif michael@0: michael@0: #include "nsImageFrame.h" michael@0: #include "nsIObserverService.h" michael@0: #include "nsLayoutUtils.h" michael@0: #include "nsObjectFrame.h" michael@0: #include "nsSVGPathGeometryFrame.h" michael@0: #include "nsTreeBodyFrame.h" michael@0: #include "nsTreeColumns.h" michael@0: #include "nsTreeUtils.h" michael@0: #include "nsXBLPrototypeBinding.h" michael@0: #include "nsXBLBinding.h" michael@0: #include "mozilla/ArrayUtils.h" michael@0: #include "mozilla/dom/DOMStringList.h" michael@0: #include "mozilla/Preferences.h" michael@0: #include "mozilla/Services.h" michael@0: #include "nsDeckFrame.h" michael@0: michael@0: #ifdef MOZ_XUL michael@0: #include "XULAlertAccessible.h" michael@0: #include "XULColorPickerAccessible.h" michael@0: #include "XULComboboxAccessible.h" michael@0: #include "XULElementAccessibles.h" michael@0: #include "XULFormControlAccessible.h" michael@0: #include "XULListboxAccessibleWrap.h" michael@0: #include "XULMenuAccessibleWrap.h" michael@0: #include "XULSliderAccessible.h" michael@0: #include "XULTabAccessible.h" michael@0: #include "XULTreeGridAccessibleWrap.h" michael@0: #endif michael@0: michael@0: #if defined(XP_WIN) || defined(MOZ_ACCESSIBILITY_ATK) michael@0: #include "nsNPAPIPluginInstance.h" michael@0: #endif michael@0: michael@0: using namespace mozilla; michael@0: using namespace mozilla::a11y; michael@0: using namespace mozilla::dom; michael@0: michael@0: //////////////////////////////////////////////////////////////////////////////// michael@0: // Statics michael@0: //////////////////////////////////////////////////////////////////////////////// michael@0: michael@0: /** michael@0: * Return true if the element must be accessible. michael@0: */ michael@0: static bool michael@0: MustBeAccessible(nsIContent* aContent, DocAccessible* aDocument) michael@0: { michael@0: if (aContent->GetPrimaryFrame()->IsFocusable()) michael@0: return true; michael@0: michael@0: uint32_t attrCount = aContent->GetAttrCount(); michael@0: for (uint32_t attrIdx = 0; attrIdx < attrCount; attrIdx++) { michael@0: const nsAttrName* attr = aContent->GetAttrNameAt(attrIdx); michael@0: if (attr->NamespaceEquals(kNameSpaceID_None)) { michael@0: nsIAtom* attrAtom = attr->Atom(); michael@0: nsDependentAtomString attrStr(attrAtom); michael@0: if (!StringBeginsWith(attrStr, NS_LITERAL_STRING("aria-"))) michael@0: continue; // not ARIA michael@0: michael@0: // A global state or a property and in case of token defined. michael@0: uint8_t attrFlags = aria::AttrCharacteristicsFor(attrAtom); michael@0: if ((attrFlags & ATTR_GLOBAL) && (!(attrFlags & ATTR_VALTOKEN) || michael@0: nsAccUtils::HasDefinedARIAToken(aContent, attrAtom))) { michael@0: return true; michael@0: } michael@0: } michael@0: } michael@0: michael@0: // If the given ID is referred by relation attribute then create an accessible michael@0: // for it. michael@0: nsAutoString id; michael@0: if (nsCoreUtils::GetID(aContent, id) && !id.IsEmpty()) michael@0: return aDocument->IsDependentID(id); michael@0: michael@0: return false; michael@0: } michael@0: michael@0: //////////////////////////////////////////////////////////////////////////////// michael@0: // nsAccessibilityService michael@0: //////////////////////////////////////////////////////////////////////////////// michael@0: michael@0: nsAccessibilityService *nsAccessibilityService::gAccessibilityService = nullptr; michael@0: ApplicationAccessible* nsAccessibilityService::gApplicationAccessible = nullptr; michael@0: bool nsAccessibilityService::gIsShutdown = true; michael@0: michael@0: nsAccessibilityService::nsAccessibilityService() : michael@0: DocManager(), FocusManager() michael@0: { michael@0: } michael@0: michael@0: nsAccessibilityService::~nsAccessibilityService() michael@0: { michael@0: NS_ASSERTION(gIsShutdown, "Accessibility wasn't shutdown!"); michael@0: gAccessibilityService = nullptr; michael@0: } michael@0: michael@0: //////////////////////////////////////////////////////////////////////////////// michael@0: // nsISupports michael@0: michael@0: NS_IMPL_ISUPPORTS_INHERITED(nsAccessibilityService, michael@0: DocManager, michael@0: nsIAccessibilityService, michael@0: nsIAccessibleRetrieval, michael@0: nsIObserver, michael@0: nsISelectionListener) // from SelectionManager michael@0: michael@0: //////////////////////////////////////////////////////////////////////////////// michael@0: // nsIObserver michael@0: michael@0: NS_IMETHODIMP michael@0: nsAccessibilityService::Observe(nsISupports *aSubject, const char *aTopic, michael@0: const char16_t *aData) michael@0: { michael@0: if (!nsCRT::strcmp(aTopic, NS_XPCOM_SHUTDOWN_OBSERVER_ID)) michael@0: Shutdown(); michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: // nsIAccessibilityService michael@0: void michael@0: nsAccessibilityService::NotifyOfAnchorJumpTo(nsIContent* aTargetNode) michael@0: { michael@0: nsIDocument* documentNode = aTargetNode->GetCurrentDoc(); michael@0: if (documentNode) { michael@0: DocAccessible* document = GetDocAccessible(documentNode); michael@0: if (document) michael@0: document->SetAnchorJump(aTargetNode); michael@0: } michael@0: } michael@0: michael@0: // nsIAccessibilityService michael@0: void michael@0: nsAccessibilityService::FireAccessibleEvent(uint32_t aEvent, michael@0: Accessible* aTarget) michael@0: { michael@0: nsEventShell::FireEvent(aEvent, aTarget); michael@0: } michael@0: michael@0: //////////////////////////////////////////////////////////////////////////////// michael@0: // nsIAccessibilityService michael@0: michael@0: Accessible* michael@0: nsAccessibilityService::GetRootDocumentAccessible(nsIPresShell* aPresShell, michael@0: bool aCanCreate) michael@0: { michael@0: nsIPresShell* ps = aPresShell; michael@0: nsIDocument* documentNode = aPresShell->GetDocument(); michael@0: if (documentNode) { michael@0: nsCOMPtr treeItem(documentNode->GetDocShell()); michael@0: if (treeItem) { michael@0: nsCOMPtr rootTreeItem; michael@0: treeItem->GetRootTreeItem(getter_AddRefs(rootTreeItem)); michael@0: if (treeItem != rootTreeItem) { michael@0: nsCOMPtr docShell(do_QueryInterface(rootTreeItem)); michael@0: ps = docShell->GetPresShell(); michael@0: } michael@0: michael@0: return aCanCreate ? GetDocAccessible(ps) : ps->GetDocAccessible(); michael@0: } michael@0: } michael@0: return nullptr; michael@0: } michael@0: michael@0: #ifdef XP_WIN michael@0: static StaticAutoPtr > > sPendingPlugins; michael@0: static StaticAutoPtr > > sPluginTimers; michael@0: michael@0: class PluginTimerCallBack MOZ_FINAL : public nsITimerCallback michael@0: { michael@0: public: michael@0: PluginTimerCallBack(nsIContent* aContent) : mContent(aContent) {} michael@0: michael@0: NS_DECL_ISUPPORTS michael@0: michael@0: NS_IMETHODIMP Notify(nsITimer* aTimer) MOZ_FINAL michael@0: { michael@0: if (!mContent->IsInDoc()) michael@0: return NS_OK; michael@0: michael@0: nsIPresShell* ps = mContent->OwnerDoc()->GetShell(); michael@0: if (ps) { michael@0: DocAccessible* doc = ps->GetDocAccessible(); michael@0: if (doc) { michael@0: // Make sure that if we created an accessible for the plugin that wasn't michael@0: // a plugin accessible we remove it before creating the right accessible. michael@0: doc->RecreateAccessible(mContent); michael@0: sPluginTimers->RemoveElement(aTimer); michael@0: return NS_OK; michael@0: } michael@0: } michael@0: michael@0: // We couldn't get a doc accessible so presumably the document went away. michael@0: // In this case don't leak our ref to the content or timer. michael@0: sPendingPlugins->RemoveElement(mContent); michael@0: sPluginTimers->RemoveElement(aTimer); michael@0: return NS_OK; michael@0: } michael@0: michael@0: private: michael@0: nsCOMPtr mContent; michael@0: }; michael@0: michael@0: NS_IMPL_ISUPPORTS(PluginTimerCallBack, nsITimerCallback) michael@0: #endif michael@0: michael@0: already_AddRefed michael@0: nsAccessibilityService::CreatePluginAccessible(nsObjectFrame* aFrame, michael@0: nsIContent* aContent, michael@0: Accessible* aContext) michael@0: { michael@0: // nsObjectFrame means a plugin, so we need to use the accessibility support michael@0: // of the plugin. michael@0: if (aFrame->GetRect().IsEmpty()) michael@0: return nullptr; michael@0: michael@0: #if defined(XP_WIN) || defined(MOZ_ACCESSIBILITY_ATK) michael@0: nsRefPtr pluginInstance; michael@0: if (NS_SUCCEEDED(aFrame->GetPluginInstance(getter_AddRefs(pluginInstance))) && michael@0: pluginInstance) { michael@0: #ifdef XP_WIN michael@0: if (!sPendingPlugins->Contains(aContent) && michael@0: (Preferences::GetBool("accessibility.delay_plugins") || michael@0: Compatibility::IsJAWS() || Compatibility::IsWE())) { michael@0: nsCOMPtr timer = do_CreateInstance(NS_TIMER_CONTRACTID); michael@0: nsRefPtr cb = new PluginTimerCallBack(aContent); michael@0: timer->InitWithCallback(cb, Preferences::GetUint("accessibility.delay_plugin_time"), michael@0: nsITimer::TYPE_ONE_SHOT); michael@0: sPluginTimers->AppendElement(timer); michael@0: sPendingPlugins->AppendElement(aContent); michael@0: return nullptr; michael@0: } michael@0: michael@0: // We need to remove aContent from the pending plugins here to avoid michael@0: // reentrancy. When the timer fires it calls michael@0: // DocAccessible::ContentInserted() which does the work async. michael@0: sPendingPlugins->RemoveElement(aContent); michael@0: michael@0: // Note: pluginPort will be null if windowless. michael@0: HWND pluginPort = nullptr; michael@0: aFrame->GetPluginPort(&pluginPort); michael@0: michael@0: nsRefPtr accessible = michael@0: new HTMLWin32ObjectOwnerAccessible(aContent, aContext->Document(), michael@0: pluginPort); michael@0: return accessible.forget(); michael@0: michael@0: #elif MOZ_ACCESSIBILITY_ATK michael@0: if (!AtkSocketAccessible::gCanEmbed) michael@0: return nullptr; michael@0: michael@0: // Note this calls into the plugin, so crazy things may happen and aFrame michael@0: // may go away. michael@0: nsCString plugId; michael@0: nsresult rv = pluginInstance->GetValueFromPlugin( michael@0: NPPVpluginNativeAccessibleAtkPlugId, &plugId); michael@0: if (NS_SUCCEEDED(rv) && !plugId.IsEmpty()) { michael@0: nsRefPtr socketAccessible = michael@0: new AtkSocketAccessible(aContent, aContext->Document(), plugId); michael@0: michael@0: return socketAccessible.forget(); michael@0: } michael@0: #endif michael@0: } michael@0: #endif michael@0: michael@0: return nullptr; michael@0: } michael@0: michael@0: void michael@0: nsAccessibilityService::DeckPanelSwitched(nsIPresShell* aPresShell, michael@0: nsIContent* aDeckNode, michael@0: nsIFrame* aPrevBoxFrame, michael@0: nsIFrame* aCurrentBoxFrame) michael@0: { michael@0: // Ignore tabpanels elements (a deck having an accessible) since their michael@0: // children are accessible not depending on selected tab. michael@0: DocAccessible* document = GetDocAccessible(aPresShell); michael@0: if (!document || document->HasAccessible(aDeckNode)) michael@0: return; michael@0: michael@0: if (aPrevBoxFrame) { michael@0: nsIContent* panelNode = aPrevBoxFrame->GetContent(); michael@0: #ifdef A11Y_LOG michael@0: if (logging::IsEnabled(logging::eTree)) { michael@0: logging::MsgBegin("TREE", "deck panel unselected"); michael@0: logging::Node("container", panelNode); michael@0: logging::Node("content", aDeckNode); michael@0: logging::MsgEnd(); michael@0: } michael@0: #endif michael@0: michael@0: document->ContentRemoved(aDeckNode, panelNode); michael@0: } michael@0: michael@0: if (aCurrentBoxFrame) { michael@0: nsIContent* panelNode = aCurrentBoxFrame->GetContent(); michael@0: #ifdef A11Y_LOG michael@0: if (logging::IsEnabled(logging::eTree)) { michael@0: logging::MsgBegin("TREE", "deck panel selected"); michael@0: logging::Node("container", panelNode); michael@0: logging::Node("content", aDeckNode); michael@0: logging::MsgEnd(); michael@0: } michael@0: #endif michael@0: michael@0: document->ContentInserted(aDeckNode, panelNode, panelNode->GetNextSibling()); michael@0: } michael@0: } michael@0: michael@0: void michael@0: nsAccessibilityService::ContentRangeInserted(nsIPresShell* aPresShell, michael@0: nsIContent* aContainer, michael@0: nsIContent* aStartChild, michael@0: nsIContent* aEndChild) michael@0: { michael@0: #ifdef A11Y_LOG michael@0: if (logging::IsEnabled(logging::eTree)) { michael@0: logging::MsgBegin("TREE", "content inserted"); michael@0: logging::Node("container", aContainer); michael@0: for (nsIContent* child = aStartChild; child != aEndChild; michael@0: child = child->GetNextSibling()) { michael@0: logging::Node("content", child); michael@0: } michael@0: logging::MsgEnd(); michael@0: logging::Stack(); michael@0: } michael@0: #endif michael@0: michael@0: DocAccessible* docAccessible = GetDocAccessible(aPresShell); michael@0: if (docAccessible) michael@0: docAccessible->ContentInserted(aContainer, aStartChild, aEndChild); michael@0: } michael@0: michael@0: void michael@0: nsAccessibilityService::ContentRemoved(nsIPresShell* aPresShell, michael@0: nsIContent* aContainer, michael@0: nsIContent* aChild) michael@0: { michael@0: #ifdef A11Y_LOG michael@0: if (logging::IsEnabled(logging::eTree)) { michael@0: logging::MsgBegin("TREE", "content removed"); michael@0: logging::Node("container", aContainer); michael@0: logging::Node("content", aChild); michael@0: logging::MsgEnd(); michael@0: logging::Stack(); michael@0: } michael@0: #endif michael@0: michael@0: DocAccessible* docAccessible = GetDocAccessible(aPresShell); michael@0: if (docAccessible) michael@0: docAccessible->ContentRemoved(aContainer, aChild); michael@0: } michael@0: michael@0: void michael@0: nsAccessibilityService::UpdateText(nsIPresShell* aPresShell, michael@0: nsIContent* aContent) michael@0: { michael@0: DocAccessible* document = GetDocAccessible(aPresShell); michael@0: if (document) michael@0: document->UpdateText(aContent); michael@0: } michael@0: michael@0: void michael@0: nsAccessibilityService::TreeViewChanged(nsIPresShell* aPresShell, michael@0: nsIContent* aContent, michael@0: nsITreeView* aView) michael@0: { michael@0: DocAccessible* document = GetDocAccessible(aPresShell); michael@0: if (document) { michael@0: Accessible* accessible = document->GetAccessible(aContent); michael@0: if (accessible) { michael@0: XULTreeAccessible* treeAcc = accessible->AsXULTree(); michael@0: if (treeAcc) michael@0: treeAcc->TreeViewChanged(aView); michael@0: } michael@0: } michael@0: } michael@0: michael@0: void michael@0: nsAccessibilityService::RangeValueChanged(nsIPresShell* aPresShell, michael@0: nsIContent* aContent) michael@0: { michael@0: DocAccessible* document = GetDocAccessible(aPresShell); michael@0: if (document) { michael@0: Accessible* accessible = document->GetAccessible(aContent); michael@0: if (accessible) { michael@0: document->FireDelayedEvent(nsIAccessibleEvent::EVENT_VALUE_CHANGE, michael@0: accessible); michael@0: } michael@0: } michael@0: } michael@0: michael@0: void michael@0: nsAccessibilityService::UpdateListBullet(nsIPresShell* aPresShell, michael@0: nsIContent* aHTMLListItemContent, michael@0: bool aHasBullet) michael@0: { michael@0: DocAccessible* document = GetDocAccessible(aPresShell); michael@0: if (document) { michael@0: Accessible* accessible = document->GetAccessible(aHTMLListItemContent); michael@0: if (accessible) { michael@0: HTMLLIAccessible* listItem = accessible->AsHTMLListItem(); michael@0: if (listItem) michael@0: listItem->UpdateBullet(aHasBullet); michael@0: } michael@0: } michael@0: } michael@0: michael@0: void michael@0: nsAccessibilityService::UpdateImageMap(nsImageFrame* aImageFrame) michael@0: { michael@0: nsIPresShell* presShell = aImageFrame->PresContext()->PresShell(); michael@0: DocAccessible* document = GetDocAccessible(presShell); michael@0: if (document) { michael@0: Accessible* accessible = michael@0: document->GetAccessible(aImageFrame->GetContent()); michael@0: if (accessible) { michael@0: HTMLImageMapAccessible* imageMap = accessible->AsImageMap(); michael@0: if (imageMap) { michael@0: imageMap->UpdateChildAreas(); michael@0: return; michael@0: } michael@0: michael@0: // If image map was initialized after we created an accessible (that'll michael@0: // be an image accessible) then recreate it. michael@0: RecreateAccessible(presShell, aImageFrame->GetContent()); michael@0: } michael@0: } michael@0: } michael@0: michael@0: void michael@0: nsAccessibilityService::UpdateLabelValue(nsIPresShell* aPresShell, michael@0: nsIContent* aLabelElm, michael@0: const nsString& aNewValue) michael@0: { michael@0: DocAccessible* document = GetDocAccessible(aPresShell); michael@0: if (document) { michael@0: Accessible* accessible = document->GetAccessible(aLabelElm); michael@0: if (accessible) { michael@0: XULLabelAccessible* xulLabel = accessible->AsXULLabel(); michael@0: NS_ASSERTION(xulLabel, michael@0: "UpdateLabelValue was called for wrong accessible!"); michael@0: if (xulLabel) michael@0: xulLabel->UpdateLabelValue(aNewValue); michael@0: } michael@0: } michael@0: } michael@0: michael@0: void michael@0: nsAccessibilityService::PresShellActivated(nsIPresShell* aPresShell) michael@0: { michael@0: DocAccessible* document = aPresShell->GetDocAccessible(); michael@0: if (document) { michael@0: RootAccessible* rootDocument = document->RootAccessible(); michael@0: NS_ASSERTION(rootDocument, "Entirely broken tree: no root document!"); michael@0: if (rootDocument) michael@0: rootDocument->DocumentActivated(document); michael@0: } michael@0: } michael@0: michael@0: void michael@0: nsAccessibilityService::RecreateAccessible(nsIPresShell* aPresShell, michael@0: nsIContent* aContent) michael@0: { michael@0: DocAccessible* document = GetDocAccessible(aPresShell); michael@0: if (document) michael@0: document->RecreateAccessible(aContent); michael@0: } michael@0: michael@0: //////////////////////////////////////////////////////////////////////////////// michael@0: // nsIAccessibleRetrieval michael@0: michael@0: NS_IMETHODIMP michael@0: nsAccessibilityService::GetApplicationAccessible(nsIAccessible** aAccessibleApplication) michael@0: { michael@0: NS_ENSURE_ARG_POINTER(aAccessibleApplication); michael@0: michael@0: NS_IF_ADDREF(*aAccessibleApplication = ApplicationAcc()); michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsAccessibilityService::GetAccessibleFor(nsIDOMNode *aNode, michael@0: nsIAccessible **aAccessible) michael@0: { michael@0: NS_ENSURE_ARG_POINTER(aAccessible); michael@0: *aAccessible = nullptr; michael@0: if (!aNode) michael@0: return NS_OK; michael@0: michael@0: nsCOMPtr node(do_QueryInterface(aNode)); michael@0: if (!node) michael@0: return NS_ERROR_INVALID_ARG; michael@0: michael@0: DocAccessible* document = GetDocAccessible(node->OwnerDoc()); michael@0: if (document) michael@0: NS_IF_ADDREF(*aAccessible = document->GetAccessible(node)); michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsAccessibilityService::GetStringRole(uint32_t aRole, nsAString& aString) michael@0: { michael@0: #define ROLE(geckoRole, stringRole, atkRole, \ michael@0: macRole, msaaRole, ia2Role, nameRule) \ michael@0: case roles::geckoRole: \ michael@0: CopyUTF8toUTF16(stringRole, aString); \ michael@0: return NS_OK; michael@0: michael@0: switch (aRole) { michael@0: #include "RoleMap.h" michael@0: default: michael@0: aString.AssignLiteral("unknown"); michael@0: return NS_OK; michael@0: } michael@0: michael@0: #undef ROLE michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsAccessibilityService::GetStringStates(uint32_t aState, uint32_t aExtraState, michael@0: nsISupports **aStringStates) michael@0: { michael@0: nsRefPtr stringStates = new DOMStringList(); michael@0: michael@0: uint64_t state = nsAccUtils::To64State(aState, aExtraState); michael@0: michael@0: // states michael@0: if (state & states::UNAVAILABLE) michael@0: stringStates->Add(NS_LITERAL_STRING("unavailable")); michael@0: if (state & states::SELECTED) michael@0: stringStates->Add(NS_LITERAL_STRING("selected")); michael@0: if (state & states::FOCUSED) michael@0: stringStates->Add(NS_LITERAL_STRING("focused")); michael@0: if (state & states::PRESSED) michael@0: stringStates->Add(NS_LITERAL_STRING("pressed")); michael@0: if (state & states::CHECKED) michael@0: stringStates->Add(NS_LITERAL_STRING("checked")); michael@0: if (state & states::MIXED) michael@0: stringStates->Add(NS_LITERAL_STRING("mixed")); michael@0: if (state & states::READONLY) michael@0: stringStates->Add(NS_LITERAL_STRING("readonly")); michael@0: if (state & states::HOTTRACKED) michael@0: stringStates->Add(NS_LITERAL_STRING("hottracked")); michael@0: if (state & states::DEFAULT) michael@0: stringStates->Add(NS_LITERAL_STRING("default")); michael@0: if (state & states::EXPANDED) michael@0: stringStates->Add(NS_LITERAL_STRING("expanded")); michael@0: if (state & states::COLLAPSED) michael@0: stringStates->Add(NS_LITERAL_STRING("collapsed")); michael@0: if (state & states::BUSY) michael@0: stringStates->Add(NS_LITERAL_STRING("busy")); michael@0: if (state & states::FLOATING) michael@0: stringStates->Add(NS_LITERAL_STRING("floating")); michael@0: if (state & states::ANIMATED) michael@0: stringStates->Add(NS_LITERAL_STRING("animated")); michael@0: if (state & states::INVISIBLE) michael@0: stringStates->Add(NS_LITERAL_STRING("invisible")); michael@0: if (state & states::OFFSCREEN) michael@0: stringStates->Add(NS_LITERAL_STRING("offscreen")); michael@0: if (state & states::SIZEABLE) michael@0: stringStates->Add(NS_LITERAL_STRING("sizeable")); michael@0: if (state & states::MOVEABLE) michael@0: stringStates->Add(NS_LITERAL_STRING("moveable")); michael@0: if (state & states::SELFVOICING) michael@0: stringStates->Add(NS_LITERAL_STRING("selfvoicing")); michael@0: if (state & states::FOCUSABLE) michael@0: stringStates->Add(NS_LITERAL_STRING("focusable")); michael@0: if (state & states::SELECTABLE) michael@0: stringStates->Add(NS_LITERAL_STRING("selectable")); michael@0: if (state & states::LINKED) michael@0: stringStates->Add(NS_LITERAL_STRING("linked")); michael@0: if (state & states::TRAVERSED) michael@0: stringStates->Add(NS_LITERAL_STRING("traversed")); michael@0: if (state & states::MULTISELECTABLE) michael@0: stringStates->Add(NS_LITERAL_STRING("multiselectable")); michael@0: if (state & states::EXTSELECTABLE) michael@0: stringStates->Add(NS_LITERAL_STRING("extselectable")); michael@0: if (state & states::PROTECTED) michael@0: stringStates->Add(NS_LITERAL_STRING("protected")); michael@0: if (state & states::HASPOPUP) michael@0: stringStates->Add(NS_LITERAL_STRING("haspopup")); michael@0: if (state & states::REQUIRED) michael@0: stringStates->Add(NS_LITERAL_STRING("required")); michael@0: if (state & states::ALERT) michael@0: stringStates->Add(NS_LITERAL_STRING("alert")); michael@0: if (state & states::INVALID) michael@0: stringStates->Add(NS_LITERAL_STRING("invalid")); michael@0: if (state & states::CHECKABLE) michael@0: stringStates->Add(NS_LITERAL_STRING("checkable")); michael@0: michael@0: // extraStates michael@0: if (state & states::SUPPORTS_AUTOCOMPLETION) michael@0: stringStates->Add(NS_LITERAL_STRING("autocompletion")); michael@0: if (state & states::DEFUNCT) michael@0: stringStates->Add(NS_LITERAL_STRING("defunct")); michael@0: if (state & states::SELECTABLE_TEXT) michael@0: stringStates->Add(NS_LITERAL_STRING("selectable text")); michael@0: if (state & states::EDITABLE) michael@0: stringStates->Add(NS_LITERAL_STRING("editable")); michael@0: if (state & states::ACTIVE) michael@0: stringStates->Add(NS_LITERAL_STRING("active")); michael@0: if (state & states::MODAL) michael@0: stringStates->Add(NS_LITERAL_STRING("modal")); michael@0: if (state & states::MULTI_LINE) michael@0: stringStates->Add(NS_LITERAL_STRING("multi line")); michael@0: if (state & states::HORIZONTAL) michael@0: stringStates->Add(NS_LITERAL_STRING("horizontal")); michael@0: if (state & states::OPAQUE1) michael@0: stringStates->Add(NS_LITERAL_STRING("opaque")); michael@0: if (state & states::SINGLE_LINE) michael@0: stringStates->Add(NS_LITERAL_STRING("single line")); michael@0: if (state & states::TRANSIENT) michael@0: stringStates->Add(NS_LITERAL_STRING("transient")); michael@0: if (state & states::VERTICAL) michael@0: stringStates->Add(NS_LITERAL_STRING("vertical")); michael@0: if (state & states::STALE) michael@0: stringStates->Add(NS_LITERAL_STRING("stale")); michael@0: if (state & states::ENABLED) michael@0: stringStates->Add(NS_LITERAL_STRING("enabled")); michael@0: if (state & states::SENSITIVE) michael@0: stringStates->Add(NS_LITERAL_STRING("sensitive")); michael@0: if (state & states::EXPANDABLE) michael@0: stringStates->Add(NS_LITERAL_STRING("expandable")); michael@0: michael@0: //unknown states michael@0: if (!stringStates->Length()) michael@0: stringStates->Add(NS_LITERAL_STRING("unknown")); michael@0: michael@0: stringStates.forget(aStringStates); michael@0: return NS_OK; michael@0: } michael@0: michael@0: // nsIAccessibleRetrieval::getStringEventType() michael@0: NS_IMETHODIMP michael@0: nsAccessibilityService::GetStringEventType(uint32_t aEventType, michael@0: nsAString& aString) michael@0: { michael@0: NS_ASSERTION(nsIAccessibleEvent::EVENT_LAST_ENTRY == ArrayLength(kEventTypeNames), michael@0: "nsIAccessibleEvent constants are out of sync to kEventTypeNames"); michael@0: michael@0: if (aEventType >= ArrayLength(kEventTypeNames)) { michael@0: aString.AssignLiteral("unknown"); michael@0: return NS_OK; michael@0: } michael@0: michael@0: CopyUTF8toUTF16(kEventTypeNames[aEventType], aString); michael@0: return NS_OK; michael@0: } michael@0: michael@0: // nsIAccessibleRetrieval::getStringRelationType() michael@0: NS_IMETHODIMP michael@0: nsAccessibilityService::GetStringRelationType(uint32_t aRelationType, michael@0: nsAString& aString) michael@0: { michael@0: NS_ENSURE_ARG(aRelationType <= static_cast(RelationType::LAST)); michael@0: michael@0: #define RELATIONTYPE(geckoType, geckoTypeName, atkType, msaaType, ia2Type) \ michael@0: case RelationType::geckoType: \ michael@0: aString.AssignLiteral(geckoTypeName); \ michael@0: return NS_OK; michael@0: michael@0: RelationType relationType = static_cast(aRelationType); michael@0: switch (relationType) { michael@0: #include "RelationTypeMap.h" michael@0: default: michael@0: aString.AssignLiteral("unknown"); michael@0: return NS_OK; michael@0: } michael@0: michael@0: #undef RELATIONTYPE michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsAccessibilityService::GetAccessibleFromCache(nsIDOMNode* aNode, michael@0: nsIAccessible** aAccessible) michael@0: { michael@0: NS_ENSURE_ARG_POINTER(aAccessible); michael@0: *aAccessible = nullptr; michael@0: if (!aNode) michael@0: return NS_OK; michael@0: michael@0: nsCOMPtr node(do_QueryInterface(aNode)); michael@0: if (!node) michael@0: return NS_ERROR_INVALID_ARG; michael@0: michael@0: // Search for an accessible in each of our per document accessible object michael@0: // caches. If we don't find it, and the given node is itself a document, check michael@0: // our cache of document accessibles (document cache). Note usually shutdown michael@0: // document accessibles are not stored in the document cache, however an michael@0: // "unofficially" shutdown document (i.e. not from DocManager) can still michael@0: // exist in the document cache. michael@0: Accessible* accessible = FindAccessibleInCache(node); michael@0: if (!accessible) { michael@0: nsCOMPtr document(do_QueryInterface(node)); michael@0: if (document) michael@0: accessible = GetExistingDocAccessible(document); michael@0: } michael@0: michael@0: NS_IF_ADDREF(*aAccessible = accessible); michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsAccessibilityService::CreateAccessiblePivot(nsIAccessible* aRoot, michael@0: nsIAccessiblePivot** aPivot) michael@0: { michael@0: NS_ENSURE_ARG_POINTER(aPivot); michael@0: NS_ENSURE_ARG(aRoot); michael@0: *aPivot = nullptr; michael@0: michael@0: nsRefPtr accessibleRoot(do_QueryObject(aRoot)); michael@0: NS_ENSURE_TRUE(accessibleRoot, NS_ERROR_INVALID_ARG); michael@0: michael@0: nsAccessiblePivot* pivot = new nsAccessiblePivot(accessibleRoot); michael@0: NS_ADDREF(*aPivot = pivot); michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsAccessibilityService::SetLogging(const nsACString& aModules) michael@0: { michael@0: #ifdef A11Y_LOG michael@0: logging::Enable(PromiseFlatCString(aModules)); michael@0: #endif michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsAccessibilityService::IsLogged(const nsAString& aModule, bool* aIsLogged) michael@0: { michael@0: NS_ENSURE_ARG_POINTER(aIsLogged); michael@0: *aIsLogged = false; michael@0: michael@0: #ifdef A11Y_LOG michael@0: *aIsLogged = logging::IsEnabled(aModule); michael@0: #endif michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: //////////////////////////////////////////////////////////////////////////////// michael@0: // nsAccessibilityService public michael@0: michael@0: Accessible* michael@0: nsAccessibilityService::GetOrCreateAccessible(nsINode* aNode, michael@0: Accessible* aContext, michael@0: bool* aIsSubtreeHidden) michael@0: { michael@0: NS_PRECONDITION(aContext && aNode && !gIsShutdown, michael@0: "Maybe let'd do a crash? Oh, yes, baby!"); michael@0: michael@0: if (aIsSubtreeHidden) michael@0: *aIsSubtreeHidden = false; michael@0: michael@0: DocAccessible* document = aContext->Document(); michael@0: michael@0: // Check to see if we already have an accessible for this node in the cache. michael@0: // XXX: we don't have context check here. It doesn't really necessary until michael@0: // we have in-law children adoption. michael@0: Accessible* cachedAccessible = document->GetAccessible(aNode); michael@0: if (cachedAccessible) michael@0: return cachedAccessible; michael@0: michael@0: // No cache entry, so we must create the accessible. michael@0: michael@0: if (aNode->IsNodeOfType(nsINode::eDOCUMENT)) { michael@0: // If it's document node then ask accessible document loader for michael@0: // document accessible, otherwise return null. michael@0: nsCOMPtr document(do_QueryInterface(aNode)); michael@0: return GetDocAccessible(document); michael@0: } michael@0: michael@0: // We have a content node. michael@0: if (!aNode->IsInDoc()) { michael@0: NS_WARNING("Creating accessible for node with no document"); michael@0: return nullptr; michael@0: } michael@0: michael@0: if (aNode->OwnerDoc() != document->DocumentNode()) { michael@0: NS_ERROR("Creating accessible for wrong document"); michael@0: return nullptr; michael@0: } michael@0: michael@0: if (!aNode->IsContent()) michael@0: return nullptr; michael@0: michael@0: nsIContent* content = aNode->AsContent(); michael@0: nsIFrame* frame = content->GetPrimaryFrame(); michael@0: michael@0: // Check frame and its visibility. Note, hidden frame allows visible michael@0: // elements in subtree. michael@0: if (!frame || !frame->StyleVisibility()->IsVisible()) { michael@0: if (aIsSubtreeHidden && !frame) michael@0: *aIsSubtreeHidden = true; michael@0: michael@0: return nullptr; michael@0: } michael@0: michael@0: if (frame->GetContent() != content) { michael@0: // Not the main content for this frame. This happens because michael@0: // elements return the image frame as their primary frame. The main content michael@0: // for the image frame is the image content. If the frame is not an image michael@0: // frame or the node is not an area element then null is returned. michael@0: // This setup will change when bug 135040 is fixed. Make sure we don't michael@0: // create area accessible here. Hopefully assertion below will handle that. michael@0: michael@0: #ifdef DEBUG michael@0: nsImageFrame* imageFrame = do_QueryFrame(frame); michael@0: NS_ASSERTION(imageFrame && content->IsHTML() && content->Tag() == nsGkAtoms::area, michael@0: "Unknown case of not main content for the frame!"); michael@0: #endif michael@0: return nullptr; michael@0: } michael@0: michael@0: #ifdef DEBUG michael@0: nsImageFrame* imageFrame = do_QueryFrame(frame); michael@0: NS_ASSERTION(!imageFrame || !content->IsHTML() || content->Tag() != nsGkAtoms::area, michael@0: "Image map manages the area accessible creation!"); michael@0: #endif michael@0: michael@0: // Attempt to create an accessible based on what we know. michael@0: nsRefPtr newAcc; michael@0: michael@0: // Create accessible for visible text frames. michael@0: if (content->IsNodeOfType(nsINode::eTEXT)) { michael@0: nsAutoString text; michael@0: frame->GetRenderedText(&text, nullptr, nullptr, 0, UINT32_MAX); michael@0: // Ignore not rendered text nodes and whitespace text nodes between table michael@0: // cells. michael@0: if (text.IsEmpty() || michael@0: (aContext->IsTableRow() && nsCoreUtils::IsWhitespaceString(text))) { michael@0: if (aIsSubtreeHidden) michael@0: *aIsSubtreeHidden = true; michael@0: michael@0: return nullptr; michael@0: } michael@0: michael@0: newAcc = CreateAccessibleByFrameType(frame, content, aContext); michael@0: if (!aContext->IsAcceptableChild(newAcc)) michael@0: return nullptr; michael@0: michael@0: document->BindToDocument(newAcc, nullptr); michael@0: newAcc->AsTextLeaf()->SetText(text); michael@0: return newAcc; michael@0: } michael@0: michael@0: bool isHTML = content->IsHTML(); michael@0: if (isHTML && content->Tag() == nsGkAtoms::map) { michael@0: // Create hyper text accessible for HTML map if it is used to group links michael@0: // (see http://www.w3.org/TR/WCAG10-HTML-TECHS/#group-bypass). If the HTML michael@0: // map rect is empty then it is used for links grouping. Otherwise it should michael@0: // be used in conjunction with HTML image element and in this case we don't michael@0: // create any accessible for it and don't walk into it. The accessibles for michael@0: // HTML area (HTMLAreaAccessible) the map contains are attached as michael@0: // children of the appropriate accessible for HTML image michael@0: // (ImageAccessible). michael@0: if (nsLayoutUtils::GetAllInFlowRectsUnion(frame, michael@0: frame->GetParent()).IsEmpty()) { michael@0: if (aIsSubtreeHidden) michael@0: *aIsSubtreeHidden = true; michael@0: michael@0: return nullptr; michael@0: } michael@0: michael@0: newAcc = new HyperTextAccessibleWrap(content, document); michael@0: if (!aContext->IsAcceptableChild(newAcc)) michael@0: return nullptr; michael@0: michael@0: document->BindToDocument(newAcc, aria::GetRoleMap(aNode)); michael@0: return newAcc; michael@0: } michael@0: michael@0: nsRoleMapEntry* roleMapEntry = aria::GetRoleMap(aNode); michael@0: michael@0: // If the element is focusable or global ARIA attribute is applied to it or michael@0: // it is referenced by ARIA relationship then treat role="presentation" on michael@0: // the element as the role is not there. michael@0: if (roleMapEntry && roleMapEntry->Is(nsGkAtoms::presentation)) { michael@0: if (!MustBeAccessible(content, document)) michael@0: return nullptr; michael@0: michael@0: roleMapEntry = nullptr; michael@0: } michael@0: michael@0: if (!newAcc && isHTML) { // HTML accessibles michael@0: if (roleMapEntry) { michael@0: // Create pure ARIA grid/treegrid related accessibles if they weren't used michael@0: // on accessible HTML table elements. michael@0: if ((roleMapEntry->accTypes & eTableCell)) { michael@0: if (aContext->IsTableRow() && michael@0: (frame->AccessibleType() != eHTMLTableCellType || michael@0: aContext->GetContent() != content->GetParent())) { michael@0: newAcc = new ARIAGridCellAccessibleWrap(content, document); michael@0: } michael@0: michael@0: } else if ((roleMapEntry->IsOfType(eTable)) && michael@0: frame->AccessibleType() != eHTMLTableType) { michael@0: newAcc = new ARIAGridAccessibleWrap(content, document); michael@0: } michael@0: } michael@0: michael@0: if (!newAcc) { michael@0: // Prefer to use markup (mostly tag name, perhaps attributes) to decide if michael@0: // and what kind of accessible to create. michael@0: newAcc = CreateHTMLAccessibleByMarkup(frame, content, aContext); michael@0: michael@0: // Try using frame to do it. michael@0: if (!newAcc) michael@0: newAcc = CreateAccessibleByFrameType(frame, content, aContext); michael@0: michael@0: // If table has strong ARIA role then all table descendants shouldn't michael@0: // expose their native roles. michael@0: if (!roleMapEntry && newAcc) { michael@0: if (frame->AccessibleType() == eHTMLTableRowType) { michael@0: nsRoleMapEntry* contextRoleMap = aContext->ARIARoleMap(); michael@0: if (contextRoleMap && !(contextRoleMap->IsOfType(eTable))) michael@0: roleMapEntry = &aria::gEmptyRoleMap; michael@0: michael@0: } else if (frame->AccessibleType() == eHTMLTableCellType && michael@0: aContext->ARIARoleMap() == &aria::gEmptyRoleMap) { michael@0: roleMapEntry = &aria::gEmptyRoleMap; michael@0: michael@0: } else if (content->Tag() == nsGkAtoms::dt || michael@0: content->Tag() == nsGkAtoms::li || michael@0: content->Tag() == nsGkAtoms::dd || michael@0: frame->AccessibleType() == eHTMLLiType) { michael@0: nsRoleMapEntry* contextRoleMap = aContext->ARIARoleMap(); michael@0: if (contextRoleMap && !(contextRoleMap->IsOfType(eList))) michael@0: roleMapEntry = &aria::gEmptyRoleMap; michael@0: } michael@0: } michael@0: } michael@0: } michael@0: michael@0: // Accessible XBL types and deck stuff are used in XUL only currently. michael@0: if (!newAcc && content->IsXUL()) { michael@0: // No accessible for not selected deck panel and its children. michael@0: if (!aContext->IsXULTabpanels()) { michael@0: nsDeckFrame* deckFrame = do_QueryFrame(frame->GetParent()); michael@0: if (deckFrame && deckFrame->GetSelectedBox() != frame) { michael@0: if (aIsSubtreeHidden) michael@0: *aIsSubtreeHidden = true; michael@0: michael@0: return nullptr; michael@0: } michael@0: } michael@0: michael@0: // XBL bindings may use @role attribute to point the accessible type michael@0: // they belong to. michael@0: newAcc = CreateAccessibleByType(content, document); michael@0: michael@0: // Any XUL box can be used as tabpanel, make sure we create a proper michael@0: // accessible for it. michael@0: if (!newAcc && aContext->IsXULTabpanels() && michael@0: content->GetParent() == aContext->GetContent()) { michael@0: nsIAtom* frameType = frame->GetType(); michael@0: if (frameType == nsGkAtoms::boxFrame || michael@0: frameType == nsGkAtoms::scrollFrame) { michael@0: newAcc = new XULTabpanelAccessible(content, document); michael@0: } michael@0: } michael@0: } michael@0: michael@0: if (!newAcc) { michael@0: if (content->IsSVG()) { michael@0: nsSVGPathGeometryFrame* pathGeometryFrame = do_QueryFrame(frame); michael@0: if (pathGeometryFrame) { michael@0: // A graphic elements: rect, circle, ellipse, line, path, polygon, michael@0: // polyline and image. A 'use' and 'text' graphic elements require michael@0: // special support. michael@0: newAcc = new EnumRoleAccessible(content, document, roles::GRAPHIC); michael@0: } else if (content->Tag() == nsGkAtoms::svg) { michael@0: newAcc = new EnumRoleAccessible(content, document, roles::DIAGRAM); michael@0: } michael@0: } else if (content->IsMathML()){ michael@0: if (content->Tag() == nsGkAtoms::math) michael@0: newAcc = new EnumRoleAccessible(content, document, roles::EQUATION); michael@0: else michael@0: newAcc = new HyperTextAccessible(content, document); michael@0: } michael@0: } michael@0: michael@0: // If no accessible, see if we need to create a generic accessible because michael@0: // of some property that makes this object interesting michael@0: // We don't do this for , , , etc. which michael@0: // correspond to the doc accessible and will be created in any case michael@0: if (!newAcc && content->Tag() != nsGkAtoms::body && content->GetParent() && michael@0: (roleMapEntry || MustBeAccessible(content, document) || michael@0: (isHTML && nsCoreUtils::HasClickListener(content)))) { michael@0: // This content is focusable or has an interesting dynamic content accessibility property. michael@0: // If it's interesting we need it in the accessibility hierarchy so that events or michael@0: // other accessibles can point to it, or so that it can hold a state, etc. michael@0: if (isHTML) { michael@0: // Interesting HTML container which may have selectable text and/or embedded objects michael@0: newAcc = new HyperTextAccessibleWrap(content, document); michael@0: } else { // XUL, SVG, MathML etc. michael@0: // Interesting generic non-HTML container michael@0: newAcc = new AccessibleWrap(content, document); michael@0: } michael@0: } michael@0: michael@0: if (!newAcc || !aContext->IsAcceptableChild(newAcc)) michael@0: return nullptr; michael@0: michael@0: document->BindToDocument(newAcc, roleMapEntry); michael@0: return newAcc; michael@0: } michael@0: michael@0: //////////////////////////////////////////////////////////////////////////////// michael@0: // nsAccessibilityService private michael@0: michael@0: bool michael@0: nsAccessibilityService::Init() michael@0: { michael@0: // Initialize accessible document manager. michael@0: if (!DocManager::Init()) michael@0: return false; michael@0: michael@0: // Add observers. michael@0: nsCOMPtr observerService = michael@0: mozilla::services::GetObserverService(); michael@0: if (!observerService) michael@0: return false; michael@0: michael@0: observerService->AddObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID, false); michael@0: michael@0: static const char16_t kInitIndicator[] = { '1', 0 }; michael@0: observerService->NotifyObservers(nullptr, "a11y-init-or-shutdown", kInitIndicator); michael@0: michael@0: #ifdef A11Y_LOG michael@0: logging::CheckEnv(); michael@0: #endif michael@0: michael@0: gApplicationAccessible = new ApplicationAccessibleWrap(); michael@0: NS_ADDREF(gApplicationAccessible); // will release in Shutdown() michael@0: michael@0: #ifdef MOZ_CRASHREPORTER michael@0: CrashReporter:: michael@0: AnnotateCrashReport(NS_LITERAL_CSTRING("Accessibility"), michael@0: NS_LITERAL_CSTRING("Active")); michael@0: #endif michael@0: michael@0: #ifdef XP_WIN michael@0: sPendingPlugins = new nsTArray >; michael@0: sPluginTimers = new nsTArray >; michael@0: #endif michael@0: michael@0: gIsShutdown = false; michael@0: michael@0: // Now its safe to start platform accessibility. michael@0: PlatformInit(); michael@0: michael@0: return true; michael@0: } michael@0: michael@0: void michael@0: nsAccessibilityService::Shutdown() michael@0: { michael@0: // Remove observers. michael@0: nsCOMPtr observerService = michael@0: mozilla::services::GetObserverService(); michael@0: if (observerService) { michael@0: observerService->RemoveObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID); michael@0: michael@0: static const char16_t kShutdownIndicator[] = { '0', 0 }; michael@0: observerService->NotifyObservers(nullptr, "a11y-init-or-shutdown", kShutdownIndicator); michael@0: } michael@0: michael@0: // Stop accessible document loader. michael@0: DocManager::Shutdown(); michael@0: michael@0: SelectionManager::Shutdown(); michael@0: michael@0: #ifdef XP_WIN michael@0: sPendingPlugins = nullptr; michael@0: michael@0: uint32_t timerCount = sPluginTimers->Length(); michael@0: for (uint32_t i = 0; i < timerCount; i++) michael@0: sPluginTimers->ElementAt(i)->Cancel(); michael@0: michael@0: sPluginTimers = nullptr; michael@0: #endif michael@0: michael@0: // Application is going to be closed, shutdown accessibility and mark michael@0: // accessibility service as shutdown to prevent calls of its methods. michael@0: // Don't null accessibility service static member at this point to be safe michael@0: // if someone will try to operate with it. michael@0: michael@0: NS_ASSERTION(!gIsShutdown, "Accessibility was shutdown already"); michael@0: michael@0: gIsShutdown = true; michael@0: michael@0: PlatformShutdown(); michael@0: gApplicationAccessible->Shutdown(); michael@0: NS_RELEASE(gApplicationAccessible); michael@0: gApplicationAccessible = nullptr; michael@0: } michael@0: michael@0: already_AddRefed michael@0: nsAccessibilityService::CreateAccessibleByType(nsIContent* aContent, michael@0: DocAccessible* aDoc) michael@0: { michael@0: nsAutoString role; michael@0: for (const nsXBLBinding* binding = aContent->GetXBLBinding(); binding; binding = binding->GetBaseBinding()) { michael@0: nsIContent* bindingElm = binding->PrototypeBinding()->GetBindingElement(); michael@0: bindingElm->GetAttr(kNameSpaceID_None, nsGkAtoms::role, role); michael@0: if (!role.IsEmpty()) michael@0: break; michael@0: } michael@0: michael@0: if (role.IsEmpty() || role.EqualsLiteral("none")) michael@0: return nullptr; michael@0: michael@0: if (role.EqualsLiteral("outerdoc")) { michael@0: nsRefPtr accessible = new OuterDocAccessible(aContent, aDoc); michael@0: return accessible.forget(); michael@0: } michael@0: michael@0: nsRefPtr accessible; michael@0: #ifdef MOZ_XUL michael@0: // XUL controls michael@0: if (role.EqualsLiteral("xul:alert")) { michael@0: accessible = new XULAlertAccessible(aContent, aDoc); michael@0: michael@0: } else if (role.EqualsLiteral("xul:button")) { michael@0: accessible = new XULButtonAccessible(aContent, aDoc); michael@0: michael@0: } else if (role.EqualsLiteral("xul:checkbox")) { michael@0: accessible = new XULCheckboxAccessible(aContent, aDoc); michael@0: michael@0: } else if (role.EqualsLiteral("xul:colorpicker")) { michael@0: accessible = new XULColorPickerAccessible(aContent, aDoc); michael@0: michael@0: } else if (role.EqualsLiteral("xul:colorpickertile")) { michael@0: accessible = new XULColorPickerTileAccessible(aContent, aDoc); michael@0: michael@0: } else if (role.EqualsLiteral("xul:combobox")) { michael@0: accessible = new XULComboboxAccessible(aContent, aDoc); michael@0: michael@0: } else if (role.EqualsLiteral("xul:tabpanels")) { michael@0: accessible = new XULTabpanelsAccessible(aContent, aDoc); michael@0: michael@0: } else if (role.EqualsLiteral("xul:dropmarker")) { michael@0: accessible = new XULDropmarkerAccessible(aContent, aDoc); michael@0: michael@0: } else if (role.EqualsLiteral("xul:groupbox")) { michael@0: accessible = new XULGroupboxAccessible(aContent, aDoc); michael@0: michael@0: } else if (role.EqualsLiteral("xul:image")) { michael@0: if (aContent->HasAttr(kNameSpaceID_None, nsGkAtoms::onclick)) { michael@0: accessible = new XULToolbarButtonAccessible(aContent, aDoc); michael@0: michael@0: } else { michael@0: // Don't include nameless images in accessible tree. michael@0: if (!aContent->HasAttr(kNameSpaceID_None, michael@0: nsGkAtoms::tooltiptext)) michael@0: return nullptr; michael@0: michael@0: accessible = new ImageAccessibleWrap(aContent, aDoc); michael@0: } michael@0: michael@0: } else if (role.EqualsLiteral("xul:link")) { michael@0: accessible = new XULLinkAccessible(aContent, aDoc); michael@0: michael@0: } else if (role.EqualsLiteral("xul:listbox")) { michael@0: accessible = new XULListboxAccessibleWrap(aContent, aDoc); michael@0: michael@0: } else if (role.EqualsLiteral("xul:listcell")) { michael@0: // Only create cells if there's more than one per row. michael@0: nsIContent* listItem = aContent->GetParent(); michael@0: if (!listItem) michael@0: return nullptr; michael@0: michael@0: for (nsIContent* child = listItem->GetFirstChild(); child; michael@0: child = child->GetNextSibling()) { michael@0: if (child->IsXUL(nsGkAtoms::listcell) && child != aContent) { michael@0: accessible = new XULListCellAccessibleWrap(aContent, aDoc); michael@0: break; michael@0: } michael@0: } michael@0: michael@0: } else if (role.EqualsLiteral("xul:listhead")) { michael@0: accessible = new XULColumAccessible(aContent, aDoc); michael@0: michael@0: } else if (role.EqualsLiteral("xul:listheader")) { michael@0: accessible = new XULColumnItemAccessible(aContent, aDoc); michael@0: michael@0: } else if (role.EqualsLiteral("xul:listitem")) { michael@0: accessible = new XULListitemAccessible(aContent, aDoc); michael@0: michael@0: } else if (role.EqualsLiteral("xul:menubar")) { michael@0: accessible = new XULMenubarAccessible(aContent, aDoc); michael@0: michael@0: } else if (role.EqualsLiteral("xul:menulist")) { michael@0: accessible = new XULComboboxAccessible(aContent, aDoc); michael@0: michael@0: } else if (role.EqualsLiteral("xul:menuitem")) { michael@0: accessible = new XULMenuitemAccessibleWrap(aContent, aDoc); michael@0: michael@0: } else if (role.EqualsLiteral("xul:menupopup")) { michael@0: #ifdef MOZ_ACCESSIBILITY_ATK michael@0: // ATK considers this node to be redundant when within menubars, and it makes menu michael@0: // navigation with assistive technologies more difficult michael@0: // XXX In the future we will should this for consistency across the nsIAccessible michael@0: // implementations on each platform for a consistent scripting environment, but michael@0: // then strip out redundant accessibles in the AccessibleWrap class for each platform. michael@0: nsIContent *parent = aContent->GetParent(); michael@0: if (parent && parent->IsXUL() && parent->Tag() == nsGkAtoms::menu) michael@0: return nullptr; michael@0: #endif michael@0: michael@0: accessible = new XULMenupopupAccessible(aContent, aDoc); michael@0: michael@0: } else if(role.EqualsLiteral("xul:menuseparator")) { michael@0: accessible = new XULMenuSeparatorAccessible(aContent, aDoc); michael@0: michael@0: } else if(role.EqualsLiteral("xul:pane")) { michael@0: accessible = new EnumRoleAccessible(aContent, aDoc, roles::PANE); michael@0: michael@0: } else if (role.EqualsLiteral("xul:panel")) { michael@0: if (aContent->AttrValueIs(kNameSpaceID_None, nsGkAtoms::noautofocus, michael@0: nsGkAtoms::_true, eCaseMatters)) michael@0: accessible = new XULAlertAccessible(aContent, aDoc); michael@0: else michael@0: accessible = new EnumRoleAccessible(aContent, aDoc, roles::PANE); michael@0: michael@0: } else if (role.EqualsLiteral("xul:progressmeter")) { michael@0: accessible = new XULProgressMeterAccessible(aContent, aDoc); michael@0: michael@0: } else if (role.EqualsLiteral("xulstatusbar")) { michael@0: accessible = new XULStatusBarAccessible(aContent, aDoc); michael@0: michael@0: } else if (role.EqualsLiteral("xul:scale")) { michael@0: accessible = new XULSliderAccessible(aContent, aDoc); michael@0: michael@0: } else if (role.EqualsLiteral("xul:radiobutton")) { michael@0: accessible = new XULRadioButtonAccessible(aContent, aDoc); michael@0: michael@0: } else if (role.EqualsLiteral("xul:radiogroup")) { michael@0: accessible = new XULRadioGroupAccessible(aContent, aDoc); michael@0: michael@0: } else if (role.EqualsLiteral("xul:tab")) { michael@0: accessible = new XULTabAccessible(aContent, aDoc); michael@0: michael@0: } else if (role.EqualsLiteral("xul:tabs")) { michael@0: accessible = new XULTabsAccessible(aContent, aDoc); michael@0: michael@0: } else if (role.EqualsLiteral("xul:text")) { michael@0: accessible = new XULLabelAccessible(aContent, aDoc); michael@0: michael@0: } else if (role.EqualsLiteral("xul:textbox")) { michael@0: accessible = new EnumRoleAccessible(aContent, aDoc, roles::SECTION); michael@0: michael@0: } else if (role.EqualsLiteral("xul:thumb")) { michael@0: accessible = new XULThumbAccessible(aContent, aDoc); michael@0: michael@0: } else if (role.EqualsLiteral("xul:tree")) { michael@0: accessible = CreateAccessibleForXULTree(aContent, aDoc); michael@0: michael@0: } else if (role.EqualsLiteral("xul:treecolumns")) { michael@0: accessible = new XULTreeColumAccessible(aContent, aDoc); michael@0: michael@0: } else if (role.EqualsLiteral("xul:treecolumnitem")) { michael@0: accessible = new XULColumnItemAccessible(aContent, aDoc); michael@0: michael@0: } else if (role.EqualsLiteral("xul:toolbar")) { michael@0: accessible = new XULToolbarAccessible(aContent, aDoc); michael@0: michael@0: } else if (role.EqualsLiteral("xul:toolbarseparator")) { michael@0: accessible = new XULToolbarSeparatorAccessible(aContent, aDoc); michael@0: michael@0: } else if (role.EqualsLiteral("xul:tooltip")) { michael@0: accessible = new XULTooltipAccessible(aContent, aDoc); michael@0: michael@0: } else if (role.EqualsLiteral("xul:toolbarbutton")) { michael@0: accessible = new XULToolbarButtonAccessible(aContent, aDoc); michael@0: michael@0: } michael@0: #endif // MOZ_XUL michael@0: michael@0: return accessible.forget(); michael@0: } michael@0: michael@0: already_AddRefed michael@0: nsAccessibilityService::CreateHTMLAccessibleByMarkup(nsIFrame* aFrame, michael@0: nsIContent* aContent, michael@0: Accessible* aContext) michael@0: { michael@0: DocAccessible* document = aContext->Document(); michael@0: if (aContext->IsTableRow()) { michael@0: if (nsCoreUtils::IsHTMLTableHeader(aContent) && michael@0: aContext->GetContent() == aContent->GetParent()) { michael@0: nsRefPtr accessible = michael@0: new HTMLTableHeaderCellAccessibleWrap(aContent, document); michael@0: return accessible.forget(); michael@0: } michael@0: michael@0: return nullptr; michael@0: } michael@0: michael@0: // This method assumes we're in an HTML namespace. michael@0: nsIAtom* tag = aContent->Tag(); michael@0: if (tag == nsGkAtoms::figcaption) { michael@0: nsRefPtr accessible = michael@0: new HTMLFigcaptionAccessible(aContent, document); michael@0: return accessible.forget(); michael@0: } michael@0: michael@0: if (tag == nsGkAtoms::figure) { michael@0: nsRefPtr accessible = michael@0: new HTMLFigureAccessible(aContent, document); michael@0: return accessible.forget(); michael@0: } michael@0: michael@0: if (tag == nsGkAtoms::legend) { michael@0: nsRefPtr accessible = michael@0: new HTMLLegendAccessible(aContent, document); michael@0: return accessible.forget(); michael@0: } michael@0: michael@0: if (tag == nsGkAtoms::option) { michael@0: nsRefPtr accessible = michael@0: new HTMLSelectOptionAccessible(aContent, document); michael@0: return accessible.forget(); michael@0: } michael@0: michael@0: if (tag == nsGkAtoms::optgroup) { michael@0: nsRefPtr accessible = michael@0: new HTMLSelectOptGroupAccessible(aContent, document); michael@0: return accessible.forget(); michael@0: } michael@0: michael@0: if (tag == nsGkAtoms::ul || tag == nsGkAtoms::ol || michael@0: tag == nsGkAtoms::dl) { michael@0: nsRefPtr accessible = michael@0: new HTMLListAccessible(aContent, document); michael@0: return accessible.forget(); michael@0: } michael@0: michael@0: if (tag == nsGkAtoms::a) { michael@0: // Only some roles truly enjoy life as HTMLLinkAccessibles, for details michael@0: // see closed bug 494807. michael@0: nsRoleMapEntry* roleMapEntry = aria::GetRoleMap(aContent); michael@0: if (roleMapEntry && roleMapEntry->role != roles::NOTHING && michael@0: roleMapEntry->role != roles::LINK) { michael@0: nsRefPtr accessible = michael@0: new HyperTextAccessibleWrap(aContent, document); michael@0: return accessible.forget(); michael@0: } michael@0: michael@0: nsRefPtr accessible = michael@0: new HTMLLinkAccessible(aContent, document); michael@0: return accessible.forget(); michael@0: } michael@0: michael@0: if (aContext->IsList()) { michael@0: // If list item is a child of accessible list then create an accessible for michael@0: // it unconditionally by tag name. nsBlockFrame creates the list item michael@0: // accessible for other elements styled as list items. michael@0: if (aContext->GetContent() == aContent->GetParent()) { michael@0: if (tag == nsGkAtoms::dt || tag == nsGkAtoms::li) { michael@0: nsRefPtr accessible = michael@0: new HTMLLIAccessible(aContent, document); michael@0: return accessible.forget(); michael@0: } michael@0: michael@0: if (tag == nsGkAtoms::dd) { michael@0: nsRefPtr accessible = michael@0: new HyperTextAccessibleWrap(aContent, document); michael@0: return accessible.forget(); michael@0: } michael@0: } michael@0: michael@0: return nullptr; michael@0: } michael@0: michael@0: if (tag == nsGkAtoms::abbr || michael@0: tag == nsGkAtoms::acronym || michael@0: tag == nsGkAtoms::article || michael@0: tag == nsGkAtoms::aside || michael@0: tag == nsGkAtoms::blockquote || michael@0: tag == nsGkAtoms::form || michael@0: tag == nsGkAtoms::footer || michael@0: tag == nsGkAtoms::header || michael@0: tag == nsGkAtoms::h1 || michael@0: tag == nsGkAtoms::h2 || michael@0: tag == nsGkAtoms::h3 || michael@0: tag == nsGkAtoms::h4 || michael@0: tag == nsGkAtoms::h5 || michael@0: tag == nsGkAtoms::h6 || michael@0: tag == nsGkAtoms::nav || michael@0: tag == nsGkAtoms::q || michael@0: tag == nsGkAtoms::section) { michael@0: nsRefPtr accessible = michael@0: new HyperTextAccessibleWrap(aContent, document); michael@0: return accessible.forget(); michael@0: } michael@0: michael@0: if (tag == nsGkAtoms::label) { michael@0: nsRefPtr accessible = michael@0: new HTMLLabelAccessible(aContent, document); michael@0: return accessible.forget(); michael@0: } michael@0: michael@0: if (tag == nsGkAtoms::output) { michael@0: nsRefPtr accessible = michael@0: new HTMLOutputAccessible(aContent, document); michael@0: return accessible.forget(); michael@0: } michael@0: michael@0: if (tag == nsGkAtoms::progress) { michael@0: nsRefPtr accessible = michael@0: new HTMLProgressMeterAccessible(aContent, document); michael@0: return accessible.forget(); michael@0: } michael@0: michael@0: return nullptr; michael@0: } michael@0: michael@0: already_AddRefed michael@0: nsAccessibilityService::CreateAccessibleByFrameType(nsIFrame* aFrame, michael@0: nsIContent* aContent, michael@0: Accessible* aContext) michael@0: { michael@0: DocAccessible* document = aContext->Document(); michael@0: michael@0: nsRefPtr newAcc; michael@0: switch (aFrame->AccessibleType()) { michael@0: case eNoType: michael@0: return nullptr; michael@0: case eHTMLBRType: michael@0: newAcc = new HTMLBRAccessible(aContent, document); michael@0: break; michael@0: case eHTMLButtonType: michael@0: newAcc = new HTMLButtonAccessible(aContent, document); michael@0: break; michael@0: case eHTMLCanvasType: michael@0: newAcc = new HTMLCanvasAccessible(aContent, document); michael@0: break; michael@0: case eHTMLCaptionType: michael@0: if (aContext->IsTable() && michael@0: aContext->GetContent() == aContent->GetParent()) { michael@0: newAcc = new HTMLCaptionAccessible(aContent, document); michael@0: } michael@0: break; michael@0: case eHTMLCheckboxType: michael@0: newAcc = new HTMLCheckboxAccessible(aContent, document); michael@0: break; michael@0: case eHTMLComboboxType: michael@0: newAcc = new HTMLComboboxAccessible(aContent, document); michael@0: break; michael@0: case eHTMLFileInputType: michael@0: newAcc = new HTMLFileInputAccessible(aContent, document); michael@0: break; michael@0: case eHTMLGroupboxType: michael@0: newAcc = new HTMLGroupboxAccessible(aContent, document); michael@0: break; michael@0: case eHTMLHRType: michael@0: newAcc = new HTMLHRAccessible(aContent, document); michael@0: break; michael@0: case eHTMLImageMapType: michael@0: newAcc = new HTMLImageMapAccessible(aContent, document); michael@0: break; michael@0: case eHTMLLiType: michael@0: if (aContext->IsList() && michael@0: aContext->GetContent() == aContent->GetParent()) { michael@0: newAcc = new HTMLLIAccessible(aContent, document); michael@0: } michael@0: break; michael@0: case eHTMLSelectListType: michael@0: newAcc = new HTMLSelectListAccessible(aContent, document); michael@0: break; michael@0: case eHTMLMediaType: michael@0: newAcc = new EnumRoleAccessible(aContent, document, roles::GROUPING); michael@0: break; michael@0: case eHTMLRadioButtonType: michael@0: newAcc = new HTMLRadioButtonAccessible(aContent, document); michael@0: break; michael@0: case eHTMLRangeType: michael@0: newAcc = new HTMLRangeAccessible(aContent, document); michael@0: break; michael@0: case eHTMLSpinnerType: michael@0: newAcc = new HTMLSpinnerAccessible(aContent, document); michael@0: break; michael@0: case eHTMLTableType: michael@0: newAcc = new HTMLTableAccessibleWrap(aContent, document); michael@0: break; michael@0: case eHTMLTableCellType: michael@0: // Accessible HTML table cell should be a child of accessible HTML table michael@0: // or its row (CSS HTML tables are polite to the used markup at michael@0: // certain degree). michael@0: // Otherwise create a generic text accessible to avoid text jamming michael@0: // when reading by AT. michael@0: if (aContext->IsHTMLTableRow() || aContext->IsHTMLTable()) michael@0: newAcc = new HTMLTableCellAccessibleWrap(aContent, document); michael@0: else michael@0: newAcc = new HyperTextAccessibleWrap(aContent, document); michael@0: break; michael@0: michael@0: case eHTMLTableRowType: { michael@0: // Accessible HTML table row must be a child of tbody/tfoot/thead of michael@0: // accessible HTML table or must be a child of accessible of HTML table. michael@0: if (aContext->IsTable()) { michael@0: nsIContent* parentContent = aContent->GetParent(); michael@0: nsIFrame* parentFrame = parentContent->GetPrimaryFrame(); michael@0: if (parentFrame->GetType() == nsGkAtoms::tableRowGroupFrame) { michael@0: parentContent = parentContent->GetParent(); michael@0: parentFrame = parentContent->GetPrimaryFrame(); michael@0: } michael@0: michael@0: if (parentFrame->GetType() == nsGkAtoms::tableOuterFrame && michael@0: aContext->GetContent() == parentContent) { michael@0: newAcc = new HTMLTableRowAccessible(aContent, document); michael@0: } michael@0: } michael@0: break; michael@0: } michael@0: case eHTMLTextFieldType: michael@0: newAcc = new HTMLTextFieldAccessible(aContent, document); michael@0: break; michael@0: case eHyperTextType: michael@0: if (aContent->Tag() != nsGkAtoms::dt && aContent->Tag() != nsGkAtoms::dd) michael@0: newAcc = new HyperTextAccessibleWrap(aContent, document); michael@0: break; michael@0: michael@0: case eImageType: michael@0: newAcc = new ImageAccessibleWrap(aContent, document); michael@0: break; michael@0: case eOuterDocType: michael@0: newAcc = new OuterDocAccessible(aContent, document); michael@0: break; michael@0: case ePluginType: { michael@0: nsObjectFrame* objectFrame = do_QueryFrame(aFrame); michael@0: newAcc = CreatePluginAccessible(objectFrame, aContent, aContext); michael@0: break; michael@0: } michael@0: case eTextLeafType: michael@0: newAcc = new TextLeafAccessibleWrap(aContent, document); michael@0: break; michael@0: default: michael@0: MOZ_ASSERT(false); michael@0: break; michael@0: } michael@0: michael@0: return newAcc.forget(); michael@0: } michael@0: michael@0: //////////////////////////////////////////////////////////////////////////////// michael@0: // nsIAccessibilityService (DON'T put methods here) michael@0: michael@0: Accessible* michael@0: nsAccessibilityService::AddNativeRootAccessible(void* aAtkAccessible) michael@0: { michael@0: #ifdef MOZ_ACCESSIBILITY_ATK michael@0: ApplicationAccessible* applicationAcc = ApplicationAcc(); michael@0: if (!applicationAcc) michael@0: return nullptr; michael@0: michael@0: GtkWindowAccessible* nativeWnd = michael@0: new GtkWindowAccessible(static_cast(aAtkAccessible)); michael@0: michael@0: if (applicationAcc->AppendChild(nativeWnd)) michael@0: return nativeWnd; michael@0: #endif michael@0: michael@0: return nullptr; michael@0: } michael@0: michael@0: void michael@0: nsAccessibilityService::RemoveNativeRootAccessible(Accessible* aAccessible) michael@0: { michael@0: #ifdef MOZ_ACCESSIBILITY_ATK michael@0: ApplicationAccessible* applicationAcc = ApplicationAcc(); michael@0: michael@0: if (applicationAcc) michael@0: applicationAcc->RemoveChild(aAccessible); michael@0: #endif michael@0: } michael@0: michael@0: //////////////////////////////////////////////////////////////////////////////// michael@0: // NS_GetAccessibilityService michael@0: //////////////////////////////////////////////////////////////////////////////// michael@0: michael@0: /** michael@0: * Return accessibility service; creating one if necessary. michael@0: */ michael@0: nsresult michael@0: NS_GetAccessibilityService(nsIAccessibilityService** aResult) michael@0: { michael@0: NS_ENSURE_TRUE(aResult, NS_ERROR_NULL_POINTER); michael@0: *aResult = nullptr; michael@0: michael@0: if (nsAccessibilityService::gAccessibilityService) { michael@0: NS_ADDREF(*aResult = nsAccessibilityService::gAccessibilityService); michael@0: return NS_OK; michael@0: } michael@0: michael@0: nsRefPtr service = new nsAccessibilityService(); michael@0: NS_ENSURE_TRUE(service, NS_ERROR_OUT_OF_MEMORY); michael@0: michael@0: if (!service->Init()) { michael@0: service->Shutdown(); michael@0: return NS_ERROR_FAILURE; michael@0: } michael@0: michael@0: statistics::A11yInitialized(); michael@0: michael@0: nsAccessibilityService::gAccessibilityService = service; michael@0: NS_ADDREF(*aResult = service); michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: //////////////////////////////////////////////////////////////////////////////// michael@0: // nsAccessibilityService private (DON'T put methods here) michael@0: michael@0: #ifdef MOZ_XUL michael@0: already_AddRefed michael@0: nsAccessibilityService::CreateAccessibleForXULTree(nsIContent* aContent, michael@0: DocAccessible* aDoc) michael@0: { michael@0: nsIContent* child = nsTreeUtils::GetDescendantChild(aContent, michael@0: nsGkAtoms::treechildren); michael@0: if (!child) michael@0: return nullptr; michael@0: michael@0: nsTreeBodyFrame* treeFrame = do_QueryFrame(child->GetPrimaryFrame()); michael@0: if (!treeFrame) michael@0: return nullptr; michael@0: michael@0: nsRefPtr treeCols = treeFrame->Columns(); michael@0: int32_t count = 0; michael@0: treeCols->GetCount(&count); michael@0: michael@0: // Outline of list accessible. michael@0: if (count == 1) { michael@0: nsRefPtr accessible = michael@0: new XULTreeAccessible(aContent, aDoc, treeFrame); michael@0: return accessible.forget(); michael@0: } michael@0: michael@0: // Table or tree table accessible. michael@0: nsRefPtr accessible = michael@0: new XULTreeGridAccessibleWrap(aContent, aDoc, treeFrame); michael@0: return accessible.forget(); michael@0: } michael@0: #endif michael@0: michael@0: //////////////////////////////////////////////////////////////////////////////// michael@0: // Services michael@0: //////////////////////////////////////////////////////////////////////////////// michael@0: michael@0: namespace mozilla { michael@0: namespace a11y { michael@0: michael@0: FocusManager* michael@0: FocusMgr() michael@0: { michael@0: return nsAccessibilityService::gAccessibilityService; michael@0: } michael@0: michael@0: SelectionManager* michael@0: SelectionMgr() michael@0: { michael@0: return nsAccessibilityService::gAccessibilityService; michael@0: } michael@0: michael@0: ApplicationAccessible* michael@0: ApplicationAcc() michael@0: { michael@0: return nsAccessibilityService::gApplicationAccessible; michael@0: } michael@0: michael@0: EPlatformDisabledState michael@0: PlatformDisabledState() michael@0: { michael@0: static int disabledState = 0xff; michael@0: michael@0: if (disabledState == 0xff) { michael@0: disabledState = Preferences::GetInt("accessibility.force_disabled", 0); michael@0: if (disabledState < ePlatformIsForceEnabled) michael@0: disabledState = ePlatformIsForceEnabled; michael@0: else if (disabledState > ePlatformIsDisabled) michael@0: disabledState = ePlatformIsDisabled; michael@0: } michael@0: michael@0: return (EPlatformDisabledState)disabledState; michael@0: } michael@0: michael@0: } michael@0: }