Line data Source code
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/. */
5 :
6 : #include "HTMLFormControlAccessible.h"
7 :
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"
15 :
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"
28 :
29 : #include "mozilla/EventStates.h"
30 : #include "mozilla/FloatingPoint.h"
31 : #include "mozilla/Preferences.h"
32 :
33 : using namespace mozilla;
34 : using namespace mozilla::dom;
35 : using namespace mozilla::a11y;
36 :
37 : ////////////////////////////////////////////////////////////////////////////////
38 : // HTMLCheckboxAccessible
39 : ////////////////////////////////////////////////////////////////////////////////
40 :
41 : role
42 0 : HTMLCheckboxAccessible::NativeRole()
43 : {
44 0 : return roles::CHECKBUTTON;
45 : }
46 :
47 : uint8_t
48 0 : HTMLCheckboxAccessible::ActionCount()
49 : {
50 0 : return 1;
51 : }
52 :
53 : void
54 0 : HTMLCheckboxAccessible::ActionNameAt(uint8_t aIndex, nsAString& aName)
55 : {
56 0 : if (aIndex == eAction_Click) { // 0 is the magic value for default action
57 0 : uint64_t state = NativeState();
58 0 : if (state & states::CHECKED)
59 0 : aName.AssignLiteral("uncheck");
60 0 : else if (state & states::MIXED)
61 0 : aName.AssignLiteral("cycle");
62 : else
63 0 : aName.AssignLiteral("check");
64 : }
65 0 : }
66 :
67 : bool
68 0 : HTMLCheckboxAccessible::DoAction(uint8_t aIndex)
69 : {
70 0 : if (aIndex != 0)
71 0 : return false;
72 :
73 0 : DoCommand();
74 0 : return true;
75 : }
76 :
77 : uint64_t
78 0 : HTMLCheckboxAccessible::NativeState()
79 : {
80 0 : uint64_t state = LeafAccessible::NativeState();
81 :
82 0 : state |= states::CHECKABLE;
83 0 : HTMLInputElement* input = HTMLInputElement::FromContent(mContent);
84 0 : if (!input)
85 0 : return state;
86 :
87 0 : if (input->Indeterminate())
88 0 : return state | states::MIXED;
89 :
90 0 : if (input->Checked())
91 0 : return state | states::CHECKED;
92 :
93 0 : return state;
94 : }
95 :
96 : ////////////////////////////////////////////////////////////////////////////////
97 : // HTMLCheckboxAccessible: Widgets
98 :
99 : bool
100 0 : HTMLCheckboxAccessible::IsWidget() const
101 : {
102 0 : return true;
103 : }
104 :
105 :
106 : ////////////////////////////////////////////////////////////////////////////////
107 : // HTMLRadioButtonAccessible
108 : ////////////////////////////////////////////////////////////////////////////////
109 :
110 : uint64_t
111 0 : HTMLRadioButtonAccessible::NativeState()
112 : {
113 0 : uint64_t state = AccessibleWrap::NativeState();
114 :
115 0 : state |= states::CHECKABLE;
116 :
117 0 : HTMLInputElement* input = HTMLInputElement::FromContent(mContent);
118 0 : if (input && input->Checked())
119 0 : state |= states::CHECKED;
120 :
121 0 : return state;
122 : }
123 :
124 : void
125 0 : HTMLRadioButtonAccessible::GetPositionAndSizeInternal(int32_t* aPosInSet,
126 : int32_t* aSetSize)
127 : {
128 0 : int32_t namespaceId = mContent->NodeInfo()->NamespaceID();
129 0 : nsAutoString tagName;
130 0 : mContent->NodeInfo()->GetName(tagName);
131 :
132 0 : nsAutoString type;
133 0 : mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::type, type);
134 0 : nsAutoString name;
135 0 : mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::name, name);
136 :
137 0 : RefPtr<nsContentList> inputElms;
138 :
139 0 : nsCOMPtr<nsIFormControl> formControlNode(do_QueryInterface(mContent));
140 0 : dom::Element* formElm = formControlNode->GetFormElement();
141 0 : if (formElm)
142 0 : inputElms = NS_GetContentList(formElm, namespaceId, tagName);
143 : else
144 0 : inputElms = NS_GetContentList(mContent->OwnerDoc(), namespaceId, tagName);
145 0 : NS_ENSURE_TRUE_VOID(inputElms);
146 :
147 0 : uint32_t inputCount = inputElms->Length(false);
148 :
149 : // Compute posinset and setsize.
150 0 : int32_t indexOf = 0;
151 0 : int32_t count = 0;
152 :
153 0 : for (uint32_t index = 0; index < inputCount; index++) {
154 0 : nsIContent* inputElm = inputElms->Item(index, false);
155 0 : if (inputElm->AttrValueIs(kNameSpaceID_None, nsGkAtoms::type,
156 0 : type, eCaseMatters) &&
157 0 : inputElm->AttrValueIs(kNameSpaceID_None, nsGkAtoms::name,
158 0 : name, eCaseMatters) && mDoc->HasAccessible(inputElm)) {
159 0 : count++;
160 0 : if (inputElm == mContent)
161 0 : indexOf = count;
162 : }
163 : }
164 :
165 0 : *aPosInSet = indexOf;
166 0 : *aSetSize = count;
167 : }
168 :
169 : ////////////////////////////////////////////////////////////////////////////////
170 : // HTMLButtonAccessible
171 : ////////////////////////////////////////////////////////////////////////////////
172 :
173 0 : HTMLButtonAccessible::
174 0 : HTMLButtonAccessible(nsIContent* aContent, DocAccessible* aDoc) :
175 0 : HyperTextAccessibleWrap(aContent, aDoc)
176 : {
177 0 : mGenericTypes |= eButton;
178 0 : }
179 :
180 : uint8_t
181 0 : HTMLButtonAccessible::ActionCount()
182 : {
183 0 : return 1;
184 : }
185 :
186 : void
187 0 : HTMLButtonAccessible::ActionNameAt(uint8_t aIndex, nsAString& aName)
188 : {
189 0 : if (aIndex == eAction_Click)
190 0 : aName.AssignLiteral("press");
191 0 : }
192 :
193 : bool
194 0 : HTMLButtonAccessible::DoAction(uint8_t aIndex)
195 : {
196 0 : if (aIndex != eAction_Click)
197 0 : return false;
198 :
199 0 : DoCommand();
200 0 : return true;
201 : }
202 :
203 : uint64_t
204 0 : HTMLButtonAccessible::State()
205 : {
206 0 : uint64_t state = HyperTextAccessibleWrap::State();
207 0 : if (state == states::DEFUNCT)
208 0 : return state;
209 :
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 0 : if (mParent && mParent->IsHTMLFileInput()) {
214 0 : uint64_t parentState = mParent->State();
215 0 : state |= parentState & (states::BUSY | states::REQUIRED |
216 : states::HASPOPUP | states::INVALID);
217 : }
218 :
219 0 : return state;
220 : }
221 :
222 : uint64_t
223 0 : HTMLButtonAccessible::NativeState()
224 : {
225 0 : uint64_t state = HyperTextAccessibleWrap::NativeState();
226 :
227 0 : EventStates elmState = mContent->AsElement()->State();
228 0 : if (elmState.HasState(NS_EVENT_STATE_DEFAULT))
229 0 : state |= states::DEFAULT;
230 :
231 0 : return state;
232 : }
233 :
234 : role
235 0 : HTMLButtonAccessible::NativeRole()
236 : {
237 0 : return roles::PUSHBUTTON;
238 : }
239 :
240 : ENameValueFlag
241 0 : HTMLButtonAccessible::NativeName(nsString& aName)
242 : {
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.
251 :
252 0 : ENameValueFlag nameFlag = Accessible::NativeName(aName);
253 0 : if (!aName.IsEmpty() || !mContent->IsHTMLElement(nsGkAtoms::input) ||
254 0 : !mContent->AttrValueIs(kNameSpaceID_None, nsGkAtoms::type,
255 : nsGkAtoms::image, eCaseMatters))
256 0 : return nameFlag;
257 :
258 0 : if (!mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::alt, aName))
259 0 : mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::value, aName);
260 :
261 0 : aName.CompressWhitespace();
262 0 : return eNameOK;
263 : }
264 :
265 : ////////////////////////////////////////////////////////////////////////////////
266 : // HTMLButtonAccessible: Widgets
267 :
268 : bool
269 0 : HTMLButtonAccessible::IsWidget() const
270 : {
271 0 : return true;
272 : }
273 :
274 :
275 : ////////////////////////////////////////////////////////////////////////////////
276 : // HTMLTextFieldAccessible
277 : ////////////////////////////////////////////////////////////////////////////////
278 :
279 0 : HTMLTextFieldAccessible::
280 0 : HTMLTextFieldAccessible(nsIContent* aContent, DocAccessible* aDoc) :
281 0 : HyperTextAccessibleWrap(aContent, aDoc)
282 : {
283 0 : mType = eHTMLTextFieldType;
284 0 : }
285 :
286 0 : NS_IMPL_ISUPPORTS_INHERITED0(HTMLTextFieldAccessible,
287 : HyperTextAccessible)
288 :
289 : role
290 0 : HTMLTextFieldAccessible::NativeRole()
291 : {
292 0 : if (mContent->AttrValueIs(kNameSpaceID_None, nsGkAtoms::type,
293 : nsGkAtoms::password, eIgnoreCase)) {
294 0 : return roles::PASSWORD_TEXT;
295 : }
296 :
297 0 : return roles::ENTRY;
298 : }
299 :
300 : already_AddRefed<nsIPersistentProperties>
301 0 : HTMLTextFieldAccessible::NativeAttributes()
302 : {
303 : nsCOMPtr<nsIPersistentProperties> attributes =
304 0 : HyperTextAccessibleWrap::NativeAttributes();
305 :
306 : // Expose type for text input elements as it gives some useful context,
307 : // especially for mobile.
308 0 : nsAutoString type;
309 0 : if (mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::type, type)) {
310 0 : nsAccUtils::SetAccAttr(attributes, nsGkAtoms::textInputType, type);
311 0 : if (!ARIARoleMap() && type.EqualsLiteral("search")) {
312 0 : nsAccUtils::SetAccAttr(attributes, nsGkAtoms::xmlroles,
313 0 : NS_LITERAL_STRING("searchbox"));
314 : }
315 : }
316 :
317 0 : return attributes.forget();
318 : }
319 :
320 : ENameValueFlag
321 0 : HTMLTextFieldAccessible::NativeName(nsString& aName)
322 : {
323 0 : ENameValueFlag nameFlag = Accessible::NativeName(aName);
324 0 : if (!aName.IsEmpty())
325 0 : return nameFlag;
326 :
327 : // If part of compound of XUL widget then grab a name from XUL widget element.
328 0 : nsIContent* widgetElm = XULWidgetElm();
329 0 : if (widgetElm)
330 0 : XULElmName(mDoc, widgetElm, aName);
331 :
332 0 : if (!aName.IsEmpty())
333 0 : return eNameOK;
334 :
335 : // text inputs and textareas might have useful placeholder text
336 0 : mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::placeholder, aName);
337 0 : return eNameOK;
338 : }
339 :
340 : void
341 0 : HTMLTextFieldAccessible::Value(nsString& aValue)
342 : {
343 0 : aValue.Truncate();
344 0 : if (NativeState() & states::PROTECTED) // Don't return password text!
345 0 : return;
346 :
347 0 : nsCOMPtr<nsIDOMHTMLTextAreaElement> textArea(do_QueryInterface(mContent));
348 0 : if (textArea) {
349 0 : textArea->GetValue(aValue);
350 0 : return;
351 : }
352 :
353 0 : HTMLInputElement* input = HTMLInputElement::FromContent(mContent);
354 0 : if (input) {
355 : // Pass NonSystem as the caller type, to be safe. We don't expect to have a
356 : // file input here.
357 0 : input->GetValue(aValue, CallerType::NonSystem);
358 : }
359 : }
360 :
361 : void
362 0 : HTMLTextFieldAccessible::ApplyARIAState(uint64_t* aState) const
363 : {
364 0 : HyperTextAccessibleWrap::ApplyARIAState(aState);
365 0 : aria::MapToState(aria::eARIAAutoComplete, mContent->AsElement(), aState);
366 :
367 : // If part of compound of XUL widget then pick up ARIA stuff from XUL widget
368 : // element.
369 0 : nsIContent* widgetElm = XULWidgetElm();
370 0 : if (widgetElm)
371 0 : aria::MapToState(aria::eARIAAutoComplete, widgetElm->AsElement(), aState);
372 0 : }
373 :
374 : uint64_t
375 0 : HTMLTextFieldAccessible::NativeState()
376 : {
377 0 : uint64_t state = HyperTextAccessibleWrap::NativeState();
378 :
379 : // Text fields are always editable, even if they are also read only or
380 : // disabled.
381 0 : state |= states::EDITABLE;
382 :
383 : // can be focusable, focused, protected. readonly, unavailable, selected
384 0 : if (mContent->AttrValueIs(kNameSpaceID_None, nsGkAtoms::type,
385 : nsGkAtoms::password, eIgnoreCase)) {
386 0 : state |= states::PROTECTED;
387 : }
388 :
389 0 : if (mContent->HasAttr(kNameSpaceID_None, nsGkAtoms::readonly)) {
390 0 : state |= states::READONLY;
391 : }
392 :
393 : // Is it an <input> or a <textarea> ?
394 0 : HTMLInputElement* input = HTMLInputElement::FromContent(mContent);
395 0 : state |= input && input->IsSingleLineTextControl() ?
396 0 : states::SINGLE_LINE : states::MULTI_LINE;
397 :
398 0 : if (state & (states::PROTECTED | states::MULTI_LINE | states::READONLY |
399 : states::UNAVAILABLE))
400 0 : return state;
401 :
402 : // Expose autocomplete states if this input is part of autocomplete widget.
403 0 : Accessible* widget = ContainerWidget();
404 0 : if (widget && widget-IsAutoComplete()) {
405 0 : state |= states::HASPOPUP | states::SUPPORTS_AUTOCOMPLETION;
406 0 : return state;
407 : }
408 :
409 : // Expose autocomplete state if it has associated autocomplete list.
410 0 : if (mContent->HasAttr(kNameSpaceID_None, nsGkAtoms::list))
411 0 : return state | states::SUPPORTS_AUTOCOMPLETION | states::HASPOPUP;
412 :
413 : // Ordinal XUL textboxes don't support autocomplete.
414 0 : if (!XULWidgetElm() && Preferences::GetBool("browser.formfill.enable")) {
415 : // Check to see if autocompletion is allowed on this input. We don't expose
416 : // it for password fields even though the entire password can be remembered
417 : // for a page if the user asks it to be. However, the kind of autocomplete
418 : // we're talking here is based on what the user types, where a popup of
419 : // possible choices comes up.
420 0 : nsAutoString autocomplete;
421 0 : mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::autocomplete,
422 0 : autocomplete);
423 :
424 0 : if (!autocomplete.LowerCaseEqualsLiteral("off")) {
425 0 : nsIContent* formContent = input->GetFormElement();
426 0 : if (formContent) {
427 : formContent->GetAttr(kNameSpaceID_None,
428 0 : nsGkAtoms::autocomplete, autocomplete);
429 : }
430 :
431 0 : if (!formContent || !autocomplete.LowerCaseEqualsLiteral("off"))
432 0 : state |= states::SUPPORTS_AUTOCOMPLETION;
433 : }
434 : }
435 :
436 0 : return state;
437 : }
438 :
439 : uint8_t
440 0 : HTMLTextFieldAccessible::ActionCount()
441 : {
442 0 : return 1;
443 : }
444 :
445 : void
446 0 : HTMLTextFieldAccessible::ActionNameAt(uint8_t aIndex, nsAString& aName)
447 : {
448 0 : if (aIndex == eAction_Click)
449 0 : aName.AssignLiteral("activate");
450 0 : }
451 :
452 : bool
453 0 : HTMLTextFieldAccessible::DoAction(uint8_t aIndex)
454 : {
455 0 : if (aIndex != 0)
456 0 : return false;
457 :
458 0 : TakeFocus();
459 0 : return true;
460 : }
461 :
462 : already_AddRefed<nsIEditor>
463 0 : HTMLTextFieldAccessible::GetEditor() const
464 : {
465 0 : nsCOMPtr<nsIDOMNSEditableElement> editableElt(do_QueryInterface(mContent));
466 0 : if (!editableElt)
467 0 : return nullptr;
468 :
469 0 : nsCOMPtr<nsIEditor> editor;
470 0 : editableElt->GetEditor(getter_AddRefs(editor));
471 :
472 0 : return editor.forget();
473 : }
474 :
475 : ////////////////////////////////////////////////////////////////////////////////
476 : // HTMLTextFieldAccessible: Widgets
477 :
478 : bool
479 0 : HTMLTextFieldAccessible::IsWidget() const
480 : {
481 0 : return true;
482 : }
483 :
484 : Accessible*
485 0 : HTMLTextFieldAccessible::ContainerWidget() const
486 : {
487 0 : if (!mParent || mParent->Role() != roles::AUTOCOMPLETE) {
488 0 : return nullptr;
489 : }
490 0 : return mParent;
491 : }
492 :
493 :
494 : ////////////////////////////////////////////////////////////////////////////////
495 : // HTMLFileInputAccessible
496 : ////////////////////////////////////////////////////////////////////////////////
497 :
498 0 : HTMLFileInputAccessible::
499 0 : HTMLFileInputAccessible(nsIContent* aContent, DocAccessible* aDoc) :
500 0 : HyperTextAccessibleWrap(aContent, aDoc)
501 : {
502 0 : mType = eHTMLFileInputType;
503 0 : }
504 :
505 : role
506 0 : HTMLFileInputAccessible::NativeRole()
507 : {
508 : // JAWS wants a text container, others don't mind. No specific role in
509 : // AT APIs.
510 0 : return roles::TEXT_CONTAINER;
511 : }
512 :
513 : nsresult
514 0 : HTMLFileInputAccessible::HandleAccEvent(AccEvent* aEvent)
515 : {
516 0 : nsresult rv = HyperTextAccessibleWrap::HandleAccEvent(aEvent);
517 0 : NS_ENSURE_SUCCESS(rv, rv);
518 :
519 : // Redirect state change events for inherited states to child controls. Note,
520 : // unavailable state is not redirected. That's a standard for unavailable
521 : // state handling.
522 0 : AccStateChangeEvent* event = downcast_accEvent(aEvent);
523 0 : if (event &&
524 0 : (event->GetState() == states::BUSY ||
525 0 : event->GetState() == states::REQUIRED ||
526 0 : event->GetState() == states::HASPOPUP ||
527 0 : event->GetState() == states::INVALID)) {
528 0 : Accessible* button = GetChildAt(0);
529 0 : if (button && button->Role() == roles::PUSHBUTTON) {
530 : RefPtr<AccStateChangeEvent> childEvent =
531 0 : new AccStateChangeEvent(button, event->GetState(),
532 0 : event->IsStateEnabled(), event->FromUserInput());
533 0 : nsEventShell::FireEvent(childEvent);
534 : }
535 : }
536 :
537 0 : return NS_OK;
538 : }
539 :
540 :
541 : ////////////////////////////////////////////////////////////////////////////////
542 : // HTMLSpinnerAccessible
543 : ////////////////////////////////////////////////////////////////////////////////
544 :
545 : role
546 0 : HTMLSpinnerAccessible::NativeRole()
547 : {
548 0 : return roles::SPINBUTTON;
549 : }
550 :
551 : void
552 0 : HTMLSpinnerAccessible::Value(nsString& aValue)
553 : {
554 0 : AccessibleWrap::Value(aValue);
555 0 : if (!aValue.IsEmpty())
556 0 : return;
557 :
558 : // Pass NonSystem as the caller type, to be safe. We don't expect to have a
559 : // file input here.
560 0 : HTMLInputElement::FromContent(mContent)->GetValue(aValue,
561 0 : CallerType::NonSystem);
562 : }
563 :
564 : double
565 0 : HTMLSpinnerAccessible::MaxValue() const
566 : {
567 0 : double value = AccessibleWrap::MaxValue();
568 0 : if (!IsNaN(value))
569 0 : return value;
570 :
571 0 : return HTMLInputElement::FromContent(mContent)->GetMaximum().toDouble();
572 : }
573 :
574 :
575 : double
576 0 : HTMLSpinnerAccessible::MinValue() const
577 : {
578 0 : double value = AccessibleWrap::MinValue();
579 0 : if (!IsNaN(value))
580 0 : return value;
581 :
582 0 : return HTMLInputElement::FromContent(mContent)->GetMinimum().toDouble();
583 : }
584 :
585 : double
586 0 : HTMLSpinnerAccessible::Step() const
587 : {
588 0 : double value = AccessibleWrap::Step();
589 0 : if (!IsNaN(value))
590 0 : return value;
591 :
592 0 : return HTMLInputElement::FromContent(mContent)->GetStep().toDouble();
593 : }
594 :
595 : double
596 0 : HTMLSpinnerAccessible::CurValue() const
597 : {
598 0 : double value = AccessibleWrap::CurValue();
599 0 : if (!IsNaN(value))
600 0 : return value;
601 :
602 0 : return HTMLInputElement::FromContent(mContent)->GetValueAsDecimal().toDouble();
603 : }
604 :
605 : bool
606 0 : HTMLSpinnerAccessible::SetCurValue(double aValue)
607 : {
608 0 : ErrorResult er;
609 0 : HTMLInputElement::FromContent(mContent)->SetValueAsNumber(aValue, er);
610 0 : return !er.Failed();
611 : }
612 :
613 :
614 : ////////////////////////////////////////////////////////////////////////////////
615 : // HTMLRangeAccessible
616 : ////////////////////////////////////////////////////////////////////////////////
617 :
618 : role
619 0 : HTMLRangeAccessible::NativeRole()
620 : {
621 0 : return roles::SLIDER;
622 : }
623 :
624 : bool
625 0 : HTMLRangeAccessible::IsWidget() const
626 : {
627 0 : return true;
628 : }
629 :
630 : void
631 0 : HTMLRangeAccessible::Value(nsString& aValue)
632 : {
633 0 : LeafAccessible::Value(aValue);
634 0 : if (!aValue.IsEmpty())
635 0 : return;
636 :
637 : // Pass NonSystem as the caller type, to be safe. We don't expect to have a
638 : // file input here.
639 0 : HTMLInputElement::FromContent(mContent)->GetValue(aValue,
640 0 : CallerType::NonSystem);
641 : }
642 :
643 : double
644 0 : HTMLRangeAccessible::MaxValue() const
645 : {
646 0 : double value = LeafAccessible::MaxValue();
647 0 : if (!IsNaN(value))
648 0 : return value;
649 :
650 0 : return HTMLInputElement::FromContent(mContent)->GetMaximum().toDouble();
651 : }
652 :
653 : double
654 0 : HTMLRangeAccessible::MinValue() const
655 : {
656 0 : double value = LeafAccessible::MinValue();
657 0 : if (!IsNaN(value))
658 0 : return value;
659 :
660 0 : return HTMLInputElement::FromContent(mContent)->GetMinimum().toDouble();
661 : }
662 :
663 : double
664 0 : HTMLRangeAccessible::Step() const
665 : {
666 0 : double value = LeafAccessible::Step();
667 0 : if (!IsNaN(value))
668 0 : return value;
669 :
670 0 : return HTMLInputElement::FromContent(mContent)->GetStep().toDouble();
671 : }
672 :
673 : double
674 0 : HTMLRangeAccessible::CurValue() const
675 : {
676 0 : double value = LeafAccessible::CurValue();
677 0 : if (!IsNaN(value))
678 0 : return value;
679 :
680 0 : return HTMLInputElement::FromContent(mContent)->GetValueAsDecimal().toDouble();
681 : }
682 :
683 : bool
684 0 : HTMLRangeAccessible::SetCurValue(double aValue)
685 : {
686 0 : ErrorResult er;
687 0 : HTMLInputElement::FromContent(mContent)->SetValueAsNumber(aValue, er);
688 0 : return !er.Failed();
689 : }
690 :
691 :
692 : ////////////////////////////////////////////////////////////////////////////////
693 : // HTMLGroupboxAccessible
694 : ////////////////////////////////////////////////////////////////////////////////
695 :
696 0 : HTMLGroupboxAccessible::
697 0 : HTMLGroupboxAccessible(nsIContent* aContent, DocAccessible* aDoc) :
698 0 : HyperTextAccessibleWrap(aContent, aDoc)
699 : {
700 0 : }
701 :
702 : role
703 0 : HTMLGroupboxAccessible::NativeRole()
704 : {
705 0 : return roles::GROUPING;
706 : }
707 :
708 : nsIContent*
709 0 : HTMLGroupboxAccessible::GetLegend() const
710 : {
711 0 : for (nsIContent* legendContent = mContent->GetFirstChild(); legendContent;
712 0 : legendContent = legendContent->GetNextSibling()) {
713 0 : if (legendContent->NodeInfo()->Equals(nsGkAtoms::legend,
714 : mContent->GetNameSpaceID())) {
715 : // Either XHTML namespace or no namespace
716 0 : return legendContent;
717 : }
718 : }
719 :
720 0 : return nullptr;
721 : }
722 :
723 : ENameValueFlag
724 0 : HTMLGroupboxAccessible::NativeName(nsString& aName)
725 : {
726 0 : ENameValueFlag nameFlag = Accessible::NativeName(aName);
727 0 : if (!aName.IsEmpty())
728 0 : return nameFlag;
729 :
730 0 : nsIContent* legendContent = GetLegend();
731 0 : if (legendContent)
732 0 : nsTextEquivUtils::AppendTextEquivFromContent(this, legendContent, &aName);
733 :
734 0 : return eNameOK;
735 : }
736 :
737 : Relation
738 0 : HTMLGroupboxAccessible::RelationByType(RelationType aType)
739 : {
740 0 : Relation rel = HyperTextAccessibleWrap::RelationByType(aType);
741 : // No override for label, so use <legend> for this <fieldset>
742 0 : if (aType == RelationType::LABELLED_BY)
743 0 : rel.AppendTarget(mDoc, GetLegend());
744 :
745 0 : return rel;
746 : }
747 :
748 : ////////////////////////////////////////////////////////////////////////////////
749 : // HTMLLegendAccessible
750 : ////////////////////////////////////////////////////////////////////////////////
751 :
752 0 : HTMLLegendAccessible::
753 0 : HTMLLegendAccessible(nsIContent* aContent, DocAccessible* aDoc) :
754 0 : HyperTextAccessibleWrap(aContent, aDoc)
755 : {
756 0 : }
757 :
758 : Relation
759 0 : HTMLLegendAccessible::RelationByType(RelationType aType)
760 : {
761 0 : Relation rel = HyperTextAccessibleWrap::RelationByType(aType);
762 0 : if (aType != RelationType::LABEL_FOR)
763 0 : return rel;
764 :
765 0 : Accessible* groupbox = Parent();
766 0 : if (groupbox && groupbox->Role() == roles::GROUPING)
767 0 : rel.AppendTarget(groupbox);
768 :
769 0 : return rel;
770 : }
771 :
772 : ////////////////////////////////////////////////////////////////////////////////
773 : // HTMLFigureAccessible
774 : ////////////////////////////////////////////////////////////////////////////////
775 :
776 0 : HTMLFigureAccessible::
777 0 : HTMLFigureAccessible(nsIContent* aContent, DocAccessible* aDoc) :
778 0 : HyperTextAccessibleWrap(aContent, aDoc)
779 : {
780 0 : }
781 :
782 : ENameValueFlag
783 0 : HTMLFigureAccessible::NativeName(nsString& aName)
784 : {
785 0 : ENameValueFlag nameFlag = HyperTextAccessibleWrap::NativeName(aName);
786 0 : if (!aName.IsEmpty())
787 0 : return nameFlag;
788 :
789 0 : nsIContent* captionContent = Caption();
790 0 : if (captionContent)
791 0 : nsTextEquivUtils::AppendTextEquivFromContent(this, captionContent, &aName);
792 :
793 0 : return eNameOK;
794 : }
795 :
796 : Relation
797 0 : HTMLFigureAccessible::RelationByType(RelationType aType)
798 : {
799 0 : Relation rel = HyperTextAccessibleWrap::RelationByType(aType);
800 0 : if (aType == RelationType::LABELLED_BY)
801 0 : rel.AppendTarget(mDoc, Caption());
802 :
803 0 : return rel;
804 : }
805 :
806 : nsIContent*
807 0 : HTMLFigureAccessible::Caption() const
808 : {
809 0 : for (nsIContent* childContent = mContent->GetFirstChild(); childContent;
810 0 : childContent = childContent->GetNextSibling()) {
811 0 : if (childContent->NodeInfo()->Equals(nsGkAtoms::figcaption,
812 : mContent->GetNameSpaceID())) {
813 0 : return childContent;
814 : }
815 : }
816 :
817 0 : return nullptr;
818 : }
819 :
820 : ////////////////////////////////////////////////////////////////////////////////
821 : // HTMLFigcaptionAccessible
822 : ////////////////////////////////////////////////////////////////////////////////
823 :
824 0 : HTMLFigcaptionAccessible::
825 0 : HTMLFigcaptionAccessible(nsIContent* aContent, DocAccessible* aDoc) :
826 0 : HyperTextAccessibleWrap(aContent, aDoc)
827 : {
828 0 : }
829 :
830 : Relation
831 0 : HTMLFigcaptionAccessible::RelationByType(RelationType aType)
832 : {
833 0 : Relation rel = HyperTextAccessibleWrap::RelationByType(aType);
834 0 : if (aType != RelationType::LABEL_FOR)
835 0 : return rel;
836 :
837 0 : Accessible* figure = Parent();
838 0 : if (figure &&
839 0 : figure->GetContent()->NodeInfo()->Equals(nsGkAtoms::figure,
840 : mContent->GetNameSpaceID())) {
841 0 : rel.AppendTarget(figure);
842 : }
843 :
844 0 : return rel;
845 : }
|