1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/accessible/src/base/nsAccessibilityService.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,1751 @@ 1.4 +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 1.5 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.7 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.8 + 1.9 +#include "nsAccessibilityService.h" 1.10 + 1.11 +// NOTE: alphabetically ordered 1.12 +#include "ApplicationAccessibleWrap.h" 1.13 +#include "ARIAGridAccessibleWrap.h" 1.14 +#include "ARIAMap.h" 1.15 +#include "DocAccessible-inl.h" 1.16 +#include "FocusManager.h" 1.17 +#include "HTMLCanvasAccessible.h" 1.18 +#include "HTMLElementAccessibles.h" 1.19 +#include "HTMLImageMapAccessible.h" 1.20 +#include "HTMLLinkAccessible.h" 1.21 +#include "HTMLListAccessible.h" 1.22 +#include "HTMLSelectAccessible.h" 1.23 +#include "HTMLTableAccessibleWrap.h" 1.24 +#include "HyperTextAccessibleWrap.h" 1.25 +#include "RootAccessible.h" 1.26 +#include "nsAccessiblePivot.h" 1.27 +#include "nsAccUtils.h" 1.28 +#include "nsAttrName.h" 1.29 +#include "nsEventShell.h" 1.30 +#include "nsIURI.h" 1.31 +#include "OuterDocAccessible.h" 1.32 +#include "Platform.h" 1.33 +#include "Role.h" 1.34 +#ifdef MOZ_ACCESSIBILITY_ATK 1.35 +#include "RootAccessibleWrap.h" 1.36 +#endif 1.37 +#include "States.h" 1.38 +#include "Statistics.h" 1.39 +#include "TextLeafAccessibleWrap.h" 1.40 + 1.41 +#ifdef MOZ_ACCESSIBILITY_ATK 1.42 +#include "AtkSocketAccessible.h" 1.43 +#endif 1.44 + 1.45 +#ifdef XP_WIN 1.46 +#include "mozilla/a11y/Compatibility.h" 1.47 +#include "HTMLWin32ObjectAccessible.h" 1.48 +#include "mozilla/StaticPtr.h" 1.49 +#endif 1.50 + 1.51 +#ifdef A11Y_LOG 1.52 +#include "Logging.h" 1.53 +#endif 1.54 + 1.55 +#ifdef MOZ_CRASHREPORTER 1.56 +#include "nsExceptionHandler.h" 1.57 +#endif 1.58 + 1.59 +#include "nsImageFrame.h" 1.60 +#include "nsIObserverService.h" 1.61 +#include "nsLayoutUtils.h" 1.62 +#include "nsObjectFrame.h" 1.63 +#include "nsSVGPathGeometryFrame.h" 1.64 +#include "nsTreeBodyFrame.h" 1.65 +#include "nsTreeColumns.h" 1.66 +#include "nsTreeUtils.h" 1.67 +#include "nsXBLPrototypeBinding.h" 1.68 +#include "nsXBLBinding.h" 1.69 +#include "mozilla/ArrayUtils.h" 1.70 +#include "mozilla/dom/DOMStringList.h" 1.71 +#include "mozilla/Preferences.h" 1.72 +#include "mozilla/Services.h" 1.73 +#include "nsDeckFrame.h" 1.74 + 1.75 +#ifdef MOZ_XUL 1.76 +#include "XULAlertAccessible.h" 1.77 +#include "XULColorPickerAccessible.h" 1.78 +#include "XULComboboxAccessible.h" 1.79 +#include "XULElementAccessibles.h" 1.80 +#include "XULFormControlAccessible.h" 1.81 +#include "XULListboxAccessibleWrap.h" 1.82 +#include "XULMenuAccessibleWrap.h" 1.83 +#include "XULSliderAccessible.h" 1.84 +#include "XULTabAccessible.h" 1.85 +#include "XULTreeGridAccessibleWrap.h" 1.86 +#endif 1.87 + 1.88 +#if defined(XP_WIN) || defined(MOZ_ACCESSIBILITY_ATK) 1.89 +#include "nsNPAPIPluginInstance.h" 1.90 +#endif 1.91 + 1.92 +using namespace mozilla; 1.93 +using namespace mozilla::a11y; 1.94 +using namespace mozilla::dom; 1.95 + 1.96 +//////////////////////////////////////////////////////////////////////////////// 1.97 +// Statics 1.98 +//////////////////////////////////////////////////////////////////////////////// 1.99 + 1.100 +/** 1.101 + * Return true if the element must be accessible. 1.102 + */ 1.103 +static bool 1.104 +MustBeAccessible(nsIContent* aContent, DocAccessible* aDocument) 1.105 +{ 1.106 + if (aContent->GetPrimaryFrame()->IsFocusable()) 1.107 + return true; 1.108 + 1.109 + uint32_t attrCount = aContent->GetAttrCount(); 1.110 + for (uint32_t attrIdx = 0; attrIdx < attrCount; attrIdx++) { 1.111 + const nsAttrName* attr = aContent->GetAttrNameAt(attrIdx); 1.112 + if (attr->NamespaceEquals(kNameSpaceID_None)) { 1.113 + nsIAtom* attrAtom = attr->Atom(); 1.114 + nsDependentAtomString attrStr(attrAtom); 1.115 + if (!StringBeginsWith(attrStr, NS_LITERAL_STRING("aria-"))) 1.116 + continue; // not ARIA 1.117 + 1.118 + // A global state or a property and in case of token defined. 1.119 + uint8_t attrFlags = aria::AttrCharacteristicsFor(attrAtom); 1.120 + if ((attrFlags & ATTR_GLOBAL) && (!(attrFlags & ATTR_VALTOKEN) || 1.121 + nsAccUtils::HasDefinedARIAToken(aContent, attrAtom))) { 1.122 + return true; 1.123 + } 1.124 + } 1.125 + } 1.126 + 1.127 + // If the given ID is referred by relation attribute then create an accessible 1.128 + // for it. 1.129 + nsAutoString id; 1.130 + if (nsCoreUtils::GetID(aContent, id) && !id.IsEmpty()) 1.131 + return aDocument->IsDependentID(id); 1.132 + 1.133 + return false; 1.134 +} 1.135 + 1.136 +//////////////////////////////////////////////////////////////////////////////// 1.137 +// nsAccessibilityService 1.138 +//////////////////////////////////////////////////////////////////////////////// 1.139 + 1.140 +nsAccessibilityService *nsAccessibilityService::gAccessibilityService = nullptr; 1.141 +ApplicationAccessible* nsAccessibilityService::gApplicationAccessible = nullptr; 1.142 +bool nsAccessibilityService::gIsShutdown = true; 1.143 + 1.144 +nsAccessibilityService::nsAccessibilityService() : 1.145 + DocManager(), FocusManager() 1.146 +{ 1.147 +} 1.148 + 1.149 +nsAccessibilityService::~nsAccessibilityService() 1.150 +{ 1.151 + NS_ASSERTION(gIsShutdown, "Accessibility wasn't shutdown!"); 1.152 + gAccessibilityService = nullptr; 1.153 +} 1.154 + 1.155 +//////////////////////////////////////////////////////////////////////////////// 1.156 +// nsISupports 1.157 + 1.158 +NS_IMPL_ISUPPORTS_INHERITED(nsAccessibilityService, 1.159 + DocManager, 1.160 + nsIAccessibilityService, 1.161 + nsIAccessibleRetrieval, 1.162 + nsIObserver, 1.163 + nsISelectionListener) // from SelectionManager 1.164 + 1.165 +//////////////////////////////////////////////////////////////////////////////// 1.166 +// nsIObserver 1.167 + 1.168 +NS_IMETHODIMP 1.169 +nsAccessibilityService::Observe(nsISupports *aSubject, const char *aTopic, 1.170 + const char16_t *aData) 1.171 +{ 1.172 + if (!nsCRT::strcmp(aTopic, NS_XPCOM_SHUTDOWN_OBSERVER_ID)) 1.173 + Shutdown(); 1.174 + 1.175 + return NS_OK; 1.176 +} 1.177 + 1.178 +// nsIAccessibilityService 1.179 +void 1.180 +nsAccessibilityService::NotifyOfAnchorJumpTo(nsIContent* aTargetNode) 1.181 +{ 1.182 + nsIDocument* documentNode = aTargetNode->GetCurrentDoc(); 1.183 + if (documentNode) { 1.184 + DocAccessible* document = GetDocAccessible(documentNode); 1.185 + if (document) 1.186 + document->SetAnchorJump(aTargetNode); 1.187 + } 1.188 +} 1.189 + 1.190 +// nsIAccessibilityService 1.191 +void 1.192 +nsAccessibilityService::FireAccessibleEvent(uint32_t aEvent, 1.193 + Accessible* aTarget) 1.194 +{ 1.195 + nsEventShell::FireEvent(aEvent, aTarget); 1.196 +} 1.197 + 1.198 +//////////////////////////////////////////////////////////////////////////////// 1.199 +// nsIAccessibilityService 1.200 + 1.201 +Accessible* 1.202 +nsAccessibilityService::GetRootDocumentAccessible(nsIPresShell* aPresShell, 1.203 + bool aCanCreate) 1.204 +{ 1.205 + nsIPresShell* ps = aPresShell; 1.206 + nsIDocument* documentNode = aPresShell->GetDocument(); 1.207 + if (documentNode) { 1.208 + nsCOMPtr<nsIDocShellTreeItem> treeItem(documentNode->GetDocShell()); 1.209 + if (treeItem) { 1.210 + nsCOMPtr<nsIDocShellTreeItem> rootTreeItem; 1.211 + treeItem->GetRootTreeItem(getter_AddRefs(rootTreeItem)); 1.212 + if (treeItem != rootTreeItem) { 1.213 + nsCOMPtr<nsIDocShell> docShell(do_QueryInterface(rootTreeItem)); 1.214 + ps = docShell->GetPresShell(); 1.215 + } 1.216 + 1.217 + return aCanCreate ? GetDocAccessible(ps) : ps->GetDocAccessible(); 1.218 + } 1.219 + } 1.220 + return nullptr; 1.221 +} 1.222 + 1.223 +#ifdef XP_WIN 1.224 +static StaticAutoPtr<nsTArray<nsCOMPtr<nsIContent> > > sPendingPlugins; 1.225 +static StaticAutoPtr<nsTArray<nsCOMPtr<nsITimer> > > sPluginTimers; 1.226 + 1.227 +class PluginTimerCallBack MOZ_FINAL : public nsITimerCallback 1.228 +{ 1.229 +public: 1.230 + PluginTimerCallBack(nsIContent* aContent) : mContent(aContent) {} 1.231 + 1.232 + NS_DECL_ISUPPORTS 1.233 + 1.234 + NS_IMETHODIMP Notify(nsITimer* aTimer) MOZ_FINAL 1.235 + { 1.236 + if (!mContent->IsInDoc()) 1.237 + return NS_OK; 1.238 + 1.239 + nsIPresShell* ps = mContent->OwnerDoc()->GetShell(); 1.240 + if (ps) { 1.241 + DocAccessible* doc = ps->GetDocAccessible(); 1.242 + if (doc) { 1.243 + // Make sure that if we created an accessible for the plugin that wasn't 1.244 + // a plugin accessible we remove it before creating the right accessible. 1.245 + doc->RecreateAccessible(mContent); 1.246 + sPluginTimers->RemoveElement(aTimer); 1.247 + return NS_OK; 1.248 + } 1.249 + } 1.250 + 1.251 + // We couldn't get a doc accessible so presumably the document went away. 1.252 + // In this case don't leak our ref to the content or timer. 1.253 + sPendingPlugins->RemoveElement(mContent); 1.254 + sPluginTimers->RemoveElement(aTimer); 1.255 + return NS_OK; 1.256 + } 1.257 + 1.258 +private: 1.259 + nsCOMPtr<nsIContent> mContent; 1.260 +}; 1.261 + 1.262 +NS_IMPL_ISUPPORTS(PluginTimerCallBack, nsITimerCallback) 1.263 +#endif 1.264 + 1.265 +already_AddRefed<Accessible> 1.266 +nsAccessibilityService::CreatePluginAccessible(nsObjectFrame* aFrame, 1.267 + nsIContent* aContent, 1.268 + Accessible* aContext) 1.269 +{ 1.270 + // nsObjectFrame means a plugin, so we need to use the accessibility support 1.271 + // of the plugin. 1.272 + if (aFrame->GetRect().IsEmpty()) 1.273 + return nullptr; 1.274 + 1.275 +#if defined(XP_WIN) || defined(MOZ_ACCESSIBILITY_ATK) 1.276 + nsRefPtr<nsNPAPIPluginInstance> pluginInstance; 1.277 + if (NS_SUCCEEDED(aFrame->GetPluginInstance(getter_AddRefs(pluginInstance))) && 1.278 + pluginInstance) { 1.279 +#ifdef XP_WIN 1.280 + if (!sPendingPlugins->Contains(aContent) && 1.281 + (Preferences::GetBool("accessibility.delay_plugins") || 1.282 + Compatibility::IsJAWS() || Compatibility::IsWE())) { 1.283 + nsCOMPtr<nsITimer> timer = do_CreateInstance(NS_TIMER_CONTRACTID); 1.284 + nsRefPtr<PluginTimerCallBack> cb = new PluginTimerCallBack(aContent); 1.285 + timer->InitWithCallback(cb, Preferences::GetUint("accessibility.delay_plugin_time"), 1.286 + nsITimer::TYPE_ONE_SHOT); 1.287 + sPluginTimers->AppendElement(timer); 1.288 + sPendingPlugins->AppendElement(aContent); 1.289 + return nullptr; 1.290 + } 1.291 + 1.292 + // We need to remove aContent from the pending plugins here to avoid 1.293 + // reentrancy. When the timer fires it calls 1.294 + // DocAccessible::ContentInserted() which does the work async. 1.295 + sPendingPlugins->RemoveElement(aContent); 1.296 + 1.297 + // Note: pluginPort will be null if windowless. 1.298 + HWND pluginPort = nullptr; 1.299 + aFrame->GetPluginPort(&pluginPort); 1.300 + 1.301 + nsRefPtr<Accessible> accessible = 1.302 + new HTMLWin32ObjectOwnerAccessible(aContent, aContext->Document(), 1.303 + pluginPort); 1.304 + return accessible.forget(); 1.305 + 1.306 +#elif MOZ_ACCESSIBILITY_ATK 1.307 + if (!AtkSocketAccessible::gCanEmbed) 1.308 + return nullptr; 1.309 + 1.310 + // Note this calls into the plugin, so crazy things may happen and aFrame 1.311 + // may go away. 1.312 + nsCString plugId; 1.313 + nsresult rv = pluginInstance->GetValueFromPlugin( 1.314 + NPPVpluginNativeAccessibleAtkPlugId, &plugId); 1.315 + if (NS_SUCCEEDED(rv) && !plugId.IsEmpty()) { 1.316 + nsRefPtr<AtkSocketAccessible> socketAccessible = 1.317 + new AtkSocketAccessible(aContent, aContext->Document(), plugId); 1.318 + 1.319 + return socketAccessible.forget(); 1.320 + } 1.321 +#endif 1.322 + } 1.323 +#endif 1.324 + 1.325 + return nullptr; 1.326 +} 1.327 + 1.328 +void 1.329 +nsAccessibilityService::DeckPanelSwitched(nsIPresShell* aPresShell, 1.330 + nsIContent* aDeckNode, 1.331 + nsIFrame* aPrevBoxFrame, 1.332 + nsIFrame* aCurrentBoxFrame) 1.333 +{ 1.334 + // Ignore tabpanels elements (a deck having an accessible) since their 1.335 + // children are accessible not depending on selected tab. 1.336 + DocAccessible* document = GetDocAccessible(aPresShell); 1.337 + if (!document || document->HasAccessible(aDeckNode)) 1.338 + return; 1.339 + 1.340 + if (aPrevBoxFrame) { 1.341 + nsIContent* panelNode = aPrevBoxFrame->GetContent(); 1.342 +#ifdef A11Y_LOG 1.343 + if (logging::IsEnabled(logging::eTree)) { 1.344 + logging::MsgBegin("TREE", "deck panel unselected"); 1.345 + logging::Node("container", panelNode); 1.346 + logging::Node("content", aDeckNode); 1.347 + logging::MsgEnd(); 1.348 + } 1.349 +#endif 1.350 + 1.351 + document->ContentRemoved(aDeckNode, panelNode); 1.352 + } 1.353 + 1.354 + if (aCurrentBoxFrame) { 1.355 + nsIContent* panelNode = aCurrentBoxFrame->GetContent(); 1.356 +#ifdef A11Y_LOG 1.357 + if (logging::IsEnabled(logging::eTree)) { 1.358 + logging::MsgBegin("TREE", "deck panel selected"); 1.359 + logging::Node("container", panelNode); 1.360 + logging::Node("content", aDeckNode); 1.361 + logging::MsgEnd(); 1.362 + } 1.363 +#endif 1.364 + 1.365 + document->ContentInserted(aDeckNode, panelNode, panelNode->GetNextSibling()); 1.366 + } 1.367 +} 1.368 + 1.369 +void 1.370 +nsAccessibilityService::ContentRangeInserted(nsIPresShell* aPresShell, 1.371 + nsIContent* aContainer, 1.372 + nsIContent* aStartChild, 1.373 + nsIContent* aEndChild) 1.374 +{ 1.375 +#ifdef A11Y_LOG 1.376 + if (logging::IsEnabled(logging::eTree)) { 1.377 + logging::MsgBegin("TREE", "content inserted"); 1.378 + logging::Node("container", aContainer); 1.379 + for (nsIContent* child = aStartChild; child != aEndChild; 1.380 + child = child->GetNextSibling()) { 1.381 + logging::Node("content", child); 1.382 + } 1.383 + logging::MsgEnd(); 1.384 + logging::Stack(); 1.385 + } 1.386 +#endif 1.387 + 1.388 + DocAccessible* docAccessible = GetDocAccessible(aPresShell); 1.389 + if (docAccessible) 1.390 + docAccessible->ContentInserted(aContainer, aStartChild, aEndChild); 1.391 +} 1.392 + 1.393 +void 1.394 +nsAccessibilityService::ContentRemoved(nsIPresShell* aPresShell, 1.395 + nsIContent* aContainer, 1.396 + nsIContent* aChild) 1.397 +{ 1.398 +#ifdef A11Y_LOG 1.399 + if (logging::IsEnabled(logging::eTree)) { 1.400 + logging::MsgBegin("TREE", "content removed"); 1.401 + logging::Node("container", aContainer); 1.402 + logging::Node("content", aChild); 1.403 + logging::MsgEnd(); 1.404 + logging::Stack(); 1.405 + } 1.406 +#endif 1.407 + 1.408 + DocAccessible* docAccessible = GetDocAccessible(aPresShell); 1.409 + if (docAccessible) 1.410 + docAccessible->ContentRemoved(aContainer, aChild); 1.411 +} 1.412 + 1.413 +void 1.414 +nsAccessibilityService::UpdateText(nsIPresShell* aPresShell, 1.415 + nsIContent* aContent) 1.416 +{ 1.417 + DocAccessible* document = GetDocAccessible(aPresShell); 1.418 + if (document) 1.419 + document->UpdateText(aContent); 1.420 +} 1.421 + 1.422 +void 1.423 +nsAccessibilityService::TreeViewChanged(nsIPresShell* aPresShell, 1.424 + nsIContent* aContent, 1.425 + nsITreeView* aView) 1.426 +{ 1.427 + DocAccessible* document = GetDocAccessible(aPresShell); 1.428 + if (document) { 1.429 + Accessible* accessible = document->GetAccessible(aContent); 1.430 + if (accessible) { 1.431 + XULTreeAccessible* treeAcc = accessible->AsXULTree(); 1.432 + if (treeAcc) 1.433 + treeAcc->TreeViewChanged(aView); 1.434 + } 1.435 + } 1.436 +} 1.437 + 1.438 +void 1.439 +nsAccessibilityService::RangeValueChanged(nsIPresShell* aPresShell, 1.440 + nsIContent* aContent) 1.441 +{ 1.442 + DocAccessible* document = GetDocAccessible(aPresShell); 1.443 + if (document) { 1.444 + Accessible* accessible = document->GetAccessible(aContent); 1.445 + if (accessible) { 1.446 + document->FireDelayedEvent(nsIAccessibleEvent::EVENT_VALUE_CHANGE, 1.447 + accessible); 1.448 + } 1.449 + } 1.450 +} 1.451 + 1.452 +void 1.453 +nsAccessibilityService::UpdateListBullet(nsIPresShell* aPresShell, 1.454 + nsIContent* aHTMLListItemContent, 1.455 + bool aHasBullet) 1.456 +{ 1.457 + DocAccessible* document = GetDocAccessible(aPresShell); 1.458 + if (document) { 1.459 + Accessible* accessible = document->GetAccessible(aHTMLListItemContent); 1.460 + if (accessible) { 1.461 + HTMLLIAccessible* listItem = accessible->AsHTMLListItem(); 1.462 + if (listItem) 1.463 + listItem->UpdateBullet(aHasBullet); 1.464 + } 1.465 + } 1.466 +} 1.467 + 1.468 +void 1.469 +nsAccessibilityService::UpdateImageMap(nsImageFrame* aImageFrame) 1.470 +{ 1.471 + nsIPresShell* presShell = aImageFrame->PresContext()->PresShell(); 1.472 + DocAccessible* document = GetDocAccessible(presShell); 1.473 + if (document) { 1.474 + Accessible* accessible = 1.475 + document->GetAccessible(aImageFrame->GetContent()); 1.476 + if (accessible) { 1.477 + HTMLImageMapAccessible* imageMap = accessible->AsImageMap(); 1.478 + if (imageMap) { 1.479 + imageMap->UpdateChildAreas(); 1.480 + return; 1.481 + } 1.482 + 1.483 + // If image map was initialized after we created an accessible (that'll 1.484 + // be an image accessible) then recreate it. 1.485 + RecreateAccessible(presShell, aImageFrame->GetContent()); 1.486 + } 1.487 + } 1.488 +} 1.489 + 1.490 +void 1.491 +nsAccessibilityService::UpdateLabelValue(nsIPresShell* aPresShell, 1.492 + nsIContent* aLabelElm, 1.493 + const nsString& aNewValue) 1.494 +{ 1.495 + DocAccessible* document = GetDocAccessible(aPresShell); 1.496 + if (document) { 1.497 + Accessible* accessible = document->GetAccessible(aLabelElm); 1.498 + if (accessible) { 1.499 + XULLabelAccessible* xulLabel = accessible->AsXULLabel(); 1.500 + NS_ASSERTION(xulLabel, 1.501 + "UpdateLabelValue was called for wrong accessible!"); 1.502 + if (xulLabel) 1.503 + xulLabel->UpdateLabelValue(aNewValue); 1.504 + } 1.505 + } 1.506 +} 1.507 + 1.508 +void 1.509 +nsAccessibilityService::PresShellActivated(nsIPresShell* aPresShell) 1.510 +{ 1.511 + DocAccessible* document = aPresShell->GetDocAccessible(); 1.512 + if (document) { 1.513 + RootAccessible* rootDocument = document->RootAccessible(); 1.514 + NS_ASSERTION(rootDocument, "Entirely broken tree: no root document!"); 1.515 + if (rootDocument) 1.516 + rootDocument->DocumentActivated(document); 1.517 + } 1.518 +} 1.519 + 1.520 +void 1.521 +nsAccessibilityService::RecreateAccessible(nsIPresShell* aPresShell, 1.522 + nsIContent* aContent) 1.523 +{ 1.524 + DocAccessible* document = GetDocAccessible(aPresShell); 1.525 + if (document) 1.526 + document->RecreateAccessible(aContent); 1.527 +} 1.528 + 1.529 +//////////////////////////////////////////////////////////////////////////////// 1.530 +// nsIAccessibleRetrieval 1.531 + 1.532 +NS_IMETHODIMP 1.533 +nsAccessibilityService::GetApplicationAccessible(nsIAccessible** aAccessibleApplication) 1.534 +{ 1.535 + NS_ENSURE_ARG_POINTER(aAccessibleApplication); 1.536 + 1.537 + NS_IF_ADDREF(*aAccessibleApplication = ApplicationAcc()); 1.538 + 1.539 + return NS_OK; 1.540 +} 1.541 + 1.542 +NS_IMETHODIMP 1.543 +nsAccessibilityService::GetAccessibleFor(nsIDOMNode *aNode, 1.544 + nsIAccessible **aAccessible) 1.545 +{ 1.546 + NS_ENSURE_ARG_POINTER(aAccessible); 1.547 + *aAccessible = nullptr; 1.548 + if (!aNode) 1.549 + return NS_OK; 1.550 + 1.551 + nsCOMPtr<nsINode> node(do_QueryInterface(aNode)); 1.552 + if (!node) 1.553 + return NS_ERROR_INVALID_ARG; 1.554 + 1.555 + DocAccessible* document = GetDocAccessible(node->OwnerDoc()); 1.556 + if (document) 1.557 + NS_IF_ADDREF(*aAccessible = document->GetAccessible(node)); 1.558 + 1.559 + return NS_OK; 1.560 +} 1.561 + 1.562 +NS_IMETHODIMP 1.563 +nsAccessibilityService::GetStringRole(uint32_t aRole, nsAString& aString) 1.564 +{ 1.565 +#define ROLE(geckoRole, stringRole, atkRole, \ 1.566 + macRole, msaaRole, ia2Role, nameRule) \ 1.567 + case roles::geckoRole: \ 1.568 + CopyUTF8toUTF16(stringRole, aString); \ 1.569 + return NS_OK; 1.570 + 1.571 + switch (aRole) { 1.572 +#include "RoleMap.h" 1.573 + default: 1.574 + aString.AssignLiteral("unknown"); 1.575 + return NS_OK; 1.576 + } 1.577 + 1.578 +#undef ROLE 1.579 +} 1.580 + 1.581 +NS_IMETHODIMP 1.582 +nsAccessibilityService::GetStringStates(uint32_t aState, uint32_t aExtraState, 1.583 + nsISupports **aStringStates) 1.584 +{ 1.585 + nsRefPtr<DOMStringList> stringStates = new DOMStringList(); 1.586 + 1.587 + uint64_t state = nsAccUtils::To64State(aState, aExtraState); 1.588 + 1.589 + // states 1.590 + if (state & states::UNAVAILABLE) 1.591 + stringStates->Add(NS_LITERAL_STRING("unavailable")); 1.592 + if (state & states::SELECTED) 1.593 + stringStates->Add(NS_LITERAL_STRING("selected")); 1.594 + if (state & states::FOCUSED) 1.595 + stringStates->Add(NS_LITERAL_STRING("focused")); 1.596 + if (state & states::PRESSED) 1.597 + stringStates->Add(NS_LITERAL_STRING("pressed")); 1.598 + if (state & states::CHECKED) 1.599 + stringStates->Add(NS_LITERAL_STRING("checked")); 1.600 + if (state & states::MIXED) 1.601 + stringStates->Add(NS_LITERAL_STRING("mixed")); 1.602 + if (state & states::READONLY) 1.603 + stringStates->Add(NS_LITERAL_STRING("readonly")); 1.604 + if (state & states::HOTTRACKED) 1.605 + stringStates->Add(NS_LITERAL_STRING("hottracked")); 1.606 + if (state & states::DEFAULT) 1.607 + stringStates->Add(NS_LITERAL_STRING("default")); 1.608 + if (state & states::EXPANDED) 1.609 + stringStates->Add(NS_LITERAL_STRING("expanded")); 1.610 + if (state & states::COLLAPSED) 1.611 + stringStates->Add(NS_LITERAL_STRING("collapsed")); 1.612 + if (state & states::BUSY) 1.613 + stringStates->Add(NS_LITERAL_STRING("busy")); 1.614 + if (state & states::FLOATING) 1.615 + stringStates->Add(NS_LITERAL_STRING("floating")); 1.616 + if (state & states::ANIMATED) 1.617 + stringStates->Add(NS_LITERAL_STRING("animated")); 1.618 + if (state & states::INVISIBLE) 1.619 + stringStates->Add(NS_LITERAL_STRING("invisible")); 1.620 + if (state & states::OFFSCREEN) 1.621 + stringStates->Add(NS_LITERAL_STRING("offscreen")); 1.622 + if (state & states::SIZEABLE) 1.623 + stringStates->Add(NS_LITERAL_STRING("sizeable")); 1.624 + if (state & states::MOVEABLE) 1.625 + stringStates->Add(NS_LITERAL_STRING("moveable")); 1.626 + if (state & states::SELFVOICING) 1.627 + stringStates->Add(NS_LITERAL_STRING("selfvoicing")); 1.628 + if (state & states::FOCUSABLE) 1.629 + stringStates->Add(NS_LITERAL_STRING("focusable")); 1.630 + if (state & states::SELECTABLE) 1.631 + stringStates->Add(NS_LITERAL_STRING("selectable")); 1.632 + if (state & states::LINKED) 1.633 + stringStates->Add(NS_LITERAL_STRING("linked")); 1.634 + if (state & states::TRAVERSED) 1.635 + stringStates->Add(NS_LITERAL_STRING("traversed")); 1.636 + if (state & states::MULTISELECTABLE) 1.637 + stringStates->Add(NS_LITERAL_STRING("multiselectable")); 1.638 + if (state & states::EXTSELECTABLE) 1.639 + stringStates->Add(NS_LITERAL_STRING("extselectable")); 1.640 + if (state & states::PROTECTED) 1.641 + stringStates->Add(NS_LITERAL_STRING("protected")); 1.642 + if (state & states::HASPOPUP) 1.643 + stringStates->Add(NS_LITERAL_STRING("haspopup")); 1.644 + if (state & states::REQUIRED) 1.645 + stringStates->Add(NS_LITERAL_STRING("required")); 1.646 + if (state & states::ALERT) 1.647 + stringStates->Add(NS_LITERAL_STRING("alert")); 1.648 + if (state & states::INVALID) 1.649 + stringStates->Add(NS_LITERAL_STRING("invalid")); 1.650 + if (state & states::CHECKABLE) 1.651 + stringStates->Add(NS_LITERAL_STRING("checkable")); 1.652 + 1.653 + // extraStates 1.654 + if (state & states::SUPPORTS_AUTOCOMPLETION) 1.655 + stringStates->Add(NS_LITERAL_STRING("autocompletion")); 1.656 + if (state & states::DEFUNCT) 1.657 + stringStates->Add(NS_LITERAL_STRING("defunct")); 1.658 + if (state & states::SELECTABLE_TEXT) 1.659 + stringStates->Add(NS_LITERAL_STRING("selectable text")); 1.660 + if (state & states::EDITABLE) 1.661 + stringStates->Add(NS_LITERAL_STRING("editable")); 1.662 + if (state & states::ACTIVE) 1.663 + stringStates->Add(NS_LITERAL_STRING("active")); 1.664 + if (state & states::MODAL) 1.665 + stringStates->Add(NS_LITERAL_STRING("modal")); 1.666 + if (state & states::MULTI_LINE) 1.667 + stringStates->Add(NS_LITERAL_STRING("multi line")); 1.668 + if (state & states::HORIZONTAL) 1.669 + stringStates->Add(NS_LITERAL_STRING("horizontal")); 1.670 + if (state & states::OPAQUE1) 1.671 + stringStates->Add(NS_LITERAL_STRING("opaque")); 1.672 + if (state & states::SINGLE_LINE) 1.673 + stringStates->Add(NS_LITERAL_STRING("single line")); 1.674 + if (state & states::TRANSIENT) 1.675 + stringStates->Add(NS_LITERAL_STRING("transient")); 1.676 + if (state & states::VERTICAL) 1.677 + stringStates->Add(NS_LITERAL_STRING("vertical")); 1.678 + if (state & states::STALE) 1.679 + stringStates->Add(NS_LITERAL_STRING("stale")); 1.680 + if (state & states::ENABLED) 1.681 + stringStates->Add(NS_LITERAL_STRING("enabled")); 1.682 + if (state & states::SENSITIVE) 1.683 + stringStates->Add(NS_LITERAL_STRING("sensitive")); 1.684 + if (state & states::EXPANDABLE) 1.685 + stringStates->Add(NS_LITERAL_STRING("expandable")); 1.686 + 1.687 + //unknown states 1.688 + if (!stringStates->Length()) 1.689 + stringStates->Add(NS_LITERAL_STRING("unknown")); 1.690 + 1.691 + stringStates.forget(aStringStates); 1.692 + return NS_OK; 1.693 +} 1.694 + 1.695 +// nsIAccessibleRetrieval::getStringEventType() 1.696 +NS_IMETHODIMP 1.697 +nsAccessibilityService::GetStringEventType(uint32_t aEventType, 1.698 + nsAString& aString) 1.699 +{ 1.700 + NS_ASSERTION(nsIAccessibleEvent::EVENT_LAST_ENTRY == ArrayLength(kEventTypeNames), 1.701 + "nsIAccessibleEvent constants are out of sync to kEventTypeNames"); 1.702 + 1.703 + if (aEventType >= ArrayLength(kEventTypeNames)) { 1.704 + aString.AssignLiteral("unknown"); 1.705 + return NS_OK; 1.706 + } 1.707 + 1.708 + CopyUTF8toUTF16(kEventTypeNames[aEventType], aString); 1.709 + return NS_OK; 1.710 +} 1.711 + 1.712 +// nsIAccessibleRetrieval::getStringRelationType() 1.713 +NS_IMETHODIMP 1.714 +nsAccessibilityService::GetStringRelationType(uint32_t aRelationType, 1.715 + nsAString& aString) 1.716 +{ 1.717 + NS_ENSURE_ARG(aRelationType <= static_cast<uint32_t>(RelationType::LAST)); 1.718 + 1.719 +#define RELATIONTYPE(geckoType, geckoTypeName, atkType, msaaType, ia2Type) \ 1.720 + case RelationType::geckoType: \ 1.721 + aString.AssignLiteral(geckoTypeName); \ 1.722 + return NS_OK; 1.723 + 1.724 + RelationType relationType = static_cast<RelationType>(aRelationType); 1.725 + switch (relationType) { 1.726 +#include "RelationTypeMap.h" 1.727 + default: 1.728 + aString.AssignLiteral("unknown"); 1.729 + return NS_OK; 1.730 + } 1.731 + 1.732 +#undef RELATIONTYPE 1.733 +} 1.734 + 1.735 +NS_IMETHODIMP 1.736 +nsAccessibilityService::GetAccessibleFromCache(nsIDOMNode* aNode, 1.737 + nsIAccessible** aAccessible) 1.738 +{ 1.739 + NS_ENSURE_ARG_POINTER(aAccessible); 1.740 + *aAccessible = nullptr; 1.741 + if (!aNode) 1.742 + return NS_OK; 1.743 + 1.744 + nsCOMPtr<nsINode> node(do_QueryInterface(aNode)); 1.745 + if (!node) 1.746 + return NS_ERROR_INVALID_ARG; 1.747 + 1.748 + // Search for an accessible in each of our per document accessible object 1.749 + // caches. If we don't find it, and the given node is itself a document, check 1.750 + // our cache of document accessibles (document cache). Note usually shutdown 1.751 + // document accessibles are not stored in the document cache, however an 1.752 + // "unofficially" shutdown document (i.e. not from DocManager) can still 1.753 + // exist in the document cache. 1.754 + Accessible* accessible = FindAccessibleInCache(node); 1.755 + if (!accessible) { 1.756 + nsCOMPtr<nsIDocument> document(do_QueryInterface(node)); 1.757 + if (document) 1.758 + accessible = GetExistingDocAccessible(document); 1.759 + } 1.760 + 1.761 + NS_IF_ADDREF(*aAccessible = accessible); 1.762 + return NS_OK; 1.763 +} 1.764 + 1.765 +NS_IMETHODIMP 1.766 +nsAccessibilityService::CreateAccessiblePivot(nsIAccessible* aRoot, 1.767 + nsIAccessiblePivot** aPivot) 1.768 +{ 1.769 + NS_ENSURE_ARG_POINTER(aPivot); 1.770 + NS_ENSURE_ARG(aRoot); 1.771 + *aPivot = nullptr; 1.772 + 1.773 + nsRefPtr<Accessible> accessibleRoot(do_QueryObject(aRoot)); 1.774 + NS_ENSURE_TRUE(accessibleRoot, NS_ERROR_INVALID_ARG); 1.775 + 1.776 + nsAccessiblePivot* pivot = new nsAccessiblePivot(accessibleRoot); 1.777 + NS_ADDREF(*aPivot = pivot); 1.778 + 1.779 + return NS_OK; 1.780 +} 1.781 + 1.782 +NS_IMETHODIMP 1.783 +nsAccessibilityService::SetLogging(const nsACString& aModules) 1.784 +{ 1.785 +#ifdef A11Y_LOG 1.786 + logging::Enable(PromiseFlatCString(aModules)); 1.787 +#endif 1.788 + return NS_OK; 1.789 +} 1.790 + 1.791 +NS_IMETHODIMP 1.792 +nsAccessibilityService::IsLogged(const nsAString& aModule, bool* aIsLogged) 1.793 +{ 1.794 + NS_ENSURE_ARG_POINTER(aIsLogged); 1.795 + *aIsLogged = false; 1.796 + 1.797 +#ifdef A11Y_LOG 1.798 + *aIsLogged = logging::IsEnabled(aModule); 1.799 +#endif 1.800 + 1.801 + return NS_OK; 1.802 +} 1.803 + 1.804 +//////////////////////////////////////////////////////////////////////////////// 1.805 +// nsAccessibilityService public 1.806 + 1.807 +Accessible* 1.808 +nsAccessibilityService::GetOrCreateAccessible(nsINode* aNode, 1.809 + Accessible* aContext, 1.810 + bool* aIsSubtreeHidden) 1.811 +{ 1.812 + NS_PRECONDITION(aContext && aNode && !gIsShutdown, 1.813 + "Maybe let'd do a crash? Oh, yes, baby!"); 1.814 + 1.815 + if (aIsSubtreeHidden) 1.816 + *aIsSubtreeHidden = false; 1.817 + 1.818 + DocAccessible* document = aContext->Document(); 1.819 + 1.820 + // Check to see if we already have an accessible for this node in the cache. 1.821 + // XXX: we don't have context check here. It doesn't really necessary until 1.822 + // we have in-law children adoption. 1.823 + Accessible* cachedAccessible = document->GetAccessible(aNode); 1.824 + if (cachedAccessible) 1.825 + return cachedAccessible; 1.826 + 1.827 + // No cache entry, so we must create the accessible. 1.828 + 1.829 + if (aNode->IsNodeOfType(nsINode::eDOCUMENT)) { 1.830 + // If it's document node then ask accessible document loader for 1.831 + // document accessible, otherwise return null. 1.832 + nsCOMPtr<nsIDocument> document(do_QueryInterface(aNode)); 1.833 + return GetDocAccessible(document); 1.834 + } 1.835 + 1.836 + // We have a content node. 1.837 + if (!aNode->IsInDoc()) { 1.838 + NS_WARNING("Creating accessible for node with no document"); 1.839 + return nullptr; 1.840 + } 1.841 + 1.842 + if (aNode->OwnerDoc() != document->DocumentNode()) { 1.843 + NS_ERROR("Creating accessible for wrong document"); 1.844 + return nullptr; 1.845 + } 1.846 + 1.847 + if (!aNode->IsContent()) 1.848 + return nullptr; 1.849 + 1.850 + nsIContent* content = aNode->AsContent(); 1.851 + nsIFrame* frame = content->GetPrimaryFrame(); 1.852 + 1.853 + // Check frame and its visibility. Note, hidden frame allows visible 1.854 + // elements in subtree. 1.855 + if (!frame || !frame->StyleVisibility()->IsVisible()) { 1.856 + if (aIsSubtreeHidden && !frame) 1.857 + *aIsSubtreeHidden = true; 1.858 + 1.859 + return nullptr; 1.860 + } 1.861 + 1.862 + if (frame->GetContent() != content) { 1.863 + // Not the main content for this frame. This happens because <area> 1.864 + // elements return the image frame as their primary frame. The main content 1.865 + // for the image frame is the image content. If the frame is not an image 1.866 + // frame or the node is not an area element then null is returned. 1.867 + // This setup will change when bug 135040 is fixed. Make sure we don't 1.868 + // create area accessible here. Hopefully assertion below will handle that. 1.869 + 1.870 +#ifdef DEBUG 1.871 + nsImageFrame* imageFrame = do_QueryFrame(frame); 1.872 + NS_ASSERTION(imageFrame && content->IsHTML() && content->Tag() == nsGkAtoms::area, 1.873 + "Unknown case of not main content for the frame!"); 1.874 +#endif 1.875 + return nullptr; 1.876 + } 1.877 + 1.878 +#ifdef DEBUG 1.879 + nsImageFrame* imageFrame = do_QueryFrame(frame); 1.880 + NS_ASSERTION(!imageFrame || !content->IsHTML() || content->Tag() != nsGkAtoms::area, 1.881 + "Image map manages the area accessible creation!"); 1.882 +#endif 1.883 + 1.884 + // Attempt to create an accessible based on what we know. 1.885 + nsRefPtr<Accessible> newAcc; 1.886 + 1.887 + // Create accessible for visible text frames. 1.888 + if (content->IsNodeOfType(nsINode::eTEXT)) { 1.889 + nsAutoString text; 1.890 + frame->GetRenderedText(&text, nullptr, nullptr, 0, UINT32_MAX); 1.891 + // Ignore not rendered text nodes and whitespace text nodes between table 1.892 + // cells. 1.893 + if (text.IsEmpty() || 1.894 + (aContext->IsTableRow() && nsCoreUtils::IsWhitespaceString(text))) { 1.895 + if (aIsSubtreeHidden) 1.896 + *aIsSubtreeHidden = true; 1.897 + 1.898 + return nullptr; 1.899 + } 1.900 + 1.901 + newAcc = CreateAccessibleByFrameType(frame, content, aContext); 1.902 + if (!aContext->IsAcceptableChild(newAcc)) 1.903 + return nullptr; 1.904 + 1.905 + document->BindToDocument(newAcc, nullptr); 1.906 + newAcc->AsTextLeaf()->SetText(text); 1.907 + return newAcc; 1.908 + } 1.909 + 1.910 + bool isHTML = content->IsHTML(); 1.911 + if (isHTML && content->Tag() == nsGkAtoms::map) { 1.912 + // Create hyper text accessible for HTML map if it is used to group links 1.913 + // (see http://www.w3.org/TR/WCAG10-HTML-TECHS/#group-bypass). If the HTML 1.914 + // map rect is empty then it is used for links grouping. Otherwise it should 1.915 + // be used in conjunction with HTML image element and in this case we don't 1.916 + // create any accessible for it and don't walk into it. The accessibles for 1.917 + // HTML area (HTMLAreaAccessible) the map contains are attached as 1.918 + // children of the appropriate accessible for HTML image 1.919 + // (ImageAccessible). 1.920 + if (nsLayoutUtils::GetAllInFlowRectsUnion(frame, 1.921 + frame->GetParent()).IsEmpty()) { 1.922 + if (aIsSubtreeHidden) 1.923 + *aIsSubtreeHidden = true; 1.924 + 1.925 + return nullptr; 1.926 + } 1.927 + 1.928 + newAcc = new HyperTextAccessibleWrap(content, document); 1.929 + if (!aContext->IsAcceptableChild(newAcc)) 1.930 + return nullptr; 1.931 + 1.932 + document->BindToDocument(newAcc, aria::GetRoleMap(aNode)); 1.933 + return newAcc; 1.934 + } 1.935 + 1.936 + nsRoleMapEntry* roleMapEntry = aria::GetRoleMap(aNode); 1.937 + 1.938 + // If the element is focusable or global ARIA attribute is applied to it or 1.939 + // it is referenced by ARIA relationship then treat role="presentation" on 1.940 + // the element as the role is not there. 1.941 + if (roleMapEntry && roleMapEntry->Is(nsGkAtoms::presentation)) { 1.942 + if (!MustBeAccessible(content, document)) 1.943 + return nullptr; 1.944 + 1.945 + roleMapEntry = nullptr; 1.946 + } 1.947 + 1.948 + if (!newAcc && isHTML) { // HTML accessibles 1.949 + if (roleMapEntry) { 1.950 + // Create pure ARIA grid/treegrid related accessibles if they weren't used 1.951 + // on accessible HTML table elements. 1.952 + if ((roleMapEntry->accTypes & eTableCell)) { 1.953 + if (aContext->IsTableRow() && 1.954 + (frame->AccessibleType() != eHTMLTableCellType || 1.955 + aContext->GetContent() != content->GetParent())) { 1.956 + newAcc = new ARIAGridCellAccessibleWrap(content, document); 1.957 + } 1.958 + 1.959 + } else if ((roleMapEntry->IsOfType(eTable)) && 1.960 + frame->AccessibleType() != eHTMLTableType) { 1.961 + newAcc = new ARIAGridAccessibleWrap(content, document); 1.962 + } 1.963 + } 1.964 + 1.965 + if (!newAcc) { 1.966 + // Prefer to use markup (mostly tag name, perhaps attributes) to decide if 1.967 + // and what kind of accessible to create. 1.968 + newAcc = CreateHTMLAccessibleByMarkup(frame, content, aContext); 1.969 + 1.970 + // Try using frame to do it. 1.971 + if (!newAcc) 1.972 + newAcc = CreateAccessibleByFrameType(frame, content, aContext); 1.973 + 1.974 + // If table has strong ARIA role then all table descendants shouldn't 1.975 + // expose their native roles. 1.976 + if (!roleMapEntry && newAcc) { 1.977 + if (frame->AccessibleType() == eHTMLTableRowType) { 1.978 + nsRoleMapEntry* contextRoleMap = aContext->ARIARoleMap(); 1.979 + if (contextRoleMap && !(contextRoleMap->IsOfType(eTable))) 1.980 + roleMapEntry = &aria::gEmptyRoleMap; 1.981 + 1.982 + } else if (frame->AccessibleType() == eHTMLTableCellType && 1.983 + aContext->ARIARoleMap() == &aria::gEmptyRoleMap) { 1.984 + roleMapEntry = &aria::gEmptyRoleMap; 1.985 + 1.986 + } else if (content->Tag() == nsGkAtoms::dt || 1.987 + content->Tag() == nsGkAtoms::li || 1.988 + content->Tag() == nsGkAtoms::dd || 1.989 + frame->AccessibleType() == eHTMLLiType) { 1.990 + nsRoleMapEntry* contextRoleMap = aContext->ARIARoleMap(); 1.991 + if (contextRoleMap && !(contextRoleMap->IsOfType(eList))) 1.992 + roleMapEntry = &aria::gEmptyRoleMap; 1.993 + } 1.994 + } 1.995 + } 1.996 + } 1.997 + 1.998 + // Accessible XBL types and deck stuff are used in XUL only currently. 1.999 + if (!newAcc && content->IsXUL()) { 1.1000 + // No accessible for not selected deck panel and its children. 1.1001 + if (!aContext->IsXULTabpanels()) { 1.1002 + nsDeckFrame* deckFrame = do_QueryFrame(frame->GetParent()); 1.1003 + if (deckFrame && deckFrame->GetSelectedBox() != frame) { 1.1004 + if (aIsSubtreeHidden) 1.1005 + *aIsSubtreeHidden = true; 1.1006 + 1.1007 + return nullptr; 1.1008 + } 1.1009 + } 1.1010 + 1.1011 + // XBL bindings may use @role attribute to point the accessible type 1.1012 + // they belong to. 1.1013 + newAcc = CreateAccessibleByType(content, document); 1.1014 + 1.1015 + // Any XUL box can be used as tabpanel, make sure we create a proper 1.1016 + // accessible for it. 1.1017 + if (!newAcc && aContext->IsXULTabpanels() && 1.1018 + content->GetParent() == aContext->GetContent()) { 1.1019 + nsIAtom* frameType = frame->GetType(); 1.1020 + if (frameType == nsGkAtoms::boxFrame || 1.1021 + frameType == nsGkAtoms::scrollFrame) { 1.1022 + newAcc = new XULTabpanelAccessible(content, document); 1.1023 + } 1.1024 + } 1.1025 + } 1.1026 + 1.1027 + if (!newAcc) { 1.1028 + if (content->IsSVG()) { 1.1029 + nsSVGPathGeometryFrame* pathGeometryFrame = do_QueryFrame(frame); 1.1030 + if (pathGeometryFrame) { 1.1031 + // A graphic elements: rect, circle, ellipse, line, path, polygon, 1.1032 + // polyline and image. A 'use' and 'text' graphic elements require 1.1033 + // special support. 1.1034 + newAcc = new EnumRoleAccessible(content, document, roles::GRAPHIC); 1.1035 + } else if (content->Tag() == nsGkAtoms::svg) { 1.1036 + newAcc = new EnumRoleAccessible(content, document, roles::DIAGRAM); 1.1037 + } 1.1038 + } else if (content->IsMathML()){ 1.1039 + if (content->Tag() == nsGkAtoms::math) 1.1040 + newAcc = new EnumRoleAccessible(content, document, roles::EQUATION); 1.1041 + else 1.1042 + newAcc = new HyperTextAccessible(content, document); 1.1043 + } 1.1044 + } 1.1045 + 1.1046 + // If no accessible, see if we need to create a generic accessible because 1.1047 + // of some property that makes this object interesting 1.1048 + // We don't do this for <body>, <html>, <window>, <dialog> etc. which 1.1049 + // correspond to the doc accessible and will be created in any case 1.1050 + if (!newAcc && content->Tag() != nsGkAtoms::body && content->GetParent() && 1.1051 + (roleMapEntry || MustBeAccessible(content, document) || 1.1052 + (isHTML && nsCoreUtils::HasClickListener(content)))) { 1.1053 + // This content is focusable or has an interesting dynamic content accessibility property. 1.1054 + // If it's interesting we need it in the accessibility hierarchy so that events or 1.1055 + // other accessibles can point to it, or so that it can hold a state, etc. 1.1056 + if (isHTML) { 1.1057 + // Interesting HTML container which may have selectable text and/or embedded objects 1.1058 + newAcc = new HyperTextAccessibleWrap(content, document); 1.1059 + } else { // XUL, SVG, MathML etc. 1.1060 + // Interesting generic non-HTML container 1.1061 + newAcc = new AccessibleWrap(content, document); 1.1062 + } 1.1063 + } 1.1064 + 1.1065 + if (!newAcc || !aContext->IsAcceptableChild(newAcc)) 1.1066 + return nullptr; 1.1067 + 1.1068 + document->BindToDocument(newAcc, roleMapEntry); 1.1069 + return newAcc; 1.1070 +} 1.1071 + 1.1072 +//////////////////////////////////////////////////////////////////////////////// 1.1073 +// nsAccessibilityService private 1.1074 + 1.1075 +bool 1.1076 +nsAccessibilityService::Init() 1.1077 +{ 1.1078 + // Initialize accessible document manager. 1.1079 + if (!DocManager::Init()) 1.1080 + return false; 1.1081 + 1.1082 + // Add observers. 1.1083 + nsCOMPtr<nsIObserverService> observerService = 1.1084 + mozilla::services::GetObserverService(); 1.1085 + if (!observerService) 1.1086 + return false; 1.1087 + 1.1088 + observerService->AddObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID, false); 1.1089 + 1.1090 + static const char16_t kInitIndicator[] = { '1', 0 }; 1.1091 + observerService->NotifyObservers(nullptr, "a11y-init-or-shutdown", kInitIndicator); 1.1092 + 1.1093 +#ifdef A11Y_LOG 1.1094 + logging::CheckEnv(); 1.1095 +#endif 1.1096 + 1.1097 + gApplicationAccessible = new ApplicationAccessibleWrap(); 1.1098 + NS_ADDREF(gApplicationAccessible); // will release in Shutdown() 1.1099 + 1.1100 +#ifdef MOZ_CRASHREPORTER 1.1101 + CrashReporter:: 1.1102 + AnnotateCrashReport(NS_LITERAL_CSTRING("Accessibility"), 1.1103 + NS_LITERAL_CSTRING("Active")); 1.1104 +#endif 1.1105 + 1.1106 +#ifdef XP_WIN 1.1107 + sPendingPlugins = new nsTArray<nsCOMPtr<nsIContent> >; 1.1108 + sPluginTimers = new nsTArray<nsCOMPtr<nsITimer> >; 1.1109 +#endif 1.1110 + 1.1111 + gIsShutdown = false; 1.1112 + 1.1113 + // Now its safe to start platform accessibility. 1.1114 + PlatformInit(); 1.1115 + 1.1116 + return true; 1.1117 +} 1.1118 + 1.1119 +void 1.1120 +nsAccessibilityService::Shutdown() 1.1121 +{ 1.1122 + // Remove observers. 1.1123 + nsCOMPtr<nsIObserverService> observerService = 1.1124 + mozilla::services::GetObserverService(); 1.1125 + if (observerService) { 1.1126 + observerService->RemoveObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID); 1.1127 + 1.1128 + static const char16_t kShutdownIndicator[] = { '0', 0 }; 1.1129 + observerService->NotifyObservers(nullptr, "a11y-init-or-shutdown", kShutdownIndicator); 1.1130 + } 1.1131 + 1.1132 + // Stop accessible document loader. 1.1133 + DocManager::Shutdown(); 1.1134 + 1.1135 + SelectionManager::Shutdown(); 1.1136 + 1.1137 +#ifdef XP_WIN 1.1138 + sPendingPlugins = nullptr; 1.1139 + 1.1140 + uint32_t timerCount = sPluginTimers->Length(); 1.1141 + for (uint32_t i = 0; i < timerCount; i++) 1.1142 + sPluginTimers->ElementAt(i)->Cancel(); 1.1143 + 1.1144 + sPluginTimers = nullptr; 1.1145 +#endif 1.1146 + 1.1147 + // Application is going to be closed, shutdown accessibility and mark 1.1148 + // accessibility service as shutdown to prevent calls of its methods. 1.1149 + // Don't null accessibility service static member at this point to be safe 1.1150 + // if someone will try to operate with it. 1.1151 + 1.1152 + NS_ASSERTION(!gIsShutdown, "Accessibility was shutdown already"); 1.1153 + 1.1154 + gIsShutdown = true; 1.1155 + 1.1156 + PlatformShutdown(); 1.1157 + gApplicationAccessible->Shutdown(); 1.1158 + NS_RELEASE(gApplicationAccessible); 1.1159 + gApplicationAccessible = nullptr; 1.1160 +} 1.1161 + 1.1162 +already_AddRefed<Accessible> 1.1163 +nsAccessibilityService::CreateAccessibleByType(nsIContent* aContent, 1.1164 + DocAccessible* aDoc) 1.1165 +{ 1.1166 + nsAutoString role; 1.1167 + for (const nsXBLBinding* binding = aContent->GetXBLBinding(); binding; binding = binding->GetBaseBinding()) { 1.1168 + nsIContent* bindingElm = binding->PrototypeBinding()->GetBindingElement(); 1.1169 + bindingElm->GetAttr(kNameSpaceID_None, nsGkAtoms::role, role); 1.1170 + if (!role.IsEmpty()) 1.1171 + break; 1.1172 + } 1.1173 + 1.1174 + if (role.IsEmpty() || role.EqualsLiteral("none")) 1.1175 + return nullptr; 1.1176 + 1.1177 + if (role.EqualsLiteral("outerdoc")) { 1.1178 + nsRefPtr<Accessible> accessible = new OuterDocAccessible(aContent, aDoc); 1.1179 + return accessible.forget(); 1.1180 + } 1.1181 + 1.1182 + nsRefPtr<Accessible> accessible; 1.1183 +#ifdef MOZ_XUL 1.1184 + // XUL controls 1.1185 + if (role.EqualsLiteral("xul:alert")) { 1.1186 + accessible = new XULAlertAccessible(aContent, aDoc); 1.1187 + 1.1188 + } else if (role.EqualsLiteral("xul:button")) { 1.1189 + accessible = new XULButtonAccessible(aContent, aDoc); 1.1190 + 1.1191 + } else if (role.EqualsLiteral("xul:checkbox")) { 1.1192 + accessible = new XULCheckboxAccessible(aContent, aDoc); 1.1193 + 1.1194 + } else if (role.EqualsLiteral("xul:colorpicker")) { 1.1195 + accessible = new XULColorPickerAccessible(aContent, aDoc); 1.1196 + 1.1197 + } else if (role.EqualsLiteral("xul:colorpickertile")) { 1.1198 + accessible = new XULColorPickerTileAccessible(aContent, aDoc); 1.1199 + 1.1200 + } else if (role.EqualsLiteral("xul:combobox")) { 1.1201 + accessible = new XULComboboxAccessible(aContent, aDoc); 1.1202 + 1.1203 + } else if (role.EqualsLiteral("xul:tabpanels")) { 1.1204 + accessible = new XULTabpanelsAccessible(aContent, aDoc); 1.1205 + 1.1206 + } else if (role.EqualsLiteral("xul:dropmarker")) { 1.1207 + accessible = new XULDropmarkerAccessible(aContent, aDoc); 1.1208 + 1.1209 + } else if (role.EqualsLiteral("xul:groupbox")) { 1.1210 + accessible = new XULGroupboxAccessible(aContent, aDoc); 1.1211 + 1.1212 + } else if (role.EqualsLiteral("xul:image")) { 1.1213 + if (aContent->HasAttr(kNameSpaceID_None, nsGkAtoms::onclick)) { 1.1214 + accessible = new XULToolbarButtonAccessible(aContent, aDoc); 1.1215 + 1.1216 + } else { 1.1217 + // Don't include nameless images in accessible tree. 1.1218 + if (!aContent->HasAttr(kNameSpaceID_None, 1.1219 + nsGkAtoms::tooltiptext)) 1.1220 + return nullptr; 1.1221 + 1.1222 + accessible = new ImageAccessibleWrap(aContent, aDoc); 1.1223 + } 1.1224 + 1.1225 + } else if (role.EqualsLiteral("xul:link")) { 1.1226 + accessible = new XULLinkAccessible(aContent, aDoc); 1.1227 + 1.1228 + } else if (role.EqualsLiteral("xul:listbox")) { 1.1229 + accessible = new XULListboxAccessibleWrap(aContent, aDoc); 1.1230 + 1.1231 + } else if (role.EqualsLiteral("xul:listcell")) { 1.1232 + // Only create cells if there's more than one per row. 1.1233 + nsIContent* listItem = aContent->GetParent(); 1.1234 + if (!listItem) 1.1235 + return nullptr; 1.1236 + 1.1237 + for (nsIContent* child = listItem->GetFirstChild(); child; 1.1238 + child = child->GetNextSibling()) { 1.1239 + if (child->IsXUL(nsGkAtoms::listcell) && child != aContent) { 1.1240 + accessible = new XULListCellAccessibleWrap(aContent, aDoc); 1.1241 + break; 1.1242 + } 1.1243 + } 1.1244 + 1.1245 + } else if (role.EqualsLiteral("xul:listhead")) { 1.1246 + accessible = new XULColumAccessible(aContent, aDoc); 1.1247 + 1.1248 + } else if (role.EqualsLiteral("xul:listheader")) { 1.1249 + accessible = new XULColumnItemAccessible(aContent, aDoc); 1.1250 + 1.1251 + } else if (role.EqualsLiteral("xul:listitem")) { 1.1252 + accessible = new XULListitemAccessible(aContent, aDoc); 1.1253 + 1.1254 + } else if (role.EqualsLiteral("xul:menubar")) { 1.1255 + accessible = new XULMenubarAccessible(aContent, aDoc); 1.1256 + 1.1257 + } else if (role.EqualsLiteral("xul:menulist")) { 1.1258 + accessible = new XULComboboxAccessible(aContent, aDoc); 1.1259 + 1.1260 + } else if (role.EqualsLiteral("xul:menuitem")) { 1.1261 + accessible = new XULMenuitemAccessibleWrap(aContent, aDoc); 1.1262 + 1.1263 + } else if (role.EqualsLiteral("xul:menupopup")) { 1.1264 +#ifdef MOZ_ACCESSIBILITY_ATK 1.1265 + // ATK considers this node to be redundant when within menubars, and it makes menu 1.1266 + // navigation with assistive technologies more difficult 1.1267 + // XXX In the future we will should this for consistency across the nsIAccessible 1.1268 + // implementations on each platform for a consistent scripting environment, but 1.1269 + // then strip out redundant accessibles in the AccessibleWrap class for each platform. 1.1270 + nsIContent *parent = aContent->GetParent(); 1.1271 + if (parent && parent->IsXUL() && parent->Tag() == nsGkAtoms::menu) 1.1272 + return nullptr; 1.1273 +#endif 1.1274 + 1.1275 + accessible = new XULMenupopupAccessible(aContent, aDoc); 1.1276 + 1.1277 + } else if(role.EqualsLiteral("xul:menuseparator")) { 1.1278 + accessible = new XULMenuSeparatorAccessible(aContent, aDoc); 1.1279 + 1.1280 + } else if(role.EqualsLiteral("xul:pane")) { 1.1281 + accessible = new EnumRoleAccessible(aContent, aDoc, roles::PANE); 1.1282 + 1.1283 + } else if (role.EqualsLiteral("xul:panel")) { 1.1284 + if (aContent->AttrValueIs(kNameSpaceID_None, nsGkAtoms::noautofocus, 1.1285 + nsGkAtoms::_true, eCaseMatters)) 1.1286 + accessible = new XULAlertAccessible(aContent, aDoc); 1.1287 + else 1.1288 + accessible = new EnumRoleAccessible(aContent, aDoc, roles::PANE); 1.1289 + 1.1290 + } else if (role.EqualsLiteral("xul:progressmeter")) { 1.1291 + accessible = new XULProgressMeterAccessible(aContent, aDoc); 1.1292 + 1.1293 + } else if (role.EqualsLiteral("xulstatusbar")) { 1.1294 + accessible = new XULStatusBarAccessible(aContent, aDoc); 1.1295 + 1.1296 + } else if (role.EqualsLiteral("xul:scale")) { 1.1297 + accessible = new XULSliderAccessible(aContent, aDoc); 1.1298 + 1.1299 + } else if (role.EqualsLiteral("xul:radiobutton")) { 1.1300 + accessible = new XULRadioButtonAccessible(aContent, aDoc); 1.1301 + 1.1302 + } else if (role.EqualsLiteral("xul:radiogroup")) { 1.1303 + accessible = new XULRadioGroupAccessible(aContent, aDoc); 1.1304 + 1.1305 + } else if (role.EqualsLiteral("xul:tab")) { 1.1306 + accessible = new XULTabAccessible(aContent, aDoc); 1.1307 + 1.1308 + } else if (role.EqualsLiteral("xul:tabs")) { 1.1309 + accessible = new XULTabsAccessible(aContent, aDoc); 1.1310 + 1.1311 + } else if (role.EqualsLiteral("xul:text")) { 1.1312 + accessible = new XULLabelAccessible(aContent, aDoc); 1.1313 + 1.1314 + } else if (role.EqualsLiteral("xul:textbox")) { 1.1315 + accessible = new EnumRoleAccessible(aContent, aDoc, roles::SECTION); 1.1316 + 1.1317 + } else if (role.EqualsLiteral("xul:thumb")) { 1.1318 + accessible = new XULThumbAccessible(aContent, aDoc); 1.1319 + 1.1320 + } else if (role.EqualsLiteral("xul:tree")) { 1.1321 + accessible = CreateAccessibleForXULTree(aContent, aDoc); 1.1322 + 1.1323 + } else if (role.EqualsLiteral("xul:treecolumns")) { 1.1324 + accessible = new XULTreeColumAccessible(aContent, aDoc); 1.1325 + 1.1326 + } else if (role.EqualsLiteral("xul:treecolumnitem")) { 1.1327 + accessible = new XULColumnItemAccessible(aContent, aDoc); 1.1328 + 1.1329 + } else if (role.EqualsLiteral("xul:toolbar")) { 1.1330 + accessible = new XULToolbarAccessible(aContent, aDoc); 1.1331 + 1.1332 + } else if (role.EqualsLiteral("xul:toolbarseparator")) { 1.1333 + accessible = new XULToolbarSeparatorAccessible(aContent, aDoc); 1.1334 + 1.1335 + } else if (role.EqualsLiteral("xul:tooltip")) { 1.1336 + accessible = new XULTooltipAccessible(aContent, aDoc); 1.1337 + 1.1338 + } else if (role.EqualsLiteral("xul:toolbarbutton")) { 1.1339 + accessible = new XULToolbarButtonAccessible(aContent, aDoc); 1.1340 + 1.1341 + } 1.1342 +#endif // MOZ_XUL 1.1343 + 1.1344 + return accessible.forget(); 1.1345 +} 1.1346 + 1.1347 +already_AddRefed<Accessible> 1.1348 +nsAccessibilityService::CreateHTMLAccessibleByMarkup(nsIFrame* aFrame, 1.1349 + nsIContent* aContent, 1.1350 + Accessible* aContext) 1.1351 +{ 1.1352 + DocAccessible* document = aContext->Document(); 1.1353 + if (aContext->IsTableRow()) { 1.1354 + if (nsCoreUtils::IsHTMLTableHeader(aContent) && 1.1355 + aContext->GetContent() == aContent->GetParent()) { 1.1356 + nsRefPtr<Accessible> accessible = 1.1357 + new HTMLTableHeaderCellAccessibleWrap(aContent, document); 1.1358 + return accessible.forget(); 1.1359 + } 1.1360 + 1.1361 + return nullptr; 1.1362 + } 1.1363 + 1.1364 + // This method assumes we're in an HTML namespace. 1.1365 + nsIAtom* tag = aContent->Tag(); 1.1366 + if (tag == nsGkAtoms::figcaption) { 1.1367 + nsRefPtr<Accessible> accessible = 1.1368 + new HTMLFigcaptionAccessible(aContent, document); 1.1369 + return accessible.forget(); 1.1370 + } 1.1371 + 1.1372 + if (tag == nsGkAtoms::figure) { 1.1373 + nsRefPtr<Accessible> accessible = 1.1374 + new HTMLFigureAccessible(aContent, document); 1.1375 + return accessible.forget(); 1.1376 + } 1.1377 + 1.1378 + if (tag == nsGkAtoms::legend) { 1.1379 + nsRefPtr<Accessible> accessible = 1.1380 + new HTMLLegendAccessible(aContent, document); 1.1381 + return accessible.forget(); 1.1382 + } 1.1383 + 1.1384 + if (tag == nsGkAtoms::option) { 1.1385 + nsRefPtr<Accessible> accessible = 1.1386 + new HTMLSelectOptionAccessible(aContent, document); 1.1387 + return accessible.forget(); 1.1388 + } 1.1389 + 1.1390 + if (tag == nsGkAtoms::optgroup) { 1.1391 + nsRefPtr<Accessible> accessible = 1.1392 + new HTMLSelectOptGroupAccessible(aContent, document); 1.1393 + return accessible.forget(); 1.1394 + } 1.1395 + 1.1396 + if (tag == nsGkAtoms::ul || tag == nsGkAtoms::ol || 1.1397 + tag == nsGkAtoms::dl) { 1.1398 + nsRefPtr<Accessible> accessible = 1.1399 + new HTMLListAccessible(aContent, document); 1.1400 + return accessible.forget(); 1.1401 + } 1.1402 + 1.1403 + if (tag == nsGkAtoms::a) { 1.1404 + // Only some roles truly enjoy life as HTMLLinkAccessibles, for details 1.1405 + // see closed bug 494807. 1.1406 + nsRoleMapEntry* roleMapEntry = aria::GetRoleMap(aContent); 1.1407 + if (roleMapEntry && roleMapEntry->role != roles::NOTHING && 1.1408 + roleMapEntry->role != roles::LINK) { 1.1409 + nsRefPtr<Accessible> accessible = 1.1410 + new HyperTextAccessibleWrap(aContent, document); 1.1411 + return accessible.forget(); 1.1412 + } 1.1413 + 1.1414 + nsRefPtr<Accessible> accessible = 1.1415 + new HTMLLinkAccessible(aContent, document); 1.1416 + return accessible.forget(); 1.1417 + } 1.1418 + 1.1419 + if (aContext->IsList()) { 1.1420 + // If list item is a child of accessible list then create an accessible for 1.1421 + // it unconditionally by tag name. nsBlockFrame creates the list item 1.1422 + // accessible for other elements styled as list items. 1.1423 + if (aContext->GetContent() == aContent->GetParent()) { 1.1424 + if (tag == nsGkAtoms::dt || tag == nsGkAtoms::li) { 1.1425 + nsRefPtr<Accessible> accessible = 1.1426 + new HTMLLIAccessible(aContent, document); 1.1427 + return accessible.forget(); 1.1428 + } 1.1429 + 1.1430 + if (tag == nsGkAtoms::dd) { 1.1431 + nsRefPtr<Accessible> accessible = 1.1432 + new HyperTextAccessibleWrap(aContent, document); 1.1433 + return accessible.forget(); 1.1434 + } 1.1435 + } 1.1436 + 1.1437 + return nullptr; 1.1438 + } 1.1439 + 1.1440 + if (tag == nsGkAtoms::abbr || 1.1441 + tag == nsGkAtoms::acronym || 1.1442 + tag == nsGkAtoms::article || 1.1443 + tag == nsGkAtoms::aside || 1.1444 + tag == nsGkAtoms::blockquote || 1.1445 + tag == nsGkAtoms::form || 1.1446 + tag == nsGkAtoms::footer || 1.1447 + tag == nsGkAtoms::header || 1.1448 + tag == nsGkAtoms::h1 || 1.1449 + tag == nsGkAtoms::h2 || 1.1450 + tag == nsGkAtoms::h3 || 1.1451 + tag == nsGkAtoms::h4 || 1.1452 + tag == nsGkAtoms::h5 || 1.1453 + tag == nsGkAtoms::h6 || 1.1454 + tag == nsGkAtoms::nav || 1.1455 + tag == nsGkAtoms::q || 1.1456 + tag == nsGkAtoms::section) { 1.1457 + nsRefPtr<Accessible> accessible = 1.1458 + new HyperTextAccessibleWrap(aContent, document); 1.1459 + return accessible.forget(); 1.1460 + } 1.1461 + 1.1462 + if (tag == nsGkAtoms::label) { 1.1463 + nsRefPtr<Accessible> accessible = 1.1464 + new HTMLLabelAccessible(aContent, document); 1.1465 + return accessible.forget(); 1.1466 + } 1.1467 + 1.1468 + if (tag == nsGkAtoms::output) { 1.1469 + nsRefPtr<Accessible> accessible = 1.1470 + new HTMLOutputAccessible(aContent, document); 1.1471 + return accessible.forget(); 1.1472 + } 1.1473 + 1.1474 + if (tag == nsGkAtoms::progress) { 1.1475 + nsRefPtr<Accessible> accessible = 1.1476 + new HTMLProgressMeterAccessible(aContent, document); 1.1477 + return accessible.forget(); 1.1478 + } 1.1479 + 1.1480 + return nullptr; 1.1481 + } 1.1482 + 1.1483 +already_AddRefed<Accessible> 1.1484 +nsAccessibilityService::CreateAccessibleByFrameType(nsIFrame* aFrame, 1.1485 + nsIContent* aContent, 1.1486 + Accessible* aContext) 1.1487 +{ 1.1488 + DocAccessible* document = aContext->Document(); 1.1489 + 1.1490 + nsRefPtr<Accessible> newAcc; 1.1491 + switch (aFrame->AccessibleType()) { 1.1492 + case eNoType: 1.1493 + return nullptr; 1.1494 + case eHTMLBRType: 1.1495 + newAcc = new HTMLBRAccessible(aContent, document); 1.1496 + break; 1.1497 + case eHTMLButtonType: 1.1498 + newAcc = new HTMLButtonAccessible(aContent, document); 1.1499 + break; 1.1500 + case eHTMLCanvasType: 1.1501 + newAcc = new HTMLCanvasAccessible(aContent, document); 1.1502 + break; 1.1503 + case eHTMLCaptionType: 1.1504 + if (aContext->IsTable() && 1.1505 + aContext->GetContent() == aContent->GetParent()) { 1.1506 + newAcc = new HTMLCaptionAccessible(aContent, document); 1.1507 + } 1.1508 + break; 1.1509 + case eHTMLCheckboxType: 1.1510 + newAcc = new HTMLCheckboxAccessible(aContent, document); 1.1511 + break; 1.1512 + case eHTMLComboboxType: 1.1513 + newAcc = new HTMLComboboxAccessible(aContent, document); 1.1514 + break; 1.1515 + case eHTMLFileInputType: 1.1516 + newAcc = new HTMLFileInputAccessible(aContent, document); 1.1517 + break; 1.1518 + case eHTMLGroupboxType: 1.1519 + newAcc = new HTMLGroupboxAccessible(aContent, document); 1.1520 + break; 1.1521 + case eHTMLHRType: 1.1522 + newAcc = new HTMLHRAccessible(aContent, document); 1.1523 + break; 1.1524 + case eHTMLImageMapType: 1.1525 + newAcc = new HTMLImageMapAccessible(aContent, document); 1.1526 + break; 1.1527 + case eHTMLLiType: 1.1528 + if (aContext->IsList() && 1.1529 + aContext->GetContent() == aContent->GetParent()) { 1.1530 + newAcc = new HTMLLIAccessible(aContent, document); 1.1531 + } 1.1532 + break; 1.1533 + case eHTMLSelectListType: 1.1534 + newAcc = new HTMLSelectListAccessible(aContent, document); 1.1535 + break; 1.1536 + case eHTMLMediaType: 1.1537 + newAcc = new EnumRoleAccessible(aContent, document, roles::GROUPING); 1.1538 + break; 1.1539 + case eHTMLRadioButtonType: 1.1540 + newAcc = new HTMLRadioButtonAccessible(aContent, document); 1.1541 + break; 1.1542 + case eHTMLRangeType: 1.1543 + newAcc = new HTMLRangeAccessible(aContent, document); 1.1544 + break; 1.1545 + case eHTMLSpinnerType: 1.1546 + newAcc = new HTMLSpinnerAccessible(aContent, document); 1.1547 + break; 1.1548 + case eHTMLTableType: 1.1549 + newAcc = new HTMLTableAccessibleWrap(aContent, document); 1.1550 + break; 1.1551 + case eHTMLTableCellType: 1.1552 + // Accessible HTML table cell should be a child of accessible HTML table 1.1553 + // or its row (CSS HTML tables are polite to the used markup at 1.1554 + // certain degree). 1.1555 + // Otherwise create a generic text accessible to avoid text jamming 1.1556 + // when reading by AT. 1.1557 + if (aContext->IsHTMLTableRow() || aContext->IsHTMLTable()) 1.1558 + newAcc = new HTMLTableCellAccessibleWrap(aContent, document); 1.1559 + else 1.1560 + newAcc = new HyperTextAccessibleWrap(aContent, document); 1.1561 + break; 1.1562 + 1.1563 + case eHTMLTableRowType: { 1.1564 + // Accessible HTML table row must be a child of tbody/tfoot/thead of 1.1565 + // accessible HTML table or must be a child of accessible of HTML table. 1.1566 + if (aContext->IsTable()) { 1.1567 + nsIContent* parentContent = aContent->GetParent(); 1.1568 + nsIFrame* parentFrame = parentContent->GetPrimaryFrame(); 1.1569 + if (parentFrame->GetType() == nsGkAtoms::tableRowGroupFrame) { 1.1570 + parentContent = parentContent->GetParent(); 1.1571 + parentFrame = parentContent->GetPrimaryFrame(); 1.1572 + } 1.1573 + 1.1574 + if (parentFrame->GetType() == nsGkAtoms::tableOuterFrame && 1.1575 + aContext->GetContent() == parentContent) { 1.1576 + newAcc = new HTMLTableRowAccessible(aContent, document); 1.1577 + } 1.1578 + } 1.1579 + break; 1.1580 + } 1.1581 + case eHTMLTextFieldType: 1.1582 + newAcc = new HTMLTextFieldAccessible(aContent, document); 1.1583 + break; 1.1584 + case eHyperTextType: 1.1585 + if (aContent->Tag() != nsGkAtoms::dt && aContent->Tag() != nsGkAtoms::dd) 1.1586 + newAcc = new HyperTextAccessibleWrap(aContent, document); 1.1587 + break; 1.1588 + 1.1589 + case eImageType: 1.1590 + newAcc = new ImageAccessibleWrap(aContent, document); 1.1591 + break; 1.1592 + case eOuterDocType: 1.1593 + newAcc = new OuterDocAccessible(aContent, document); 1.1594 + break; 1.1595 + case ePluginType: { 1.1596 + nsObjectFrame* objectFrame = do_QueryFrame(aFrame); 1.1597 + newAcc = CreatePluginAccessible(objectFrame, aContent, aContext); 1.1598 + break; 1.1599 + } 1.1600 + case eTextLeafType: 1.1601 + newAcc = new TextLeafAccessibleWrap(aContent, document); 1.1602 + break; 1.1603 + default: 1.1604 + MOZ_ASSERT(false); 1.1605 + break; 1.1606 + } 1.1607 + 1.1608 + return newAcc.forget(); 1.1609 +} 1.1610 + 1.1611 +//////////////////////////////////////////////////////////////////////////////// 1.1612 +// nsIAccessibilityService (DON'T put methods here) 1.1613 + 1.1614 +Accessible* 1.1615 +nsAccessibilityService::AddNativeRootAccessible(void* aAtkAccessible) 1.1616 +{ 1.1617 +#ifdef MOZ_ACCESSIBILITY_ATK 1.1618 + ApplicationAccessible* applicationAcc = ApplicationAcc(); 1.1619 + if (!applicationAcc) 1.1620 + return nullptr; 1.1621 + 1.1622 + GtkWindowAccessible* nativeWnd = 1.1623 + new GtkWindowAccessible(static_cast<AtkObject*>(aAtkAccessible)); 1.1624 + 1.1625 + if (applicationAcc->AppendChild(nativeWnd)) 1.1626 + return nativeWnd; 1.1627 +#endif 1.1628 + 1.1629 + return nullptr; 1.1630 +} 1.1631 + 1.1632 +void 1.1633 +nsAccessibilityService::RemoveNativeRootAccessible(Accessible* aAccessible) 1.1634 +{ 1.1635 +#ifdef MOZ_ACCESSIBILITY_ATK 1.1636 + ApplicationAccessible* applicationAcc = ApplicationAcc(); 1.1637 + 1.1638 + if (applicationAcc) 1.1639 + applicationAcc->RemoveChild(aAccessible); 1.1640 +#endif 1.1641 +} 1.1642 + 1.1643 +//////////////////////////////////////////////////////////////////////////////// 1.1644 +// NS_GetAccessibilityService 1.1645 +//////////////////////////////////////////////////////////////////////////////// 1.1646 + 1.1647 +/** 1.1648 + * Return accessibility service; creating one if necessary. 1.1649 + */ 1.1650 +nsresult 1.1651 +NS_GetAccessibilityService(nsIAccessibilityService** aResult) 1.1652 +{ 1.1653 + NS_ENSURE_TRUE(aResult, NS_ERROR_NULL_POINTER); 1.1654 + *aResult = nullptr; 1.1655 + 1.1656 + if (nsAccessibilityService::gAccessibilityService) { 1.1657 + NS_ADDREF(*aResult = nsAccessibilityService::gAccessibilityService); 1.1658 + return NS_OK; 1.1659 + } 1.1660 + 1.1661 + nsRefPtr<nsAccessibilityService> service = new nsAccessibilityService(); 1.1662 + NS_ENSURE_TRUE(service, NS_ERROR_OUT_OF_MEMORY); 1.1663 + 1.1664 + if (!service->Init()) { 1.1665 + service->Shutdown(); 1.1666 + return NS_ERROR_FAILURE; 1.1667 + } 1.1668 + 1.1669 + statistics::A11yInitialized(); 1.1670 + 1.1671 + nsAccessibilityService::gAccessibilityService = service; 1.1672 + NS_ADDREF(*aResult = service); 1.1673 + 1.1674 + return NS_OK; 1.1675 +} 1.1676 + 1.1677 +//////////////////////////////////////////////////////////////////////////////// 1.1678 +// nsAccessibilityService private (DON'T put methods here) 1.1679 + 1.1680 +#ifdef MOZ_XUL 1.1681 +already_AddRefed<Accessible> 1.1682 +nsAccessibilityService::CreateAccessibleForXULTree(nsIContent* aContent, 1.1683 + DocAccessible* aDoc) 1.1684 +{ 1.1685 + nsIContent* child = nsTreeUtils::GetDescendantChild(aContent, 1.1686 + nsGkAtoms::treechildren); 1.1687 + if (!child) 1.1688 + return nullptr; 1.1689 + 1.1690 + nsTreeBodyFrame* treeFrame = do_QueryFrame(child->GetPrimaryFrame()); 1.1691 + if (!treeFrame) 1.1692 + return nullptr; 1.1693 + 1.1694 + nsRefPtr<nsTreeColumns> treeCols = treeFrame->Columns(); 1.1695 + int32_t count = 0; 1.1696 + treeCols->GetCount(&count); 1.1697 + 1.1698 + // Outline of list accessible. 1.1699 + if (count == 1) { 1.1700 + nsRefPtr<Accessible> accessible = 1.1701 + new XULTreeAccessible(aContent, aDoc, treeFrame); 1.1702 + return accessible.forget(); 1.1703 + } 1.1704 + 1.1705 + // Table or tree table accessible. 1.1706 + nsRefPtr<Accessible> accessible = 1.1707 + new XULTreeGridAccessibleWrap(aContent, aDoc, treeFrame); 1.1708 + return accessible.forget(); 1.1709 +} 1.1710 +#endif 1.1711 + 1.1712 +//////////////////////////////////////////////////////////////////////////////// 1.1713 +// Services 1.1714 +//////////////////////////////////////////////////////////////////////////////// 1.1715 + 1.1716 +namespace mozilla { 1.1717 +namespace a11y { 1.1718 + 1.1719 +FocusManager* 1.1720 +FocusMgr() 1.1721 +{ 1.1722 + return nsAccessibilityService::gAccessibilityService; 1.1723 +} 1.1724 + 1.1725 +SelectionManager* 1.1726 +SelectionMgr() 1.1727 +{ 1.1728 + return nsAccessibilityService::gAccessibilityService; 1.1729 +} 1.1730 + 1.1731 +ApplicationAccessible* 1.1732 +ApplicationAcc() 1.1733 +{ 1.1734 + return nsAccessibilityService::gApplicationAccessible; 1.1735 +} 1.1736 + 1.1737 +EPlatformDisabledState 1.1738 +PlatformDisabledState() 1.1739 +{ 1.1740 + static int disabledState = 0xff; 1.1741 + 1.1742 + if (disabledState == 0xff) { 1.1743 + disabledState = Preferences::GetInt("accessibility.force_disabled", 0); 1.1744 + if (disabledState < ePlatformIsForceEnabled) 1.1745 + disabledState = ePlatformIsForceEnabled; 1.1746 + else if (disabledState > ePlatformIsDisabled) 1.1747 + disabledState = ePlatformIsDisabled; 1.1748 + } 1.1749 + 1.1750 + return (EPlatformDisabledState)disabledState; 1.1751 +} 1.1752 + 1.1753 +} 1.1754 +}