Fix typo in 9b54bd30006c008b4a951331b273613d5bac3abf
[pm.git] / accessible / html / HTMLFormControlAccessible.cpp
blob0431388d56b4b7dd99c9577ed9240026f3e9e531
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 "nsIDOMNSEditableElement.h"
19 #include "nsIDOMHTMLTextAreaElement.h"
20 #include "nsIEditor.h"
21 #include "nsIFormControl.h"
22 #include "nsIPersistentProperties2.h"
23 #include "nsISelectionController.h"
24 #include "nsIServiceManager.h"
25 #include "nsITextControlFrame.h"
26 #include "nsNameSpaceManager.h"
27 #include "mozilla/dom/ScriptSettings.h"
29 #include "mozilla/EventStates.h"
30 #include "mozilla/FloatingPoint.h"
31 #include "mozilla/Preferences.h"
33 using namespace mozilla;
34 using namespace mozilla::dom;
35 using namespace mozilla::a11y;
37 ////////////////////////////////////////////////////////////////////////////////
38 // HTMLCheckboxAccessible
39 ////////////////////////////////////////////////////////////////////////////////
41 role
42 HTMLCheckboxAccessible::NativeRole()
44 return roles::CHECKBUTTON;
47 uint8_t
48 HTMLCheckboxAccessible::ActionCount()
50 return 1;
53 void
54 HTMLCheckboxAccessible::ActionNameAt(uint8_t aIndex, nsAString& aName)
56 if (aIndex == eAction_Click) { // 0 is the magic value for default action
57 uint64_t state = NativeState();
58 if (state & states::CHECKED)
59 aName.AssignLiteral("uncheck");
60 else if (state & states::MIXED)
61 aName.AssignLiteral("cycle");
62 else
63 aName.AssignLiteral("check");
67 bool
68 HTMLCheckboxAccessible::DoAction(uint8_t aIndex)
70 if (aIndex != 0)
71 return false;
73 DoCommand();
74 return true;
77 uint64_t
78 HTMLCheckboxAccessible::NativeState()
80 uint64_t state = LeafAccessible::NativeState();
82 state |= states::CHECKABLE;
83 HTMLInputElement* input = HTMLInputElement::FromContent(mContent);
84 if (!input)
85 return state;
87 if (input->Indeterminate())
88 return state | states::MIXED;
90 if (input->Checked())
91 return state | states::CHECKED;
93 return state;
96 ////////////////////////////////////////////////////////////////////////////////
97 // HTMLCheckboxAccessible: Widgets
99 bool
100 HTMLCheckboxAccessible::IsWidget() const
102 return true;
106 ////////////////////////////////////////////////////////////////////////////////
107 // HTMLRadioButtonAccessible
108 ////////////////////////////////////////////////////////////////////////////////
110 uint64_t
111 HTMLRadioButtonAccessible::NativeState()
113 uint64_t state = AccessibleWrap::NativeState();
115 state |= states::CHECKABLE;
117 HTMLInputElement* input = HTMLInputElement::FromContent(mContent);
118 if (input && input->Checked())
119 state |= states::CHECKED;
121 return state;
124 void
125 HTMLRadioButtonAccessible::GetPositionAndSizeInternal(int32_t* aPosInSet,
126 int32_t* aSetSize)
128 int32_t namespaceId = mContent->NodeInfo()->NamespaceID();
129 nsAutoString tagName;
130 mContent->NodeInfo()->GetName(tagName);
132 nsAutoString type;
133 mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::type, type);
134 nsAutoString name;
135 mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::name, name);
137 nsRefPtr<nsContentList> inputElms;
139 nsCOMPtr<nsIFormControl> formControlNode(do_QueryInterface(mContent));
140 dom::Element* formElm = formControlNode->GetFormElement();
141 if (formElm)
142 inputElms = NS_GetContentList(formElm, namespaceId, tagName);
143 else
144 inputElms = NS_GetContentList(mContent->OwnerDoc(), namespaceId, tagName);
145 NS_ENSURE_TRUE_VOID(inputElms);
147 uint32_t inputCount = inputElms->Length(false);
149 // Compute posinset and setsize.
150 int32_t indexOf = 0;
151 int32_t count = 0;
153 for (uint32_t index = 0; index < inputCount; index++) {
154 nsIContent* inputElm = inputElms->Item(index, false);
155 if (inputElm->AttrValueIs(kNameSpaceID_None, nsGkAtoms::type,
156 type, eCaseMatters) &&
157 inputElm->AttrValueIs(kNameSpaceID_None, nsGkAtoms::name,
158 name, eCaseMatters) && mDoc->HasAccessible(inputElm)) {
159 count++;
160 if (inputElm == mContent)
161 indexOf = count;
165 *aPosInSet = indexOf;
166 *aSetSize = count;
169 ////////////////////////////////////////////////////////////////////////////////
170 // HTMLButtonAccessible
171 ////////////////////////////////////////////////////////////////////////////////
173 HTMLButtonAccessible::
174 HTMLButtonAccessible(nsIContent* aContent, DocAccessible* aDoc) :
175 HyperTextAccessibleWrap(aContent, aDoc)
177 mGenericTypes |= eButton;
180 uint8_t
181 HTMLButtonAccessible::ActionCount()
183 return 1;
186 void
187 HTMLButtonAccessible::ActionNameAt(uint8_t aIndex, nsAString& aName)
189 if (aIndex == eAction_Click)
190 aName.AssignLiteral("press");
193 bool
194 HTMLButtonAccessible::DoAction(uint8_t aIndex)
196 if (aIndex != eAction_Click)
197 return false;
199 DoCommand();
200 return true;
203 uint64_t
204 HTMLButtonAccessible::State()
206 uint64_t state = HyperTextAccessibleWrap::State();
207 if (state == states::DEFUNCT)
208 return state;
210 // Inherit states from input@type="file" suitable for the button. Note,
211 // no special processing for unavailable state since inheritance is supplied
212 // other code paths.
213 if (mParent && mParent->IsHTMLFileInput()) {
214 uint64_t parentState = mParent->State();
215 state |= parentState & (states::BUSY | states::REQUIRED |
216 states::HASPOPUP | states::INVALID);
219 return state;
222 uint64_t
223 HTMLButtonAccessible::NativeState()
225 uint64_t state = HyperTextAccessibleWrap::NativeState();
227 EventStates elmState = mContent->AsElement()->State();
228 if (elmState.HasState(NS_EVENT_STATE_DEFAULT))
229 state |= states::DEFAULT;
231 return state;
234 role
235 HTMLButtonAccessible::NativeRole()
237 return roles::PUSHBUTTON;
240 ENameValueFlag
241 HTMLButtonAccessible::NativeName(nsString& aName)
243 // No need to check @value attribute for buttons since this attribute results
244 // in native anonymous text node and the name is calculated from subtree.
245 // The same magic works for @alt and @value attributes in case of type="image"
246 // element that has no valid @src (note if input@type="image" has an image
247 // then neither @alt nor @value attributes are used to generate a visual label
248 // and thus we need to obtain the accessible name directly from attribute
249 // value). Also the same algorithm works in case of default labels for
250 // type="submit"/"reset"/"image" elements.
252 ENameValueFlag nameFlag = Accessible::NativeName(aName);
253 if (!aName.IsEmpty() || mContent->Tag() != nsGkAtoms::input ||
254 !mContent->AttrValueIs(kNameSpaceID_None, nsGkAtoms::type,
255 nsGkAtoms::image, eCaseMatters))
256 return nameFlag;
258 if (!mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::alt, aName))
259 mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::value, aName);
261 aName.CompressWhitespace();
262 return eNameOK;
265 ////////////////////////////////////////////////////////////////////////////////
266 // HTMLButtonAccessible: Widgets
268 bool
269 HTMLButtonAccessible::IsWidget() const
271 return true;
275 ////////////////////////////////////////////////////////////////////////////////
276 // HTMLTextFieldAccessible
277 ////////////////////////////////////////////////////////////////////////////////
279 HTMLTextFieldAccessible::
280 HTMLTextFieldAccessible(nsIContent* aContent, DocAccessible* aDoc) :
281 HyperTextAccessibleWrap(aContent, aDoc)
283 mType = eHTMLTextFieldType;
286 NS_IMPL_ISUPPORTS_INHERITED0(HTMLTextFieldAccessible,
287 HyperTextAccessible)
289 role
290 HTMLTextFieldAccessible::NativeRole()
292 if (mContent->AttrValueIs(kNameSpaceID_None, nsGkAtoms::type,
293 nsGkAtoms::password, eIgnoreCase)) {
294 return roles::PASSWORD_TEXT;
297 return roles::ENTRY;
300 already_AddRefed<nsIPersistentProperties>
301 HTMLTextFieldAccessible::NativeAttributes()
303 nsCOMPtr<nsIPersistentProperties> attributes =
304 HyperTextAccessibleWrap::NativeAttributes();
306 // Expose type for text input elements as it gives some useful context,
307 // especially for mobile.
308 nsAutoString type;
309 if (mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::type, type))
310 nsAccUtils::SetAccAttr(attributes, nsGkAtoms::textInputType, type);
312 return attributes.forget();
315 ENameValueFlag
316 HTMLTextFieldAccessible::NativeName(nsString& aName)
318 ENameValueFlag nameFlag = Accessible::NativeName(aName);
319 if (!aName.IsEmpty())
320 return nameFlag;
322 // If part of compound of XUL widget then grab a name from XUL widget element.
323 nsIContent* widgetElm = XULWidgetElm();
324 if (widgetElm)
325 XULElmName(mDoc, widgetElm, aName);
327 if (!aName.IsEmpty())
328 return eNameOK;
330 // text inputs and textareas might have useful placeholder text
331 mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::placeholder, aName);
332 return eNameOK;
335 void
336 HTMLTextFieldAccessible::Value(nsString& aValue)
338 aValue.Truncate();
339 if (NativeState() & states::PROTECTED) // Don't return password text!
340 return;
342 nsCOMPtr<nsIDOMHTMLTextAreaElement> textArea(do_QueryInterface(mContent));
343 if (textArea) {
344 textArea->GetValue(aValue);
345 return;
348 HTMLInputElement* input = HTMLInputElement::FromContent(mContent);
349 if (input)
350 input->GetValue(aValue);
353 void
354 HTMLTextFieldAccessible::ApplyARIAState(uint64_t* aState) const
356 HyperTextAccessibleWrap::ApplyARIAState(aState);
357 aria::MapToState(aria::eARIAAutoComplete, mContent->AsElement(), aState);
359 // If part of compound of XUL widget then pick up ARIA stuff from XUL widget
360 // element.
361 nsIContent* widgetElm = XULWidgetElm();
362 if (widgetElm)
363 aria::MapToState(aria::eARIAAutoComplete, widgetElm->AsElement(), aState);
366 uint64_t
367 HTMLTextFieldAccessible::NativeState()
369 uint64_t state = HyperTextAccessibleWrap::NativeState();
371 // Text fields are always editable, even if they are also read only or
372 // disabled.
373 state |= states::EDITABLE;
375 // can be focusable, focused, protected. readonly, unavailable, selected
376 if (mContent->AttrValueIs(kNameSpaceID_None, nsGkAtoms::type,
377 nsGkAtoms::password, eIgnoreCase)) {
378 state |= states::PROTECTED;
381 if (mContent->HasAttr(kNameSpaceID_None, nsGkAtoms::readonly)) {
382 state |= states::READONLY;
385 // Is it an <input> or a <textarea> ?
386 HTMLInputElement* input = HTMLInputElement::FromContent(mContent);
387 state |= input && input->IsSingleLineTextControl() ?
388 states::SINGLE_LINE : states::MULTI_LINE;
390 if (state & (states::PROTECTED | states::MULTI_LINE | states::READONLY |
391 states::UNAVAILABLE))
392 return state;
394 // Expose autocomplete states if this input is part of autocomplete widget.
395 Accessible* widget = ContainerWidget();
396 if (widget && widget-IsAutoComplete()) {
397 state |= states::HASPOPUP | states::SUPPORTS_AUTOCOMPLETION;
398 return state;
401 // Expose autocomplete state if it has associated autocomplete list.
402 if (mContent->HasAttr(kNameSpaceID_None, nsGkAtoms::list))
403 return state | states::SUPPORTS_AUTOCOMPLETION | states::HASPOPUP;
405 // Ordinal XUL textboxes don't support autocomplete.
406 if (!XULWidgetElm() && Preferences::GetBool("browser.formfill.enable")) {
407 // Check to see if autocompletion is allowed on this input. We don't expose
408 // it for password fields even though the entire password can be remembered
409 // for a page if the user asks it to be. However, the kind of autocomplete
410 // we're talking here is based on what the user types, where a popup of
411 // possible choices comes up.
412 nsAutoString autocomplete;
413 mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::autocomplete,
414 autocomplete);
416 if (!autocomplete.LowerCaseEqualsLiteral("off")) {
417 nsIContent* formContent = input->GetFormElement();
418 if (formContent) {
419 formContent->GetAttr(kNameSpaceID_None,
420 nsGkAtoms::autocomplete, autocomplete);
423 if (!formContent || !autocomplete.LowerCaseEqualsLiteral("off"))
424 state |= states::SUPPORTS_AUTOCOMPLETION;
428 return state;
431 uint8_t
432 HTMLTextFieldAccessible::ActionCount()
434 return 1;
437 void
438 HTMLTextFieldAccessible::ActionNameAt(uint8_t aIndex, nsAString& aName)
440 if (aIndex == eAction_Click)
441 aName.AssignLiteral("activate");
444 bool
445 HTMLTextFieldAccessible::DoAction(uint8_t aIndex)
447 if (aIndex != 0)
448 return false;
450 TakeFocus();
451 return true;
454 already_AddRefed<nsIEditor>
455 HTMLTextFieldAccessible::GetEditor() const
457 nsCOMPtr<nsIDOMNSEditableElement> editableElt(do_QueryInterface(mContent));
458 if (!editableElt)
459 return nullptr;
461 // nsGenericHTMLElement::GetEditor has a security check.
462 // Make sure we're not restricted by the permissions of
463 // whatever script is currently running.
464 mozilla::dom::AutoNoJSAPI nojsapi;
466 nsCOMPtr<nsIEditor> editor;
467 editableElt->GetEditor(getter_AddRefs(editor));
469 return editor.forget();
472 ////////////////////////////////////////////////////////////////////////////////
473 // HTMLTextFieldAccessible: Widgets
475 bool
476 HTMLTextFieldAccessible::IsWidget() const
478 return true;
481 Accessible*
482 HTMLTextFieldAccessible::ContainerWidget() const
484 return mParent && mParent->Role() == roles::AUTOCOMPLETE ? mParent : nullptr;
488 ////////////////////////////////////////////////////////////////////////////////
489 // HTMLFileInputAccessible
490 ////////////////////////////////////////////////////////////////////////////////
492 HTMLFileInputAccessible::
493 HTMLFileInputAccessible(nsIContent* aContent, DocAccessible* aDoc) :
494 HyperTextAccessibleWrap(aContent, aDoc)
496 mType = eHTMLFileInputType;
499 role
500 HTMLFileInputAccessible::NativeRole()
502 // JAWS wants a text container, others don't mind. No specific role in
503 // AT APIs.
504 return roles::TEXT_CONTAINER;
507 nsresult
508 HTMLFileInputAccessible::HandleAccEvent(AccEvent* aEvent)
510 nsresult rv = HyperTextAccessibleWrap::HandleAccEvent(aEvent);
511 NS_ENSURE_SUCCESS(rv, rv);
513 // Redirect state change events for inherited states to child controls. Note,
514 // unavailable state is not redirected. That's a standard for unavailable
515 // state handling.
516 AccStateChangeEvent* event = downcast_accEvent(aEvent);
517 if (event &&
518 (event->GetState() == states::BUSY ||
519 event->GetState() == states::REQUIRED ||
520 event->GetState() == states::HASPOPUP ||
521 event->GetState() == states::INVALID)) {
522 Accessible* button = GetChildAt(0);
523 if (button && button->Role() == roles::PUSHBUTTON) {
524 nsRefPtr<AccStateChangeEvent> childEvent =
525 new AccStateChangeEvent(button, event->GetState(),
526 event->IsStateEnabled(), event->FromUserInput());
527 nsEventShell::FireEvent(childEvent);
531 return NS_OK;
535 ////////////////////////////////////////////////////////////////////////////////
536 // HTMLSpinnerAccessible
537 ////////////////////////////////////////////////////////////////////////////////
539 role
540 HTMLSpinnerAccessible::NativeRole()
542 return roles::SPINBUTTON;
545 void
546 HTMLSpinnerAccessible::Value(nsString& aValue)
548 AccessibleWrap::Value(aValue);
549 if (!aValue.IsEmpty())
550 return;
552 HTMLInputElement::FromContent(mContent)->GetValue(aValue);
555 double
556 HTMLSpinnerAccessible::MaxValue() const
558 double value = AccessibleWrap::MaxValue();
559 if (!IsNaN(value))
560 return value;
562 return HTMLInputElement::FromContent(mContent)->GetMaximum().toDouble();
566 double
567 HTMLSpinnerAccessible::MinValue() const
569 double value = AccessibleWrap::MinValue();
570 if (!IsNaN(value))
571 return value;
573 return HTMLInputElement::FromContent(mContent)->GetMinimum().toDouble();
576 double
577 HTMLSpinnerAccessible::Step() const
579 double value = AccessibleWrap::Step();
580 if (!IsNaN(value))
581 return value;
583 return HTMLInputElement::FromContent(mContent)->GetStep().toDouble();
586 double
587 HTMLSpinnerAccessible::CurValue() const
589 double value = AccessibleWrap::CurValue();
590 if (!IsNaN(value))
591 return value;
593 return HTMLInputElement::FromContent(mContent)->GetValueAsDecimal().toDouble();
596 bool
597 HTMLSpinnerAccessible::SetCurValue(double aValue)
599 ErrorResult er;
600 HTMLInputElement::FromContent(mContent)->SetValueAsNumber(aValue, er);
601 return !er.Failed();
605 ////////////////////////////////////////////////////////////////////////////////
606 // HTMLRangeAccessible
607 ////////////////////////////////////////////////////////////////////////////////
609 role
610 HTMLRangeAccessible::NativeRole()
612 return roles::SLIDER;
615 bool
616 HTMLRangeAccessible::IsWidget() const
618 return true;
621 void
622 HTMLRangeAccessible::Value(nsString& aValue)
624 LeafAccessible::Value(aValue);
625 if (!aValue.IsEmpty())
626 return;
628 HTMLInputElement::FromContent(mContent)->GetValue(aValue);
631 double
632 HTMLRangeAccessible::MaxValue() const
634 double value = LeafAccessible::MaxValue();
635 if (!IsNaN(value))
636 return value;
638 return HTMLInputElement::FromContent(mContent)->GetMaximum().toDouble();
641 double
642 HTMLRangeAccessible::MinValue() const
644 double value = LeafAccessible::MinValue();
645 if (!IsNaN(value))
646 return value;
648 return HTMLInputElement::FromContent(mContent)->GetMinimum().toDouble();
651 double
652 HTMLRangeAccessible::Step() const
654 double value = LeafAccessible::Step();
655 if (!IsNaN(value))
656 return value;
658 return HTMLInputElement::FromContent(mContent)->GetStep().toDouble();
661 double
662 HTMLRangeAccessible::CurValue() const
664 double value = LeafAccessible::CurValue();
665 if (!IsNaN(value))
666 return value;
668 return HTMLInputElement::FromContent(mContent)->GetValueAsDecimal().toDouble();
671 bool
672 HTMLRangeAccessible::SetCurValue(double aValue)
674 ErrorResult er;
675 HTMLInputElement::FromContent(mContent)->SetValueAsNumber(aValue, er);
676 return !er.Failed();
680 ////////////////////////////////////////////////////////////////////////////////
681 // HTMLGroupboxAccessible
682 ////////////////////////////////////////////////////////////////////////////////
684 HTMLGroupboxAccessible::
685 HTMLGroupboxAccessible(nsIContent* aContent, DocAccessible* aDoc) :
686 HyperTextAccessibleWrap(aContent, aDoc)
690 role
691 HTMLGroupboxAccessible::NativeRole()
693 return roles::GROUPING;
696 nsIContent*
697 HTMLGroupboxAccessible::GetLegend() const
699 for (nsIContent* legendContent = mContent->GetFirstChild(); legendContent;
700 legendContent = legendContent->GetNextSibling()) {
701 if (legendContent->NodeInfo()->Equals(nsGkAtoms::legend,
702 mContent->GetNameSpaceID())) {
703 // Either XHTML namespace or no namespace
704 return legendContent;
708 return nullptr;
711 ENameValueFlag
712 HTMLGroupboxAccessible::NativeName(nsString& aName)
714 ENameValueFlag nameFlag = Accessible::NativeName(aName);
715 if (!aName.IsEmpty())
716 return nameFlag;
718 nsIContent* legendContent = GetLegend();
719 if (legendContent)
720 nsTextEquivUtils::AppendTextEquivFromContent(this, legendContent, &aName);
722 return eNameOK;
725 Relation
726 HTMLGroupboxAccessible::RelationByType(RelationType aType)
728 Relation rel = HyperTextAccessibleWrap::RelationByType(aType);
729 // No override for label, so use <legend> for this <fieldset>
730 if (aType == RelationType::LABELLED_BY)
731 rel.AppendTarget(mDoc, GetLegend());
733 return rel;
736 ////////////////////////////////////////////////////////////////////////////////
737 // HTMLLegendAccessible
738 ////////////////////////////////////////////////////////////////////////////////
740 HTMLLegendAccessible::
741 HTMLLegendAccessible(nsIContent* aContent, DocAccessible* aDoc) :
742 HyperTextAccessibleWrap(aContent, aDoc)
746 Relation
747 HTMLLegendAccessible::RelationByType(RelationType aType)
749 Relation rel = HyperTextAccessibleWrap::RelationByType(aType);
750 if (aType != RelationType::LABEL_FOR)
751 return rel;
753 Accessible* groupbox = Parent();
754 if (groupbox && groupbox->Role() == roles::GROUPING)
755 rel.AppendTarget(groupbox);
757 return rel;
760 role
761 HTMLLegendAccessible::NativeRole()
763 return roles::LABEL;
766 ////////////////////////////////////////////////////////////////////////////////
767 // HTMLFigureAccessible
768 ////////////////////////////////////////////////////////////////////////////////
770 HTMLFigureAccessible::
771 HTMLFigureAccessible(nsIContent* aContent, DocAccessible* aDoc) :
772 HyperTextAccessibleWrap(aContent, aDoc)
776 already_AddRefed<nsIPersistentProperties>
777 HTMLFigureAccessible::NativeAttributes()
779 nsCOMPtr<nsIPersistentProperties> attributes =
780 HyperTextAccessibleWrap::NativeAttributes();
782 // Expose figure xml-role.
783 nsAccUtils::SetAccAttr(attributes, nsGkAtoms::xmlroles,
784 NS_LITERAL_STRING("figure"));
785 return attributes.forget();
788 role
789 HTMLFigureAccessible::NativeRole()
791 return roles::FIGURE;
794 ENameValueFlag
795 HTMLFigureAccessible::NativeName(nsString& aName)
797 ENameValueFlag nameFlag = HyperTextAccessibleWrap::NativeName(aName);
798 if (!aName.IsEmpty())
799 return nameFlag;
801 nsIContent* captionContent = Caption();
802 if (captionContent)
803 nsTextEquivUtils::AppendTextEquivFromContent(this, captionContent, &aName);
805 return eNameOK;
808 Relation
809 HTMLFigureAccessible::RelationByType(RelationType aType)
811 Relation rel = HyperTextAccessibleWrap::RelationByType(aType);
812 if (aType == RelationType::LABELLED_BY)
813 rel.AppendTarget(mDoc, Caption());
815 return rel;
818 nsIContent*
819 HTMLFigureAccessible::Caption() const
821 for (nsIContent* childContent = mContent->GetFirstChild(); childContent;
822 childContent = childContent->GetNextSibling()) {
823 if (childContent->NodeInfo()->Equals(nsGkAtoms::figcaption,
824 mContent->GetNameSpaceID())) {
825 return childContent;
829 return nullptr;
832 ////////////////////////////////////////////////////////////////////////////////
833 // HTMLFigcaptionAccessible
834 ////////////////////////////////////////////////////////////////////////////////
836 HTMLFigcaptionAccessible::
837 HTMLFigcaptionAccessible(nsIContent* aContent, DocAccessible* aDoc) :
838 HyperTextAccessibleWrap(aContent, aDoc)
842 role
843 HTMLFigcaptionAccessible::NativeRole()
845 return roles::CAPTION;
848 Relation
849 HTMLFigcaptionAccessible::RelationByType(RelationType aType)
851 Relation rel = HyperTextAccessibleWrap::RelationByType(aType);
852 if (aType != RelationType::LABEL_FOR)
853 return rel;
855 Accessible* figure = Parent();
856 if (figure &&
857 figure->GetContent()->NodeInfo()->Equals(nsGkAtoms::figure,
858 mContent->GetNameSpaceID())) {
859 rel.AppendTarget(figure);
862 return rel;