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
4 : *
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/
9 : *
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.
14 : *
15 : * The Original Code is mozilla.org code.
16 : *
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.
21 : *
22 : * Contributor(s):
23 : * Author: Eric Vaughan (evaughan@netscape.com)
24 : *
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.
36 : *
37 : * ***** END LICENSE BLOCK ***** */
38 :
39 : #include "nsHTMLFormControlAccessible.h"
40 :
41 : #include "nsAccUtils.h"
42 : #include "nsTextEquivUtils.h"
43 : #include "Relation.h"
44 : #include "Role.h"
45 : #include "States.h"
46 :
47 : #include "nsIAccessibleRelation.h"
48 : #include "nsIDOMDocument.h"
49 : #include "nsIDOMHTMLInputElement.h"
50 : #include "nsIDOMNSEditableElement.h"
51 : #include "nsIDOMHTMLFormElement.h"
52 : #include "nsIDOMHTMLLegendElement.h"
53 : #include "nsIDOMHTMLTextAreaElement.h"
54 : #include "nsIDOMNodeList.h"
55 : #include "nsIEditor.h"
56 : #include "nsIFrame.h"
57 : #include "nsINameSpaceManager.h"
58 : #include "nsISelectionController.h"
59 : #include "jsapi.h"
60 : #include "nsIJSContextStack.h"
61 : #include "nsIServiceManager.h"
62 : #include "nsITextControlFrame.h"
63 :
64 : using namespace mozilla::a11y;
65 :
66 : ////////////////////////////////////////////////////////////////////////////////
67 : // nsHTMLCheckboxAccessible
68 : ////////////////////////////////////////////////////////////////////////////////
69 :
70 0 : nsHTMLCheckboxAccessible::
71 : nsHTMLCheckboxAccessible(nsIContent* aContent, nsDocAccessible* aDoc) :
72 0 : nsFormControlAccessible(aContent, aDoc)
73 : {
74 0 : }
75 :
76 : role
77 0 : nsHTMLCheckboxAccessible::NativeRole()
78 : {
79 0 : return roles::CHECKBUTTON;
80 : }
81 :
82 : PRUint8
83 0 : nsHTMLCheckboxAccessible::ActionCount()
84 : {
85 0 : return 1;
86 : }
87 :
88 0 : NS_IMETHODIMP nsHTMLCheckboxAccessible::GetActionName(PRUint8 aIndex, nsAString& aName)
89 : {
90 0 : if (aIndex == eAction_Click) { // 0 is the magic value for default action
91 : // cycle, check or uncheck
92 0 : PRUint64 state = NativeState();
93 :
94 0 : if (state & states::CHECKED)
95 0 : aName.AssignLiteral("uncheck");
96 0 : else if (state & states::MIXED)
97 0 : aName.AssignLiteral("cycle");
98 : else
99 0 : aName.AssignLiteral("check");
100 :
101 0 : return NS_OK;
102 : }
103 0 : return NS_ERROR_INVALID_ARG;
104 : }
105 :
106 : NS_IMETHODIMP
107 0 : nsHTMLCheckboxAccessible::DoAction(PRUint8 aIndex)
108 : {
109 0 : if (aIndex != 0)
110 0 : return NS_ERROR_INVALID_ARG;
111 :
112 0 : DoCommand();
113 0 : return NS_OK;
114 : }
115 :
116 : PRUint64
117 0 : nsHTMLCheckboxAccessible::NativeState()
118 : {
119 0 : PRUint64 state = nsFormControlAccessible::NativeState();
120 :
121 0 : state |= states::CHECKABLE;
122 0 : bool checkState = false; // Radio buttons and check boxes can be checked or mixed
123 :
124 : nsCOMPtr<nsIDOMHTMLInputElement> htmlCheckboxElement =
125 0 : do_QueryInterface(mContent);
126 :
127 0 : if (htmlCheckboxElement) {
128 0 : htmlCheckboxElement->GetIndeterminate(&checkState);
129 :
130 0 : if (checkState) {
131 0 : state |= states::MIXED;
132 : } else { // indeterminate can't be checked at the same time.
133 0 : htmlCheckboxElement->GetChecked(&checkState);
134 :
135 0 : if (checkState)
136 0 : state |= states::CHECKED;
137 : }
138 : }
139 0 : return state;
140 : }
141 :
142 : ////////////////////////////////////////////////////////////////////////////////
143 : // nsHTMLCheckboxAccessible: Widgets
144 :
145 : bool
146 0 : nsHTMLCheckboxAccessible::IsWidget() const
147 : {
148 0 : return true;
149 : }
150 :
151 :
152 : ////////////////////////////////////////////////////////////////////////////////
153 : // nsHTMLRadioButtonAccessible
154 : ////////////////////////////////////////////////////////////////////////////////
155 :
156 0 : nsHTMLRadioButtonAccessible::
157 : nsHTMLRadioButtonAccessible(nsIContent* aContent, nsDocAccessible* aDoc) :
158 0 : nsRadioButtonAccessible(aContent, aDoc)
159 : {
160 0 : }
161 :
162 : PRUint64
163 0 : nsHTMLRadioButtonAccessible::NativeState()
164 : {
165 0 : PRUint64 state = nsAccessibleWrap::NativeState();
166 :
167 0 : state |= states::CHECKABLE;
168 :
169 0 : bool checked = false; // Radio buttons and check boxes can be checked
170 :
171 : nsCOMPtr<nsIDOMHTMLInputElement> htmlRadioElement =
172 0 : do_QueryInterface(mContent);
173 0 : if (htmlRadioElement)
174 0 : htmlRadioElement->GetChecked(&checked);
175 :
176 0 : if (checked)
177 0 : state |= states::CHECKED;
178 :
179 0 : return state;
180 : }
181 :
182 : void
183 0 : nsHTMLRadioButtonAccessible::GetPositionAndSizeInternal(PRInt32 *aPosInSet,
184 : PRInt32 *aSetSize)
185 : {
186 0 : nsAutoString nsURI;
187 0 : mContent->NodeInfo()->GetNamespaceURI(nsURI);
188 0 : nsAutoString tagName;
189 0 : mContent->NodeInfo()->GetName(tagName);
190 :
191 0 : nsAutoString type;
192 0 : mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::type, type);
193 0 : nsAutoString name;
194 0 : mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::name, name);
195 :
196 0 : nsCOMPtr<nsIDOMNodeList> inputs;
197 :
198 0 : nsCOMPtr<nsIDOMHTMLInputElement> radio(do_QueryInterface(mContent));
199 0 : nsCOMPtr<nsIDOMHTMLFormElement> form;
200 0 : radio->GetForm(getter_AddRefs(form));
201 0 : if (form) {
202 0 : form->GetElementsByTagNameNS(nsURI, tagName, getter_AddRefs(inputs));
203 : } else {
204 0 : nsIDocument* doc = mContent->OwnerDoc();
205 0 : nsCOMPtr<nsIDOMDocument> document(do_QueryInterface(doc));
206 0 : if (document)
207 0 : document->GetElementsByTagNameNS(nsURI, tagName, getter_AddRefs(inputs));
208 : }
209 :
210 0 : NS_ENSURE_TRUE(inputs, );
211 :
212 0 : PRUint32 inputsCount = 0;
213 0 : inputs->GetLength(&inputsCount);
214 :
215 : // Compute posinset and setsize.
216 0 : PRInt32 indexOf = 0;
217 0 : PRInt32 count = 0;
218 :
219 0 : for (PRUint32 index = 0; index < inputsCount; index++) {
220 0 : nsCOMPtr<nsIDOMNode> itemNode;
221 0 : inputs->Item(index, getter_AddRefs(itemNode));
222 :
223 0 : nsCOMPtr<nsIContent> item(do_QueryInterface(itemNode));
224 0 : if (item &&
225 0 : item->AttrValueIs(kNameSpaceID_None, nsGkAtoms::type,
226 0 : type, eCaseMatters) &&
227 0 : item->AttrValueIs(kNameSpaceID_None, nsGkAtoms::name,
228 0 : name, eCaseMatters)) {
229 :
230 0 : count++;
231 :
232 0 : if (item == mContent)
233 0 : indexOf = count;
234 : }
235 : }
236 :
237 0 : *aPosInSet = indexOf;
238 0 : *aSetSize = count;
239 : }
240 :
241 : ////////////////////////////////////////////////////////////////////////////////
242 : // nsHTMLButtonAccessible
243 : ////////////////////////////////////////////////////////////////////////////////
244 :
245 0 : nsHTMLButtonAccessible::
246 : nsHTMLButtonAccessible(nsIContent* aContent, nsDocAccessible* aDoc) :
247 0 : nsHyperTextAccessibleWrap(aContent, aDoc)
248 : {
249 0 : }
250 :
251 : PRUint8
252 0 : nsHTMLButtonAccessible::ActionCount()
253 : {
254 0 : return 1;
255 : }
256 :
257 0 : NS_IMETHODIMP nsHTMLButtonAccessible::GetActionName(PRUint8 aIndex, nsAString& aName)
258 : {
259 0 : if (aIndex == eAction_Click) {
260 0 : aName.AssignLiteral("press");
261 0 : return NS_OK;
262 : }
263 0 : return NS_ERROR_INVALID_ARG;
264 : }
265 :
266 : NS_IMETHODIMP
267 0 : nsHTMLButtonAccessible::DoAction(PRUint8 aIndex)
268 : {
269 0 : if (aIndex != eAction_Click)
270 0 : return NS_ERROR_INVALID_ARG;
271 :
272 0 : DoCommand();
273 0 : return NS_OK;
274 : }
275 :
276 : PRUint64
277 0 : nsHTMLButtonAccessible::State()
278 : {
279 0 : PRUint64 state = nsHyperTextAccessibleWrap::State();
280 0 : if (state == states::DEFUNCT)
281 0 : return state;
282 :
283 : // Inherit states from input@type="file" suitable for the button. Note,
284 : // no special processing for unavailable state since inheritance is supplied
285 : // other code paths.
286 0 : if (mParent && mParent->IsHTMLFileInput()) {
287 0 : PRUint64 parentState = mParent->State();
288 : state |= parentState & (states::BUSY | states::REQUIRED |
289 0 : states::HASPOPUP | states::INVALID);
290 : }
291 :
292 0 : return state;
293 : }
294 :
295 : PRUint64
296 0 : nsHTMLButtonAccessible::NativeState()
297 : {
298 0 : PRUint64 state = nsHyperTextAccessibleWrap::NativeState();
299 :
300 0 : nsEventStates elmState = mContent->AsElement()->State();
301 0 : if (elmState.HasState(NS_EVENT_STATE_DEFAULT))
302 0 : state |= states::DEFAULT;
303 :
304 0 : return state;
305 : }
306 :
307 : role
308 0 : nsHTMLButtonAccessible::NativeRole()
309 : {
310 0 : return roles::PUSHBUTTON;
311 : }
312 :
313 : nsresult
314 0 : nsHTMLButtonAccessible::GetNameInternal(nsAString& aName)
315 : {
316 0 : nsAccessible::GetNameInternal(aName);
317 0 : if (!aName.IsEmpty() || mContent->Tag() != nsGkAtoms::input)
318 0 : return NS_OK;
319 :
320 : // No name from HTML or ARIA
321 0 : nsAutoString name;
322 0 : if (!mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::value,
323 0 : name) &&
324 0 : !mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::alt,
325 0 : name)) {
326 : // Use the button's (default) label if nothing else works
327 0 : nsIFrame* frame = GetFrame();
328 0 : if (frame) {
329 0 : nsIFormControlFrame* fcFrame = do_QueryFrame(frame);
330 0 : if (fcFrame)
331 0 : fcFrame->GetFormProperty(nsGkAtoms::defaultLabel, name);
332 : }
333 : }
334 :
335 0 : if (name.IsEmpty() &&
336 0 : !mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::src, name)) {
337 0 : mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::data, name);
338 : }
339 :
340 0 : name.CompressWhitespace();
341 0 : aName = name;
342 :
343 0 : return NS_OK;
344 : }
345 :
346 : ////////////////////////////////////////////////////////////////////////////////
347 : // nsHTMLButtonAccessible: Widgets
348 :
349 : bool
350 0 : nsHTMLButtonAccessible::IsWidget() const
351 : {
352 0 : return true;
353 : }
354 :
355 :
356 : ////////////////////////////////////////////////////////////////////////////////
357 : // nsHTMLTextFieldAccessible
358 : ////////////////////////////////////////////////////////////////////////////////
359 :
360 0 : nsHTMLTextFieldAccessible::
361 : nsHTMLTextFieldAccessible(nsIContent* aContent, nsDocAccessible* aDoc) :
362 0 : nsHyperTextAccessibleWrap(aContent, aDoc)
363 : {
364 0 : }
365 :
366 0 : NS_IMPL_ISUPPORTS_INHERITED3(nsHTMLTextFieldAccessible, nsAccessible, nsHyperTextAccessible, nsIAccessibleText, nsIAccessibleEditableText)
367 :
368 : role
369 0 : nsHTMLTextFieldAccessible::NativeRole()
370 : {
371 0 : if (mContent->AttrValueIs(kNameSpaceID_None, nsGkAtoms::type,
372 0 : nsGkAtoms::password, eIgnoreCase)) {
373 0 : return roles::PASSWORD_TEXT;
374 : }
375 :
376 0 : return roles::ENTRY;
377 : }
378 :
379 : nsresult
380 0 : nsHTMLTextFieldAccessible::GetNameInternal(nsAString& aName)
381 : {
382 0 : nsresult rv = nsAccessible::GetNameInternal(aName);
383 0 : NS_ENSURE_SUCCESS(rv, rv);
384 :
385 0 : if (!aName.IsEmpty())
386 0 : return NS_OK;
387 :
388 0 : if (mContent->GetBindingParent())
389 : {
390 : // XXX: bug 459640
391 : // There's a binding parent.
392 : // This means we're part of another control, so use parent accessible for name.
393 : // This ensures that a textbox inside of a XUL widget gets
394 : // an accessible name.
395 0 : nsAccessible* parent = Parent();
396 0 : if (parent)
397 0 : parent->GetName(aName);
398 : }
399 :
400 0 : if (!aName.IsEmpty())
401 0 : return NS_OK;
402 :
403 : // text inputs and textareas might have useful placeholder text
404 0 : mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::placeholder, aName);
405 :
406 0 : return NS_OK;
407 : }
408 :
409 0 : NS_IMETHODIMP nsHTMLTextFieldAccessible::GetValue(nsAString& _retval)
410 : {
411 0 : if (IsDefunct())
412 0 : return NS_ERROR_FAILURE;
413 :
414 0 : if (NativeState() & states::PROTECTED) // Don't return password text!
415 0 : return NS_ERROR_FAILURE;
416 :
417 0 : nsCOMPtr<nsIDOMHTMLTextAreaElement> textArea(do_QueryInterface(mContent));
418 0 : if (textArea) {
419 0 : return textArea->GetValue(_retval);
420 : }
421 :
422 0 : nsCOMPtr<nsIDOMHTMLInputElement> inputElement(do_QueryInterface(mContent));
423 0 : if (inputElement) {
424 0 : return inputElement->GetValue(_retval);
425 : }
426 :
427 0 : return NS_ERROR_FAILURE;
428 : }
429 :
430 : void
431 0 : nsHTMLTextFieldAccessible::ApplyARIAState(PRUint64* aState)
432 : {
433 0 : nsHyperTextAccessibleWrap::ApplyARIAState(aState);
434 :
435 0 : nsStateMapEntry::MapToStates(mContent, aState, eARIAAutoComplete);
436 0 : }
437 :
438 : PRUint64
439 0 : nsHTMLTextFieldAccessible::State()
440 : {
441 0 : PRUint64 state = nsHyperTextAccessibleWrap::State();
442 0 : if (state & states::DEFUNCT)
443 0 : return state;
444 :
445 : // Inherit states from input@type="file" suitable for the button. Note,
446 : // no special processing for unavailable state since inheritance is supplied
447 : // by other code paths.
448 0 : if (mParent && mParent->IsHTMLFileInput()) {
449 0 : PRUint64 parentState = mParent->State();
450 : state |= parentState & (states::BUSY | states::REQUIRED |
451 0 : states::HASPOPUP | states::INVALID);
452 : }
453 :
454 0 : return state;
455 : }
456 :
457 : PRUint64
458 0 : nsHTMLTextFieldAccessible::NativeState()
459 : {
460 0 : PRUint64 state = nsHyperTextAccessibleWrap::NativeState();
461 :
462 : // can be focusable, focused, protected. readonly, unavailable, selected
463 0 : if (mContent->AttrValueIs(kNameSpaceID_None, nsGkAtoms::type,
464 0 : nsGkAtoms::password, eIgnoreCase)) {
465 0 : state |= states::PROTECTED;
466 : }
467 :
468 0 : if (mContent->HasAttr(kNameSpaceID_None, nsGkAtoms::readonly)) {
469 0 : state |= states::READONLY;
470 : }
471 :
472 : // Is it an <input> or a <textarea> ?
473 0 : nsCOMPtr<nsIDOMHTMLInputElement> htmlInput(do_QueryInterface(mContent));
474 0 : state |= htmlInput ? states::SINGLE_LINE : states::MULTI_LINE;
475 :
476 0 : if (!(state & states::EDITABLE) ||
477 : (state & (states::PROTECTED | states::MULTI_LINE)))
478 0 : return state;
479 :
480 : // Expose autocomplete states if this input is part of autocomplete widget.
481 0 : nsAccessible* widget = ContainerWidget();
482 0 : if (widget && widget-IsAutoComplete()) {
483 0 : state |= states::HASPOPUP | states::SUPPORTS_AUTOCOMPLETION;
484 0 : return state;
485 : }
486 :
487 : // Expose autocomplete state if it has associated autocomplete list.
488 0 : if (mContent->HasAttr(kNameSpaceID_None, nsGkAtoms::list))
489 0 : return state | states::SUPPORTS_AUTOCOMPLETION;
490 :
491 : // No parent can mean a fake widget created for XUL textbox. If accessible
492 : // is unattached from tree then we don't care.
493 0 : if (mParent && gIsFormFillEnabled) {
494 : // Check to see if autocompletion is allowed on this input. We don't expose
495 : // it for password fields even though the entire password can be remembered
496 : // for a page if the user asks it to be. However, the kind of autocomplete
497 : // we're talking here is based on what the user types, where a popup of
498 : // possible choices comes up.
499 0 : nsAutoString autocomplete;
500 0 : mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::autocomplete,
501 0 : autocomplete);
502 :
503 0 : if (!autocomplete.LowerCaseEqualsLiteral("off")) {
504 0 : nsCOMPtr<nsIDOMHTMLFormElement> form;
505 0 : htmlInput->GetForm(getter_AddRefs(form));
506 0 : nsCOMPtr<nsIContent> formContent(do_QueryInterface(form));
507 0 : if (formContent) {
508 0 : formContent->GetAttr(kNameSpaceID_None,
509 0 : nsGkAtoms::autocomplete, autocomplete);
510 : }
511 :
512 0 : if (!formContent || !autocomplete.LowerCaseEqualsLiteral("off"))
513 0 : state |= states::SUPPORTS_AUTOCOMPLETION;
514 : }
515 : }
516 :
517 0 : return state;
518 : }
519 :
520 : PRUint8
521 0 : nsHTMLTextFieldAccessible::ActionCount()
522 : {
523 0 : return 1;
524 : }
525 :
526 0 : NS_IMETHODIMP nsHTMLTextFieldAccessible::GetActionName(PRUint8 aIndex, nsAString& aName)
527 : {
528 0 : if (aIndex == eAction_Click) {
529 0 : aName.AssignLiteral("activate");
530 0 : return NS_OK;
531 : }
532 0 : return NS_ERROR_INVALID_ARG;
533 : }
534 :
535 0 : NS_IMETHODIMP nsHTMLTextFieldAccessible::DoAction(PRUint8 index)
536 : {
537 0 : if (index == 0) {
538 0 : nsCOMPtr<nsIDOMHTMLElement> element(do_QueryInterface(mContent));
539 0 : if ( element ) {
540 0 : return element->Focus();
541 : }
542 0 : return NS_ERROR_FAILURE;
543 : }
544 0 : return NS_ERROR_INVALID_ARG;
545 : }
546 :
547 : already_AddRefed<nsIEditor>
548 0 : nsHTMLTextFieldAccessible::GetEditor() const
549 : {
550 0 : nsCOMPtr<nsIDOMNSEditableElement> editableElt(do_QueryInterface(mContent));
551 0 : if (!editableElt)
552 0 : return nsnull;
553 :
554 : // nsGenericHTMLElement::GetEditor has a security check.
555 : // Make sure we're not restricted by the permissions of
556 : // whatever script is currently running.
557 : nsCOMPtr<nsIJSContextStack> stack =
558 0 : do_GetService("@mozilla.org/js/xpc/ContextStack;1");
559 0 : bool pushed = stack && NS_SUCCEEDED(stack->Push(nsnull));
560 :
561 0 : nsCOMPtr<nsIEditor> editor;
562 0 : editableElt->GetEditor(getter_AddRefs(editor));
563 :
564 0 : if (pushed) {
565 : JSContext* cx;
566 0 : stack->Pop(&cx);
567 0 : NS_ASSERTION(!cx, "context should be null");
568 : }
569 :
570 0 : return editor.forget();
571 : }
572 :
573 : ////////////////////////////////////////////////////////////////////////////////
574 : // nsHTMLTextFieldAccessible: Widgets
575 :
576 : bool
577 0 : nsHTMLTextFieldAccessible::IsWidget() const
578 : {
579 0 : return true;
580 : }
581 :
582 : nsAccessible*
583 0 : nsHTMLTextFieldAccessible::ContainerWidget() const
584 : {
585 0 : return mParent && mParent->Role() == roles::AUTOCOMPLETE ? mParent : nsnull;
586 : }
587 :
588 :
589 : ////////////////////////////////////////////////////////////////////////////////
590 : // nsHTMLGroupboxAccessible
591 : ////////////////////////////////////////////////////////////////////////////////
592 :
593 0 : nsHTMLFileInputAccessible::
594 : nsHTMLFileInputAccessible(nsIContent* aContent, nsDocAccessible* aDoc) :
595 0 : nsHyperTextAccessibleWrap(aContent, aDoc)
596 : {
597 0 : mFlags |= eHTMLFileInputAccessible;
598 0 : }
599 :
600 : role
601 0 : nsHTMLFileInputAccessible::NativeRole()
602 : {
603 : // JAWS wants a text container, others don't mind. No specific role in
604 : // AT APIs.
605 0 : return roles::TEXT_CONTAINER;
606 : }
607 :
608 : nsresult
609 0 : nsHTMLFileInputAccessible::HandleAccEvent(AccEvent* aEvent)
610 : {
611 0 : nsresult rv = nsHyperTextAccessibleWrap::HandleAccEvent(aEvent);
612 0 : NS_ENSURE_SUCCESS(rv, rv);
613 :
614 : // Redirect state change events for inherited states to child controls. Note,
615 : // unavailable state is not redirected. That's a standard for unavailable
616 : // state handling.
617 0 : AccStateChangeEvent* event = downcast_accEvent(aEvent);
618 0 : if (event &&
619 0 : (event->GetState() == states::BUSY ||
620 0 : event->GetState() == states::REQUIRED ||
621 0 : event->GetState() == states::HASPOPUP ||
622 0 : event->GetState() == states::INVALID)) {
623 0 : nsAccessible* input = GetChildAt(0);
624 0 : if (input && input->Role() == roles::ENTRY) {
625 : nsRefPtr<AccStateChangeEvent> childEvent =
626 : new AccStateChangeEvent(input, event->GetState(),
627 0 : event->IsStateEnabled(),
628 0 : (event->IsFromUserInput() ? eFromUserInput : eNoUserInput));
629 0 : nsEventShell::FireEvent(childEvent);
630 : }
631 :
632 0 : nsAccessible* button = GetChildAt(1);
633 0 : if (button && button->Role() == roles::PUSHBUTTON) {
634 : nsRefPtr<AccStateChangeEvent> childEvent =
635 : new AccStateChangeEvent(button, event->GetState(),
636 0 : event->IsStateEnabled(),
637 0 : (event->IsFromUserInput() ? eFromUserInput : eNoUserInput));
638 0 : nsEventShell::FireEvent(childEvent);
639 : }
640 : }
641 0 : return NS_OK;
642 : }
643 :
644 : ////////////////////////////////////////////////////////////////////////////////
645 : // nsHTMLGroupboxAccessible
646 : ////////////////////////////////////////////////////////////////////////////////
647 :
648 0 : nsHTMLGroupboxAccessible::
649 : nsHTMLGroupboxAccessible(nsIContent* aContent, nsDocAccessible* aDoc) :
650 0 : nsHyperTextAccessibleWrap(aContent, aDoc)
651 : {
652 0 : }
653 :
654 : role
655 0 : nsHTMLGroupboxAccessible::NativeRole()
656 : {
657 0 : return roles::GROUPING;
658 : }
659 :
660 : nsIContent*
661 0 : nsHTMLGroupboxAccessible::GetLegend()
662 : {
663 0 : for (nsIContent* legendContent = mContent->GetFirstChild(); legendContent;
664 0 : legendContent = legendContent->GetNextSibling()) {
665 0 : if (legendContent->NodeInfo()->Equals(nsGkAtoms::legend,
666 0 : mContent->GetNameSpaceID())) {
667 : // Either XHTML namespace or no namespace
668 0 : return legendContent;
669 : }
670 : }
671 :
672 0 : return nsnull;
673 : }
674 :
675 : nsresult
676 0 : nsHTMLGroupboxAccessible::GetNameInternal(nsAString& aName)
677 : {
678 0 : nsresult rv = nsAccessible::GetNameInternal(aName);
679 0 : NS_ENSURE_SUCCESS(rv, rv);
680 :
681 0 : if (!aName.IsEmpty())
682 0 : return NS_OK;
683 :
684 0 : nsIContent *legendContent = GetLegend();
685 0 : if (legendContent) {
686 : return nsTextEquivUtils::
687 0 : AppendTextEquivFromContent(this, legendContent, &aName);
688 : }
689 :
690 0 : return NS_OK;
691 : }
692 :
693 : Relation
694 0 : nsHTMLGroupboxAccessible::RelationByType(PRUint32 aType)
695 : {
696 0 : Relation rel = nsHyperTextAccessibleWrap::RelationByType(aType);
697 : // No override for label, so use <legend> for this <fieldset>
698 0 : if (aType == nsIAccessibleRelation::RELATION_LABELLED_BY)
699 0 : rel.AppendTarget(GetLegend());
700 :
701 : return rel;
702 : }
703 :
704 : ////////////////////////////////////////////////////////////////////////////////
705 : // nsHTMLLegendAccessible
706 : ////////////////////////////////////////////////////////////////////////////////
707 :
708 0 : nsHTMLLegendAccessible::
709 : nsHTMLLegendAccessible(nsIContent* aContent, nsDocAccessible* aDoc) :
710 0 : nsHyperTextAccessibleWrap(aContent, aDoc)
711 : {
712 0 : }
713 :
714 : Relation
715 0 : nsHTMLLegendAccessible::RelationByType(PRUint32 aType)
716 : {
717 0 : Relation rel = nsHyperTextAccessibleWrap::RelationByType(aType);
718 0 : if (aType != nsIAccessibleRelation::RELATION_LABEL_FOR)
719 0 : return rel;
720 :
721 0 : nsAccessible* groupbox = Parent();
722 0 : if (groupbox && groupbox->Role() == roles::GROUPING)
723 0 : rel.AppendTarget(groupbox);
724 :
725 0 : return rel;
726 : }
727 :
728 : role
729 0 : nsHTMLLegendAccessible::NativeRole()
730 : {
731 0 : return roles::LABEL;
732 : }
733 :
734 : ////////////////////////////////////////////////////////////////////////////////
735 : // nsHTMLFigureAccessible
736 : ////////////////////////////////////////////////////////////////////////////////
737 :
738 0 : nsHTMLFigureAccessible::
739 : nsHTMLFigureAccessible(nsIContent* aContent, nsDocAccessible* aDoc) :
740 0 : nsHyperTextAccessibleWrap(aContent, aDoc)
741 : {
742 0 : }
743 :
744 : nsresult
745 0 : nsHTMLFigureAccessible::GetAttributesInternal(nsIPersistentProperties* aAttributes)
746 : {
747 0 : nsresult rv = nsHyperTextAccessibleWrap::GetAttributesInternal(aAttributes);
748 0 : NS_ENSURE_SUCCESS(rv, rv);
749 :
750 : // Expose figure xml-role.
751 : nsAccUtils::SetAccAttr(aAttributes, nsGkAtoms::xmlroles,
752 0 : NS_LITERAL_STRING("figure"));
753 0 : return NS_OK;
754 : }
755 :
756 : role
757 0 : nsHTMLFigureAccessible::NativeRole()
758 : {
759 0 : return roles::FIGURE;
760 : }
761 :
762 : nsresult
763 0 : nsHTMLFigureAccessible::GetNameInternal(nsAString& aName)
764 : {
765 0 : nsresult rv = nsHyperTextAccessibleWrap::GetNameInternal(aName);
766 0 : NS_ENSURE_SUCCESS(rv, rv);
767 :
768 0 : if (!aName.IsEmpty())
769 0 : return NS_OK;
770 :
771 0 : nsIContent* captionContent = Caption();
772 0 : if (captionContent) {
773 : return nsTextEquivUtils::
774 0 : AppendTextEquivFromContent(this, captionContent, &aName);
775 : }
776 :
777 0 : return NS_OK;
778 : }
779 :
780 : Relation
781 0 : nsHTMLFigureAccessible::RelationByType(PRUint32 aType)
782 : {
783 0 : Relation rel = nsHyperTextAccessibleWrap::RelationByType(aType);
784 0 : if (aType == nsIAccessibleRelation::RELATION_LABELLED_BY)
785 0 : rel.AppendTarget(Caption());
786 :
787 : return rel;
788 : }
789 :
790 : nsIContent*
791 0 : nsHTMLFigureAccessible::Caption() const
792 : {
793 0 : for (nsIContent* childContent = mContent->GetFirstChild(); childContent;
794 0 : childContent = childContent->GetNextSibling()) {
795 0 : if (childContent->NodeInfo()->Equals(nsGkAtoms::figcaption,
796 0 : mContent->GetNameSpaceID())) {
797 0 : return childContent;
798 : }
799 : }
800 :
801 0 : return nsnull;
802 : }
803 :
804 : ////////////////////////////////////////////////////////////////////////////////
805 : // nsHTMLFigcaptionAccessible
806 : ////////////////////////////////////////////////////////////////////////////////
807 :
808 0 : nsHTMLFigcaptionAccessible::
809 : nsHTMLFigcaptionAccessible(nsIContent* aContent, nsDocAccessible* aDoc) :
810 0 : nsHyperTextAccessibleWrap(aContent, aDoc)
811 : {
812 0 : }
813 :
814 : role
815 0 : nsHTMLFigcaptionAccessible::NativeRole()
816 : {
817 0 : return roles::CAPTION;
818 : }
819 :
820 : Relation
821 0 : nsHTMLFigcaptionAccessible::RelationByType(PRUint32 aType)
822 : {
823 0 : Relation rel = nsHyperTextAccessibleWrap::RelationByType(aType);
824 0 : if (aType != nsIAccessibleRelation::RELATION_LABEL_FOR)
825 0 : return rel;
826 :
827 0 : nsAccessible* figure = Parent();
828 0 : if (figure &&
829 : figure->GetContent()->NodeInfo()->Equals(nsGkAtoms::figure,
830 0 : mContent->GetNameSpaceID())) {
831 0 : rel.AppendTarget(figure);
832 : }
833 :
834 0 : return rel;
835 : }
|