Coverage Report

Created: 2018-09-25 14:53

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