Bug 460926 A11y hierachy is broken on Ubuntu 8.10 (GNOME 2.24), r=Evan.Yan sr=roc
[wine-gecko.git] / accessible / src / base / nsAccessibilityService.cpp
blob27ab6227bcd5aa7cf25e91c187c5cb3b3373320e
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* ***** BEGIN LICENSE BLOCK *****
3 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
5 * The contents of this file are subject to the Mozilla Public License Version
6 * 1.1 (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at
8 * http://www.mozilla.org/MPL/
10 * Software distributed under the License is distributed on an "AS IS" basis,
11 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12 * for the specific language governing rights and limitations under the
13 * License.
15 * The Original Code is mozilla.org code.
17 * The Initial Developer of the Original Code is
18 * Netscape Communications Corporation.
19 * Portions created by the Initial Developer are Copyright (C) 1998
20 * the Initial Developer. All Rights Reserved.
22 * Contributor(s):
23 * John Gaunt (jgaunt@netscape.com)
25 * Alternatively, the contents of this file may be used under the terms of
26 * either of the GNU General Public License Version 2 or later (the "GPL"),
27 * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
28 * in which case the provisions of the GPL or the LGPL are applicable instead
29 * of those above. If you wish to allow use of your version of this file only
30 * under the terms of either the GPL or the LGPL, and not to allow others to
31 * use your version of this file under the terms of the MPL, indicate your
32 * decision by deleting the provisions above and replace them with the notice
33 * and other provisions required by the GPL or the LGPL. If you do not delete
34 * the provisions above, a recipient may use your version of this file under
35 * the terms of any one of the MPL, the GPL or the LGPL.
37 * ***** END LICENSE BLOCK ***** */
39 // NOTE: alphabetically ordered
40 #include "nsAccessibilityAtoms.h"
41 #include "nsAccessibilityService.h"
42 #include "nsCoreUtils.h"
43 #include "nsAccUtils.h"
44 #include "nsARIAMap.h"
45 #include "nsIContentViewer.h"
46 #include "nsCURILoader.h"
47 #include "nsDocAccessible.h"
48 #include "nsHTMLImageAccessibleWrap.h"
49 #include "nsHTMLLinkAccessible.h"
50 #include "nsHTMLSelectAccessible.h"
51 #include "nsHTMLTableAccessibleWrap.h"
52 #include "nsHTMLTextAccessible.h"
53 #include "nsHyperTextAccessibleWrap.h"
54 #include "nsIAccessibilityService.h"
55 #include "nsIAccessibleProvider.h"
56 #include "nsIDOMDocument.h"
57 #include "nsIDOMHTMLAreaElement.h"
58 #include "nsIDOMHTMLLegendElement.h"
59 #include "nsIDOMHTMLObjectElement.h"
60 #include "nsIDOMHTMLOptGroupElement.h"
61 #include "nsIDOMHTMLOptionElement.h"
62 #include "nsIDOMWindow.h"
63 #include "nsIDOMXULElement.h"
64 #include "nsIDocShell.h"
65 #include "nsIFrame.h"
66 #include "nsIInterfaceRequestorUtils.h"
67 #include "nsIImageFrame.h"
68 #include "nsILink.h"
69 #include "nsINameSpaceManager.h"
70 #include "nsIObserverService.h"
71 #include "nsIPluginInstance.h"
72 #include "nsIPresShell.h"
73 #include "nsISupportsUtils.h"
74 #include "nsIWebNavigation.h"
75 #include "nsObjectFrame.h"
76 #include "nsOuterDocAccessible.h"
77 #include "nsRootAccessibleWrap.h"
78 #include "nsTextFragment.h"
79 #include "nsPresContext.h"
80 #include "nsServiceManagerUtils.h"
81 #include "nsUnicharUtils.h"
82 #include "nsIWebProgress.h"
83 #include "nsNetError.h"
84 #include "nsDocShellLoadTypes.h"
86 #ifdef MOZ_XUL
87 #include "nsXULAlertAccessible.h"
88 #include "nsXULColorPickerAccessible.h"
89 #include "nsXULFormControlAccessible.h"
90 #include "nsXULMenuAccessibleWrap.h"
91 #include "nsXULSelectAccessible.h"
92 #include "nsXULSliderAccessible.h"
93 #include "nsXULTabAccessible.h"
94 #include "nsXULTextAccessible.h"
95 #include "nsXULTreeAccessibleWrap.h"
96 #endif
98 // For native window support for object/embed/applet tags
99 #ifdef XP_WIN
100 #include "nsHTMLWin32ObjectAccessible.h"
101 #endif
103 #ifndef DISABLE_XFORMS_HOOKS
104 #include "nsXFormsFormControlsAccessible.h"
105 #include "nsXFormsWidgetsAccessible.h"
106 #endif
108 #ifdef MOZ_ACCESSIBILITY_ATK
109 #include "nsAppRootAccessible.h"
110 #else
111 #include "nsApplicationAccessibleWrap.h"
112 #endif
114 nsAccessibilityService *nsAccessibilityService::gAccessibilityService = nsnull;
117 * nsAccessibilityService
120 nsAccessibilityService::nsAccessibilityService()
122 nsCOMPtr<nsIObserverService> observerService =
123 do_GetService("@mozilla.org/observer-service;1");
124 if (!observerService)
125 return;
127 observerService->AddObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID, PR_FALSE);
128 nsCOMPtr<nsIWebProgress> progress(do_GetService(NS_DOCUMENTLOADER_SERVICE_CONTRACTID));
129 if (progress) {
130 progress->AddProgressListener(static_cast<nsIWebProgressListener*>(this),
131 nsIWebProgress::NOTIFY_STATE_DOCUMENT |
132 nsIWebProgress::NOTIFY_LOCATION);
134 nsAccessNodeWrap::InitAccessibility();
137 nsAccessibilityService::~nsAccessibilityService()
139 nsAccessibilityService::gAccessibilityService = nsnull;
140 nsAccessNodeWrap::ShutdownAccessibility();
143 NS_IMPL_THREADSAFE_ISUPPORTS5(nsAccessibilityService, nsIAccessibilityService, nsIAccessibleRetrieval,
144 nsIObserver, nsIWebProgressListener, nsISupportsWeakReference)
146 // nsIObserver
148 NS_IMETHODIMP
149 nsAccessibilityService::Observe(nsISupports *aSubject, const char *aTopic,
150 const PRUnichar *aData)
152 if (!nsCRT::strcmp(aTopic, NS_XPCOM_SHUTDOWN_OBSERVER_ID)) {
153 nsCOMPtr<nsIObserverService> observerService =
154 do_GetService("@mozilla.org/observer-service;1");
155 if (observerService) {
156 observerService->RemoveObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID);
158 nsCOMPtr<nsIWebProgress> progress(do_GetService(NS_DOCUMENTLOADER_SERVICE_CONTRACTID));
159 if (progress)
160 progress->RemoveProgressListener(static_cast<nsIWebProgressListener*>(this));
161 nsAccessNodeWrap::ShutdownAccessibility();
162 // Cancel and release load timers
163 while (mLoadTimers.Count() > 0 ) {
164 nsCOMPtr<nsITimer> timer = mLoadTimers.ObjectAt(0);
165 void *closure = nsnull;
166 timer->GetClosure(&closure);
167 if (closure) {
168 nsIWebProgress *webProgress = static_cast<nsIWebProgress*>(closure);
169 NS_RELEASE(webProgress); // Release nsIWebProgress for timer
171 timer->Cancel();
172 mLoadTimers.RemoveObjectAt(0);
175 return NS_OK;
178 // nsIWebProgressListener
179 NS_IMETHODIMP nsAccessibilityService::OnStateChange(nsIWebProgress *aWebProgress,
180 nsIRequest *aRequest, PRUint32 aStateFlags, nsresult aStatus)
182 NS_ASSERTION(aStateFlags & STATE_IS_DOCUMENT, "Other notifications excluded");
184 if (!aWebProgress || 0 == (aStateFlags & (STATE_START | STATE_STOP))) {
185 return NS_OK;
188 nsCAutoString name;
189 aRequest->GetName(name);
190 if (name.EqualsLiteral("about:blank"))
191 return NS_OK;
193 if (NS_FAILED(aStatus) && (aStateFlags & STATE_START))
194 return NS_OK;
196 nsCOMPtr<nsITimer> timer = do_CreateInstance("@mozilla.org/timer;1");
197 if (!timer)
198 return NS_OK;
199 mLoadTimers.AppendObject(timer);
200 NS_ADDREF(aWebProgress);
202 if (aStateFlags & STATE_START)
203 timer->InitWithFuncCallback(StartLoadCallback, aWebProgress, 0,
204 nsITimer::TYPE_ONE_SHOT);
205 else if (NS_SUCCEEDED(aStatus))
206 timer->InitWithFuncCallback(EndLoadCallback, aWebProgress, 0,
207 nsITimer::TYPE_ONE_SHOT);
208 else // Failed end load
209 timer->InitWithFuncCallback(FailedLoadCallback, aWebProgress, 0,
210 nsITimer::TYPE_ONE_SHOT);
211 return NS_OK;
214 NS_IMETHODIMP nsAccessibilityService::ProcessDocLoadEvent(nsITimer *aTimer, void *aClosure, PRUint32 aEventType)
216 nsCOMPtr<nsIDOMWindow> domWindow;
217 nsIWebProgress *webProgress = static_cast<nsIWebProgress*>(aClosure);
218 webProgress->GetDOMWindow(getter_AddRefs(domWindow));
219 NS_RELEASE(webProgress);
220 mLoadTimers.RemoveObject(aTimer);
221 NS_ENSURE_STATE(domWindow);
223 if (aEventType == nsIAccessibleEvent::EVENT_DOCUMENT_LOAD_START) {
224 nsCOMPtr<nsIWebNavigation> webNav(do_GetInterface(domWindow));
225 nsCOMPtr<nsIDocShell> docShell(do_QueryInterface(webNav));
226 NS_ENSURE_STATE(docShell);
227 PRUint32 loadType;
228 docShell->GetLoadType(&loadType);
229 if (loadType == LOAD_RELOAD_NORMAL ||
230 loadType == LOAD_RELOAD_BYPASS_CACHE ||
231 loadType == LOAD_RELOAD_BYPASS_PROXY ||
232 loadType == LOAD_RELOAD_BYPASS_PROXY_AND_CACHE) {
233 aEventType = nsIAccessibleEvent::EVENT_DOCUMENT_RELOAD;
237 nsCOMPtr<nsIDOMDocument> domDoc;
238 domWindow->GetDocument(getter_AddRefs(domDoc));
239 nsCOMPtr<nsIDOMNode> docNode = do_QueryInterface(domDoc);
240 NS_ENSURE_STATE(docNode);
242 nsCOMPtr<nsIAccessible> accessible;
243 GetAccessibleFor(docNode, getter_AddRefs(accessible));
244 nsCOMPtr<nsPIAccessibleDocument> privDocAccessible = do_QueryInterface(accessible);
245 NS_ENSURE_STATE(privDocAccessible);
246 privDocAccessible->FireDocLoadEvents(aEventType);
248 return NS_OK;
251 NS_IMETHODIMP
252 nsAccessibilityService::FireAccessibleEvent(PRUint32 aEvent,
253 nsIAccessible *aTarget)
255 return nsAccUtils::FireAccEvent(aEvent, aTarget);
258 void nsAccessibilityService::StartLoadCallback(nsITimer *aTimer, void *aClosure)
260 nsIAccessibilityService *accService = nsAccessNode::GetAccService();
261 if (accService)
262 accService->ProcessDocLoadEvent(aTimer, aClosure, nsIAccessibleEvent::EVENT_DOCUMENT_LOAD_START);
265 void nsAccessibilityService::EndLoadCallback(nsITimer *aTimer, void *aClosure)
267 nsIAccessibilityService *accService = nsAccessNode::GetAccService();
268 if (accService)
269 accService->ProcessDocLoadEvent(aTimer, aClosure, nsIAccessibleEvent::EVENT_DOCUMENT_LOAD_COMPLETE);
272 void nsAccessibilityService::FailedLoadCallback(nsITimer *aTimer, void *aClosure)
274 nsIAccessibilityService *accService = nsAccessNode::GetAccService();
275 if (accService)
276 accService->ProcessDocLoadEvent(aTimer, aClosure, nsIAccessibleEvent::EVENT_DOCUMENT_LOAD_STOPPED);
279 /* void onProgressChange (in nsIWebProgress aWebProgress, in nsIRequest aRequest, in long aCurSelfProgress, in long aMaxSelfProgress, in long aCurTotalProgress, in long aMaxTotalProgress); */
280 NS_IMETHODIMP nsAccessibilityService::OnProgressChange(nsIWebProgress *aWebProgress,
281 nsIRequest *aRequest, PRInt32 aCurSelfProgress, PRInt32 aMaxSelfProgress,
282 PRInt32 aCurTotalProgress, PRInt32 aMaxTotalProgress)
284 NS_NOTREACHED("notification excluded in AddProgressListener(...)");
285 return NS_OK;
288 /* void onLocationChange (in nsIWebProgress aWebProgress, in nsIRequest aRequest, in nsIURI location); */
289 NS_IMETHODIMP nsAccessibilityService::OnLocationChange(nsIWebProgress *aWebProgress,
290 nsIRequest *aRequest, nsIURI *location)
292 // If the document is already loaded, this will just check to see
293 // if an anchor jump event needs to be fired.
294 // If there is no accessible for the document, we will ignore
295 // this and the anchor jump event will be fired via OnStateChange
296 // and nsIAccessibleStates::STATE_STOP
297 nsCOMPtr<nsIDOMWindow> domWindow;
298 aWebProgress->GetDOMWindow(getter_AddRefs(domWindow));
299 NS_ASSERTION(domWindow, "DOM Window for state change is null");
300 NS_ENSURE_TRUE(domWindow, NS_ERROR_FAILURE);
302 nsCOMPtr<nsIDOMDocument> domDoc;
303 domWindow->GetDocument(getter_AddRefs(domDoc));
304 nsCOMPtr<nsIDOMNode> domDocRootNode(do_QueryInterface(domDoc));
305 NS_ENSURE_TRUE(domDocRootNode, NS_ERROR_FAILURE);
307 nsCOMPtr<nsIAccessibleDocument> accessibleDoc =
308 nsAccessNode::GetDocAccessibleFor(domDocRootNode);
309 nsCOMPtr<nsPIAccessibleDocument> privateAccessibleDoc =
310 do_QueryInterface(accessibleDoc);
311 if (!privateAccessibleDoc) {
312 return NS_OK;
314 return privateAccessibleDoc->FireAnchorJumpEvent();
317 /* void onStatusChange (in nsIWebProgress aWebProgress, in nsIRequest aRequest, in nsresult aStatus, in wstring aMessage); */
318 NS_IMETHODIMP nsAccessibilityService::OnStatusChange(nsIWebProgress *aWebProgress,
319 nsIRequest *aRequest, nsresult aStatus, const PRUnichar *aMessage)
321 NS_NOTREACHED("notification excluded in AddProgressListener(...)");
322 return NS_OK;
325 /* void onSecurityChange (in nsIWebProgress aWebProgress, in nsIRequest aRequest, in unsigned long state); */
326 NS_IMETHODIMP nsAccessibilityService::OnSecurityChange(nsIWebProgress *aWebProgress,
327 nsIRequest *aRequest, PRUint32 state)
329 NS_NOTREACHED("notification excluded in AddProgressListener(...)");
330 return NS_OK;
334 nsresult
335 nsAccessibilityService::GetInfo(nsISupports* aFrame, nsIFrame** aRealFrame, nsIWeakReference** aShell, nsIDOMNode** aNode)
337 NS_ASSERTION(aFrame,"Error -- 1st argument (aFrame) is null!!");
338 *aRealFrame = static_cast<nsIFrame*>(aFrame);
339 nsCOMPtr<nsIContent> content = (*aRealFrame)->GetContent();
340 nsCOMPtr<nsIDOMNode> node(do_QueryInterface(content));
341 if (!content || !node)
342 return NS_ERROR_FAILURE;
343 *aNode = node;
344 NS_IF_ADDREF(*aNode);
346 nsCOMPtr<nsIDocument> document = content->GetDocument();
347 if (!document)
348 return NS_ERROR_FAILURE;
350 NS_ASSERTION(document->GetPrimaryShell(),"Error no shells!");
352 // do_GetWR only works into a |nsCOMPtr| :-(
353 nsCOMPtr<nsIWeakReference> weakShell =
354 do_GetWeakReference(document->GetPrimaryShell());
355 NS_IF_ADDREF(*aShell = weakShell);
357 return NS_OK;
360 nsresult
361 nsAccessibilityService::GetShellFromNode(nsIDOMNode *aNode, nsIWeakReference **aWeakShell)
363 nsCOMPtr<nsIDOMDocument> domDoc;
364 aNode->GetOwnerDocument(getter_AddRefs(domDoc));
365 nsCOMPtr<nsIDocument> doc(do_QueryInterface(domDoc));
366 if (!doc)
367 return NS_ERROR_INVALID_ARG;
369 // ---- Get the pres shell ----
370 nsIPresShell *shell = doc->GetPrimaryShell();
371 if (!shell)
372 return NS_ERROR_FAILURE;
374 nsCOMPtr<nsIWeakReference> weakRef(do_GetWeakReference(shell));
376 *aWeakShell = weakRef;
377 NS_IF_ADDREF(*aWeakShell);
379 return NS_OK;
383 * nsIAccessibilityService methods:
386 NS_IMETHODIMP
387 nsAccessibilityService::CreateOuterDocAccessible(nsIDOMNode* aDOMNode,
388 nsIAccessible **aOuterDocAccessible)
390 NS_ENSURE_ARG_POINTER(aDOMNode);
392 *aOuterDocAccessible = nsnull;
394 nsCOMPtr<nsIWeakReference> outerWeakShell;
395 GetShellFromNode(aDOMNode, getter_AddRefs(outerWeakShell));
396 NS_ENSURE_TRUE(outerWeakShell, NS_ERROR_FAILURE);
398 nsOuterDocAccessible *outerDocAccessible =
399 new nsOuterDocAccessible(aDOMNode, outerWeakShell);
400 NS_ENSURE_TRUE(outerDocAccessible, NS_ERROR_FAILURE);
402 NS_ADDREF(*aOuterDocAccessible = outerDocAccessible);
404 return NS_OK;
407 NS_IMETHODIMP
408 nsAccessibilityService::CreateRootAccessible(nsIPresShell *aShell,
409 nsIDocument* aDocument,
410 nsIAccessible **aRootAcc)
412 *aRootAcc = nsnull;
414 nsCOMPtr<nsIDOMNode> rootNode(do_QueryInterface(aDocument));
415 NS_ENSURE_TRUE(rootNode, NS_ERROR_FAILURE);
417 nsIPresShell *presShell = aShell;
418 if (!presShell) {
419 presShell = aDocument->GetPrimaryShell();
421 nsCOMPtr<nsIWeakReference> weakShell(do_GetWeakReference(presShell));
423 nsCOMPtr<nsISupports> container = aDocument->GetContainer();
424 nsCOMPtr<nsIDocShell> docShell = do_QueryInterface(container);
425 NS_ENSURE_TRUE(docShell, NS_ERROR_FAILURE);
426 nsCOMPtr<nsIContentViewer> contentViewer;
427 docShell->GetContentViewer(getter_AddRefs(contentViewer));
428 NS_ENSURE_TRUE(contentViewer, NS_ERROR_FAILURE); // Doc was already shut down
429 PRUint32 busyFlags;
430 docShell->GetBusyFlags(&busyFlags);
431 if (busyFlags != nsIDocShell::BUSY_FLAGS_NONE) {
432 nsCOMPtr<nsIWebNavigation> webNav(do_GetInterface(docShell));
433 nsCOMPtr<nsIURI> uri;
434 webNav->GetCurrentURI(getter_AddRefs(uri));
435 NS_ENSURE_STATE(uri);
436 nsCAutoString url;
437 uri->GetSpec(url);
438 if (url.EqualsLiteral("about:blank")) {
439 return NS_OK; // No load events for a busy about:blank -- they are often temporary
443 nsCOMPtr<nsIDocShellTreeItem> docShellTreeItem =
444 do_QueryInterface(container);
445 NS_ENSURE_TRUE(docShellTreeItem, NS_ERROR_FAILURE);
447 nsCOMPtr<nsIDocShellTreeItem> parentTreeItem;
448 docShellTreeItem->GetParent(getter_AddRefs(parentTreeItem));
450 if (parentTreeItem) {
451 // We only create root accessibles for the true root, othewise create a
452 // doc accessible
453 *aRootAcc = new nsDocAccessibleWrap(rootNode, weakShell);
455 else {
456 *aRootAcc = new nsRootAccessibleWrap(rootNode, weakShell);
458 if (!*aRootAcc)
459 return NS_ERROR_OUT_OF_MEMORY;
461 nsRefPtr<nsAccessNode> rootAcc = nsAccUtils::QueryAccessNode(*aRootAcc);
462 rootAcc->Init();
464 nsRoleMapEntry *roleMapEntry = nsAccUtils::GetRoleMapEntry(rootNode);
465 nsCOMPtr<nsPIAccessible> privateAccessible(do_QueryInterface(*aRootAcc));
466 privateAccessible->SetRoleMapEntry(roleMapEntry);
468 NS_ADDREF(*aRootAcc);
470 return NS_OK;
474 * HTML widget creation
476 NS_IMETHODIMP
477 nsAccessibilityService::CreateHTML4ButtonAccessible(nsISupports *aFrame, nsIAccessible **_retval)
479 nsIFrame* frame;
480 nsCOMPtr<nsIDOMNode> node;
481 nsCOMPtr<nsIWeakReference> weakShell;
482 nsresult rv = GetInfo(aFrame, &frame, getter_AddRefs(weakShell), getter_AddRefs(node));
483 if (NS_FAILED(rv))
484 return rv;
486 *_retval = new nsHTML4ButtonAccessible(node, weakShell);
487 if (! *_retval)
488 return NS_ERROR_OUT_OF_MEMORY;
490 NS_ADDREF(*_retval);
491 return NS_OK;
494 NS_IMETHODIMP
495 nsAccessibilityService::CreateHTMLButtonAccessible(nsISupports *aFrame, nsIAccessible **_retval)
497 nsIFrame* frame;
498 nsCOMPtr<nsIDOMNode> node;
499 nsCOMPtr<nsIWeakReference> weakShell;
500 nsresult rv = GetInfo(aFrame, &frame, getter_AddRefs(weakShell), getter_AddRefs(node));
501 if (NS_FAILED(rv))
502 return rv;
504 *_retval = new nsHTMLButtonAccessible(node, weakShell);
505 if (! *_retval)
506 return NS_ERROR_OUT_OF_MEMORY;
508 NS_ADDREF(*_retval);
509 return NS_OK;
512 nsresult
513 nsAccessibilityService::CreateHTMLAccessibleByMarkup(nsIFrame *aFrame,
514 nsIWeakReference *aWeakShell,
515 nsIDOMNode *aNode,
516 nsIAccessible **aAccessible)
518 // This method assumes we're in an HTML namespace.
519 *aAccessible = nsnull;
520 nsCOMPtr<nsIContent> content(do_QueryInterface(aNode));
521 nsIAtom *tag = content->Tag();
522 if (tag == nsAccessibilityAtoms::legend) {
523 *aAccessible = new nsHTMLLegendAccessible(aNode, aWeakShell);
525 else if (tag == nsAccessibilityAtoms::option) {
526 *aAccessible = new nsHTMLSelectOptionAccessible(aNode, aWeakShell);
528 else if (tag == nsAccessibilityAtoms::optgroup) {
529 *aAccessible = new nsHTMLSelectOptGroupAccessible(aNode, aWeakShell);
531 else if (tag == nsAccessibilityAtoms::ul || tag == nsAccessibilityAtoms::ol) {
532 *aAccessible = new nsHTMLListAccessible(aNode, aWeakShell);
534 else if (tag == nsAccessibilityAtoms::a) {
535 *aAccessible = new nsHTMLLinkAccessible(aNode, aWeakShell);
537 else if (tag == nsAccessibilityAtoms::li && aFrame->GetType() != nsAccessibilityAtoms::blockFrame) {
538 // Normally this is created by the list item frame which knows about the bullet frame
539 // However, in this case the list item must have been styled using display: foo
540 *aAccessible = new nsHTMLLIAccessible(aNode, aWeakShell, EmptyString());
542 else if (tag == nsAccessibilityAtoms::abbr ||
543 tag == nsAccessibilityAtoms::acronym ||
544 tag == nsAccessibilityAtoms::blockquote ||
545 tag == nsAccessibilityAtoms::dd ||
546 tag == nsAccessibilityAtoms::dl ||
547 tag == nsAccessibilityAtoms::dt ||
548 tag == nsAccessibilityAtoms::form ||
549 tag == nsAccessibilityAtoms::h1 ||
550 tag == nsAccessibilityAtoms::h2 ||
551 tag == nsAccessibilityAtoms::h3 ||
552 tag == nsAccessibilityAtoms::h4 ||
553 tag == nsAccessibilityAtoms::h5 ||
554 tag == nsAccessibilityAtoms::h6 ||
555 #ifndef MOZ_ACCESSIBILITY_ATK
556 tag == nsAccessibilityAtoms::tbody ||
557 tag == nsAccessibilityAtoms::tfoot ||
558 tag == nsAccessibilityAtoms::thead ||
559 #endif
560 tag == nsAccessibilityAtoms::q) {
561 return CreateHyperTextAccessible(aFrame, aAccessible);
563 NS_IF_ADDREF(*aAccessible);
564 return NS_OK;
567 NS_IMETHODIMP
568 nsAccessibilityService::CreateHTMLLIAccessible(nsISupports *aFrame,
569 nsISupports *aBulletFrame,
570 const nsAString& aBulletText,
571 nsIAccessible **_retval)
573 nsIFrame* frame;
574 nsCOMPtr<nsIDOMNode> node;
575 nsCOMPtr<nsIWeakReference> weakShell;
576 nsresult rv = GetInfo(aFrame, &frame, getter_AddRefs(weakShell), getter_AddRefs(node));
577 if (NS_FAILED(rv))
578 return rv;
580 *_retval = new nsHTMLLIAccessible(node, weakShell, aBulletText);
581 if (! *_retval)
582 return NS_ERROR_OUT_OF_MEMORY;
584 NS_ADDREF(*_retval);
585 return NS_OK;
588 NS_IMETHODIMP
589 nsAccessibilityService::CreateHyperTextAccessible(nsISupports *aFrame, nsIAccessible **aAccessible)
591 nsIFrame* frame;
592 nsCOMPtr<nsIDOMNode> node;
593 nsCOMPtr<nsIWeakReference> weakShell;
594 nsresult rv = GetInfo(aFrame, &frame, getter_AddRefs(weakShell), getter_AddRefs(node));
595 if (NS_FAILED(rv))
596 return rv;
598 nsCOMPtr<nsIContent> content(do_QueryInterface(node));
599 NS_ENSURE_TRUE(content, NS_ERROR_FAILURE);
601 *aAccessible = new nsHyperTextAccessibleWrap(node, weakShell);
602 NS_ENSURE_TRUE(*aAccessible, NS_ERROR_OUT_OF_MEMORY);
604 NS_ADDREF(*aAccessible);
605 return NS_OK;
608 NS_IMETHODIMP
609 nsAccessibilityService::CreateHTMLCheckboxAccessible(nsISupports *aFrame, nsIAccessible **_retval)
611 nsIFrame* frame;
612 nsCOMPtr<nsIDOMNode> node;
613 nsCOMPtr<nsIWeakReference> weakShell;
614 nsresult rv = GetInfo(aFrame, &frame, getter_AddRefs(weakShell), getter_AddRefs(node));
615 if (NS_FAILED(rv))
616 return rv;
618 *_retval = new nsHTMLCheckboxAccessible(node, weakShell);
619 if (! *_retval)
620 return NS_ERROR_OUT_OF_MEMORY;
622 NS_ADDREF(*_retval);
623 return NS_OK;
626 NS_IMETHODIMP
627 nsAccessibilityService::CreateHTMLComboboxAccessible(nsIDOMNode* aDOMNode, nsIWeakReference* aPresShell, nsIAccessible **_retval)
629 *_retval = new nsHTMLComboboxAccessible(aDOMNode, aPresShell);
630 if (! *_retval)
631 return NS_ERROR_OUT_OF_MEMORY;
633 NS_ADDREF(*_retval);
634 return NS_OK;
637 NS_IMETHODIMP
638 nsAccessibilityService::CreateHTMLImageAccessible(nsISupports *aFrame, nsIAccessible **_retval)
640 nsIFrame* frame;
641 nsCOMPtr<nsIDOMNode> node;
642 nsCOMPtr<nsIWeakReference> weakShell;
643 nsresult rv = GetInfo(aFrame, &frame, getter_AddRefs(weakShell), getter_AddRefs(node));
644 if (NS_FAILED(rv))
645 return rv;
647 *_retval = nsnull;
648 nsCOMPtr<nsIDOMElement> domElement(do_QueryInterface(node));
649 if (domElement) {
650 *_retval = new nsHTMLImageAccessibleWrap(node, weakShell);
653 if (! *_retval)
654 return NS_ERROR_OUT_OF_MEMORY;
656 NS_ADDREF(*_retval);
657 return NS_OK;
660 NS_IMETHODIMP
661 nsAccessibilityService::CreateHTMLGenericAccessible(nsISupports *aFrame, nsIAccessible **aAccessible)
663 return CreateHyperTextAccessible(aFrame, aAccessible);
666 NS_IMETHODIMP
667 nsAccessibilityService::CreateHTMLGroupboxAccessible(nsISupports *aFrame, nsIAccessible **_retval)
669 nsIFrame* frame;
670 nsCOMPtr<nsIDOMNode> node;
671 nsCOMPtr<nsIWeakReference> weakShell;
672 nsresult rv = GetInfo(aFrame, &frame, getter_AddRefs(weakShell), getter_AddRefs(node));
673 if (NS_FAILED(rv))
674 return rv;
676 *_retval = new nsHTMLGroupboxAccessible(node, weakShell);
677 if (! *_retval)
678 return NS_ERROR_OUT_OF_MEMORY;
680 NS_ADDREF(*_retval);
681 return NS_OK;
684 NS_IMETHODIMP
685 nsAccessibilityService::CreateHTMLListboxAccessible(nsIDOMNode* aDOMNode, nsIWeakReference* aPresShell, nsIAccessible **_retval)
687 *_retval = new nsHTMLSelectListAccessible(aDOMNode, aPresShell);
688 if (! *_retval)
689 return NS_ERROR_OUT_OF_MEMORY;
691 NS_ADDREF(*_retval);
692 return NS_OK;
696 * We can have several cases here.
697 * 1) a text or html embedded document where the contentDocument
698 * variable in the object element holds the content
699 * 2) web content that uses a plugin, which means we will
700 * have to go to the plugin to get the accessible content
701 * 3) An image or imagemap, where the image frame points back to
702 * the object element DOMNode
704 NS_IMETHODIMP
705 nsAccessibilityService::CreateHTMLObjectFrameAccessible(nsObjectFrame *aFrame,
706 nsIAccessible **aAccessible)
708 nsCOMPtr<nsIDOMNode> node;
709 nsCOMPtr<nsIWeakReference> weakShell;
710 nsIFrame *frame;
711 GetInfo(static_cast<nsIFrame*>(aFrame), &frame, getter_AddRefs(weakShell), getter_AddRefs(node));
713 *aAccessible = nsnull;
714 if (!frame || frame->GetRect().IsEmpty()) {
715 return NS_ERROR_FAILURE;
717 // 1) for object elements containing either HTML or TXT documents
718 nsCOMPtr<nsIDOMDocument> domDoc;
719 nsCOMPtr<nsIDOMHTMLObjectElement> obj(do_QueryInterface(node));
720 if (obj)
721 obj->GetContentDocument(getter_AddRefs(domDoc));
722 else
723 domDoc = do_QueryInterface(node);
724 if (domDoc)
725 return CreateOuterDocAccessible(node, aAccessible);
727 #ifdef XP_WIN
728 // 2) for plugins
729 nsCOMPtr<nsIPluginInstance> pluginInstance ;
730 aFrame->GetPluginInstance(*getter_AddRefs(pluginInstance));
731 if (pluginInstance) {
732 HWND pluginPort = nsnull;
733 aFrame->GetPluginPort(&pluginPort);
734 if (pluginPort) {
735 *aAccessible = new nsHTMLWin32ObjectOwnerAccessible(node, weakShell, pluginPort);
736 if (*aAccessible) {
737 NS_ADDREF(*aAccessible);
738 return NS_OK;
742 #endif
744 // 3) for images and imagemaps, or anything else with a child frame
745 // we have the object frame, get the image frame
746 frame = aFrame->GetFirstChild(nsnull);
747 if (frame)
748 return frame->GetAccessible(aAccessible);
750 return NS_OK;
753 NS_IMETHODIMP
754 nsAccessibilityService::CreateHTMLRadioButtonAccessible(nsISupports *aFrame, nsIAccessible **_retval)
756 nsIFrame* frame;
757 nsCOMPtr<nsIDOMNode> node;
758 nsCOMPtr<nsIWeakReference> weakShell;
759 nsresult rv = GetInfo(aFrame, &frame, getter_AddRefs(weakShell), getter_AddRefs(node));
760 if (NS_FAILED(rv))
761 return rv;
763 *_retval = new nsHTMLRadioButtonAccessible(node, weakShell);
764 if (! *_retval)
765 return NS_ERROR_OUT_OF_MEMORY;
767 NS_ADDREF(*_retval);
768 return NS_OK;
771 NS_IMETHODIMP
772 nsAccessibilityService::CreateHTMLSelectOptionAccessible(nsIDOMNode* aDOMNode,
773 nsIAccessible *aParent,
774 nsIWeakReference* aPresShell,
775 nsIAccessible **_retval)
777 *_retval = new nsHTMLSelectOptionAccessible(aDOMNode, aPresShell);
778 if (! *_retval)
779 return NS_ERROR_OUT_OF_MEMORY;
781 NS_ADDREF(*_retval);
782 return NS_OK;
785 NS_IMETHODIMP
786 nsAccessibilityService::CreateHTMLTableAccessible(nsISupports *aFrame, nsIAccessible **_retval)
788 nsIFrame* frame;
789 nsCOMPtr<nsIDOMNode> node;
790 nsCOMPtr<nsIWeakReference> weakShell;
791 nsresult rv = GetInfo(aFrame, &frame, getter_AddRefs(weakShell), getter_AddRefs(node));
792 if (NS_FAILED(rv))
793 return rv;
795 *_retval = new nsHTMLTableAccessibleWrap(node, weakShell);
796 if (! *_retval)
797 return NS_ERROR_OUT_OF_MEMORY;
799 NS_ADDREF(*_retval);
800 return NS_OK;
803 NS_IMETHODIMP
804 nsAccessibilityService::CreateHTMLTableHeadAccessible(nsIDOMNode *aDOMNode, nsIAccessible **_retval)
806 #ifndef MOZ_ACCESSIBILITY_ATK
807 *_retval = nsnull;
808 return NS_ERROR_FAILURE;
809 #else
810 NS_ENSURE_ARG_POINTER(aDOMNode);
812 nsresult rv = NS_OK;
814 nsCOMPtr<nsIWeakReference> weakShell;
815 rv = GetShellFromNode(aDOMNode, getter_AddRefs(weakShell));
816 NS_ENSURE_SUCCESS(rv, rv);
818 nsHTMLTableHeadAccessibleWrap* accTableHead =
819 new nsHTMLTableHeadAccessibleWrap(aDOMNode, weakShell);
821 NS_ENSURE_TRUE(accTableHead, NS_ERROR_OUT_OF_MEMORY);
823 *_retval = static_cast<nsIAccessible *>(accTableHead);
824 NS_IF_ADDREF(*_retval);
826 return rv;
827 #endif
830 NS_IMETHODIMP
831 nsAccessibilityService::CreateHTMLTableCellAccessible(nsISupports *aFrame, nsIAccessible **_retval)
833 nsIFrame* frame;
834 nsCOMPtr<nsIDOMNode> node;
835 nsCOMPtr<nsIWeakReference> weakShell;
836 nsresult rv = GetInfo(aFrame, &frame, getter_AddRefs(weakShell), getter_AddRefs(node));
837 if (NS_FAILED(rv))
838 return rv;
840 *_retval = new nsHTMLTableCellAccessible(node, weakShell);
841 if (! *_retval)
842 return NS_ERROR_OUT_OF_MEMORY;
844 NS_ADDREF(*_retval);
845 return NS_OK;
848 NS_IMETHODIMP
849 nsAccessibilityService::CreateHTMLTextAccessible(nsISupports *aFrame, nsIAccessible **_retval)
851 *_retval = nsnull;
853 nsIFrame* frame;
854 nsCOMPtr<nsIDOMNode> node;
855 nsCOMPtr<nsIWeakReference> weakShell;
856 nsresult rv = GetInfo(aFrame, &frame, getter_AddRefs(weakShell), getter_AddRefs(node));
857 if (NS_FAILED(rv))
858 return rv;
860 // XXX Don't create ATK objects for these
861 *_retval = new nsHTMLTextAccessible(node, weakShell);
862 if (! *_retval)
863 return NS_ERROR_OUT_OF_MEMORY;
865 NS_ADDREF(*_retval);
866 return NS_OK;
869 NS_IMETHODIMP
870 nsAccessibilityService::CreateHTMLTextFieldAccessible(nsISupports *aFrame, nsIAccessible **_retval)
872 nsIFrame* frame;
873 nsCOMPtr<nsIDOMNode> node;
874 nsCOMPtr<nsIWeakReference> weakShell;
875 nsresult rv = GetInfo(aFrame, &frame, getter_AddRefs(weakShell), getter_AddRefs(node));
876 if (NS_FAILED(rv))
877 return rv;
879 *_retval = new nsHTMLTextFieldAccessible(node, weakShell);
880 if (! *_retval)
881 return NS_ERROR_OUT_OF_MEMORY;
883 NS_ADDREF(*_retval);
884 return NS_OK;
887 NS_IMETHODIMP
888 nsAccessibilityService::CreateHTMLLabelAccessible(nsISupports *aFrame, nsIAccessible **_retval)
890 nsIFrame* frame;
891 nsCOMPtr<nsIDOMNode> node;
892 nsCOMPtr<nsIWeakReference> weakShell;
893 nsresult rv = GetInfo(aFrame, &frame, getter_AddRefs(weakShell), getter_AddRefs(node));
894 if (NS_FAILED(rv))
895 return rv;
897 *_retval = new nsHTMLLabelAccessible(node, weakShell);
898 if (! *_retval)
899 return NS_ERROR_OUT_OF_MEMORY;
901 NS_ADDREF(*_retval);
902 return NS_OK;
905 NS_IMETHODIMP
906 nsAccessibilityService::CreateHTMLHRAccessible(nsISupports *aFrame, nsIAccessible **_retval)
908 nsIFrame* frame;
909 nsCOMPtr<nsIDOMNode> node;
910 nsCOMPtr<nsIWeakReference> weakShell;
911 nsresult rv = GetInfo(aFrame, &frame, getter_AddRefs(weakShell), getter_AddRefs(node));
912 if (NS_FAILED(rv))
913 return rv;
915 *_retval = new nsHTMLHRAccessible(node, weakShell);
916 if (! *_retval)
917 return NS_ERROR_OUT_OF_MEMORY;
919 NS_ADDREF(*_retval);
920 return NS_OK;
923 NS_IMETHODIMP
924 nsAccessibilityService::CreateHTMLBRAccessible(nsISupports *aFrame, nsIAccessible **_retval)
926 nsIFrame* frame;
927 nsCOMPtr<nsIDOMNode> node;
928 nsCOMPtr<nsIWeakReference> weakShell;
929 nsresult rv = GetInfo(aFrame, &frame, getter_AddRefs(weakShell), getter_AddRefs(node));
930 if (NS_FAILED(rv))
931 return rv;
933 *_retval = new nsHTMLBRAccessible(node, weakShell);
934 if (! *_retval)
935 return NS_ERROR_OUT_OF_MEMORY;
937 NS_ADDREF(*_retval);
938 return NS_OK;
941 NS_IMETHODIMP
942 nsAccessibilityService::CreateHTMLCaptionAccessible(nsISupports *aFrame, nsIAccessible **_retval)
944 nsIFrame* frame;
945 nsCOMPtr<nsIDOMNode> node;
946 nsCOMPtr<nsIWeakReference> weakShell;
947 nsresult rv = GetInfo(aFrame, &frame, getter_AddRefs(weakShell), getter_AddRefs(node));
948 if (NS_FAILED(rv))
949 return rv;
951 *_retval = new nsHTMLCaptionAccessible(node, weakShell);
952 if (! *_retval)
953 return NS_ERROR_OUT_OF_MEMORY;
955 NS_ADDREF(*_retval);
956 return NS_OK;
959 NS_IMETHODIMP nsAccessibilityService::GetCachedAccessible(nsIDOMNode *aNode,
960 nsIWeakReference *aWeakShell,
961 nsIAccessible **aAccessible)
963 nsCOMPtr<nsIAccessNode> accessNode;
964 nsresult rv = GetCachedAccessNode(aNode, aWeakShell, getter_AddRefs(accessNode));
965 nsCOMPtr<nsIAccessible> accessible(do_QueryInterface(accessNode));
966 NS_IF_ADDREF(*aAccessible = accessible);
967 return rv;
970 NS_IMETHODIMP nsAccessibilityService::GetCachedAccessNode(nsIDOMNode *aNode,
971 nsIWeakReference *aWeakShell,
972 nsIAccessNode **aAccessNode)
974 nsCOMPtr<nsIAccessibleDocument> accessibleDoc =
975 nsAccessNode::GetDocAccessibleFor(aWeakShell);
977 if (!accessibleDoc) {
978 *aAccessNode = nsnull;
979 return NS_ERROR_FAILURE;
982 return accessibleDoc->GetCachedAccessNode(static_cast<void*>(aNode), aAccessNode);
985 NS_IMETHODIMP
986 nsAccessibilityService::GetStringRole(PRUint32 aRole, nsAString& aString)
988 if ( aRole >= NS_ARRAY_LENGTH(kRoleNames)) {
989 aString.AssignLiteral("unknown");
990 return NS_OK;
993 CopyUTF8toUTF16(kRoleNames[aRole], aString);
994 return NS_OK;
997 NS_IMETHODIMP
998 nsAccessibilityService::GetStringStates(PRUint32 aStates, PRUint32 aExtraStates,
999 nsIDOMDOMStringList **aStringStates)
1001 nsAccessibleDOMStringList *stringStates = new nsAccessibleDOMStringList();
1002 NS_ENSURE_TRUE(stringStates, NS_ERROR_OUT_OF_MEMORY);
1004 //states
1005 if (aStates & nsIAccessibleStates::STATE_UNAVAILABLE)
1006 stringStates->Add(NS_LITERAL_STRING("unavailable"));
1007 if (aStates & nsIAccessibleStates::STATE_SELECTED)
1008 stringStates->Add(NS_LITERAL_STRING("selected"));
1009 if (aStates & nsIAccessibleStates::STATE_FOCUSED)
1010 stringStates->Add(NS_LITERAL_STRING("focused"));
1011 if (aStates & nsIAccessibleStates::STATE_PRESSED)
1012 stringStates->Add(NS_LITERAL_STRING("pressed"));
1013 if (aStates & nsIAccessibleStates::STATE_CHECKED)
1014 stringStates->Add(NS_LITERAL_STRING("checked"));
1015 if (aStates & nsIAccessibleStates::STATE_MIXED)
1016 stringStates->Add(NS_LITERAL_STRING("mixed"));
1017 if (aStates & nsIAccessibleStates::STATE_READONLY)
1018 stringStates->Add(NS_LITERAL_STRING("readonly"));
1019 if (aStates & nsIAccessibleStates::STATE_HOTTRACKED)
1020 stringStates->Add(NS_LITERAL_STRING("hottracked"));
1021 if (aStates & nsIAccessibleStates::STATE_DEFAULT)
1022 stringStates->Add(NS_LITERAL_STRING("default"));
1023 if (aStates & nsIAccessibleStates::STATE_EXPANDED)
1024 stringStates->Add(NS_LITERAL_STRING("expanded"));
1025 if (aStates & nsIAccessibleStates::STATE_COLLAPSED)
1026 stringStates->Add(NS_LITERAL_STRING("collapsed"));
1027 if (aStates & nsIAccessibleStates::STATE_BUSY)
1028 stringStates->Add(NS_LITERAL_STRING("busy"));
1029 if (aStates & nsIAccessibleStates::STATE_FLOATING)
1030 stringStates->Add(NS_LITERAL_STRING("floating"));
1031 if (aStates & nsIAccessibleStates::STATE_ANIMATED)
1032 stringStates->Add(NS_LITERAL_STRING("animated"));
1033 if (aStates & nsIAccessibleStates::STATE_INVISIBLE)
1034 stringStates->Add(NS_LITERAL_STRING("invisible"));
1035 if (aStates & nsIAccessibleStates::STATE_OFFSCREEN)
1036 stringStates->Add(NS_LITERAL_STRING("offscreen"));
1037 if (aStates & nsIAccessibleStates::STATE_SIZEABLE)
1038 stringStates->Add(NS_LITERAL_STRING("sizeable"));
1039 if (aStates & nsIAccessibleStates::STATE_MOVEABLE)
1040 stringStates->Add(NS_LITERAL_STRING("moveable"));
1041 if (aStates & nsIAccessibleStates::STATE_SELFVOICING)
1042 stringStates->Add(NS_LITERAL_STRING("selfvoicing"));
1043 if (aStates & nsIAccessibleStates::STATE_FOCUSABLE)
1044 stringStates->Add(NS_LITERAL_STRING("focusable"));
1045 if (aStates & nsIAccessibleStates::STATE_SELECTABLE)
1046 stringStates->Add(NS_LITERAL_STRING("selectable"));
1047 if (aStates & nsIAccessibleStates::STATE_LINKED)
1048 stringStates->Add(NS_LITERAL_STRING("linked"));
1049 if (aStates & nsIAccessibleStates::STATE_TRAVERSED)
1050 stringStates->Add(NS_LITERAL_STRING("traversed"));
1051 if (aStates & nsIAccessibleStates::STATE_MULTISELECTABLE)
1052 stringStates->Add(NS_LITERAL_STRING("multiselectable"));
1053 if (aStates & nsIAccessibleStates::STATE_EXTSELECTABLE)
1054 stringStates->Add(NS_LITERAL_STRING("extselectable"));
1055 if (aStates & nsIAccessibleStates::STATE_PROTECTED)
1056 stringStates->Add(NS_LITERAL_STRING("protected"));
1057 if (aStates & nsIAccessibleStates::STATE_HASPOPUP)
1058 stringStates->Add(NS_LITERAL_STRING("haspopup"));
1059 if (aStates & nsIAccessibleStates::STATE_REQUIRED)
1060 stringStates->Add(NS_LITERAL_STRING("required"));
1061 if (aStates & nsIAccessibleStates::STATE_IMPORTANT)
1062 stringStates->Add(NS_LITERAL_STRING("important"));
1063 if (aStates & nsIAccessibleStates::STATE_INVALID)
1064 stringStates->Add(NS_LITERAL_STRING("invalid"));
1065 if (aStates & nsIAccessibleStates::STATE_CHECKABLE)
1066 stringStates->Add(NS_LITERAL_STRING("checkable"));
1068 //extraStates
1069 if (aExtraStates & nsIAccessibleStates::EXT_STATE_SUPPORTS_AUTOCOMPLETION)
1070 stringStates->Add(NS_LITERAL_STRING("autocompletion"));
1071 if (aExtraStates & nsIAccessibleStates::EXT_STATE_DEFUNCT)
1072 stringStates->Add(NS_LITERAL_STRING("defunct"));
1073 if (aExtraStates & nsIAccessibleStates::EXT_STATE_SELECTABLE_TEXT)
1074 stringStates->Add(NS_LITERAL_STRING("selectable text"));
1075 if (aExtraStates & nsIAccessibleStates::EXT_STATE_EDITABLE)
1076 stringStates->Add(NS_LITERAL_STRING("editable"));
1077 if (aExtraStates & nsIAccessibleStates::EXT_STATE_ACTIVE)
1078 stringStates->Add(NS_LITERAL_STRING("active"));
1079 if (aExtraStates & nsIAccessibleStates::EXT_STATE_MODAL)
1080 stringStates->Add(NS_LITERAL_STRING("modal"));
1081 if (aExtraStates & nsIAccessibleStates::EXT_STATE_MULTI_LINE)
1082 stringStates->Add(NS_LITERAL_STRING("multi line"));
1083 if (aExtraStates & nsIAccessibleStates::EXT_STATE_HORIZONTAL)
1084 stringStates->Add(NS_LITERAL_STRING("horizontal"));
1085 if (aExtraStates & nsIAccessibleStates::EXT_STATE_OPAQUE)
1086 stringStates->Add(NS_LITERAL_STRING("opaque"));
1087 if (aExtraStates & nsIAccessibleStates::EXT_STATE_SINGLE_LINE)
1088 stringStates->Add(NS_LITERAL_STRING("single line"));
1089 if (aExtraStates & nsIAccessibleStates::EXT_STATE_TRANSIENT)
1090 stringStates->Add(NS_LITERAL_STRING("transient"));
1091 if (aExtraStates & nsIAccessibleStates::EXT_STATE_VERTICAL)
1092 stringStates->Add(NS_LITERAL_STRING("vertical"));
1093 if (aExtraStates & nsIAccessibleStates::EXT_STATE_STALE)
1094 stringStates->Add(NS_LITERAL_STRING("stale"));
1095 if (aExtraStates & nsIAccessibleStates::EXT_STATE_ENABLED)
1096 stringStates->Add(NS_LITERAL_STRING("enabled"));
1097 if (aExtraStates & nsIAccessibleStates::EXT_STATE_SENSITIVE)
1098 stringStates->Add(NS_LITERAL_STRING("sensitive"));
1099 if (aExtraStates & nsIAccessibleStates::EXT_STATE_EXPANDABLE)
1100 stringStates->Add(NS_LITERAL_STRING("expandable"));
1102 //unknown states
1103 PRUint32 stringStatesLength = 0;
1105 stringStates->GetLength(&stringStatesLength);
1106 if (!stringStatesLength)
1107 stringStates->Add(NS_LITERAL_STRING("unknown"));
1109 NS_ADDREF(*aStringStates = stringStates);
1110 return NS_OK;
1113 // nsIAccessibleRetrieval::getStringEventType()
1114 NS_IMETHODIMP
1115 nsAccessibilityService::GetStringEventType(PRUint32 aEventType,
1116 nsAString& aString)
1118 NS_ASSERTION(nsIAccessibleEvent::EVENT_LAST_ENTRY == NS_ARRAY_LENGTH(kEventTypeNames),
1119 "nsIAccessibleEvent constants are out of sync to kEventTypeNames");
1121 if (aEventType >= NS_ARRAY_LENGTH(kEventTypeNames)) {
1122 aString.AssignLiteral("unknown");
1123 return NS_OK;
1126 CopyUTF8toUTF16(kEventTypeNames[aEventType], aString);
1127 return NS_OK;
1130 // nsIAccessibleRetrieval::getStringRelationType()
1131 NS_IMETHODIMP
1132 nsAccessibilityService::GetStringRelationType(PRUint32 aRelationType,
1133 nsAString& aString)
1135 if (aRelationType >= NS_ARRAY_LENGTH(kRelationTypeNames)) {
1136 aString.AssignLiteral("unknown");
1137 return NS_OK;
1140 CopyUTF8toUTF16(kRelationTypeNames[aRelationType], aString);
1141 return NS_OK;
1146 * GetAccessibleFor - get an nsIAccessible from a DOM node
1149 NS_IMETHODIMP
1150 nsAccessibilityService::GetAccessibleFor(nsIDOMNode *aNode,
1151 nsIAccessible **aAccessible)
1153 NS_ENSURE_ARG_POINTER(aAccessible);
1154 *aAccessible = nsnull;
1156 NS_ENSURE_ARG(aNode);
1158 // We use presentation shell #0 because we assume that is presentation of
1159 // given node window.
1160 nsCOMPtr<nsIContent> content(do_QueryInterface(aNode));
1161 nsCOMPtr<nsIDocument> doc;
1162 if (content) {
1163 doc = content->GetDocument();
1165 else {// Could be document node
1166 doc = do_QueryInterface(aNode);
1168 if (!doc)
1169 return NS_ERROR_FAILURE;
1171 nsIPresShell *presShell = doc->GetPrimaryShell();
1172 return GetAccessibleInShell(aNode, presShell, aAccessible);
1175 NS_IMETHODIMP
1176 nsAccessibilityService::GetAttachedAccessibleFor(nsIDOMNode *aNode,
1177 nsIAccessible **aAccessible)
1179 NS_ENSURE_ARG(aNode);
1180 NS_ENSURE_ARG_POINTER(aAccessible);
1182 *aAccessible = nsnull;
1184 nsCOMPtr<nsIDOMNode> relevantNode;
1185 nsresult rv = GetRelevantContentNodeFor(aNode, getter_AddRefs(relevantNode));
1186 NS_ENSURE_SUCCESS(rv, rv);
1188 if (relevantNode != aNode)
1189 return NS_OK;
1191 return GetAccessibleFor(aNode, aAccessible);
1194 NS_IMETHODIMP nsAccessibilityService::GetAccessibleInWindow(nsIDOMNode *aNode,
1195 nsIDOMWindow *aWin,
1196 nsIAccessible **aAccessible)
1198 NS_ENSURE_ARG_POINTER(aAccessible);
1199 *aAccessible = nsnull;
1201 NS_ENSURE_ARG(aNode);
1202 NS_ENSURE_ARG(aWin);
1204 nsCOMPtr<nsIWebNavigation> webNav(do_GetInterface(aWin));
1205 nsCOMPtr<nsIDocShell> docShell(do_QueryInterface(webNav));
1206 if (!docShell)
1207 return NS_ERROR_FAILURE;
1209 nsCOMPtr<nsIPresShell> presShell;
1210 docShell->GetPresShell(getter_AddRefs(presShell));
1211 return GetAccessibleInShell(aNode, presShell, aAccessible);
1214 NS_IMETHODIMP nsAccessibilityService::GetAccessibleInShell(nsIDOMNode *aNode,
1215 nsIPresShell *aPresShell,
1216 nsIAccessible **aAccessible)
1218 NS_ENSURE_ARG_POINTER(aAccessible);
1219 *aAccessible = nsnull;
1221 NS_ENSURE_ARG(aNode);
1222 NS_ENSURE_ARG(aPresShell);
1224 nsCOMPtr<nsIWeakReference> weakShell(do_GetWeakReference(aPresShell));
1225 nsIFrame *outFrameUnused = NULL;
1226 PRBool isHiddenUnused = false;
1227 return GetAccessible(aNode, aPresShell, weakShell,
1228 &outFrameUnused, &isHiddenUnused, aAccessible);
1231 NS_IMETHODIMP nsAccessibilityService::GetAccessibleInWeakShell(nsIDOMNode *aNode,
1232 nsIWeakReference *aWeakShell,
1233 nsIAccessible **aAccessible)
1235 NS_ENSURE_ARG_POINTER(aAccessible);
1236 *aAccessible = nsnull;
1238 NS_ENSURE_ARG(aNode);
1239 NS_ENSURE_ARG(aWeakShell);
1241 nsCOMPtr<nsIPresShell> presShell(do_QueryReferent(aWeakShell));
1242 nsIFrame *outFrameUnused = NULL;
1243 PRBool isHiddenUnused = false;
1244 return GetAccessible(aNode, presShell, aWeakShell,
1245 &outFrameUnused, &isHiddenUnused, aAccessible);
1248 nsresult nsAccessibilityService::InitAccessible(nsIAccessible *aAccessibleIn,
1249 nsIAccessible **aAccessibleOut,
1250 nsRoleMapEntry *aRoleMapEntry)
1252 if (!aAccessibleIn) {
1253 return NS_ERROR_FAILURE; // No accessible to init
1255 NS_ASSERTION(aAccessibleOut && !*aAccessibleOut, "Out param should already be cleared out");
1257 nsRefPtr<nsAccessNode> acc = nsAccUtils::QueryAccessNode(aAccessibleIn);
1258 nsresult rv = acc->Init(); // Add to cache, etc.
1259 NS_ENSURE_SUCCESS(rv, rv);
1261 nsCOMPtr<nsPIAccessible> privateAccessible =
1262 do_QueryInterface(aAccessibleIn);
1263 privateAccessible->SetRoleMapEntry(aRoleMapEntry);
1264 NS_ADDREF(*aAccessibleOut = aAccessibleIn);
1266 return NS_OK;
1269 static PRBool HasRelatedContent(nsIContent *aContent)
1271 nsAutoString id;
1272 if (!aContent || !nsCoreUtils::GetID(aContent, id) || id.IsEmpty()) {
1273 return PR_FALSE;
1276 nsIAtom *relationAttrs[] = {nsAccessibilityAtoms::aria_labelledby,
1277 nsAccessibilityAtoms::aria_describedby,
1278 nsAccessibilityAtoms::aria_owns,
1279 nsAccessibilityAtoms::aria_controls,
1280 nsAccessibilityAtoms::aria_flowto};
1281 if (nsCoreUtils::FindNeighbourPointingToNode(aContent, relationAttrs,
1282 NS_ARRAY_LENGTH(relationAttrs))) {
1283 return PR_TRUE;
1286 nsIContent *ancestorContent = aContent;
1287 while ((ancestorContent = ancestorContent->GetParent()) != nsnull) {
1288 if (ancestorContent->HasAttr(kNameSpaceID_None, nsAccessibilityAtoms::aria_activedescendant)) {
1289 // ancestor has activedescendant property, this content could be active
1290 return PR_TRUE;
1294 return PR_FALSE;
1297 NS_IMETHODIMP nsAccessibilityService::GetAccessible(nsIDOMNode *aNode,
1298 nsIPresShell *aPresShell,
1299 nsIWeakReference *aWeakShell,
1300 nsIFrame **aFrameHint,
1301 PRBool *aIsHidden,
1302 nsIAccessible **aAccessible)
1304 NS_ENSURE_ARG_POINTER(aAccessible);
1305 NS_ENSURE_ARG_POINTER(aFrameHint);
1306 *aAccessible = nsnull;
1307 if (!aPresShell || !aWeakShell) {
1308 return NS_ERROR_FAILURE;
1311 NS_ASSERTION(aNode, "GetAccessible() called with no node.");
1313 *aIsHidden = PR_FALSE;
1315 #ifdef DEBUG_A11Y
1316 // Please leave this in for now, it's a convenient debugging method
1317 nsAutoString name;
1318 aNode->GetLocalName(name);
1319 if (name.LowerCaseEqualsLiteral("h1"))
1320 printf("## aaronl debugging tag name\n");
1322 nsAutoString attrib;
1323 nsCOMPtr<nsIDOMElement> element(do_QueryInterface(aNode));
1324 if (element) {
1325 element->GetAttribute(NS_LITERAL_STRING("type"), attrib);
1326 if (attrib.EqualsLiteral("statusbarpanel"))
1327 printf("## aaronl debugging attribute\n");
1329 #endif
1331 // Check to see if we already have an accessible for this
1332 // node in the cache
1333 nsCOMPtr<nsIAccessNode> accessNode;
1334 GetCachedAccessNode(aNode, aWeakShell, getter_AddRefs(accessNode));
1336 nsCOMPtr<nsIAccessible> newAcc;
1337 if (accessNode) {
1338 // Retrieved from cache. QI might not succeed if it's a node that's not
1339 // accessible. In this case try to create new accessible because one and
1340 // the same DOM node may be accessible or not in time (for example,
1341 // when it is visible or hidden).
1342 newAcc = do_QueryInterface(accessNode);
1343 if (newAcc) {
1344 NS_ADDREF(*aAccessible = newAcc);
1345 return NS_OK;
1349 nsCOMPtr<nsIContent> content(do_QueryInterface(aNode));
1351 // No cache entry, so we must create the accessible
1352 // Check to see if hidden first
1353 nsCOMPtr<nsIDocument> nodeIsDoc;
1354 if (!content) {
1355 // This happens when we're on the document node, which will not QI to an
1356 // nsIContent.
1357 nodeIsDoc = do_QueryInterface(aNode);
1358 NS_ENSURE_TRUE(nodeIsDoc, NS_ERROR_FAILURE); // No content, and not doc node
1360 nsCOMPtr<nsIAccessibleDocument> accessibleDoc =
1361 nsAccessNode::GetDocAccessibleFor(aWeakShell);
1362 if (accessibleDoc) {
1363 newAcc = do_QueryInterface(accessibleDoc);
1364 NS_ASSERTION(newAcc, "nsIAccessibleDocument is not an nsIAccessible");
1366 else {
1367 CreateRootAccessible(aPresShell, nodeIsDoc, getter_AddRefs(newAcc)); // Does Init() for us
1370 *aFrameHint = aPresShell->GetRootFrame();
1371 NS_IF_ADDREF(*aAccessible = newAcc);
1372 return NS_OK;
1375 NS_ASSERTION(content->GetDocument(), "Creating accessible for node with no document");
1376 if (!content->GetDocument()) {
1377 return NS_ERROR_FAILURE;
1379 NS_ASSERTION(content->GetDocument() == aPresShell->GetDocument(), "Creating accessible for wrong pres shell");
1380 if (content->GetDocument() != aPresShell->GetDocument()) {
1381 return NS_ERROR_FAILURE;
1384 // We have a content node
1385 nsIFrame *frame = *aFrameHint;
1386 #ifdef DEBUG_A11Y
1387 static int frameHintFailed, frameHintTried, frameHintNonexistant, frameHintFailedForText;
1388 ++frameHintTried;
1389 #endif
1390 if (!frame || content != frame->GetContent()) {
1391 // Frame hint not correct, get true frame, we try to optimize away from this
1392 frame = aPresShell->GetRealPrimaryFrameFor(content);
1393 if (frame) {
1394 #ifdef DEBUG_A11Y_FRAME_OPTIMIZATION
1395 // Frame hint debugging
1396 ++frameHintFailed;
1397 if (content->IsNodeOfType(nsINode::eTEXT)) {
1398 ++frameHintFailedForText;
1400 frameHintNonexistant += !*aFrameHint;
1401 printf("Frame hint failures: %d / %d . Text fails = %d. No hint fails = %d \n", frameHintFailed, frameHintTried, frameHintFailedForText, frameHintNonexistant);
1402 if (frameHintTried >= 354) {
1403 printf("* "); // Aaron's break point
1405 #endif
1406 if (frame->GetContent() != content) {
1407 // Not the main content for this frame!
1408 // For example, this happens because <area> elements return the
1409 // image frame as their primary frame. The main content for the
1410 // image frame is the image content.
1412 // Check if frame is an image frame, and content is <area>
1413 nsIImageFrame *imageFrame;
1414 CallQueryInterface(frame, &imageFrame);
1415 nsCOMPtr<nsIDOMHTMLAreaElement> areaElmt = do_QueryInterface(content);
1416 if (imageFrame && areaElmt) {
1417 nsCOMPtr<nsIAccessible> imageAcc;
1418 CreateHTMLImageAccessible(frame, getter_AddRefs(imageAcc));
1419 if (imageAcc) {
1420 // cache children
1421 PRInt32 childCount;
1422 imageAcc->GetChildCount(&childCount);
1423 // area accessible should be in cache now
1424 return GetCachedAccessible(aNode, aWeakShell, aAccessible);
1428 return NS_OK;
1430 *aFrameHint = frame;
1434 // Check frame to see if it is hidden
1435 if (!frame || !frame->GetStyleVisibility()->IsVisible()) {
1436 *aIsHidden = PR_TRUE;
1439 if (*aIsHidden)
1440 return NS_OK;
1443 * Attempt to create an accessible based on what we know
1445 if (content->IsNodeOfType(nsINode::eTEXT)) {
1446 // --- Create HTML for visible text frames ---
1447 if (frame->IsEmpty()) {
1448 nsAutoString renderedWhitespace;
1449 frame->GetRenderedText(&renderedWhitespace, nsnull, nsnull, 0, 1);
1450 if (renderedWhitespace.IsEmpty()) {
1451 // Really empty -- nothing is rendered
1452 *aIsHidden = PR_TRUE;
1453 return NS_OK;
1456 frame->GetAccessible(getter_AddRefs(newAcc));
1457 return InitAccessible(newAcc, aAccessible, nsnull);
1460 PRBool isHTML = content->IsNodeOfType(nsINode::eHTML);
1461 if (isHTML && content->Tag() == nsAccessibilityAtoms::map) {
1462 // Create hyper text accessible for HTML map if it is used to group links
1463 // (see http://www.w3.org/TR/WCAG10-HTML-TECHS/#group-bypass). If the HTML
1464 // map doesn't have 'name' attribute (or has empty name attribute) then we
1465 // suppose it is used for links grouping. Otherwise we think it is used in
1466 // conjuction with HTML image element and in this case we don't create any
1467 // accessible for it and don't walk into it. The accessibles for HTML area
1468 // (nsHTMLAreaAccessible) the map contains are attached as children of the
1469 // appropriate accessible for HTML image (nsHTMLImageAccessible).
1470 nsAutoString name;
1471 content->GetAttr(kNameSpaceID_None, nsAccessibilityAtoms::name, name);
1472 if (!name.IsEmpty()) {
1473 *aIsHidden = PR_TRUE;
1474 return NS_OK;
1477 nsresult rv = CreateHyperTextAccessible(frame, getter_AddRefs(newAcc));
1478 NS_ENSURE_SUCCESS(rv, rv);
1481 nsRoleMapEntry *roleMapEntry = nsAccUtils::GetRoleMapEntry(aNode);
1482 if (roleMapEntry && !nsCRT::strcmp(roleMapEntry->roleString, "presentation") &&
1483 !content->IsFocusable()) { // For presentation only
1484 // Only create accessible for role of "presentation" if it is focusable --
1485 // in that case we need an accessible in case it gets focused, we
1486 // don't want focus ever to be 'lost'
1487 return NS_OK;
1490 // Elements may implement nsIAccessibleProvider via XBL. This allows them to
1491 // say what kind of accessible to create.
1492 nsresult rv = GetAccessibleByType(aNode, getter_AddRefs(newAcc));
1493 NS_ENSURE_SUCCESS(rv, rv);
1495 if (!newAcc && !isHTML) {
1496 if (content->GetNameSpaceID() == kNameSpaceID_SVG &&
1497 content->Tag() == nsAccessibilityAtoms::svg) {
1498 newAcc = new nsEnumRoleAccessible(aNode, aWeakShell,
1499 nsIAccessibleRole::ROLE_DIAGRAM);
1501 else if (content->GetNameSpaceID() == kNameSpaceID_MathML &&
1502 content->Tag() == nsAccessibilityAtoms::math) {
1503 newAcc = new nsEnumRoleAccessible(aNode, aWeakShell,
1504 nsIAccessibleRole::ROLE_EQUATION);
1506 } else if (!newAcc) { // HTML accessibles
1507 PRBool tryTagNameOrFrame = PR_TRUE;
1509 nsIAtom *frameType = frame->GetType();
1510 if (!roleMapEntry &&
1511 (frameType == nsAccessibilityAtoms::tableCaptionFrame ||
1512 frameType == nsAccessibilityAtoms::tableCellFrame ||
1513 frameType == nsAccessibilityAtoms::tableRowGroupFrame ||
1514 frameType == nsAccessibilityAtoms::tableRowFrame)) {
1515 // Table-related frames don't get table-related roles
1516 // unless they are inside a table, but they may still get generic
1517 // accessibles
1518 nsIContent *tableContent = content;
1519 while ((tableContent = tableContent->GetParent()) != nsnull) {
1520 nsIFrame *tableFrame = aPresShell->GetPrimaryFrameFor(tableContent);
1521 if (!tableFrame)
1522 continue;
1523 if (tableFrame->GetType() == nsAccessibilityAtoms::tableOuterFrame) {
1524 nsCOMPtr<nsIDOMNode> tableNode(do_QueryInterface(tableContent));
1525 nsCOMPtr<nsIAccessible> tableAccessible;
1526 GetAccessibleInShell(tableNode, aPresShell, getter_AddRefs(tableAccessible));
1527 if (!tableAccessible && !content->IsFocusable()) {
1528 #ifdef DEBUG
1529 nsRoleMapEntry *tableRoleMapEntry =
1530 nsAccUtils::GetRoleMapEntry(tableNode);
1531 NS_ASSERTION(tableRoleMapEntry &&
1532 !nsCRT::strcmp(tableRoleMapEntry->roleString, "presentation"),
1533 "No accessible for parent table and it didn't have role of presentation");
1534 #endif
1535 // Table-related descendants of presentation table are also presentation
1536 // Don't create accessibles for them unless they need to fire focus events
1537 return NS_OK;
1539 if (tableAccessible &&
1540 nsAccUtils::Role(tableAccessible) != nsIAccessibleRole::ROLE_TABLE) {
1541 NS_ASSERTION(!roleMapEntry, "Should not be changing ARIA role, just overriding impl class role");
1542 // Not in table: override role (roleMap entry was null).
1543 roleMapEntry = &nsARIAMap::gEmptyRoleMap;
1545 break;
1547 else if (tableContent->Tag() == nsAccessibilityAtoms::table) {
1548 // Stop before we are fooled by any additional table ancestors
1549 // This table cell frameis part of a separate ancestor table.
1550 tryTagNameOrFrame = PR_FALSE;
1551 break;
1555 if (!tableContent)
1556 tryTagNameOrFrame = PR_FALSE;
1559 if (tryTagNameOrFrame) {
1560 // Prefer to use markup (mostly tag name, perhaps attributes) to
1561 // decide if and what kind of accessible to create.
1562 // The method creates accessibles for table related content too therefore
1563 // we do not call it if accessibles for table related content are
1564 // prevented above.
1565 rv = CreateHTMLAccessibleByMarkup(frame, aWeakShell, aNode,
1566 getter_AddRefs(newAcc));
1567 NS_ENSURE_SUCCESS(rv, rv);
1569 if (!newAcc) {
1570 // Do not create accessible object subtrees for non-rendered table
1571 // captions. This could not be done in
1572 // nsTableCaptionFrame::GetAccessible() because the descendants of
1573 // the table caption would still be created. By setting
1574 // *aIsHidden = PR_TRUE we ensure that no descendant accessibles are
1575 // created.
1576 if (frame->GetType() == nsAccessibilityAtoms::tableCaptionFrame &&
1577 frame->GetRect().IsEmpty()) {
1578 // XXX This is not the ideal place for this code, but right now there
1579 // is no better place:
1580 *aIsHidden = PR_TRUE;
1581 return NS_OK;
1583 frame->GetAccessible(getter_AddRefs(newAcc)); // Try using frame to do it
1588 if (!newAcc) {
1589 GetAccessibleForDeckChildren(aNode, getter_AddRefs(newAcc));
1592 // If no accessible, see if we need to create a generic accessible because
1593 // of some property that makes this object interesting
1594 // We don't do this for <body>, <html>, <window>, <dialog> etc. which
1595 // correspond to the doc accessible and will be created in any case
1596 if (!newAcc && content->Tag() != nsAccessibilityAtoms::body && content->GetParent() &&
1597 (frame->IsFocusable() ||
1598 (isHTML && nsCoreUtils::HasListener(content, NS_LITERAL_STRING("click"))) ||
1599 HasUniversalAriaProperty(content, aWeakShell) || roleMapEntry ||
1600 HasRelatedContent(content) || nsCoreUtils::IsXLink(content))) {
1601 // This content is focusable or has an interesting dynamic content accessibility property.
1602 // If it's interesting we need it in the accessibility hierarchy so that events or
1603 // other accessibles can point to it, or so that it can hold a state, etc.
1604 if (isHTML) {
1605 // Interesting HTML container which may have selectable text and/or embedded objects
1606 CreateHyperTextAccessible(frame, getter_AddRefs(newAcc));
1608 else { // XUL, SVG, MathML etc.
1609 // Interesting generic non-HTML container
1610 newAcc = new nsAccessibleWrap(aNode, aWeakShell);
1614 return InitAccessible(newAcc, aAccessible, roleMapEntry);
1617 PRBool
1618 nsAccessibilityService::HasUniversalAriaProperty(nsIContent *aContent,
1619 nsIWeakReference *aWeakShell)
1621 return aContent->HasAttr(kNameSpaceID_None, nsAccessibilityAtoms::aria_atomic) ||
1622 aContent->HasAttr(kNameSpaceID_None, nsAccessibilityAtoms::aria_busy) ||
1623 aContent->HasAttr(kNameSpaceID_None, nsAccessibilityAtoms::aria_channel) ||
1624 aContent->HasAttr(kNameSpaceID_None, nsAccessibilityAtoms::aria_controls) ||
1625 aContent->HasAttr(kNameSpaceID_None, nsAccessibilityAtoms::aria_datatype) ||
1626 aContent->HasAttr(kNameSpaceID_None, nsAccessibilityAtoms::aria_describedby) ||
1627 aContent->HasAttr(kNameSpaceID_None, nsAccessibilityAtoms::aria_dropeffect) ||
1628 aContent->HasAttr(kNameSpaceID_None, nsAccessibilityAtoms::aria_flowto) ||
1629 aContent->HasAttr(kNameSpaceID_None, nsAccessibilityAtoms::aria_grab) ||
1630 aContent->HasAttr(kNameSpaceID_None, nsAccessibilityAtoms::aria_haspopup) ||
1631 aContent->HasAttr(kNameSpaceID_None, nsAccessibilityAtoms::aria_invalid) ||
1632 aContent->HasAttr(kNameSpaceID_None, nsAccessibilityAtoms::aria_label) ||
1633 aContent->HasAttr(kNameSpaceID_None, nsAccessibilityAtoms::aria_labelledby) ||
1634 aContent->HasAttr(kNameSpaceID_None, nsAccessibilityAtoms::aria_live) ||
1635 aContent->HasAttr(kNameSpaceID_None, nsAccessibilityAtoms::aria_owns) ||
1636 aContent->HasAttr(kNameSpaceID_None, nsAccessibilityAtoms::aria_relevant) ||
1637 aContent->HasAttr(kNameSpaceID_None, nsAccessibilityAtoms::aria_required) ||
1638 aContent->HasAttr(kNameSpaceID_None, nsAccessibilityAtoms::aria_sort);
1641 NS_IMETHODIMP
1642 nsAccessibilityService::GetRelevantContentNodeFor(nsIDOMNode *aNode,
1643 nsIDOMNode **aRelevantNode)
1645 // The method returns node that is relevant for attached accessible check.
1646 // Sometimes element that is XBL widget hasn't accessible children in
1647 // anonymous content. This method check whether given node can be accessible
1648 // by looking through all nested bindings that given node is anonymous for. If
1649 // there is XBL widget that deniedes to be accessible for given node then the
1650 // method returns that XBL widget otherwise it returns given node.
1652 // For example, the algorithm allows us to handle following cases:
1653 // 1. xul:dialog element has buttons (like 'ok' and 'cancel') in anonymous
1654 // content. When node is dialog's button then we dialog's button since button
1655 // of xul:dialog is accessible anonymous node.
1656 // 2. xul:texbox has html:input in anonymous content. When given node is
1657 // html:input elmement then we return xul:textbox since xul:textbox doesn't
1658 // allow accessible nodes in anonymous content.
1659 // 3. xforms:input that is hosted in xul document contains xul:textbox
1660 // element. When given node is html:input or xul:textbox then we return
1661 // xforms:input element since xforms:input hasn't accessible anonymous
1662 // children.
1664 NS_ENSURE_ARG(aNode);
1665 NS_ENSURE_ARG_POINTER(aRelevantNode);
1667 nsresult rv;
1668 nsCOMPtr<nsIContent> content(do_QueryInterface(aNode));
1669 if (content) {
1670 // Build stack of binding parents so we can walk it in reverse.
1671 nsIContent *bindingParent;
1672 nsCOMArray<nsIContent> bindingsStack;
1674 for (bindingParent = content->GetBindingParent(); bindingParent != nsnull &&
1675 bindingParent != bindingParent->GetBindingParent();
1676 bindingParent = bindingParent->GetBindingParent()) {
1677 bindingsStack.AppendObject(bindingParent);
1680 PRInt32 bindingsCount = bindingsStack.Count();
1681 for (PRInt32 index = bindingsCount - 1; index >= 0 ; index--) {
1682 bindingParent = bindingsStack[index];
1683 nsCOMPtr<nsIDOMNode> bindingNode(do_QueryInterface(bindingParent));
1684 if (bindingNode) {
1685 // Try to get an accessible by type since XBL widget can be accessible
1686 // only if it implements nsIAccessibleProvider interface.
1687 nsCOMPtr<nsIAccessible> accessible;
1688 rv = GetAccessibleByType(bindingNode, getter_AddRefs(accessible));
1690 if (NS_SUCCEEDED(rv)) {
1691 nsCOMPtr<nsPIAccessible> paccessible(do_QueryInterface(accessible));
1692 if (paccessible) {
1693 PRBool allowsAnonChildren = PR_FALSE;
1694 paccessible->GetAllowsAnonChildAccessibles(&allowsAnonChildren);
1695 if (!allowsAnonChildren) {
1696 NS_ADDREF(*aRelevantNode = bindingNode);
1697 return NS_OK;
1705 NS_ADDREF(*aRelevantNode = aNode);
1706 return NS_OK;
1709 nsresult nsAccessibilityService::GetAccessibleByType(nsIDOMNode *aNode,
1710 nsIAccessible **aAccessible)
1712 NS_ENSURE_ARG(aNode);
1713 NS_ENSURE_ARG_POINTER(aAccessible);
1715 *aAccessible = nsnull;
1717 nsCOMPtr<nsIAccessibleProvider> accessibleProvider(do_QueryInterface(aNode));
1718 if (!accessibleProvider)
1719 return NS_OK;
1721 PRInt32 type;
1722 nsresult rv = accessibleProvider->GetAccessibleType(&type);
1723 NS_ENSURE_SUCCESS(rv, rv);
1725 if (type == nsIAccessibleProvider::OuterDoc)
1726 return CreateOuterDocAccessible(aNode, aAccessible);
1728 nsCOMPtr<nsIWeakReference> weakShell;
1729 GetShellFromNode(aNode, getter_AddRefs(weakShell));
1731 switch (type)
1733 #ifdef MOZ_XUL
1734 case nsIAccessibleProvider::NoAccessible:
1735 return NS_OK;
1736 // XUL controls
1737 case nsIAccessibleProvider::XULAlert:
1738 *aAccessible = new nsXULAlertAccessible(aNode, weakShell);
1739 break;
1740 case nsIAccessibleProvider::XULButton:
1741 *aAccessible = new nsXULButtonAccessible(aNode, weakShell);
1742 break;
1743 case nsIAccessibleProvider::XULCheckbox:
1744 *aAccessible = new nsXULCheckboxAccessible(aNode, weakShell);
1745 break;
1746 case nsIAccessibleProvider::XULColorPicker:
1747 *aAccessible = new nsXULColorPickerAccessible(aNode, weakShell);
1748 break;
1749 case nsIAccessibleProvider::XULColorPickerTile:
1750 *aAccessible = new nsXULColorPickerTileAccessible(aNode, weakShell);
1751 break;
1752 case nsIAccessibleProvider::XULCombobox:
1753 *aAccessible = new nsXULComboboxAccessible(aNode, weakShell);
1754 break;
1755 case nsIAccessibleProvider::XULDropmarker:
1756 *aAccessible = new nsXULDropmarkerAccessible(aNode, weakShell);
1757 break;
1758 case nsIAccessibleProvider::XULGroupbox:
1759 *aAccessible = new nsXULGroupboxAccessible(aNode, weakShell);
1760 break;
1761 case nsIAccessibleProvider::XULImage:
1763 // Don't include nameless images in accessible tree
1764 nsCOMPtr<nsIDOMElement> elt(do_QueryInterface(aNode));
1765 if (!elt)
1766 return NS_ERROR_FAILURE;
1768 PRBool hasTextEquivalent;
1769 // Prefer value over tooltiptext
1770 elt->HasAttribute(NS_LITERAL_STRING("tooltiptext"), &hasTextEquivalent);
1771 if (!hasTextEquivalent)
1772 return NS_OK;
1774 *aAccessible = new nsHTMLImageAccessibleWrap(aNode, weakShell);
1775 break;
1777 case nsIAccessibleProvider::XULLink:
1778 *aAccessible = new nsXULLinkAccessible(aNode, weakShell);
1779 break;
1780 case nsIAccessibleProvider::XULListbox:
1781 *aAccessible = new nsXULListboxAccessible(aNode, weakShell);
1782 break;
1783 case nsIAccessibleProvider::XULListCell:
1784 *aAccessible = new nsXULListCellAccessible(aNode, weakShell);
1785 break;
1786 case nsIAccessibleProvider::XULListHead:
1787 *aAccessible = new nsXULColumnsAccessible(aNode, weakShell);
1788 break;
1789 case nsIAccessibleProvider::XULListHeader:
1790 *aAccessible = new nsXULColumnItemAccessible(aNode, weakShell);
1791 break;
1792 case nsIAccessibleProvider::XULListitem:
1793 *aAccessible = new nsXULListitemAccessible(aNode, weakShell);
1794 break;
1795 case nsIAccessibleProvider::XULMenubar:
1796 *aAccessible = new nsXULMenubarAccessible(aNode, weakShell);
1797 break;
1798 case nsIAccessibleProvider::XULMenuitem:
1799 *aAccessible = new nsXULMenuitemAccessibleWrap(aNode, weakShell);
1800 break;
1801 case nsIAccessibleProvider::XULMenupopup:
1803 #ifdef MOZ_ACCESSIBILITY_ATK
1804 // ATK considers this node to be redundant when within menubars, and it makes menu
1805 // navigation with assistive technologies more difficult
1806 // XXX In the future we will should this for consistency across the nsIAccessible
1807 // implementations on each platform for a consistent scripting environment, but
1808 // then strip out redundant accessibles in the nsAccessibleWrap class for each platform.
1809 nsCOMPtr<nsIContent> content = do_QueryInterface(aNode);
1810 if (content) {
1811 nsIContent *parent = content->GetParent();
1812 if (parent && parent->NodeInfo()->Equals(nsAccessibilityAtoms::menu, kNameSpaceID_XUL)) {
1813 return NS_OK;
1816 #endif
1817 *aAccessible = new nsXULMenupopupAccessible(aNode, weakShell);
1818 break;
1820 case nsIAccessibleProvider::XULMenuSeparator:
1821 *aAccessible = new nsXULMenuSeparatorAccessible(aNode, weakShell);
1822 break;
1823 case nsIAccessibleProvider::XULPane:
1824 *aAccessible = new nsEnumRoleAccessible(aNode, weakShell, nsIAccessibleRole::ROLE_PANE);
1825 break;
1826 case nsIAccessibleProvider::XULProgressMeter:
1827 *aAccessible = new nsXULProgressMeterAccessible(aNode, weakShell);
1828 break;
1829 case nsIAccessibleProvider::XULStatusBar:
1830 *aAccessible = new nsXULStatusBarAccessible(aNode, weakShell);
1831 break;
1832 case nsIAccessibleProvider::XULScale:
1833 *aAccessible = new nsXULSliderAccessible(aNode, weakShell);
1834 break;
1835 case nsIAccessibleProvider::XULRadioButton:
1836 *aAccessible = new nsXULRadioButtonAccessible(aNode, weakShell);
1837 break;
1838 case nsIAccessibleProvider::XULRadioGroup:
1839 *aAccessible = new nsXULRadioGroupAccessible(aNode, weakShell);
1840 break;
1841 case nsIAccessibleProvider::XULTab:
1842 *aAccessible = new nsXULTabAccessible(aNode, weakShell);
1843 break;
1844 case nsIAccessibleProvider::XULTabBox:
1845 *aAccessible = new nsXULTabBoxAccessible(aNode, weakShell);
1846 break;
1847 case nsIAccessibleProvider::XULTabs:
1848 *aAccessible = new nsXULTabsAccessible(aNode, weakShell);
1849 break;
1850 case nsIAccessibleProvider::XULText:
1851 *aAccessible = new nsXULTextAccessible(aNode, weakShell);
1852 break;
1853 case nsIAccessibleProvider::XULTextBox:
1854 *aAccessible = new nsXULTextFieldAccessible(aNode, weakShell);
1855 break;
1856 case nsIAccessibleProvider::XULThumb:
1857 *aAccessible = new nsXULThumbAccessible(aNode, weakShell);
1858 break;
1859 case nsIAccessibleProvider::XULTree:
1860 *aAccessible = new nsXULTreeAccessibleWrap(aNode, weakShell);
1861 break;
1862 case nsIAccessibleProvider::XULTreeColumns:
1863 *aAccessible = new nsXULTreeColumnsAccessibleWrap(aNode, weakShell);
1864 break;
1865 case nsIAccessibleProvider::XULTreeColumnItem:
1866 *aAccessible = new nsXULColumnItemAccessible(aNode, weakShell);
1867 break;
1868 case nsIAccessibleProvider::XULToolbar:
1869 *aAccessible = new nsXULToolbarAccessible(aNode, weakShell);
1870 break;
1871 case nsIAccessibleProvider::XULToolbarSeparator:
1872 *aAccessible = new nsXULToolbarSeparatorAccessible(aNode, weakShell);
1873 break;
1874 case nsIAccessibleProvider::XULTooltip:
1875 *aAccessible = new nsXULTooltipAccessible(aNode, weakShell);
1876 break;
1877 case nsIAccessibleProvider::XULToolbarButton:
1878 *aAccessible = new nsXULToolbarButtonAccessible(aNode, weakShell);
1879 break;
1880 #endif // MOZ_XUL
1882 #ifndef DISABLE_XFORMS_HOOKS
1883 // XForms elements
1884 case nsIAccessibleProvider::XFormsContainer:
1885 *aAccessible = new nsXFormsContainerAccessible(aNode, weakShell);
1886 break;
1888 case nsIAccessibleProvider::XFormsLabel:
1889 *aAccessible = new nsXFormsLabelAccessible(aNode, weakShell);
1890 break;
1891 case nsIAccessibleProvider::XFormsOuput:
1892 *aAccessible = new nsXFormsOutputAccessible(aNode, weakShell);
1893 break;
1894 case nsIAccessibleProvider::XFormsTrigger:
1895 *aAccessible = new nsXFormsTriggerAccessible(aNode, weakShell);
1896 break;
1897 case nsIAccessibleProvider::XFormsInput:
1898 *aAccessible = new nsXFormsInputAccessible(aNode, weakShell);
1899 break;
1900 case nsIAccessibleProvider::XFormsInputBoolean:
1901 *aAccessible = new nsXFormsInputBooleanAccessible(aNode, weakShell);
1902 break;
1903 case nsIAccessibleProvider::XFormsInputDate:
1904 *aAccessible = new nsXFormsInputDateAccessible(aNode, weakShell);
1905 break;
1906 case nsIAccessibleProvider::XFormsSecret:
1907 *aAccessible = new nsXFormsSecretAccessible(aNode, weakShell);
1908 break;
1909 case nsIAccessibleProvider::XFormsSliderRange:
1910 *aAccessible = new nsXFormsRangeAccessible(aNode, weakShell);
1911 break;
1912 case nsIAccessibleProvider::XFormsSelect:
1913 *aAccessible = new nsXFormsSelectAccessible(aNode, weakShell);
1914 break;
1915 case nsIAccessibleProvider::XFormsChoices:
1916 *aAccessible = new nsXFormsChoicesAccessible(aNode, weakShell);
1917 break;
1918 case nsIAccessibleProvider::XFormsSelectFull:
1919 *aAccessible = new nsXFormsSelectFullAccessible(aNode, weakShell);
1920 break;
1921 case nsIAccessibleProvider::XFormsItemCheckgroup:
1922 *aAccessible = new nsXFormsItemCheckgroupAccessible(aNode, weakShell);
1923 break;
1924 case nsIAccessibleProvider::XFormsItemRadiogroup:
1925 *aAccessible = new nsXFormsItemRadiogroupAccessible(aNode, weakShell);
1926 break;
1927 case nsIAccessibleProvider::XFormsSelectCombobox:
1928 *aAccessible = new nsXFormsSelectComboboxAccessible(aNode, weakShell);
1929 break;
1930 case nsIAccessibleProvider::XFormsItemCombobox:
1931 *aAccessible = new nsXFormsItemComboboxAccessible(aNode, weakShell);
1932 break;
1934 case nsIAccessibleProvider::XFormsDropmarkerWidget:
1935 *aAccessible = new nsXFormsDropmarkerWidgetAccessible(aNode, weakShell);
1936 break;
1937 case nsIAccessibleProvider::XFormsCalendarWidget:
1938 *aAccessible = new nsXFormsCalendarWidgetAccessible(aNode, weakShell);
1939 break;
1940 case nsIAccessibleProvider::XFormsComboboxPopupWidget:
1941 *aAccessible = new nsXFormsComboboxPopupWidgetAccessible(aNode, weakShell);
1942 break;
1943 #endif
1945 default:
1946 return NS_ERROR_FAILURE;
1949 if (!*aAccessible)
1950 return NS_ERROR_OUT_OF_MEMORY;
1952 NS_ADDREF(*aAccessible);
1953 return NS_OK;
1956 NS_IMETHODIMP nsAccessibilityService::AddNativeRootAccessible(void * aAtkAccessible, nsIAccessible **aRootAccessible)
1958 #ifdef MOZ_ACCESSIBILITY_ATK
1959 nsNativeRootAccessibleWrap* rootAccWrap =
1960 new nsNativeRootAccessibleWrap((AtkObject*)aAtkAccessible);
1962 *aRootAccessible = static_cast<nsIAccessible*>(rootAccWrap);
1963 NS_ADDREF(*aRootAccessible);
1965 nsRefPtr<nsApplicationAccessibleWrap> appRoot =
1966 nsAccessNode::GetApplicationAccessible();
1967 NS_ENSURE_STATE(appRoot);
1969 appRoot->AddRootAccessible(*aRootAccessible);
1971 return NS_OK;
1972 #else
1973 return NS_ERROR_NOT_IMPLEMENTED;
1974 #endif
1977 NS_IMETHODIMP nsAccessibilityService::RemoveNativeRootAccessible(nsIAccessible * aRootAccessible)
1979 #ifdef MOZ_ACCESSIBILITY_ATK
1980 void* atkAccessible;
1981 aRootAccessible->GetNativeInterface(&atkAccessible);
1983 nsRefPtr<nsApplicationAccessibleWrap> appRoot =
1984 nsAccessNode::GetApplicationAccessible();
1985 NS_ENSURE_STATE(appRoot);
1987 appRoot->RemoveRootAccessible(aRootAccessible);
1989 return NS_OK;
1990 #else
1991 return NS_ERROR_NOT_IMPLEMENTED;
1992 #endif
1995 // Called from layout when the frame tree owned by a node changes significantly
1996 NS_IMETHODIMP nsAccessibilityService::InvalidateSubtreeFor(nsIPresShell *aShell,
1997 nsIContent *aChangeContent,
1998 PRUint32 aEvent)
2000 NS_ASSERTION(aEvent == nsIAccessibleEvent::EVENT_ASYNCH_SIGNIFICANT_CHANGE ||
2001 aEvent == nsIAccessibleEvent::EVENT_ASYNCH_SHOW ||
2002 aEvent == nsIAccessibleEvent::EVENT_ASYNCH_HIDE ||
2003 aEvent == nsIAccessibleEvent::EVENT_DOM_SIGNIFICANT_CHANGE ||
2004 aEvent == nsIAccessibleEvent::EVENT_DOM_CREATE ||
2005 aEvent == nsIAccessibleEvent::EVENT_DOM_DESTROY,
2006 "Incorrect aEvent passed in");
2008 NS_ENSURE_ARG_POINTER(aShell);
2009 nsCOMPtr<nsIAccessibleDocument> accessibleDoc =
2010 nsAccessNode::GetDocAccessibleFor(aShell->GetDocument());
2011 nsCOMPtr<nsPIAccessibleDocument> privateAccessibleDoc =
2012 do_QueryInterface(accessibleDoc);
2013 if (!privateAccessibleDoc) {
2014 return NS_OK;
2016 return privateAccessibleDoc->InvalidateCacheSubtree(aChangeContent, aEvent);
2019 //////////////////////////////////////////////////////////////////////
2020 //////////////////////////////////////////////////////////////////////
2022 nsresult
2023 nsAccessibilityService::GetAccessibilityService(nsIAccessibilityService** aResult)
2025 NS_PRECONDITION(aResult != nsnull, "null ptr");
2026 if (! aResult)
2027 return NS_ERROR_NULL_POINTER;
2029 *aResult = nsnull;
2030 if (!nsAccessibilityService::gAccessibilityService) {
2031 gAccessibilityService = new nsAccessibilityService();
2032 if (!gAccessibilityService ) {
2033 return NS_ERROR_OUT_OF_MEMORY;
2036 *aResult = nsAccessibilityService::gAccessibilityService;
2037 NS_ADDREF(*aResult);
2038 return NS_OK;
2041 nsresult
2042 NS_GetAccessibilityService(nsIAccessibilityService** aResult)
2044 return nsAccessibilityService::GetAccessibilityService(aResult);
2047 nsresult
2048 nsAccessibilityService::GetAccessibleForDeckChildren(nsIDOMNode *aNode, nsIAccessible** aAccessible)
2050 nsCOMPtr<nsIWeakReference> weakShell;
2051 GetShellFromNode(aNode, getter_AddRefs(weakShell));
2052 NS_ENSURE_TRUE(weakShell, NS_ERROR_FAILURE);
2053 nsCOMPtr<nsIPresShell> shell(do_QueryReferent(weakShell));
2054 NS_ENSURE_TRUE(shell, NS_ERROR_FAILURE);
2056 nsIFrame* frame = nsnull;
2057 nsIFrame* parentFrame = nsnull;
2058 nsCOMPtr<nsIContent> content(do_QueryInterface(aNode));
2060 if (content) {
2061 frame = shell->GetPrimaryFrameFor(content);
2064 if (frame && (frame->GetType() == nsAccessibilityAtoms::boxFrame ||
2065 frame->GetType() == nsAccessibilityAtoms::scrollFrame)) {
2066 parentFrame = frame->GetParent();
2067 if (parentFrame && parentFrame->GetType() == nsAccessibilityAtoms::deckFrame) {
2068 // If deck frame is for xul:tabpanels element then the given node has
2069 // tabpanel accessible.
2070 nsCOMPtr<nsIContent> parentContent = parentFrame->GetContent();
2071 #ifdef MOZ_XUL
2072 if (parentContent->NodeInfo()->Equals(nsAccessibilityAtoms::tabpanels,
2073 kNameSpaceID_XUL)) {
2074 *aAccessible = new nsXULTabpanelAccessible(aNode, weakShell);
2075 } else
2076 #endif
2077 *aAccessible =
2078 new nsEnumRoleAccessible(aNode, weakShell,
2079 nsIAccessibleRole::ROLE_PROPERTYPAGE);
2081 NS_ENSURE_TRUE(*aAccessible, NS_ERROR_OUT_OF_MEMORY);
2083 NS_ADDREF(*aAccessible);
2087 return NS_OK;