Wed, 31 Dec 2014 06:09:35 +0100
Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 #include "HTMLFormControlAccessible.h"
8 #include "Accessible-inl.h"
9 #include "nsAccUtils.h"
10 #include "nsEventShell.h"
11 #include "nsTextEquivUtils.h"
12 #include "Relation.h"
13 #include "Role.h"
14 #include "States.h"
16 #include "nsContentList.h"
17 #include "mozilla/dom/HTMLInputElement.h"
18 #include "nsIAccessibleRelation.h"
19 #include "nsIDOMNSEditableElement.h"
20 #include "nsIDOMHTMLTextAreaElement.h"
21 #include "nsIEditor.h"
22 #include "nsIFormControl.h"
23 #include "nsIPersistentProperties2.h"
24 #include "nsISelectionController.h"
25 #include "nsIServiceManager.h"
26 #include "nsITextControlFrame.h"
27 #include "nsNameSpaceManager.h"
28 #include "mozilla/dom/ScriptSettings.h"
30 #include "mozilla/EventStates.h"
31 #include "mozilla/FloatingPoint.h"
32 #include "mozilla/Preferences.h"
34 using namespace mozilla;
35 using namespace mozilla::dom;
36 using namespace mozilla::a11y;
38 ////////////////////////////////////////////////////////////////////////////////
39 // HTMLCheckboxAccessible
40 ////////////////////////////////////////////////////////////////////////////////
42 role
43 HTMLCheckboxAccessible::NativeRole()
44 {
45 return roles::CHECKBUTTON;
46 }
48 uint8_t
49 HTMLCheckboxAccessible::ActionCount()
50 {
51 return 1;
52 }
54 NS_IMETHODIMP
55 HTMLCheckboxAccessible::GetActionName(uint8_t aIndex, nsAString& aName)
56 {
57 if (aIndex == eAction_Click) { // 0 is the magic value for default action
58 // cycle, check or uncheck
59 uint64_t state = NativeState();
61 if (state & states::CHECKED)
62 aName.AssignLiteral("uncheck");
63 else if (state & states::MIXED)
64 aName.AssignLiteral("cycle");
65 else
66 aName.AssignLiteral("check");
68 return NS_OK;
69 }
70 return NS_ERROR_INVALID_ARG;
71 }
73 NS_IMETHODIMP
74 HTMLCheckboxAccessible::DoAction(uint8_t aIndex)
75 {
76 if (aIndex != 0)
77 return NS_ERROR_INVALID_ARG;
79 DoCommand();
80 return NS_OK;
81 }
83 uint64_t
84 HTMLCheckboxAccessible::NativeState()
85 {
86 uint64_t state = LeafAccessible::NativeState();
88 state |= states::CHECKABLE;
89 HTMLInputElement* input = HTMLInputElement::FromContent(mContent);
90 if (!input)
91 return state;
93 if (input->Indeterminate())
94 return state | states::MIXED;
96 if (input->Checked())
97 return state | states::CHECKED;
99 return state;
100 }
102 ////////////////////////////////////////////////////////////////////////////////
103 // HTMLCheckboxAccessible: Widgets
105 bool
106 HTMLCheckboxAccessible::IsWidget() const
107 {
108 return true;
109 }
112 ////////////////////////////////////////////////////////////////////////////////
113 // HTMLRadioButtonAccessible
114 ////////////////////////////////////////////////////////////////////////////////
116 uint64_t
117 HTMLRadioButtonAccessible::NativeState()
118 {
119 uint64_t state = AccessibleWrap::NativeState();
121 state |= states::CHECKABLE;
123 HTMLInputElement* input = HTMLInputElement::FromContent(mContent);
124 if (input && input->Checked())
125 state |= states::CHECKED;
127 return state;
128 }
130 void
131 HTMLRadioButtonAccessible::GetPositionAndSizeInternal(int32_t* aPosInSet,
132 int32_t* aSetSize)
133 {
134 int32_t namespaceId = mContent->NodeInfo()->NamespaceID();
135 nsAutoString tagName;
136 mContent->NodeInfo()->GetName(tagName);
138 nsAutoString type;
139 mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::type, type);
140 nsAutoString name;
141 mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::name, name);
143 nsRefPtr<nsContentList> inputElms;
145 nsCOMPtr<nsIFormControl> formControlNode(do_QueryInterface(mContent));
146 dom::Element* formElm = formControlNode->GetFormElement();
147 if (formElm)
148 inputElms = NS_GetContentList(formElm, namespaceId, tagName);
149 else
150 inputElms = NS_GetContentList(mContent->OwnerDoc(), namespaceId, tagName);
151 NS_ENSURE_TRUE_VOID(inputElms);
153 uint32_t inputCount = inputElms->Length(false);
155 // Compute posinset and setsize.
156 int32_t indexOf = 0;
157 int32_t count = 0;
159 for (uint32_t index = 0; index < inputCount; index++) {
160 nsIContent* inputElm = inputElms->Item(index, false);
161 if (inputElm->AttrValueIs(kNameSpaceID_None, nsGkAtoms::type,
162 type, eCaseMatters) &&
163 inputElm->AttrValueIs(kNameSpaceID_None, nsGkAtoms::name,
164 name, eCaseMatters) && mDoc->HasAccessible(inputElm)) {
165 count++;
166 if (inputElm == mContent)
167 indexOf = count;
168 }
169 }
171 *aPosInSet = indexOf;
172 *aSetSize = count;
173 }
175 ////////////////////////////////////////////////////////////////////////////////
176 // HTMLButtonAccessible
177 ////////////////////////////////////////////////////////////////////////////////
179 HTMLButtonAccessible::
180 HTMLButtonAccessible(nsIContent* aContent, DocAccessible* aDoc) :
181 HyperTextAccessibleWrap(aContent, aDoc)
182 {
183 mGenericTypes |= eButton;
184 }
186 uint8_t
187 HTMLButtonAccessible::ActionCount()
188 {
189 return 1;
190 }
192 NS_IMETHODIMP
193 HTMLButtonAccessible::GetActionName(uint8_t aIndex, nsAString& aName)
194 {
195 if (aIndex == eAction_Click) {
196 aName.AssignLiteral("press");
197 return NS_OK;
198 }
199 return NS_ERROR_INVALID_ARG;
200 }
202 NS_IMETHODIMP
203 HTMLButtonAccessible::DoAction(uint8_t aIndex)
204 {
205 if (aIndex != eAction_Click)
206 return NS_ERROR_INVALID_ARG;
208 DoCommand();
209 return NS_OK;
210 }
212 uint64_t
213 HTMLButtonAccessible::State()
214 {
215 uint64_t state = HyperTextAccessibleWrap::State();
216 if (state == states::DEFUNCT)
217 return state;
219 // Inherit states from input@type="file" suitable for the button. Note,
220 // no special processing for unavailable state since inheritance is supplied
221 // other code paths.
222 if (mParent && mParent->IsHTMLFileInput()) {
223 uint64_t parentState = mParent->State();
224 state |= parentState & (states::BUSY | states::REQUIRED |
225 states::HASPOPUP | states::INVALID);
226 }
228 return state;
229 }
231 uint64_t
232 HTMLButtonAccessible::NativeState()
233 {
234 uint64_t state = HyperTextAccessibleWrap::NativeState();
236 EventStates elmState = mContent->AsElement()->State();
237 if (elmState.HasState(NS_EVENT_STATE_DEFAULT))
238 state |= states::DEFAULT;
240 return state;
241 }
243 role
244 HTMLButtonAccessible::NativeRole()
245 {
246 return roles::PUSHBUTTON;
247 }
249 ENameValueFlag
250 HTMLButtonAccessible::NativeName(nsString& aName)
251 {
252 // No need to check @value attribute for buttons since this attribute results
253 // in native anonymous text node and the name is calculated from subtree.
254 // The same magic works for @alt and @value attributes in case of type="image"
255 // element that has no valid @src (note if input@type="image" has an image
256 // then neither @alt nor @value attributes are used to generate a visual label
257 // and thus we need to obtain the accessible name directly from attribute
258 // value). Also the same algorithm works in case of default labels for
259 // type="submit"/"reset"/"image" elements.
261 ENameValueFlag nameFlag = Accessible::NativeName(aName);
262 if (!aName.IsEmpty() || mContent->Tag() != nsGkAtoms::input ||
263 !mContent->AttrValueIs(kNameSpaceID_None, nsGkAtoms::type,
264 nsGkAtoms::image, eCaseMatters))
265 return nameFlag;
267 if (!mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::alt, aName))
268 mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::value, aName);
270 aName.CompressWhitespace();
271 return eNameOK;
272 }
274 ////////////////////////////////////////////////////////////////////////////////
275 // HTMLButtonAccessible: Widgets
277 bool
278 HTMLButtonAccessible::IsWidget() const
279 {
280 return true;
281 }
284 ////////////////////////////////////////////////////////////////////////////////
285 // HTMLTextFieldAccessible
286 ////////////////////////////////////////////////////////////////////////////////
288 HTMLTextFieldAccessible::
289 HTMLTextFieldAccessible(nsIContent* aContent, DocAccessible* aDoc) :
290 HyperTextAccessibleWrap(aContent, aDoc)
291 {
292 mType = eHTMLTextFieldType;
293 }
295 NS_IMPL_ISUPPORTS_INHERITED(HTMLTextFieldAccessible,
296 Accessible,
297 nsIAccessibleText,
298 nsIAccessibleEditableText)
300 role
301 HTMLTextFieldAccessible::NativeRole()
302 {
303 if (mContent->AttrValueIs(kNameSpaceID_None, nsGkAtoms::type,
304 nsGkAtoms::password, eIgnoreCase)) {
305 return roles::PASSWORD_TEXT;
306 }
308 return roles::ENTRY;
309 }
311 already_AddRefed<nsIPersistentProperties>
312 HTMLTextFieldAccessible::NativeAttributes()
313 {
314 nsCOMPtr<nsIPersistentProperties> attributes =
315 HyperTextAccessibleWrap::NativeAttributes();
317 // Expose type for text input elements as it gives some useful context,
318 // especially for mobile.
319 nsAutoString type;
320 if (mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::type, type))
321 nsAccUtils::SetAccAttr(attributes, nsGkAtoms::textInputType, type);
323 return attributes.forget();
324 }
326 ENameValueFlag
327 HTMLTextFieldAccessible::NativeName(nsString& aName)
328 {
329 ENameValueFlag nameFlag = Accessible::NativeName(aName);
330 if (!aName.IsEmpty())
331 return nameFlag;
333 // If part of compound of XUL widget then grab a name from XUL widget element.
334 nsIContent* widgetElm = XULWidgetElm();
335 if (widgetElm)
336 XULElmName(mDoc, widgetElm, aName);
338 if (!aName.IsEmpty())
339 return eNameOK;
341 // text inputs and textareas might have useful placeholder text
342 mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::placeholder, aName);
343 return eNameOK;
344 }
346 void
347 HTMLTextFieldAccessible::Value(nsString& aValue)
348 {
349 aValue.Truncate();
350 if (NativeState() & states::PROTECTED) // Don't return password text!
351 return;
353 nsCOMPtr<nsIDOMHTMLTextAreaElement> textArea(do_QueryInterface(mContent));
354 if (textArea) {
355 textArea->GetValue(aValue);
356 return;
357 }
359 HTMLInputElement* input = HTMLInputElement::FromContent(mContent);
360 if (input)
361 input->GetValue(aValue);
362 }
364 void
365 HTMLTextFieldAccessible::ApplyARIAState(uint64_t* aState) const
366 {
367 HyperTextAccessibleWrap::ApplyARIAState(aState);
368 aria::MapToState(aria::eARIAAutoComplete, mContent->AsElement(), aState);
370 // If part of compound of XUL widget then pick up ARIA stuff from XUL widget
371 // element.
372 nsIContent* widgetElm = XULWidgetElm();
373 if (widgetElm)
374 aria::MapToState(aria::eARIAAutoComplete, widgetElm->AsElement(), aState);
375 }
377 uint64_t
378 HTMLTextFieldAccessible::NativeState()
379 {
380 uint64_t state = HyperTextAccessibleWrap::NativeState();
382 // Text fields are always editable, even if they are also read only or
383 // disabled.
384 state |= states::EDITABLE;
386 // can be focusable, focused, protected. readonly, unavailable, selected
387 if (mContent->AttrValueIs(kNameSpaceID_None, nsGkAtoms::type,
388 nsGkAtoms::password, eIgnoreCase)) {
389 state |= states::PROTECTED;
390 }
392 if (mContent->HasAttr(kNameSpaceID_None, nsGkAtoms::readonly)) {
393 state |= states::READONLY;
394 }
396 // Is it an <input> or a <textarea> ?
397 HTMLInputElement* input = HTMLInputElement::FromContent(mContent);
398 state |= input && input->IsSingleLineTextControl() ?
399 states::SINGLE_LINE : states::MULTI_LINE;
401 if (state & (states::PROTECTED | states::MULTI_LINE | states::READONLY |
402 states::UNAVAILABLE))
403 return state;
405 // Expose autocomplete states if this input is part of autocomplete widget.
406 Accessible* widget = ContainerWidget();
407 if (widget && widget-IsAutoComplete()) {
408 state |= states::HASPOPUP | states::SUPPORTS_AUTOCOMPLETION;
409 return state;
410 }
412 // Expose autocomplete state if it has associated autocomplete list.
413 if (mContent->HasAttr(kNameSpaceID_None, nsGkAtoms::list))
414 return state | states::SUPPORTS_AUTOCOMPLETION | states::HASPOPUP;
416 // Ordinal XUL textboxes don't support autocomplete.
417 if (!XULWidgetElm() && Preferences::GetBool("browser.formfill.enable")) {
418 // Check to see if autocompletion is allowed on this input. We don't expose
419 // it for password fields even though the entire password can be remembered
420 // for a page if the user asks it to be. However, the kind of autocomplete
421 // we're talking here is based on what the user types, where a popup of
422 // possible choices comes up.
423 nsAutoString autocomplete;
424 mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::autocomplete,
425 autocomplete);
427 if (!autocomplete.LowerCaseEqualsLiteral("off")) {
428 nsIContent* formContent = input->GetFormElement();
429 if (formContent) {
430 formContent->GetAttr(kNameSpaceID_None,
431 nsGkAtoms::autocomplete, autocomplete);
432 }
434 if (!formContent || !autocomplete.LowerCaseEqualsLiteral("off"))
435 state |= states::SUPPORTS_AUTOCOMPLETION;
436 }
437 }
439 return state;
440 }
442 uint8_t
443 HTMLTextFieldAccessible::ActionCount()
444 {
445 return 1;
446 }
448 NS_IMETHODIMP
449 HTMLTextFieldAccessible::GetActionName(uint8_t aIndex, nsAString& aName)
450 {
451 if (aIndex == eAction_Click) {
452 aName.AssignLiteral("activate");
453 return NS_OK;
454 }
455 return NS_ERROR_INVALID_ARG;
456 }
458 NS_IMETHODIMP
459 HTMLTextFieldAccessible::DoAction(uint8_t aIndex)
460 {
461 if (aIndex == 0)
462 return TakeFocus();
464 return NS_ERROR_INVALID_ARG;
465 }
467 already_AddRefed<nsIEditor>
468 HTMLTextFieldAccessible::GetEditor() const
469 {
470 nsCOMPtr<nsIDOMNSEditableElement> editableElt(do_QueryInterface(mContent));
471 if (!editableElt)
472 return nullptr;
474 // nsGenericHTMLElement::GetEditor has a security check.
475 // Make sure we're not restricted by the permissions of
476 // whatever script is currently running.
477 mozilla::dom::AutoNoJSAPI nojsapi;
479 nsCOMPtr<nsIEditor> editor;
480 editableElt->GetEditor(getter_AddRefs(editor));
482 return editor.forget();
483 }
485 ////////////////////////////////////////////////////////////////////////////////
486 // HTMLTextFieldAccessible: Widgets
488 bool
489 HTMLTextFieldAccessible::IsWidget() const
490 {
491 return true;
492 }
494 Accessible*
495 HTMLTextFieldAccessible::ContainerWidget() const
496 {
497 return mParent && mParent->Role() == roles::AUTOCOMPLETE ? mParent : nullptr;
498 }
501 ////////////////////////////////////////////////////////////////////////////////
502 // HTMLFileInputAccessible
503 ////////////////////////////////////////////////////////////////////////////////
505 HTMLFileInputAccessible::
506 HTMLFileInputAccessible(nsIContent* aContent, DocAccessible* aDoc) :
507 HyperTextAccessibleWrap(aContent, aDoc)
508 {
509 mType = eHTMLFileInputType;
510 }
512 role
513 HTMLFileInputAccessible::NativeRole()
514 {
515 // JAWS wants a text container, others don't mind. No specific role in
516 // AT APIs.
517 return roles::TEXT_CONTAINER;
518 }
520 nsresult
521 HTMLFileInputAccessible::HandleAccEvent(AccEvent* aEvent)
522 {
523 nsresult rv = HyperTextAccessibleWrap::HandleAccEvent(aEvent);
524 NS_ENSURE_SUCCESS(rv, rv);
526 // Redirect state change events for inherited states to child controls. Note,
527 // unavailable state is not redirected. That's a standard for unavailable
528 // state handling.
529 AccStateChangeEvent* event = downcast_accEvent(aEvent);
530 if (event &&
531 (event->GetState() == states::BUSY ||
532 event->GetState() == states::REQUIRED ||
533 event->GetState() == states::HASPOPUP ||
534 event->GetState() == states::INVALID)) {
535 Accessible* button = GetChildAt(0);
536 if (button && button->Role() == roles::PUSHBUTTON) {
537 nsRefPtr<AccStateChangeEvent> childEvent =
538 new AccStateChangeEvent(button, event->GetState(),
539 event->IsStateEnabled(), event->FromUserInput());
540 nsEventShell::FireEvent(childEvent);
541 }
542 }
544 return NS_OK;
545 }
548 ////////////////////////////////////////////////////////////////////////////////
549 // HTMLSpinnerAccessible
550 ////////////////////////////////////////////////////////////////////////////////
552 role
553 HTMLSpinnerAccessible::NativeRole()
554 {
555 return roles::SPINBUTTON;
556 }
558 void
559 HTMLSpinnerAccessible::Value(nsString& aValue)
560 {
561 AccessibleWrap::Value(aValue);
562 if (!aValue.IsEmpty())
563 return;
565 HTMLInputElement::FromContent(mContent)->GetValue(aValue);
566 }
568 double
569 HTMLSpinnerAccessible::MaxValue() const
570 {
571 double value = AccessibleWrap::MaxValue();
572 if (!IsNaN(value))
573 return value;
575 return HTMLInputElement::FromContent(mContent)->GetMaximum().toDouble();
576 }
579 double
580 HTMLSpinnerAccessible::MinValue() const
581 {
582 double value = AccessibleWrap::MinValue();
583 if (!IsNaN(value))
584 return value;
586 return HTMLInputElement::FromContent(mContent)->GetMinimum().toDouble();
587 }
589 double
590 HTMLSpinnerAccessible::Step() const
591 {
592 double value = AccessibleWrap::Step();
593 if (!IsNaN(value))
594 return value;
596 return HTMLInputElement::FromContent(mContent)->GetStep().toDouble();
597 }
599 double
600 HTMLSpinnerAccessible::CurValue() const
601 {
602 double value = AccessibleWrap::CurValue();
603 if (!IsNaN(value))
604 return value;
606 return HTMLInputElement::FromContent(mContent)->GetValueAsDecimal().toDouble();
607 }
609 bool
610 HTMLSpinnerAccessible::SetCurValue(double aValue)
611 {
612 ErrorResult er;
613 HTMLInputElement::FromContent(mContent)->SetValueAsNumber(aValue, er);
614 return !er.Failed();
615 }
618 ////////////////////////////////////////////////////////////////////////////////
619 // HTMLRangeAccessible
620 ////////////////////////////////////////////////////////////////////////////////
622 role
623 HTMLRangeAccessible::NativeRole()
624 {
625 return roles::SLIDER;
626 }
628 bool
629 HTMLRangeAccessible::IsWidget() const
630 {
631 return true;
632 }
634 void
635 HTMLRangeAccessible::Value(nsString& aValue)
636 {
637 LeafAccessible::Value(aValue);
638 if (!aValue.IsEmpty())
639 return;
641 HTMLInputElement::FromContent(mContent)->GetValue(aValue);
642 }
644 double
645 HTMLRangeAccessible::MaxValue() const
646 {
647 double value = LeafAccessible::MaxValue();
648 if (!IsNaN(value))
649 return value;
651 return HTMLInputElement::FromContent(mContent)->GetMaximum().toDouble();
652 }
654 double
655 HTMLRangeAccessible::MinValue() const
656 {
657 double value = LeafAccessible::MinValue();
658 if (!IsNaN(value))
659 return value;
661 return HTMLInputElement::FromContent(mContent)->GetMinimum().toDouble();
662 }
664 double
665 HTMLRangeAccessible::Step() const
666 {
667 double value = LeafAccessible::Step();
668 if (!IsNaN(value))
669 return value;
671 return HTMLInputElement::FromContent(mContent)->GetStep().toDouble();
672 }
674 double
675 HTMLRangeAccessible::CurValue() const
676 {
677 double value = LeafAccessible::CurValue();
678 if (!IsNaN(value))
679 return value;
681 return HTMLInputElement::FromContent(mContent)->GetValueAsDecimal().toDouble();
682 }
684 bool
685 HTMLRangeAccessible::SetCurValue(double aValue)
686 {
687 ErrorResult er;
688 HTMLInputElement::FromContent(mContent)->SetValueAsNumber(aValue, er);
689 return !er.Failed();
690 }
693 ////////////////////////////////////////////////////////////////////////////////
694 // HTMLGroupboxAccessible
695 ////////////////////////////////////////////////////////////////////////////////
697 HTMLGroupboxAccessible::
698 HTMLGroupboxAccessible(nsIContent* aContent, DocAccessible* aDoc) :
699 HyperTextAccessibleWrap(aContent, aDoc)
700 {
701 }
703 role
704 HTMLGroupboxAccessible::NativeRole()
705 {
706 return roles::GROUPING;
707 }
709 nsIContent*
710 HTMLGroupboxAccessible::GetLegend()
711 {
712 for (nsIContent* legendContent = mContent->GetFirstChild(); legendContent;
713 legendContent = legendContent->GetNextSibling()) {
714 if (legendContent->NodeInfo()->Equals(nsGkAtoms::legend,
715 mContent->GetNameSpaceID())) {
716 // Either XHTML namespace or no namespace
717 return legendContent;
718 }
719 }
721 return nullptr;
722 }
724 ENameValueFlag
725 HTMLGroupboxAccessible::NativeName(nsString& aName)
726 {
727 ENameValueFlag nameFlag = Accessible::NativeName(aName);
728 if (!aName.IsEmpty())
729 return nameFlag;
731 nsIContent* legendContent = GetLegend();
732 if (legendContent)
733 nsTextEquivUtils::AppendTextEquivFromContent(this, legendContent, &aName);
735 return eNameOK;
736 }
738 Relation
739 HTMLGroupboxAccessible::RelationByType(RelationType aType)
740 {
741 Relation rel = HyperTextAccessibleWrap::RelationByType(aType);
742 // No override for label, so use <legend> for this <fieldset>
743 if (aType == RelationType::LABELLED_BY)
744 rel.AppendTarget(mDoc, GetLegend());
746 return rel;
747 }
749 ////////////////////////////////////////////////////////////////////////////////
750 // HTMLLegendAccessible
751 ////////////////////////////////////////////////////////////////////////////////
753 HTMLLegendAccessible::
754 HTMLLegendAccessible(nsIContent* aContent, DocAccessible* aDoc) :
755 HyperTextAccessibleWrap(aContent, aDoc)
756 {
757 }
759 Relation
760 HTMLLegendAccessible::RelationByType(RelationType aType)
761 {
762 Relation rel = HyperTextAccessibleWrap::RelationByType(aType);
763 if (aType != RelationType::LABEL_FOR)
764 return rel;
766 Accessible* groupbox = Parent();
767 if (groupbox && groupbox->Role() == roles::GROUPING)
768 rel.AppendTarget(groupbox);
770 return rel;
771 }
773 role
774 HTMLLegendAccessible::NativeRole()
775 {
776 return roles::LABEL;
777 }
779 ////////////////////////////////////////////////////////////////////////////////
780 // HTMLFigureAccessible
781 ////////////////////////////////////////////////////////////////////////////////
783 HTMLFigureAccessible::
784 HTMLFigureAccessible(nsIContent* aContent, DocAccessible* aDoc) :
785 HyperTextAccessibleWrap(aContent, aDoc)
786 {
787 }
789 already_AddRefed<nsIPersistentProperties>
790 HTMLFigureAccessible::NativeAttributes()
791 {
792 nsCOMPtr<nsIPersistentProperties> attributes =
793 HyperTextAccessibleWrap::NativeAttributes();
795 // Expose figure xml-role.
796 nsAccUtils::SetAccAttr(attributes, nsGkAtoms::xmlroles,
797 NS_LITERAL_STRING("figure"));
798 return attributes.forget();
799 }
801 role
802 HTMLFigureAccessible::NativeRole()
803 {
804 return roles::FIGURE;
805 }
807 ENameValueFlag
808 HTMLFigureAccessible::NativeName(nsString& aName)
809 {
810 ENameValueFlag nameFlag = HyperTextAccessibleWrap::NativeName(aName);
811 if (!aName.IsEmpty())
812 return nameFlag;
814 nsIContent* captionContent = Caption();
815 if (captionContent)
816 nsTextEquivUtils::AppendTextEquivFromContent(this, captionContent, &aName);
818 return eNameOK;
819 }
821 Relation
822 HTMLFigureAccessible::RelationByType(RelationType aType)
823 {
824 Relation rel = HyperTextAccessibleWrap::RelationByType(aType);
825 if (aType == RelationType::LABELLED_BY)
826 rel.AppendTarget(mDoc, Caption());
828 return rel;
829 }
831 nsIContent*
832 HTMLFigureAccessible::Caption() const
833 {
834 for (nsIContent* childContent = mContent->GetFirstChild(); childContent;
835 childContent = childContent->GetNextSibling()) {
836 if (childContent->NodeInfo()->Equals(nsGkAtoms::figcaption,
837 mContent->GetNameSpaceID())) {
838 return childContent;
839 }
840 }
842 return nullptr;
843 }
845 ////////////////////////////////////////////////////////////////////////////////
846 // HTMLFigcaptionAccessible
847 ////////////////////////////////////////////////////////////////////////////////
849 HTMLFigcaptionAccessible::
850 HTMLFigcaptionAccessible(nsIContent* aContent, DocAccessible* aDoc) :
851 HyperTextAccessibleWrap(aContent, aDoc)
852 {
853 }
855 role
856 HTMLFigcaptionAccessible::NativeRole()
857 {
858 return roles::CAPTION;
859 }
861 Relation
862 HTMLFigcaptionAccessible::RelationByType(RelationType aType)
863 {
864 Relation rel = HyperTextAccessibleWrap::RelationByType(aType);
865 if (aType != RelationType::LABEL_FOR)
866 return rel;
868 Accessible* figure = Parent();
869 if (figure &&
870 figure->GetContent()->NodeInfo()->Equals(nsGkAtoms::figure,
871 mContent->GetNameSpaceID())) {
872 rel.AppendTarget(figure);
873 }
875 return rel;
876 }