accessible/src/base/ARIAMap.cpp

changeset 0
6474c204b198
equal deleted inserted replaced
-1:000000000000 0:d0cfd99b5f3f
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim:expandtab:shiftwidth=2:tabstop=2:
3 */
4 /* This Source Code Form is subject to the terms of the Mozilla Public
5 * License, v. 2.0. If a copy of the MPL was not distributed with this
6 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7
8 #include "ARIAMap.h"
9
10 #include "nsAccUtils.h"
11 #include "nsCoreUtils.h"
12 #include "Role.h"
13 #include "States.h"
14
15 #include "nsAttrName.h"
16 #include "nsWhitespaceTokenizer.h"
17
18 using namespace mozilla;
19 using namespace mozilla::a11y;
20 using namespace mozilla::a11y::aria;
21
22 static const uint32_t kGenericAccType = 0;
23
24 /**
25 * This list of WAI-defined roles are currently hardcoded.
26 * Eventually we will most likely be loading an RDF resource that contains this information
27 * Using RDF will also allow for role extensibility. See bug 280138.
28 *
29 * Definition of nsRoleMapEntry contains comments explaining this table.
30 *
31 * When no nsIAccessibleRole enum mapping exists for an ARIA role, the
32 * role will be exposed via the object attribute "xml-roles".
33 * In addition, in MSAA, the unmapped role will also be exposed as a BSTR string role.
34 *
35 * There are no nsIAccessibleRole enums for the following landmark roles:
36 * banner, contentinfo, main, navigation, note, search, secondary, seealso, breadcrumbs
37 */
38
39 static nsRoleMapEntry sWAIRoleMaps[] =
40 {
41 { // alert
42 &nsGkAtoms::alert,
43 roles::ALERT,
44 kUseMapRole,
45 eNoValue,
46 eNoAction,
47 eNoLiveAttr,
48 kGenericAccType,
49 kNoReqStates
50 },
51 { // alertdialog
52 &nsGkAtoms::alertdialog,
53 roles::DIALOG,
54 kUseMapRole,
55 eNoValue,
56 eNoAction,
57 eNoLiveAttr,
58 kGenericAccType,
59 kNoReqStates
60 },
61 { // application
62 &nsGkAtoms::application,
63 roles::APPLICATION,
64 kUseMapRole,
65 eNoValue,
66 eNoAction,
67 eNoLiveAttr,
68 kGenericAccType,
69 kNoReqStates
70 },
71 { // article
72 &nsGkAtoms::article,
73 roles::DOCUMENT,
74 kUseMapRole,
75 eNoValue,
76 eNoAction,
77 eNoLiveAttr,
78 kGenericAccType,
79 kNoReqStates,
80 eReadonlyUntilEditable
81 },
82 { // button
83 &nsGkAtoms::button,
84 roles::PUSHBUTTON,
85 kUseMapRole,
86 eNoValue,
87 ePressAction,
88 eNoLiveAttr,
89 eButton,
90 kNoReqStates
91 // eARIAPressed is auto applied on any button
92 },
93 { // checkbox
94 &nsGkAtoms::checkbox,
95 roles::CHECKBUTTON,
96 kUseMapRole,
97 eNoValue,
98 eCheckUncheckAction,
99 eNoLiveAttr,
100 kGenericAccType,
101 kNoReqStates,
102 eARIACheckableMixed,
103 eARIAReadonly
104 },
105 { // columnheader
106 &nsGkAtoms::columnheader,
107 roles::COLUMNHEADER,
108 kUseMapRole,
109 eNoValue,
110 eSortAction,
111 eNoLiveAttr,
112 eTableCell,
113 kNoReqStates,
114 eARIASelectableIfDefined,
115 eARIAReadonlyOrEditableIfDefined
116 },
117 { // combobox
118 &nsGkAtoms::combobox,
119 roles::COMBOBOX,
120 kUseMapRole,
121 eNoValue,
122 eOpenCloseAction,
123 eNoLiveAttr,
124 kGenericAccType,
125 states::COLLAPSED | states::HASPOPUP,
126 eARIAAutoComplete,
127 eARIAReadonly
128 },
129 { // dialog
130 &nsGkAtoms::dialog,
131 roles::DIALOG,
132 kUseMapRole,
133 eNoValue,
134 eNoAction,
135 eNoLiveAttr,
136 kGenericAccType,
137 kNoReqStates
138 },
139 { // directory
140 &nsGkAtoms::directory,
141 roles::LIST,
142 kUseMapRole,
143 eNoValue,
144 eNoAction,
145 eNoLiveAttr,
146 eList,
147 kNoReqStates
148 },
149 { // document
150 &nsGkAtoms::document,
151 roles::DOCUMENT,
152 kUseMapRole,
153 eNoValue,
154 eNoAction,
155 eNoLiveAttr,
156 kGenericAccType,
157 kNoReqStates,
158 eReadonlyUntilEditable
159 },
160 { // form
161 &nsGkAtoms::form,
162 roles::FORM,
163 kUseMapRole,
164 eNoValue,
165 eNoAction,
166 eNoLiveAttr,
167 kGenericAccType,
168 kNoReqStates
169 },
170 { // grid
171 &nsGkAtoms::grid,
172 roles::TABLE,
173 kUseMapRole,
174 eNoValue,
175 eNoAction,
176 eNoLiveAttr,
177 eSelect | eTable,
178 kNoReqStates,
179 eARIAMultiSelectable,
180 eARIAReadonlyOrEditable,
181 eFocusableUntilDisabled
182 },
183 { // gridcell
184 &nsGkAtoms::gridcell,
185 roles::GRID_CELL,
186 kUseMapRole,
187 eNoValue,
188 eNoAction,
189 eNoLiveAttr,
190 eTableCell,
191 kNoReqStates,
192 eARIASelectable,
193 eARIAReadonlyOrEditableIfDefined
194 },
195 { // group
196 &nsGkAtoms::group,
197 roles::GROUPING,
198 kUseMapRole,
199 eNoValue,
200 eNoAction,
201 eNoLiveAttr,
202 kGenericAccType,
203 kNoReqStates
204 },
205 { // heading
206 &nsGkAtoms::heading,
207 roles::HEADING,
208 kUseMapRole,
209 eNoValue,
210 eNoAction,
211 eNoLiveAttr,
212 kGenericAccType,
213 kNoReqStates
214 },
215 { // img
216 &nsGkAtoms::img,
217 roles::GRAPHIC,
218 kUseMapRole,
219 eNoValue,
220 eNoAction,
221 eNoLiveAttr,
222 kGenericAccType,
223 kNoReqStates
224 },
225 { // key
226 &nsGkAtoms::key,
227 roles::KEY,
228 kUseMapRole,
229 eNoValue,
230 ePressAction,
231 eNoLiveAttr,
232 kGenericAccType,
233 kNoReqStates,
234 eARIAPressed
235 },
236 { // link
237 &nsGkAtoms::link,
238 roles::LINK,
239 kUseMapRole,
240 eNoValue,
241 eJumpAction,
242 eNoLiveAttr,
243 kGenericAccType,
244 states::LINKED
245 },
246 { // list
247 &nsGkAtoms::list,
248 roles::LIST,
249 kUseMapRole,
250 eNoValue,
251 eNoAction,
252 eNoLiveAttr,
253 eList,
254 states::READONLY
255 },
256 { // listbox
257 &nsGkAtoms::listbox,
258 roles::LISTBOX,
259 kUseMapRole,
260 eNoValue,
261 eNoAction,
262 eNoLiveAttr,
263 eListControl | eSelect,
264 kNoReqStates,
265 eARIAMultiSelectable,
266 eARIAReadonly,
267 eFocusableUntilDisabled
268 },
269 { // listitem
270 &nsGkAtoms::listitem,
271 roles::LISTITEM,
272 kUseMapRole,
273 eNoValue,
274 eNoAction, // XXX: should depend on state, parent accessible
275 eNoLiveAttr,
276 kGenericAccType,
277 states::READONLY
278 },
279 { // log
280 &nsGkAtoms::log_,
281 roles::NOTHING,
282 kUseNativeRole,
283 eNoValue,
284 eNoAction,
285 ePoliteLiveAttr,
286 kGenericAccType,
287 kNoReqStates
288 },
289 { // marquee
290 &nsGkAtoms::marquee,
291 roles::ANIMATION,
292 kUseMapRole,
293 eNoValue,
294 eNoAction,
295 eOffLiveAttr,
296 kGenericAccType,
297 kNoReqStates
298 },
299 { // math
300 &nsGkAtoms::math,
301 roles::FLAT_EQUATION,
302 kUseMapRole,
303 eNoValue,
304 eNoAction,
305 eNoLiveAttr,
306 kGenericAccType,
307 kNoReqStates
308 },
309 { // menu
310 &nsGkAtoms::menu,
311 roles::MENUPOPUP,
312 kUseMapRole,
313 eNoValue,
314 eNoAction, // XXX: technically accessibles of menupopup role haven't
315 // any action, but menu can be open or close.
316 eNoLiveAttr,
317 kGenericAccType,
318 kNoReqStates
319 },
320 { // menubar
321 &nsGkAtoms::menubar,
322 roles::MENUBAR,
323 kUseMapRole,
324 eNoValue,
325 eNoAction,
326 eNoLiveAttr,
327 kGenericAccType,
328 kNoReqStates
329 },
330 { // menuitem
331 &nsGkAtoms::menuitem,
332 roles::MENUITEM,
333 kUseMapRole,
334 eNoValue,
335 eClickAction,
336 eNoLiveAttr,
337 kGenericAccType,
338 kNoReqStates,
339 eARIACheckedMixed
340 },
341 { // menuitemcheckbox
342 &nsGkAtoms::menuitemcheckbox,
343 roles::CHECK_MENU_ITEM,
344 kUseMapRole,
345 eNoValue,
346 eClickAction,
347 eNoLiveAttr,
348 kGenericAccType,
349 kNoReqStates,
350 eARIACheckableMixed
351 },
352 { // menuitemradio
353 &nsGkAtoms::menuitemradio,
354 roles::RADIO_MENU_ITEM,
355 kUseMapRole,
356 eNoValue,
357 eClickAction,
358 eNoLiveAttr,
359 kGenericAccType,
360 kNoReqStates,
361 eARIACheckableBool
362 },
363 { // note
364 &nsGkAtoms::note_,
365 roles::NOTE,
366 kUseMapRole,
367 eNoValue,
368 eNoAction,
369 eNoLiveAttr,
370 kGenericAccType,
371 kNoReqStates
372 },
373 { // option
374 &nsGkAtoms::option,
375 roles::OPTION,
376 kUseMapRole,
377 eNoValue,
378 eSelectAction,
379 eNoLiveAttr,
380 kGenericAccType,
381 kNoReqStates,
382 eARIASelectable,
383 eARIACheckedMixed
384 },
385 { // presentation
386 &nsGkAtoms::presentation,
387 roles::NOTHING,
388 kUseMapRole,
389 eNoValue,
390 eNoAction,
391 eNoLiveAttr,
392 kGenericAccType,
393 kNoReqStates
394 },
395 { // progressbar
396 &nsGkAtoms::progressbar,
397 roles::PROGRESSBAR,
398 kUseMapRole,
399 eHasValueMinMax,
400 eNoAction,
401 eNoLiveAttr,
402 kGenericAccType,
403 states::READONLY,
404 eIndeterminateIfNoValue
405 },
406 { // radio
407 &nsGkAtoms::radio,
408 roles::RADIOBUTTON,
409 kUseMapRole,
410 eNoValue,
411 eSelectAction,
412 eNoLiveAttr,
413 kGenericAccType,
414 kNoReqStates,
415 eARIACheckableBool
416 },
417 { // radiogroup
418 &nsGkAtoms::radiogroup,
419 roles::GROUPING,
420 kUseMapRole,
421 eNoValue,
422 eNoAction,
423 eNoLiveAttr,
424 kGenericAccType,
425 kNoReqStates
426 },
427 { // region
428 &nsGkAtoms::region,
429 roles::PANE,
430 kUseMapRole,
431 eNoValue,
432 eNoAction,
433 eNoLiveAttr,
434 kGenericAccType,
435 kNoReqStates
436 },
437 { // row
438 &nsGkAtoms::row,
439 roles::ROW,
440 kUseMapRole,
441 eNoValue,
442 eNoAction,
443 eNoLiveAttr,
444 eTableRow,
445 kNoReqStates,
446 eARIASelectable
447 },
448 { // rowgroup
449 &nsGkAtoms::rowgroup,
450 roles::GROUPING,
451 kUseMapRole,
452 eNoValue,
453 eNoAction,
454 eNoLiveAttr,
455 kGenericAccType,
456 kNoReqStates
457 },
458 { // rowheader
459 &nsGkAtoms::rowheader,
460 roles::ROWHEADER,
461 kUseMapRole,
462 eNoValue,
463 eSortAction,
464 eNoLiveAttr,
465 eTableCell,
466 kNoReqStates,
467 eARIASelectableIfDefined,
468 eARIAReadonlyOrEditableIfDefined
469 },
470 { // scrollbar
471 &nsGkAtoms::scrollbar,
472 roles::SCROLLBAR,
473 kUseMapRole,
474 eHasValueMinMax,
475 eNoAction,
476 eNoLiveAttr,
477 kGenericAccType,
478 kNoReqStates,
479 eARIAOrientation,
480 eARIAReadonly
481 },
482 { // separator
483 &nsGkAtoms::separator_,
484 roles::SEPARATOR,
485 kUseMapRole,
486 eNoValue,
487 eNoAction,
488 eNoLiveAttr,
489 kGenericAccType,
490 kNoReqStates,
491 eARIAOrientation
492 },
493 { // slider
494 &nsGkAtoms::slider,
495 roles::SLIDER,
496 kUseMapRole,
497 eHasValueMinMax,
498 eNoAction,
499 eNoLiveAttr,
500 kGenericAccType,
501 kNoReqStates,
502 eARIAOrientation,
503 eARIAReadonly
504 },
505 { // spinbutton
506 &nsGkAtoms::spinbutton,
507 roles::SPINBUTTON,
508 kUseMapRole,
509 eHasValueMinMax,
510 eNoAction,
511 eNoLiveAttr,
512 kGenericAccType,
513 kNoReqStates,
514 eARIAReadonly
515 },
516 { // status
517 &nsGkAtoms::status,
518 roles::STATUSBAR,
519 kUseMapRole,
520 eNoValue,
521 eNoAction,
522 ePoliteLiveAttr,
523 kGenericAccType,
524 kNoReqStates
525 },
526 { // tab
527 &nsGkAtoms::tab,
528 roles::PAGETAB,
529 kUseMapRole,
530 eNoValue,
531 eSwitchAction,
532 eNoLiveAttr,
533 kGenericAccType,
534 kNoReqStates,
535 eARIASelectable
536 },
537 { // tablist
538 &nsGkAtoms::tablist,
539 roles::PAGETABLIST,
540 kUseMapRole,
541 eNoValue,
542 eNoAction,
543 eNoLiveAttr,
544 eSelect,
545 kNoReqStates
546 },
547 { // tabpanel
548 &nsGkAtoms::tabpanel,
549 roles::PROPERTYPAGE,
550 kUseMapRole,
551 eNoValue,
552 eNoAction,
553 eNoLiveAttr,
554 kGenericAccType,
555 kNoReqStates
556 },
557 { // textbox
558 &nsGkAtoms::textbox,
559 roles::ENTRY,
560 kUseMapRole,
561 eNoValue,
562 eActivateAction,
563 eNoLiveAttr,
564 kGenericAccType,
565 kNoReqStates,
566 eARIAAutoComplete,
567 eARIAMultiline,
568 eARIAReadonlyOrEditable
569 },
570 { // timer
571 &nsGkAtoms::timer,
572 roles::NOTHING,
573 kUseNativeRole,
574 eNoValue,
575 eNoAction,
576 eOffLiveAttr,
577 kNoReqStates
578 },
579 { // toolbar
580 &nsGkAtoms::toolbar,
581 roles::TOOLBAR,
582 kUseMapRole,
583 eNoValue,
584 eNoAction,
585 eNoLiveAttr,
586 kGenericAccType,
587 kNoReqStates
588 },
589 { // tooltip
590 &nsGkAtoms::tooltip,
591 roles::TOOLTIP,
592 kUseMapRole,
593 eNoValue,
594 eNoAction,
595 eNoLiveAttr,
596 kGenericAccType,
597 kNoReqStates
598 },
599 { // tree
600 &nsGkAtoms::tree,
601 roles::OUTLINE,
602 kUseMapRole,
603 eNoValue,
604 eNoAction,
605 eNoLiveAttr,
606 eSelect,
607 kNoReqStates,
608 eARIAReadonly,
609 eARIAMultiSelectable,
610 eFocusableUntilDisabled
611 },
612 { // treegrid
613 &nsGkAtoms::treegrid,
614 roles::TREE_TABLE,
615 kUseMapRole,
616 eNoValue,
617 eNoAction,
618 eNoLiveAttr,
619 eSelect | eTable,
620 kNoReqStates,
621 eARIAReadonlyOrEditable,
622 eARIAMultiSelectable,
623 eFocusableUntilDisabled
624 },
625 { // treeitem
626 &nsGkAtoms::treeitem,
627 roles::OUTLINEITEM,
628 kUseMapRole,
629 eNoValue,
630 eActivateAction, // XXX: should expose second 'expand/collapse' action based
631 // on states
632 eNoLiveAttr,
633 kGenericAccType,
634 kNoReqStates,
635 eARIASelectable,
636 eARIACheckedMixed
637 }
638 };
639
640 static nsRoleMapEntry sLandmarkRoleMap = {
641 &nsGkAtoms::_empty,
642 roles::NOTHING,
643 kUseNativeRole,
644 eNoValue,
645 eNoAction,
646 eNoLiveAttr,
647 kGenericAccType,
648 kNoReqStates
649 };
650
651 nsRoleMapEntry aria::gEmptyRoleMap = {
652 &nsGkAtoms::_empty,
653 roles::NOTHING,
654 kUseMapRole,
655 eNoValue,
656 eNoAction,
657 eNoLiveAttr,
658 kGenericAccType,
659 kNoReqStates
660 };
661
662 /**
663 * Universal (Global) states:
664 * The following state rules are applied to any accessible element,
665 * whether there is an ARIA role or not:
666 */
667 static const EStateRule sWAIUnivStateMap[] = {
668 eARIABusy,
669 eARIADisabled,
670 eARIAExpanded, // Currently under spec review but precedent exists
671 eARIAHasPopup, // Note this is technically a "property"
672 eARIAInvalid,
673 eARIARequired, // XXX not global, Bug 553117
674 eARIANone
675 };
676
677
678 /**
679 * ARIA attribute map for attribute characteristics.
680 * @note ARIA attributes that don't have any flags are not included here.
681 */
682
683 struct AttrCharacteristics
684 {
685 nsIAtom** attributeName;
686 const uint8_t characteristics;
687 };
688
689 static const AttrCharacteristics gWAIUnivAttrMap[] = {
690 {&nsGkAtoms::aria_activedescendant, ATTR_BYPASSOBJ },
691 {&nsGkAtoms::aria_atomic, ATTR_BYPASSOBJ_IF_FALSE | ATTR_VALTOKEN | ATTR_GLOBAL },
692 {&nsGkAtoms::aria_busy, ATTR_VALTOKEN | ATTR_GLOBAL },
693 {&nsGkAtoms::aria_checked, ATTR_BYPASSOBJ | ATTR_VALTOKEN }, /* exposes checkable obj attr */
694 {&nsGkAtoms::aria_controls, ATTR_BYPASSOBJ | ATTR_GLOBAL },
695 {&nsGkAtoms::aria_describedby, ATTR_BYPASSOBJ | ATTR_GLOBAL },
696 {&nsGkAtoms::aria_disabled, ATTR_BYPASSOBJ | ATTR_VALTOKEN | ATTR_GLOBAL },
697 {&nsGkAtoms::aria_dropeffect, ATTR_VALTOKEN | ATTR_GLOBAL },
698 {&nsGkAtoms::aria_expanded, ATTR_BYPASSOBJ | ATTR_VALTOKEN },
699 {&nsGkAtoms::aria_flowto, ATTR_BYPASSOBJ | ATTR_GLOBAL },
700 {&nsGkAtoms::aria_grabbed, ATTR_VALTOKEN | ATTR_GLOBAL },
701 {&nsGkAtoms::aria_haspopup, ATTR_BYPASSOBJ | ATTR_VALTOKEN | ATTR_GLOBAL },
702 {&nsGkAtoms::aria_hidden, ATTR_BYPASSOBJ_IF_FALSE | ATTR_VALTOKEN | ATTR_GLOBAL },
703 {&nsGkAtoms::aria_invalid, ATTR_BYPASSOBJ | ATTR_VALTOKEN | ATTR_GLOBAL },
704 {&nsGkAtoms::aria_label, ATTR_BYPASSOBJ | ATTR_GLOBAL },
705 {&nsGkAtoms::aria_labelledby, ATTR_BYPASSOBJ | ATTR_GLOBAL },
706 {&nsGkAtoms::aria_level, ATTR_BYPASSOBJ }, /* handled via groupPosition */
707 {&nsGkAtoms::aria_live, ATTR_VALTOKEN | ATTR_GLOBAL },
708 {&nsGkAtoms::aria_multiline, ATTR_BYPASSOBJ | ATTR_VALTOKEN },
709 {&nsGkAtoms::aria_multiselectable, ATTR_BYPASSOBJ | ATTR_VALTOKEN },
710 {&nsGkAtoms::aria_owns, ATTR_BYPASSOBJ | ATTR_GLOBAL },
711 {&nsGkAtoms::aria_orientation, ATTR_VALTOKEN },
712 {&nsGkAtoms::aria_posinset, ATTR_BYPASSOBJ }, /* handled via groupPosition */
713 {&nsGkAtoms::aria_pressed, ATTR_BYPASSOBJ | ATTR_VALTOKEN },
714 {&nsGkAtoms::aria_readonly, ATTR_BYPASSOBJ | ATTR_VALTOKEN },
715 {&nsGkAtoms::aria_relevant, ATTR_BYPASSOBJ | ATTR_GLOBAL },
716 {&nsGkAtoms::aria_required, ATTR_BYPASSOBJ | ATTR_VALTOKEN },
717 {&nsGkAtoms::aria_selected, ATTR_BYPASSOBJ | ATTR_VALTOKEN },
718 {&nsGkAtoms::aria_setsize, ATTR_BYPASSOBJ }, /* handled via groupPosition */
719 {&nsGkAtoms::aria_sort, ATTR_VALTOKEN },
720 {&nsGkAtoms::aria_valuenow, ATTR_BYPASSOBJ },
721 {&nsGkAtoms::aria_valuemin, ATTR_BYPASSOBJ },
722 {&nsGkAtoms::aria_valuemax, ATTR_BYPASSOBJ },
723 {&nsGkAtoms::aria_valuetext, ATTR_BYPASSOBJ }
724 };
725
726 nsRoleMapEntry*
727 aria::GetRoleMap(nsINode* aNode)
728 {
729 nsIContent* content = nsCoreUtils::GetRoleContent(aNode);
730 nsAutoString roles;
731 if (!content ||
732 !content->GetAttr(kNameSpaceID_None, nsGkAtoms::role, roles) ||
733 roles.IsEmpty()) {
734 // We treat role="" as if the role attribute is absent (per aria spec:8.1.1)
735 return nullptr;
736 }
737
738 nsWhitespaceTokenizer tokenizer(roles);
739 while (tokenizer.hasMoreTokens()) {
740 // Do a binary search through table for the next role in role list
741 const nsDependentSubstring role = tokenizer.nextToken();
742 uint32_t low = 0;
743 uint32_t high = ArrayLength(sWAIRoleMaps);
744 while (low < high) {
745 uint32_t idx = (low + high) / 2;
746 int32_t compare = Compare(role, sWAIRoleMaps[idx].ARIARoleString());
747 if (compare == 0)
748 return sWAIRoleMaps + idx;
749
750 if (compare < 0)
751 high = idx;
752 else
753 low = idx + 1;
754 }
755 }
756
757 // Always use some entry if there is a non-empty role string
758 // To ensure an accessible object is created
759 return &sLandmarkRoleMap;
760 }
761
762 uint64_t
763 aria::UniversalStatesFor(mozilla::dom::Element* aElement)
764 {
765 uint64_t state = 0;
766 uint32_t index = 0;
767 while (MapToState(sWAIUnivStateMap[index], aElement, &state))
768 index++;
769
770 return state;
771 }
772
773 uint8_t
774 aria::AttrCharacteristicsFor(nsIAtom* aAtom)
775 {
776 for (uint32_t i = 0; i < ArrayLength(gWAIUnivAttrMap); i++)
777 if (*gWAIUnivAttrMap[i].attributeName == aAtom)
778 return gWAIUnivAttrMap[i].characteristics;
779
780 return 0;
781 }
782
783 ////////////////////////////////////////////////////////////////////////////////
784 // AttrIterator class
785
786 bool
787 AttrIterator::Next(nsAString& aAttrName, nsAString& aAttrValue)
788 {
789 while (mAttrIdx < mAttrCount) {
790 const nsAttrName* attr = mContent->GetAttrNameAt(mAttrIdx);
791 mAttrIdx++;
792 if (attr->NamespaceEquals(kNameSpaceID_None)) {
793 nsIAtom* attrAtom = attr->Atom();
794 nsDependentAtomString attrStr(attrAtom);
795 if (!StringBeginsWith(attrStr, NS_LITERAL_STRING("aria-")))
796 continue; // Not ARIA
797
798 uint8_t attrFlags = aria::AttrCharacteristicsFor(attrAtom);
799 if (attrFlags & ATTR_BYPASSOBJ)
800 continue; // No need to handle exposing as obj attribute here
801
802 if ((attrFlags & ATTR_VALTOKEN) &&
803 !nsAccUtils::HasDefinedARIAToken(mContent, attrAtom))
804 continue; // only expose token based attributes if they are defined
805
806 if ((attrFlags & ATTR_BYPASSOBJ_IF_FALSE) &&
807 mContent->AttrValueIs(kNameSpaceID_None, attrAtom,
808 nsGkAtoms::_false, eCaseMatters)) {
809 continue; // only expose token based attribute if value is not 'false'.
810 }
811
812 nsAutoString value;
813 if (mContent->GetAttr(kNameSpaceID_None, attrAtom, value)) {
814 aAttrName.Assign(Substring(attrStr, 5));
815 aAttrValue.Assign(value);
816 return true;
817 }
818 }
819 }
820
821 return false;
822 }
823

mercurial