From 5f8de423f190bbb79a62f804151bc24824fa32d8 Mon Sep 17 00:00:00 2001 From: "Matt A. Tobin" Date: Fri, 2 Feb 2018 04:16:08 -0500 Subject: Add m-esr52 at 52.6.0 --- accessible/.eslintrc.js | 17 + accessible/aom/AccessibleNode.cpp | 68 + accessible/aom/AccessibleNode.h | 53 + accessible/aom/moz.build | 40 + accessible/atk/ARIAGridAccessibleWrap.h | 21 + accessible/atk/AccessibleWrap.cpp | 1759 ++++++++++++ accessible/atk/AccessibleWrap.h | 92 + accessible/atk/ApplicationAccessibleWrap.cpp | 167 ++ accessible/atk/ApplicationAccessibleWrap.h | 35 + accessible/atk/AtkSocketAccessible.cpp | 126 + accessible/atk/AtkSocketAccessible.h | 56 + accessible/atk/DocAccessibleWrap.cpp | 25 + accessible/atk/DocAccessibleWrap.h | 31 + accessible/atk/HTMLTableAccessibleWrap.h | 23 + accessible/atk/HyperTextAccessibleWrap.h | 21 + accessible/atk/ImageAccessibleWrap.h | 21 + accessible/atk/InterfaceInitFuncs.h | 44 + accessible/atk/Platform.cpp | 377 +++ accessible/atk/RootAccessibleWrap.cpp | 24 + accessible/atk/RootAccessibleWrap.h | 34 + accessible/atk/TextLeafAccessibleWrap.h | 20 + accessible/atk/UtilInterface.cpp | 411 +++ accessible/atk/XULListboxAccessibleWrap.h | 21 + accessible/atk/XULMenuAccessibleWrap.h | 20 + accessible/atk/XULTreeGridAccessibleWrap.h | 22 + accessible/atk/moz.build | 63 + accessible/atk/nsMai.h | 149 + accessible/atk/nsMaiHyperlink.cpp | 262 ++ accessible/atk/nsMaiHyperlink.h | 55 + accessible/atk/nsMaiInterfaceAction.cpp | 105 + accessible/atk/nsMaiInterfaceComponent.cpp | 151 ++ accessible/atk/nsMaiInterfaceDocument.cpp | 151 ++ accessible/atk/nsMaiInterfaceEditableText.cpp | 134 + accessible/atk/nsMaiInterfaceHyperlinkImpl.cpp | 37 + accessible/atk/nsMaiInterfaceHypertext.cpp | 94 + accessible/atk/nsMaiInterfaceImage.cpp | 77 + accessible/atk/nsMaiInterfaceSelection.cpp | 152 ++ accessible/atk/nsMaiInterfaceTable.cpp | 391 +++ accessible/atk/nsMaiInterfaceTableCell.cpp | 216 ++ accessible/atk/nsMaiInterfaceText.cpp | 629 +++++ accessible/atk/nsMaiInterfaceValue.cpp | 133 + accessible/atk/nsStateMap.h | 117 + accessible/base/ARIAMap.cpp | 1008 +++++++ accessible/base/ARIAMap.h | 305 +++ accessible/base/ARIAStateMap.cpp | 376 +++ accessible/base/ARIAStateMap.h | 67 + accessible/base/AccEvent.cpp | 271 ++ accessible/base/AccEvent.h | 570 ++++ accessible/base/AccGroupInfo.cpp | 227 ++ accessible/base/AccGroupInfo.h | 114 + accessible/base/AccIterator.cpp | 414 +++ accessible/base/AccIterator.h | 325 +++ accessible/base/AccTypes.h | 94 + accessible/base/AccessibleOrProxy.cpp | 27 + accessible/base/AccessibleOrProxy.h | 123 + accessible/base/Asserts.cpp | 26 + accessible/base/DocManager.cpp | 594 ++++ accessible/base/DocManager.h | 189 ++ accessible/base/EmbeddedObjCollector.cpp | 81 + accessible/base/EmbeddedObjCollector.h | 69 + accessible/base/EventQueue.cpp | 344 +++ accessible/base/EventQueue.h | 77 + accessible/base/EventTree.cpp | 618 +++++ accessible/base/EventTree.h | 121 + accessible/base/Filters.cpp | 51 + accessible/base/Filters.h | 50 + accessible/base/FocusManager.cpp | 404 +++ accessible/base/FocusManager.h | 132 + accessible/base/Logging.cpp | 1039 +++++++ accessible/base/Logging.h | 225 ++ accessible/base/MarkupMap.h | 340 +++ accessible/base/NotificationController.cpp | 947 +++++++ accessible/base/NotificationController.h | 439 +++ accessible/base/Platform.h | 88 + accessible/base/Relation.h | 108 + accessible/base/RelationType.h | 163 ++ accessible/base/RelationTypeMap.h | 154 ++ accessible/base/Role.h | 995 +++++++ accessible/base/RoleMap.h | 1370 ++++++++++ accessible/base/SelectionManager.cpp | 232 ++ accessible/base/SelectionManager.h | 133 + accessible/base/States.h | 285 ++ accessible/base/Statistics.h | 39 + accessible/base/StyleInfo.cpp | 122 + accessible/base/StyleInfo.h | 48 + accessible/base/TextAttrs.cpp | 913 +++++++ accessible/base/TextAttrs.h | 478 ++++ accessible/base/TextRange-inl.h | 29 + accessible/base/TextRange.cpp | 380 +++ accessible/base/TextRange.h | 270 ++ accessible/base/TextUpdater.cpp | 202 ++ accessible/base/TextUpdater.h | 96 + accessible/base/TreeWalker.cpp | 325 +++ accessible/base/TreeWalker.h | 144 + accessible/base/moz.build | 114 + accessible/base/nsAccCache.h | 28 + accessible/base/nsAccUtils.cpp | 447 +++ accessible/base/nsAccUtils.h | 243 ++ accessible/base/nsAccessibilityService.cpp | 1885 +++++++++++++ accessible/base/nsAccessibilityService.h | 442 +++ accessible/base/nsAccessiblePivot.cpp | 924 +++++++ accessible/base/nsAccessiblePivot.h | 144 + accessible/base/nsCoreUtils.cpp | 683 +++++ accessible/base/nsCoreUtils.h | 329 +++ accessible/base/nsEventShell.cpp | 79 + accessible/base/nsEventShell.h | 67 + accessible/base/nsTextEquivUtils.cpp | 364 +++ accessible/base/nsTextEquivUtils.h | 162 ++ accessible/generic/ARIAGridAccessible-inl.h | 39 + accessible/generic/ARIAGridAccessible.cpp | 702 +++++ accessible/generic/ARIAGridAccessible.h | 138 + accessible/generic/Accessible-inl.h | 135 + accessible/generic/Accessible.cpp | 2856 ++++++++++++++++++++ accessible/generic/Accessible.h | 1269 +++++++++ accessible/generic/ApplicationAccessible.cpp | 201 ++ accessible/generic/ApplicationAccessible.h | 120 + accessible/generic/BaseAccessibles.cpp | 264 ++ accessible/generic/BaseAccessibles.h | 132 + accessible/generic/DocAccessible-inl.h | 189 ++ accessible/generic/DocAccessible.cpp | 2387 ++++++++++++++++ accessible/generic/DocAccessible.h | 718 +++++ accessible/generic/FormControlAccessible.cpp | 193 ++ accessible/generic/FormControlAccessible.h | 76 + accessible/generic/HyperTextAccessible-inl.h | 180 ++ accessible/generic/HyperTextAccessible.cpp | 2230 +++++++++++++++ accessible/generic/HyperTextAccessible.h | 592 ++++ accessible/generic/ImageAccessible.cpp | 224 ++ accessible/generic/ImageAccessible.h | 87 + accessible/generic/OuterDocAccessible.cpp | 218 ++ accessible/generic/OuterDocAccessible.h | 61 + accessible/generic/RootAccessible.cpp | 732 +++++ accessible/generic/RootAccessible.h | 92 + accessible/generic/TableAccessible.h | 187 ++ accessible/generic/TableCellAccessible.cpp | 67 + accessible/generic/TableCellAccessible.h | 70 + accessible/generic/TextLeafAccessible.cpp | 54 + accessible/generic/TextLeafAccessible.h | 51 + accessible/generic/moz.build | 70 + accessible/html/HTMLCanvasAccessible.cpp | 24 + accessible/html/HTMLCanvasAccessible.h | 35 + accessible/html/HTMLElementAccessibles.cpp | 204 ++ accessible/html/HTMLElementAccessibles.h | 120 + accessible/html/HTMLFormControlAccessible.cpp | 841 ++++++ accessible/html/HTMLFormControlAccessible.h | 284 ++ accessible/html/HTMLImageMapAccessible.cpp | 228 ++ accessible/html/HTMLImageMapAccessible.h | 89 + accessible/html/HTMLLinkAccessible.cpp | 147 + accessible/html/HTMLLinkAccessible.h | 51 + accessible/html/HTMLListAccessible.cpp | 199 ++ accessible/html/HTMLListAccessible.h | 105 + accessible/html/HTMLSelectAccessible.cpp | 610 +++++ accessible/html/HTMLSelectAccessible.h | 222 ++ accessible/html/HTMLTableAccessible.cpp | 1139 ++++++++ accessible/html/HTMLTableAccessible.h | 226 ++ accessible/html/moz.build | 50 + accessible/interfaces/ia2/IA2Marshal.def | 11 + accessible/interfaces/ia2/IA2Marshal.dll.manifest | 12 + accessible/interfaces/ia2/IA2Marshal.rc | 5 + accessible/interfaces/ia2/IA2Typelib.idl | 61 + accessible/interfaces/ia2/Makefile.in | 108 + accessible/interfaces/ia2/moz.build | 33 + accessible/interfaces/moz.build | 40 + accessible/interfaces/msaa/AccessibleMarshal.def | 11 + accessible/interfaces/msaa/AccessibleMarshal.rc | 5 + accessible/interfaces/msaa/ISimpleDOMDocument.idl | 83 + accessible/interfaces/msaa/ISimpleDOMNode.idl | 188 ++ accessible/interfaces/msaa/ISimpleDOMText.idl | 79 + accessible/interfaces/msaa/Makefile.in | 50 + accessible/interfaces/msaa/moz.build | 41 + accessible/interfaces/nsIAccessibilityService.idl | 108 + accessible/interfaces/nsIAccessible.idl | 300 ++ accessible/interfaces/nsIAccessibleApplication.idl | 34 + .../interfaces/nsIAccessibleCaretMoveEvent.idl | 18 + accessible/interfaces/nsIAccessibleDocument.idl | 74 + .../interfaces/nsIAccessibleEditableText.idl | 56 + accessible/interfaces/nsIAccessibleEvent.idl | 455 ++++ accessible/interfaces/nsIAccessibleHideEvent.idl | 28 + accessible/interfaces/nsIAccessibleHyperLink.idl | 86 + accessible/interfaces/nsIAccessibleHyperText.idl | 54 + accessible/interfaces/nsIAccessibleImage.idl | 31 + .../nsIAccessibleObjectAttributeChangedEvent.idl | 21 + accessible/interfaces/nsIAccessiblePivot.idl | 259 ++ accessible/interfaces/nsIAccessibleRelation.idl | 173 ++ accessible/interfaces/nsIAccessibleRole.idl | 980 +++++++ accessible/interfaces/nsIAccessibleSelectable.idl | 59 + .../interfaces/nsIAccessibleStateChangeEvent.idl | 29 + accessible/interfaces/nsIAccessibleStates.idl | 76 + accessible/interfaces/nsIAccessibleTable.idl | 268 ++ .../interfaces/nsIAccessibleTableChangeEvent.idl | 20 + accessible/interfaces/nsIAccessibleText.idl | 237 ++ .../interfaces/nsIAccessibleTextChangeEvent.idl | 33 + accessible/interfaces/nsIAccessibleTextRange.idl | 159 ++ accessible/interfaces/nsIAccessibleTypes.idl | 81 + accessible/interfaces/nsIAccessibleValue.idl | 35 + .../nsIAccessibleVirtualCursorChangeEvent.idl | 34 + accessible/interfaces/nsIXBLAccessible.idl | 20 + accessible/ipc/DocAccessibleChildBase.cpp | 97 + accessible/ipc/DocAccessibleChildBase.h | 81 + accessible/ipc/DocAccessibleParent.cpp | 526 ++++ accessible/ipc/DocAccessibleParent.h | 198 ++ accessible/ipc/IPCTypes.h | 49 + accessible/ipc/ProxyAccessibleBase.cpp | 175 ++ accessible/ipc/ProxyAccessibleBase.h | 211 ++ accessible/ipc/ProxyAccessibleShared.h | 277 ++ accessible/ipc/moz.build | 61 + accessible/ipc/other/DocAccessibleChild.cpp | 1998 ++++++++++++++ accessible/ipc/other/DocAccessibleChild.h | 489 ++++ accessible/ipc/other/PDocAccessible.ipdl | 264 ++ accessible/ipc/other/ProxyAccessible.cpp | 1080 ++++++++ accessible/ipc/other/ProxyAccessible.h | 50 + accessible/ipc/other/moz.build | 47 + accessible/ipc/win/COMPtrTypes.cpp | 50 + accessible/ipc/win/COMPtrTypes.h | 27 + accessible/ipc/win/DocAccessibleChild.cpp | 237 ++ accessible/ipc/win/DocAccessibleChild.h | 318 +++ accessible/ipc/win/PDocAccessible.ipdl | 75 + accessible/ipc/win/PlatformChild.cpp | 62 + accessible/ipc/win/PlatformChild.h | 35 + accessible/ipc/win/ProxyAccessible.cpp | 599 ++++ accessible/ipc/win/ProxyAccessible.h | 58 + accessible/ipc/win/moz.build | 39 + accessible/ipc/win/typelib/Accessible.idl | 16 + accessible/ipc/win/typelib/Makefile.in | 31 + accessible/ipc/win/typelib/moz.build | 13 + accessible/jsat/AccessFu.css | 59 + accessible/jsat/AccessFu.jsm | 1000 +++++++ accessible/jsat/Constants.jsm | 59 + accessible/jsat/ContentControl.jsm | 528 ++++ accessible/jsat/EventManager.jsm | 723 +++++ accessible/jsat/Gestures.jsm | 956 +++++++ accessible/jsat/OutputGenerator.jsm | 1003 +++++++ accessible/jsat/PointerAdapter.jsm | 174 ++ accessible/jsat/Presentation.jsm | 769 ++++++ accessible/jsat/Traversal.jsm | 419 +++ accessible/jsat/Utils.jsm | 1114 ++++++++ accessible/jsat/content-script.js | 151 ++ accessible/jsat/jar.mn | 10 + accessible/jsat/moz.build | 20 + accessible/jsat/sounds/clicked.ogg | Bin 0 -> 6618 bytes accessible/jsat/sounds/virtual_cursor_key.ogg | Bin 0 -> 4224 bytes accessible/jsat/sounds/virtual_cursor_move.ogg | Bin 0 -> 5636 bytes accessible/mac/ARIAGridAccessibleWrap.h | 22 + accessible/mac/AccessibleWrap.h | 103 + accessible/mac/AccessibleWrap.mm | 256 ++ accessible/mac/ApplicationAccessibleWrap.h | 22 + accessible/mac/DocAccessibleWrap.h | 25 + accessible/mac/DocAccessibleWrap.mm | 21 + accessible/mac/HTMLTableAccessibleWrap.h | 24 + accessible/mac/HyperTextAccessibleWrap.h | 20 + accessible/mac/ImageAccessibleWrap.h | 22 + accessible/mac/MacUtils.h | 27 + accessible/mac/MacUtils.mm | 33 + accessible/mac/Platform.mm | 175 ++ accessible/mac/RootAccessibleWrap.h | 34 + accessible/mac/RootAccessibleWrap.mm | 53 + accessible/mac/TextLeafAccessibleWrap.h | 19 + accessible/mac/XULListboxAccessibleWrap.h | 20 + accessible/mac/XULMenuAccessibleWrap.h | 19 + accessible/mac/XULTreeGridAccessibleWrap.h | 20 + accessible/mac/moz.build | 45 + accessible/mac/mozAccessible.h | 181 ++ accessible/mac/mozAccessible.mm | 1236 +++++++++ accessible/mac/mozAccessibleProtocol.h | 69 + accessible/mac/mozActionElements.h | 37 + accessible/mac/mozActionElements.mm | 340 +++ accessible/mac/mozDocAccessible.h | 31 + accessible/mac/mozDocAccessible.mm | 111 + accessible/mac/mozHTMLAccessible.h | 16 + accessible/mac/mozHTMLAccessible.mm | 139 + accessible/mac/mozTableAccessible.h | 28 + accessible/mac/mozTableAccessible.mm | 240 ++ accessible/mac/mozTextAccessible.h | 17 + accessible/mac/mozTextAccessible.mm | 626 +++++ accessible/moz.build | 36 + accessible/other/ARIAGridAccessibleWrap.h | 23 + accessible/other/AccessibleWrap.cpp | 25 + accessible/other/AccessibleWrap.h | 29 + accessible/other/ApplicationAccessibleWrap.h | 21 + accessible/other/DocAccessibleWrap.h | 23 + accessible/other/HTMLTableAccessibleWrap.h | 24 + accessible/other/HyperTextAccessibleWrap.h | 20 + accessible/other/ImageAccessibleWrap.h | 22 + accessible/other/Platform.cpp | 61 + accessible/other/RootAccessibleWrap.h | 23 + accessible/other/TextLeafAccessibleWrap.h | 19 + accessible/other/XULListboxAccessibleWrap.h | 20 + accessible/other/XULMenuAccessibleWrap.h | 19 + accessible/other/XULTreeGridAccessibleWrap.h | 20 + accessible/other/moz.build | 27 + accessible/tests/browser/.eslintrc.js | 218 ++ accessible/tests/browser/browser.ini | 17 + .../browser/browser_shutdown_multi_reference.js | 48 + .../browser_shutdown_parent_own_reference.js | 72 + .../browser_shutdown_remote_no_reference.js | 48 + .../tests/browser/browser_shutdown_remote_only.js | 40 + .../browser_shutdown_remote_own_reference.js | 75 + .../browser/browser_shutdown_scope_lifecycle.js | 21 + .../browser/browser_shutdown_start_restart.js | 41 + accessible/tests/browser/e10s/browser.ini | 51 + .../browser/e10s/browser_caching_attributes.js | 117 + .../browser/e10s/browser_caching_description.js | 164 ++ .../tests/browser/e10s/browser_caching_name.js | 434 +++ .../browser/e10s/browser_caching_relations.js | 86 + .../tests/browser/e10s/browser_caching_states.js | 120 + .../tests/browser/e10s/browser_caching_value.js | 155 ++ .../tests/browser/e10s/browser_events_caretmove.js | 21 + .../tests/browser/e10s/browser_events_hide.js | 35 + .../tests/browser/e10s/browser_events_show.js | 17 + .../browser/e10s/browser_events_statechange.js | 62 + .../browser/e10s/browser_events_textchange.js | 74 + .../browser/e10s/browser_treeupdate_ariadialog.js | 43 + .../browser/e10s/browser_treeupdate_ariaowns.js | 318 +++ .../browser/e10s/browser_treeupdate_canvas.js | 25 + .../browser/e10s/browser_treeupdate_cssoverflow.js | 64 + .../tests/browser/e10s/browser_treeupdate_doc.js | 312 +++ .../browser/e10s/browser_treeupdate_gencontent.js | 78 + .../browser/e10s/browser_treeupdate_hidden.js | 30 + .../browser/e10s/browser_treeupdate_imagemap.js | 176 ++ .../tests/browser/e10s/browser_treeupdate_list.js | 43 + .../e10s/browser_treeupdate_list_editabledoc.js | 39 + .../browser/e10s/browser_treeupdate_listener.js | 29 + .../browser/e10s/browser_treeupdate_optgroup.js | 91 + .../browser/e10s/browser_treeupdate_removal.js | 39 + .../tests/browser/e10s/browser_treeupdate_table.js | 51 + .../browser/e10s/browser_treeupdate_textleaf.js | 35 + .../browser/e10s/browser_treeupdate_visibility.js | 196 ++ .../browser/e10s/browser_treeupdate_whitespace.js | 71 + .../browser/e10s/doc_treeupdate_ariadialog.html | 23 + .../browser/e10s/doc_treeupdate_ariaowns.html | 44 + .../browser/e10s/doc_treeupdate_imagemap.html | 21 + .../browser/e10s/doc_treeupdate_removal.xhtml | 11 + .../browser/e10s/doc_treeupdate_visibility.html | 78 + .../browser/e10s/doc_treeupdate_whitespace.html | 10 + accessible/tests/browser/e10s/events.js | 127 + accessible/tests/browser/e10s/head.js | 84 + accessible/tests/browser/head.js | 116 + accessible/tests/browser/shared-head.js | 229 ++ accessible/tests/crashtests/448064.xhtml | 73 + accessible/tests/crashtests/471493.xul | 35 + accessible/tests/crashtests/crashtests.list | 3 + accessible/tests/mochitest/a11y.ini | 17 + accessible/tests/mochitest/actions.js | 187 ++ accessible/tests/mochitest/actions/a11y.ini | 18 + .../tests/mochitest/actions/test_anchors.html | 150 + accessible/tests/mochitest/actions/test_aria.html | 202 ++ .../tests/mochitest/actions/test_controls.html | 109 + .../tests/mochitest/actions/test_general.html | 107 + .../tests/mochitest/actions/test_general.xul | 145 + accessible/tests/mochitest/actions/test_keys.html | 60 + .../tests/mochitest/actions/test_keys_menu.xul | 99 + accessible/tests/mochitest/actions/test_link.html | 147 + accessible/tests/mochitest/actions/test_media.html | 121 + .../tests/mochitest/actions/test_select.html | 105 + accessible/tests/mochitest/actions/test_tree.xul | 128 + .../tests/mochitest/actions/test_treegrid.xul | 197 ++ accessible/tests/mochitest/aom/a11y.ini | 3 + accessible/tests/mochitest/aom/test_general.html | 55 + accessible/tests/mochitest/attributes.js | 382 +++ accessible/tests/mochitest/attributes/a11y.ini | 12 + .../tests/mochitest/attributes/test_obj.html | 278 ++ .../tests/mochitest/attributes/test_obj_css.html | 231 ++ .../tests/mochitest/attributes/test_obj_css.xul | 73 + .../tests/mochitest/attributes/test_obj_group.html | 469 ++++ .../tests/mochitest/attributes/test_obj_group.xul | 216 ++ .../mochitest/attributes/test_obj_group_tree.xul | 85 + .../tests/mochitest/attributes/test_tag.html | 82 + .../tests/mochitest/attributes/test_xml-roles.html | 251 ++ accessible/tests/mochitest/autocomplete.js | 221 ++ accessible/tests/mochitest/bounds/a11y.ini | 8 + accessible/tests/mochitest/bounds/test_list.html | 81 + accessible/tests/mochitest/bounds/test_select.html | 85 + accessible/tests/mochitest/bounds/test_zoom.html | 96 + .../tests/mochitest/bounds/test_zoom_text.html | 77 + accessible/tests/mochitest/browser.js | 153 ++ accessible/tests/mochitest/common.js | 952 +++++++ accessible/tests/mochitest/dumbfile.zip | Bin 0 -> 22 bytes accessible/tests/mochitest/editabletext/a11y.ini | 7 + .../tests/mochitest/editabletext/editabletext.js | 353 +++ .../tests/mochitest/editabletext/test_1.html | 144 + .../tests/mochitest/editabletext/test_2.html | 63 + accessible/tests/mochitest/elm/a11y.ini | 16 + accessible/tests/mochitest/elm/test_HTMLSpec.html | 1671 ++++++++++++ .../tests/mochitest/elm/test_MathMLSpec.html | 620 +++++ accessible/tests/mochitest/elm/test_canvas.html | 58 + accessible/tests/mochitest/elm/test_figure.html | 62 + accessible/tests/mochitest/elm/test_listbox.xul | 74 + .../tests/mochitest/elm/test_nsApplicationAcc.html | 75 + accessible/tests/mochitest/elm/test_plugin.html | 79 + .../tests/mochitest/elm/test_shadowroot.html | 60 + accessible/tests/mochitest/events.js | 2329 ++++++++++++++++ accessible/tests/mochitest/events/a11y.ini | 67 + accessible/tests/mochitest/events/docload_wnd.html | 39 + accessible/tests/mochitest/events/focus.html | 10 + accessible/tests/mochitest/events/scroll.html | 181 ++ .../tests/mochitest/events/test_aria_alert.html | 92 + .../tests/mochitest/events/test_aria_menu.html | 285 ++ .../tests/mochitest/events/test_aria_objattr.html | 118 + .../tests/mochitest/events/test_aria_owns.html | 129 + .../mochitest/events/test_aria_statechange.html | 208 ++ accessible/tests/mochitest/events/test_attrs.html | 90 + .../tests/mochitest/events/test_bug1322593-2.html | 83 + .../tests/mochitest/events/test_bug1322593.html | 80 + .../tests/mochitest/events/test_caretmove.html | 140 + .../tests/mochitest/events/test_caretmove.xul | 72 + .../tests/mochitest/events/test_coalescence.html | 864 ++++++ .../tests/mochitest/events/test_contextmenu.html | 139 + .../tests/mochitest/events/test_descrchange.html | 85 + .../tests/mochitest/events/test_docload.html | 360 +++ accessible/tests/mochitest/events/test_docload.xul | 243 ++ .../tests/mochitest/events/test_docload_aria.html | 83 + .../tests/mochitest/events/test_dragndrop.html | 110 + accessible/tests/mochitest/events/test_flush.html | 77 + .../events/test_focus_aria_activedescendant.html | 120 + .../mochitest/events/test_focus_autocomplete.xul | 518 ++++ .../mochitest/events/test_focus_browserui.xul | 149 + .../tests/mochitest/events/test_focus_canvas.html | 61 + .../mochitest/events/test_focus_contextmenu.xul | 99 + .../mochitest/events/test_focus_controls.html | 75 + .../tests/mochitest/events/test_focus_dialog.html | 164 ++ .../tests/mochitest/events/test_focus_doc.html | 95 + .../tests/mochitest/events/test_focus_general.html | 179 ++ .../tests/mochitest/events/test_focus_general.xul | 179 ++ .../mochitest/events/test_focus_listcontrols.xul | 189 ++ .../tests/mochitest/events/test_focus_menu.xul | 119 + .../tests/mochitest/events/test_focus_name.html | 122 + .../tests/mochitest/events/test_focus_selects.html | 118 + .../tests/mochitest/events/test_focus_tabbox.xul | 103 + .../tests/mochitest/events/test_focus_tree.xul | 122 + .../tests/mochitest/events/test_fromUserInput.html | 127 + accessible/tests/mochitest/events/test_label.xul | 177 ++ accessible/tests/mochitest/events/test_menu.xul | 202 ++ .../tests/mochitest/events/test_mutation.html | 632 +++++ .../tests/mochitest/events/test_mutation.xhtml | 97 + .../tests/mochitest/events/test_namechange.html | 123 + .../tests/mochitest/events/test_namechange.xul | 92 + accessible/tests/mochitest/events/test_scroll.xul | 131 + .../tests/mochitest/events/test_scroll_caret.xul | 91 + .../tests/mochitest/events/test_selection.html | 118 + .../tests/mochitest/events/test_selection.xul | 255 ++ .../mochitest/events/test_selection_aria.html | 127 + .../tests/mochitest/events/test_statechange.html | 287 ++ accessible/tests/mochitest/events/test_text.html | 339 +++ .../tests/mochitest/events/test_text_alg.html | 249 ++ .../mochitest/events/test_textattrchange.html | 115 + .../tests/mochitest/events/test_textselchange.html | 86 + accessible/tests/mochitest/events/test_tree.xul | 348 +++ .../tests/mochitest/events/test_valuechange.html | 255 ++ accessible/tests/mochitest/focus/a11y.ini | 9 + .../tests/mochitest/focus/test_focusedChild.html | 87 + .../tests/mochitest/focus/test_takeFocus.html | 128 + .../tests/mochitest/focus/test_takeFocus.xul | 106 + accessible/tests/mochitest/formimage.png | Bin 0 -> 20105 bytes accessible/tests/mochitest/grid.js | 149 + accessible/tests/mochitest/hittest/a11y.ini | 14 + .../tests/mochitest/hittest/test_browser.html | 63 + .../mochitest/hittest/test_canvas_hitregion.html | 88 + .../tests/mochitest/hittest/test_general.html | 115 + accessible/tests/mochitest/hittest/test_menu.xul | 134 + .../tests/mochitest/hittest/test_shadowroot.html | 72 + accessible/tests/mochitest/hittest/test_zoom.html | 61 + .../tests/mochitest/hittest/test_zoom_text.html | 57 + .../tests/mochitest/hittest/test_zoom_tree.xul | 100 + accessible/tests/mochitest/hittest/zoom_tree.xul | 18 + accessible/tests/mochitest/hyperlink/a11y.ini | 7 + accessible/tests/mochitest/hyperlink/hyperlink.js | 42 + .../tests/mochitest/hyperlink/test_general.html | 279 ++ .../tests/mochitest/hyperlink/test_general.xul | 97 + accessible/tests/mochitest/hypertext/a11y.ini | 7 + .../tests/mochitest/hypertext/test_general.html | 156 ++ .../tests/mochitest/hypertext/test_update.html | 236 ++ accessible/tests/mochitest/jsat/a11y.ini | 30 + .../mochitest/jsat/doc_content_integration.html | 115 + .../tests/mochitest/jsat/doc_content_text.html | 15 + accessible/tests/mochitest/jsat/doc_traversal.html | 164 ++ accessible/tests/mochitest/jsat/dom_helper.js | 209 ++ accessible/tests/mochitest/jsat/gestures.json | 352 +++ accessible/tests/mochitest/jsat/jsatcommon.js | 739 +++++ accessible/tests/mochitest/jsat/output.js | 114 + accessible/tests/mochitest/jsat/test_alive.html | 81 + .../mochitest/jsat/test_content_integration.html | 343 +++ .../tests/mochitest/jsat/test_content_text.html | 292 ++ .../tests/mochitest/jsat/test_explicit_names.html | 191 ++ .../tests/mochitest/jsat/test_gesture_tracker.html | 51 + accessible/tests/mochitest/jsat/test_hints.html | 89 + .../tests/mochitest/jsat/test_landmarks.html | 183 ++ .../tests/mochitest/jsat/test_live_regions.html | 472 ++++ accessible/tests/mochitest/jsat/test_output.html | 673 +++++ .../tests/mochitest/jsat/test_output_mathml.html | 313 +++ .../tests/mochitest/jsat/test_pointer_relay.html | 95 + .../tests/mochitest/jsat/test_quicknav_modes.html | 107 + accessible/tests/mochitest/jsat/test_tables.html | 579 ++++ .../tests/mochitest/jsat/test_traversal.html | 167 ++ .../mochitest/jsat/test_traversal_helper.html | 113 + accessible/tests/mochitest/layout.js | 258 ++ accessible/tests/mochitest/letters.gif | Bin 0 -> 5596 bytes accessible/tests/mochitest/longdesc_src.html | 8 + accessible/tests/mochitest/moz.build | 37 + accessible/tests/mochitest/moz.png | Bin 0 -> 1991 bytes accessible/tests/mochitest/name.js | 33 + accessible/tests/mochitest/name/a11y.ini | 20 + accessible/tests/mochitest/name/general.css | 11 + accessible/tests/mochitest/name/general.xbl | 32 + accessible/tests/mochitest/name/markup.js | 382 +++ accessible/tests/mochitest/name/markuprules.xml | 373 +++ accessible/tests/mochitest/name/test_browserui.xul | 107 + .../tests/mochitest/name/test_counterstyle.html | 153 ++ accessible/tests/mochitest/name/test_general.html | 631 +++++ accessible/tests/mochitest/name/test_general.xul | 382 +++ accessible/tests/mochitest/name/test_link.html | 89 + accessible/tests/mochitest/name/test_list.html | 89 + accessible/tests/mochitest/name/test_markup.html | 60 + accessible/tests/mochitest/name/test_svg.html | 55 + .../tests/mochitest/name/test_toolbaritem.xul | 84 + accessible/tests/mochitest/name/test_tree.xul | 211 ++ accessible/tests/mochitest/pivot.js | 551 ++++ accessible/tests/mochitest/pivot/a11y.ini | 8 + .../tests/mochitest/pivot/doc_virtualcursor.html | 38 + .../mochitest/pivot/doc_virtualcursor_text.html | 29 + .../tests/mochitest/pivot/test_virtualcursor.html | 129 + .../mochitest/pivot/test_virtualcursor_text.html | 241 ++ accessible/tests/mochitest/relations.js | 192 ++ accessible/tests/mochitest/relations/a11y.ini | 12 + .../tests/mochitest/relations/test_bindings.xhtml | 103 + .../tests/mochitest/relations/test_embeds.xul | 122 + .../tests/mochitest/relations/test_general.html | 406 +++ .../tests/mochitest/relations/test_general.xul | 238 ++ .../tests/mochitest/relations/test_tabbrowser.xul | 103 + accessible/tests/mochitest/relations/test_tree.xul | 106 + .../mochitest/relations/test_ui_modalprompt.html | 107 + .../tests/mochitest/relations/test_update.html | 225 ++ accessible/tests/mochitest/role.js | 178 ++ accessible/tests/mochitest/role/a11y.ini | 10 + accessible/tests/mochitest/role/test_aria.html | 345 +++ accessible/tests/mochitest/role/test_aria.xul | 72 + accessible/tests/mochitest/role/test_general.html | 186 ++ accessible/tests/mochitest/role/test_general.xul | 57 + accessible/tests/mochitest/role/test_svg.html | 70 + accessible/tests/mochitest/scroll/a11y.ini | 6 + accessible/tests/mochitest/scroll/test_zoom.html | 148 + .../tests/mochitest/scroll/test_zoom_text.html | 158 ++ accessible/tests/mochitest/selectable.js | 80 + accessible/tests/mochitest/selectable/a11y.ini | 11 + .../tests/mochitest/selectable/test_aria.html | 225 ++ .../tests/mochitest/selectable/test_listbox.xul | 152 ++ .../tests/mochitest/selectable/test_menu.xul | 78 + .../tests/mochitest/selectable/test_menulist.xul | 96 + .../tests/mochitest/selectable/test_select.html | 243 ++ .../tests/mochitest/selectable/test_tree.xul | 188 ++ accessible/tests/mochitest/states.js | 266 ++ accessible/tests/mochitest/states/a11y.ini | 37 + accessible/tests/mochitest/states/test_aria.html | 629 +++++ accessible/tests/mochitest/states/test_aria.xul | 60 + .../tests/mochitest/states/test_aria_imgmap.html | 79 + .../mochitest/states/test_aria_widgetitems.html | 162 ++ .../tests/mochitest/states/test_buttons.html | 85 + .../tests/mochitest/states/test_controls.html | 53 + .../tests/mochitest/states/test_controls.xul | 182 ++ accessible/tests/mochitest/states/test_doc.html | 89 + .../tests/mochitest/states/test_doc_busy.html | 79 + .../tests/mochitest/states/test_docarticle.html | 80 + .../tests/mochitest/states/test_editablebody.html | 46 + .../tests/mochitest/states/test_expandable.xul | 118 + accessible/tests/mochitest/states/test_frames.html | 95 + accessible/tests/mochitest/states/test_inputs.html | 271 ++ accessible/tests/mochitest/states/test_link.html | 144 + accessible/tests/mochitest/states/test_popup.xul | 55 + .../tests/mochitest/states/test_selects.html | 203 ++ accessible/tests/mochitest/states/test_stale.html | 115 + accessible/tests/mochitest/states/test_tabs.xul | 70 + accessible/tests/mochitest/states/test_textbox.xul | 153 ++ accessible/tests/mochitest/states/test_tree.xul | 152 ++ .../tests/mochitest/states/test_visibility.html | 175 ++ .../tests/mochitest/states/test_visibility.xul | 152 ++ accessible/tests/mochitest/states/z_frames.html | 11 + .../tests/mochitest/states/z_frames_article.html | 11 + .../tests/mochitest/states/z_frames_checkbox.html | 11 + .../tests/mochitest/states/z_frames_textbox.html | 11 + .../tests/mochitest/states/z_frames_update.html | 22 + accessible/tests/mochitest/table.js | 778 ++++++ accessible/tests/mochitest/table/a11y.ini | 27 + .../tests/mochitest/table/test_css_tables.html | 116 + .../mochitest/table/test_headers_ariagrid.html | 185 ++ .../mochitest/table/test_headers_ariatable.html | 96 + .../tests/mochitest/table/test_headers_listbox.xul | 194 ++ .../tests/mochitest/table/test_headers_table.html | 713 +++++ .../tests/mochitest/table/test_headers_tree.xul | 101 + .../mochitest/table/test_indexes_ariagrid.html | 139 + .../tests/mochitest/table/test_indexes_listbox.xul | 85 + .../tests/mochitest/table/test_indexes_table.html | 410 +++ .../tests/mochitest/table/test_indexes_tree.xul | 71 + .../tests/mochitest/table/test_layoutguess.html | 506 ++++ accessible/tests/mochitest/table/test_mtable.html | 128 + .../tests/mochitest/table/test_sels_ariagrid.html | 161 ++ .../tests/mochitest/table/test_sels_listbox.xul | 247 ++ .../tests/mochitest/table/test_sels_table.html | 180 ++ .../tests/mochitest/table/test_sels_tree.xul | 79 + .../mochitest/table/test_struct_ariagrid.html | 149 + .../mochitest/table/test_struct_ariatreegrid.html | 76 + .../tests/mochitest/table/test_struct_listbox.xul | 117 + .../tests/mochitest/table/test_struct_table.html | 203 ++ .../tests/mochitest/table/test_struct_tree.xul | 74 + accessible/tests/mochitest/table/test_table_1.html | 105 + accessible/tests/mochitest/table/test_table_2.html | 89 + .../tests/mochitest/test_OuterDocAccessible.html | 89 + .../tests/mochitest/test_aria_token_attrs.html | 329 +++ accessible/tests/mochitest/test_bug420863.html | 103 + accessible/tests/mochitest/test_descr.html | 121 + .../mochitest/test_nsIAccessibleDocument.html | 96 + .../tests/mochitest/test_nsIAccessibleImage.html | 202 ++ accessible/tests/mochitest/text.js | 634 +++++ accessible/tests/mochitest/text/a11y.ini | 16 + accessible/tests/mochitest/text/doc.html | 9 + .../tests/mochitest/text/test_atcaretoffset.html | 455 ++++ .../tests/mochitest/text/test_charboundary.html | 140 + accessible/tests/mochitest/text/test_doc.html | 42 + accessible/tests/mochitest/text/test_dynamic.html | 88 + accessible/tests/mochitest/text/test_general.xul | 80 + accessible/tests/mochitest/text/test_gettext.html | 112 + .../tests/mochitest/text/test_hypertext.html | 147 + .../tests/mochitest/text/test_lineboundary.html | 265 ++ .../tests/mochitest/text/test_passwords.html | 60 + .../tests/mochitest/text/test_selection.html | 101 + .../tests/mochitest/text/test_wordboundary.html | 291 ++ accessible/tests/mochitest/text/test_words.html | 133 + accessible/tests/mochitest/textattrs/a11y.ini | 7 + .../tests/mochitest/textattrs/test_general.html | 735 +++++ .../tests/mochitest/textattrs/test_invalid.html | 62 + accessible/tests/mochitest/textcaret/a11y.ini | 6 + .../tests/mochitest/textcaret/test_browserui.xul | 67 + .../tests/mochitest/textcaret/test_general.html | 183 ++ accessible/tests/mochitest/textrange/a11y.ini | 7 + .../tests/mochitest/textrange/test_general.html | 108 + .../tests/mochitest/textrange/test_selection.html | 120 + accessible/tests/mochitest/textselection/a11y.ini | 6 + .../mochitest/textselection/test_general.html | 221 ++ .../mochitest/textselection/test_userinput.html | 95 + accessible/tests/mochitest/tree/a11y.ini | 51 + accessible/tests/mochitest/tree/dockids.html | 30 + .../tests/mochitest/tree/test_applicationacc.xul | 74 + .../tests/mochitest/tree/test_aria_globals.html | 129 + .../tests/mochitest/tree/test_aria_grid.html | 279 ++ .../tests/mochitest/tree/test_aria_imgmap.html | 108 + .../tests/mochitest/tree/test_aria_list.html | 92 + .../tests/mochitest/tree/test_aria_menu.html | 93 + .../tests/mochitest/tree/test_aria_owns.html | 187 ++ .../mochitest/tree/test_aria_presentation.html | 179 ++ .../tests/mochitest/tree/test_aria_table.html | 63 + .../tests/mochitest/tree/test_brokencontext.html | 265 ++ accessible/tests/mochitest/tree/test_button.xul | 73 + accessible/tests/mochitest/tree/test_canvas.html | 55 + accessible/tests/mochitest/tree/test_combobox.xul | 291 ++ .../tests/mochitest/tree/test_cssflexbox.html | 80 + .../tests/mochitest/tree/test_cssoverflow.html | 146 + .../tests/mochitest/tree/test_dochierarchy.html | 86 + accessible/tests/mochitest/tree/test_dockids.html | 65 + accessible/tests/mochitest/tree/test_filectrl.html | 58 + accessible/tests/mochitest/tree/test_formctrl.html | 132 + accessible/tests/mochitest/tree/test_formctrl.xul | 130 + .../tests/mochitest/tree/test_gencontent.html | 71 + accessible/tests/mochitest/tree/test_groupbox.xul | 64 + accessible/tests/mochitest/tree/test_iframe.html | 52 + accessible/tests/mochitest/tree/test_img.html | 88 + .../tests/mochitest/tree/test_invalid_img.xhtml | 50 + .../mochitest/tree/test_invalidationlist.html | 57 + accessible/tests/mochitest/tree/test_list.html | 247 ++ accessible/tests/mochitest/tree/test_map.html | 83 + accessible/tests/mochitest/tree/test_media.html | 84 + accessible/tests/mochitest/tree/test_select.html | 139 + accessible/tests/mochitest/tree/test_tabbox.xul | 99 + .../tests/mochitest/tree/test_tabbrowser.xul | 255 ++ accessible/tests/mochitest/tree/test_table.html | 282 ++ accessible/tests/mochitest/tree/test_tree.xul | 182 ++ accessible/tests/mochitest/tree/test_txtcntr.html | 234 ++ accessible/tests/mochitest/tree/test_txtctrl.html | 173 ++ accessible/tests/mochitest/tree/test_txtctrl.xul | 219 ++ accessible/tests/mochitest/tree/wnd.xul | 8 + accessible/tests/mochitest/treeupdate/a11y.ini | 41 + .../mochitest/treeupdate/test_ariadialog.html | 119 + .../tests/mochitest/treeupdate/test_ariaowns.html | 693 +++++ .../mochitest/treeupdate/test_bug1040735.html | 42 + .../mochitest/treeupdate/test_bug1100602.html | 114 + .../mochitest/treeupdate/test_bug1175913.html | 105 + .../mochitest/treeupdate/test_bug1189277.html | 86 + .../mochitest/treeupdate/test_bug1276857.html | 143 + .../mochitest/treeupdate/test_bug852150.xhtml | 59 + .../mochitest/treeupdate/test_bug883708.xhtml | 33 + .../mochitest/treeupdate/test_bug884251.xhtml | 21 + .../tests/mochitest/treeupdate/test_bug895082.html | 51 + .../tests/mochitest/treeupdate/test_canvas.html | 92 + .../mochitest/treeupdate/test_colorpicker.xul | 150 + .../mochitest/treeupdate/test_contextmenu.xul | 317 +++ .../mochitest/treeupdate/test_cssoverflow.html | 143 + .../tests/mochitest/treeupdate/test_deck.xul | 109 + .../tests/mochitest/treeupdate/test_doc.html | 466 ++++ .../mochitest/treeupdate/test_gencontent.html | 160 ++ .../tests/mochitest/treeupdate/test_general.html | 150 + .../tests/mochitest/treeupdate/test_hidden.html | 135 + .../tests/mochitest/treeupdate/test_imagemap.html | 442 +++ .../tests/mochitest/treeupdate/test_list.html | 152 ++ .../treeupdate/test_list_editabledoc.html | 106 + .../tests/mochitest/treeupdate/test_listbox.xul | 180 ++ .../tests/mochitest/treeupdate/test_menu.xul | 128 + .../tests/mochitest/treeupdate/test_menubutton.xul | 198 ++ .../tests/mochitest/treeupdate/test_optgroup.html | 137 + .../mochitest/treeupdate/test_recreation.html | 155 ++ .../tests/mochitest/treeupdate/test_select.html | 130 + .../tests/mochitest/treeupdate/test_shutdown.xul | 132 + .../tests/mochitest/treeupdate/test_table.html | 81 + .../tests/mochitest/treeupdate/test_textleaf.html | 180 ++ .../mochitest/treeupdate/test_visibility.html | 437 +++ .../mochitest/treeupdate/test_whitespace.html | 187 ++ accessible/tests/mochitest/treeview.css | 15 + accessible/tests/mochitest/treeview.js | 289 ++ accessible/tests/mochitest/value.js | 32 + accessible/tests/mochitest/value/a11y.ini | 9 + accessible/tests/mochitest/value/test_general.html | 159 ++ accessible/tests/mochitest/value/test_number.html | 59 + .../tests/mochitest/value/test_progress.html | 61 + accessible/tests/mochitest/value/test_progress.xul | 72 + accessible/tests/mochitest/value/test_range.html | 59 + accessible/windows/ProxyWrappers.h | 92 + accessible/windows/ia2/ia2Accessible.cpp | 810 ++++++ accessible/windows/ia2/ia2Accessible.h | 122 + accessible/windows/ia2/ia2AccessibleAction.cpp | 188 ++ accessible/windows/ia2/ia2AccessibleAction.h | 93 + accessible/windows/ia2/ia2AccessibleComponent.cpp | 127 + accessible/windows/ia2/ia2AccessibleComponent.h | 38 + .../windows/ia2/ia2AccessibleEditableText.cpp | 153 ++ accessible/windows/ia2/ia2AccessibleEditableText.h | 56 + accessible/windows/ia2/ia2AccessibleHyperlink.cpp | 205 ++ accessible/windows/ia2/ia2AccessibleHyperlink.h | 51 + accessible/windows/ia2/ia2AccessibleHypertext.cpp | 93 + accessible/windows/ia2/ia2AccessibleHypertext.h | 43 + accessible/windows/ia2/ia2AccessibleImage.cpp | 119 + accessible/windows/ia2/ia2AccessibleImage.h | 40 + accessible/windows/ia2/ia2AccessibleRelation.cpp | 125 + accessible/windows/ia2/ia2AccessibleRelation.h | 85 + accessible/windows/ia2/ia2AccessibleTable.cpp | 747 +++++ accessible/windows/ia2/ia2AccessibleTable.h | 176 ++ accessible/windows/ia2/ia2AccessibleTableCell.cpp | 257 ++ accessible/windows/ia2/ia2AccessibleTableCell.h | 69 + accessible/windows/ia2/ia2AccessibleText.cpp | 598 ++++ accessible/windows/ia2/ia2AccessibleText.h | 275 ++ accessible/windows/ia2/ia2AccessibleValue.cpp | 151 ++ accessible/windows/ia2/ia2AccessibleValue.h | 41 + accessible/windows/ia2/moz.build | 58 + accessible/windows/moz.build | 8 + accessible/windows/msaa/ARIAGridAccessibleWrap.cpp | 47 + accessible/windows/msaa/ARIAGridAccessibleWrap.h | 65 + accessible/windows/msaa/AccessibleWrap.cpp | 1686 ++++++++++++ accessible/windows/msaa/AccessibleWrap.h | 265 ++ .../windows/msaa/ApplicationAccessibleWrap.cpp | 162 ++ .../windows/msaa/ApplicationAccessibleWrap.h | 52 + accessible/windows/msaa/Compatibility.cpp | 112 + accessible/windows/msaa/Compatibility.h | 79 + accessible/windows/msaa/DocAccessibleWrap.cpp | 165 ++ accessible/windows/msaa/DocAccessibleWrap.h | 65 + accessible/windows/msaa/EnumVariant.cpp | 108 + accessible/windows/msaa/EnumVariant.h | 60 + .../windows/msaa/HTMLTableAccessibleWrap.cpp | 64 + accessible/windows/msaa/HTMLTableAccessibleWrap.h | 93 + .../windows/msaa/HTMLWin32ObjectAccessible.cpp | 109 + .../windows/msaa/HTMLWin32ObjectAccessible.h | 70 + .../windows/msaa/HyperTextAccessibleWrap.cpp | 67 + accessible/windows/msaa/HyperTextAccessibleWrap.h | 46 + accessible/windows/msaa/IDSet.h | 136 + accessible/windows/msaa/IUnknownImpl.cpp | 58 + accessible/windows/msaa/IUnknownImpl.h | 192 ++ accessible/windows/msaa/ImageAccessibleWrap.cpp | 20 + accessible/windows/msaa/ImageAccessibleWrap.h | 38 + accessible/windows/msaa/MsaaIdGenerator.cpp | 243 ++ accessible/windows/msaa/MsaaIdGenerator.h | 56 + accessible/windows/msaa/Platform.cpp | 147 + accessible/windows/msaa/RootAccessibleWrap.cpp | 45 + accessible/windows/msaa/RootAccessibleWrap.h | 27 + accessible/windows/msaa/ServiceProvider.cpp | 96 + accessible/windows/msaa/ServiceProvider.h | 38 + accessible/windows/msaa/TextLeafAccessibleWrap.cpp | 21 + accessible/windows/msaa/TextLeafAccessibleWrap.h | 33 + .../windows/msaa/XULListboxAccessibleWrap.cpp | 46 + accessible/windows/msaa/XULListboxAccessibleWrap.h | 64 + accessible/windows/msaa/XULMenuAccessibleWrap.cpp | 36 + accessible/windows/msaa/XULMenuAccessibleWrap.h | 27 + .../windows/msaa/XULTreeGridAccessibleWrap.cpp | 44 + .../windows/msaa/XULTreeGridAccessibleWrap.h | 71 + accessible/windows/msaa/moz.build | 76 + accessible/windows/msaa/nsEventMap.h | 103 + accessible/windows/msaa/nsWinUtils.cpp | 181 ++ accessible/windows/msaa/nsWinUtils.h | 86 + accessible/windows/sdn/moz.build | 24 + accessible/windows/sdn/sdnAccessible-inl.h | 34 + accessible/windows/sdn/sdnAccessible.cpp | 539 ++++ accessible/windows/sdn/sdnAccessible.h | 119 + accessible/windows/sdn/sdnDocAccessible.cpp | 157 ++ accessible/windows/sdn/sdnDocAccessible.h | 53 + accessible/windows/sdn/sdnTextAccessible.cpp | 210 ++ accessible/windows/sdn/sdnTextAccessible.h | 71 + accessible/windows/uia/moz.build | 22 + accessible/windows/uia/uiaRawElmProvider.cpp | 246 ++ accessible/windows/uia/uiaRawElmProvider.h | 75 + accessible/xpcom/AccEventGen.py | 228 ++ accessible/xpcom/AccEvents.conf | 18 + accessible/xpcom/moz.build | 66 + accessible/xpcom/nsAccessibleRelation.cpp | 79 + accessible/xpcom/nsAccessibleRelation.h | 50 + accessible/xpcom/xpcAccessibilityService.cpp | 246 ++ accessible/xpcom/xpcAccessibilityService.h | 66 + accessible/xpcom/xpcAccessible.cpp | 826 ++++++ accessible/xpcom/xpcAccessible.h | 106 + accessible/xpcom/xpcAccessibleApplication.cpp | 69 + accessible/xpcom/xpcAccessibleApplication.h | 48 + accessible/xpcom/xpcAccessibleDocument.cpp | 262 ++ accessible/xpcom/xpcAccessibleDocument.h | 150 + accessible/xpcom/xpcAccessibleGeneric.cpp | 46 + accessible/xpcom/xpcAccessibleGeneric.h | 110 + accessible/xpcom/xpcAccessibleHyperLink.cpp | 180 ++ accessible/xpcom/xpcAccessibleHyperLink.h | 48 + accessible/xpcom/xpcAccessibleHyperText.cpp | 822 ++++++ accessible/xpcom/xpcAccessibleHyperText.h | 62 + accessible/xpcom/xpcAccessibleImage.cpp | 55 + accessible/xpcom/xpcAccessibleImage.h | 47 + accessible/xpcom/xpcAccessibleSelectable.cpp | 134 + accessible/xpcom/xpcAccessibleSelectable.h | 54 + accessible/xpcom/xpcAccessibleTable.cpp | 493 ++++ accessible/xpcom/xpcAccessibleTable.h | 96 + accessible/xpcom/xpcAccessibleTableCell.cpp | 161 ++ accessible/xpcom/xpcAccessibleTableCell.h | 62 + accessible/xpcom/xpcAccessibleTextRange.cpp | 221 ++ accessible/xpcom/xpcAccessibleTextRange.h | 85 + accessible/xpcom/xpcAccessibleValue.cpp | 133 + accessible/xpcom/xpcAccessibleValue.h | 43 + accessible/xul/XULAlertAccessible.cpp | 68 + accessible/xul/XULAlertAccessible.h | 41 + accessible/xul/XULColorPickerAccessible.cpp | 143 + accessible/xul/XULColorPickerAccessible.h | 57 + accessible/xul/XULComboboxAccessible.cpp | 194 ++ accessible/xul/XULComboboxAccessible.h | 43 + accessible/xul/XULElementAccessibles.cpp | 288 ++ accessible/xul/XULElementAccessibles.h | 116 + accessible/xul/XULFormControlAccessible.cpp | 633 +++++ accessible/xul/XULFormControlAccessible.h | 218 ++ accessible/xul/XULListboxAccessible.cpp | 828 ++++++ accessible/xul/XULListboxAccessible.h | 173 ++ accessible/xul/XULMenuAccessible.cpp | 591 ++++ accessible/xul/XULMenuAccessible.h | 122 + accessible/xul/XULSelectControlAccessible.cpp | 256 ++ accessible/xul/XULSelectControlAccessible.h | 52 + accessible/xul/XULSliderAccessible.cpp | 214 ++ accessible/xul/XULSliderAccessible.h | 75 + accessible/xul/XULTabAccessible.cpp | 209 ++ accessible/xul/XULTabAccessible.h | 96 + accessible/xul/XULTreeAccessible.cpp | 1184 ++++++++ accessible/xul/XULTreeAccessible.h | 279 ++ accessible/xul/XULTreeGridAccessible.cpp | 823 ++++++ accessible/xul/XULTreeGridAccessible.h | 187 ++ accessible/xul/moz.build | 55 + 856 files changed, 160468 insertions(+) create mode 100644 accessible/.eslintrc.js create mode 100644 accessible/aom/AccessibleNode.cpp create mode 100644 accessible/aom/AccessibleNode.h create mode 100644 accessible/aom/moz.build create mode 100644 accessible/atk/ARIAGridAccessibleWrap.h create mode 100644 accessible/atk/AccessibleWrap.cpp create mode 100644 accessible/atk/AccessibleWrap.h create mode 100644 accessible/atk/ApplicationAccessibleWrap.cpp create mode 100644 accessible/atk/ApplicationAccessibleWrap.h create mode 100644 accessible/atk/AtkSocketAccessible.cpp create mode 100644 accessible/atk/AtkSocketAccessible.h create mode 100644 accessible/atk/DocAccessibleWrap.cpp create mode 100644 accessible/atk/DocAccessibleWrap.h create mode 100644 accessible/atk/HTMLTableAccessibleWrap.h create mode 100644 accessible/atk/HyperTextAccessibleWrap.h create mode 100644 accessible/atk/ImageAccessibleWrap.h create mode 100644 accessible/atk/InterfaceInitFuncs.h create mode 100644 accessible/atk/Platform.cpp create mode 100644 accessible/atk/RootAccessibleWrap.cpp create mode 100644 accessible/atk/RootAccessibleWrap.h create mode 100644 accessible/atk/TextLeafAccessibleWrap.h create mode 100644 accessible/atk/UtilInterface.cpp create mode 100644 accessible/atk/XULListboxAccessibleWrap.h create mode 100644 accessible/atk/XULMenuAccessibleWrap.h create mode 100644 accessible/atk/XULTreeGridAccessibleWrap.h create mode 100644 accessible/atk/moz.build create mode 100644 accessible/atk/nsMai.h create mode 100644 accessible/atk/nsMaiHyperlink.cpp create mode 100644 accessible/atk/nsMaiHyperlink.h create mode 100644 accessible/atk/nsMaiInterfaceAction.cpp create mode 100644 accessible/atk/nsMaiInterfaceComponent.cpp create mode 100644 accessible/atk/nsMaiInterfaceDocument.cpp create mode 100644 accessible/atk/nsMaiInterfaceEditableText.cpp create mode 100644 accessible/atk/nsMaiInterfaceHyperlinkImpl.cpp create mode 100644 accessible/atk/nsMaiInterfaceHypertext.cpp create mode 100644 accessible/atk/nsMaiInterfaceImage.cpp create mode 100644 accessible/atk/nsMaiInterfaceSelection.cpp create mode 100644 accessible/atk/nsMaiInterfaceTable.cpp create mode 100644 accessible/atk/nsMaiInterfaceTableCell.cpp create mode 100644 accessible/atk/nsMaiInterfaceText.cpp create mode 100644 accessible/atk/nsMaiInterfaceValue.cpp create mode 100644 accessible/atk/nsStateMap.h create mode 100644 accessible/base/ARIAMap.cpp create mode 100644 accessible/base/ARIAMap.h create mode 100644 accessible/base/ARIAStateMap.cpp create mode 100644 accessible/base/ARIAStateMap.h create mode 100644 accessible/base/AccEvent.cpp create mode 100644 accessible/base/AccEvent.h create mode 100644 accessible/base/AccGroupInfo.cpp create mode 100644 accessible/base/AccGroupInfo.h create mode 100644 accessible/base/AccIterator.cpp create mode 100644 accessible/base/AccIterator.h create mode 100644 accessible/base/AccTypes.h create mode 100644 accessible/base/AccessibleOrProxy.cpp create mode 100644 accessible/base/AccessibleOrProxy.h create mode 100644 accessible/base/Asserts.cpp create mode 100644 accessible/base/DocManager.cpp create mode 100644 accessible/base/DocManager.h create mode 100644 accessible/base/EmbeddedObjCollector.cpp create mode 100644 accessible/base/EmbeddedObjCollector.h create mode 100644 accessible/base/EventQueue.cpp create mode 100644 accessible/base/EventQueue.h create mode 100644 accessible/base/EventTree.cpp create mode 100644 accessible/base/EventTree.h create mode 100644 accessible/base/Filters.cpp create mode 100644 accessible/base/Filters.h create mode 100644 accessible/base/FocusManager.cpp create mode 100644 accessible/base/FocusManager.h create mode 100644 accessible/base/Logging.cpp create mode 100644 accessible/base/Logging.h create mode 100644 accessible/base/MarkupMap.h create mode 100644 accessible/base/NotificationController.cpp create mode 100644 accessible/base/NotificationController.h create mode 100644 accessible/base/Platform.h create mode 100644 accessible/base/Relation.h create mode 100644 accessible/base/RelationType.h create mode 100644 accessible/base/RelationTypeMap.h create mode 100644 accessible/base/Role.h create mode 100644 accessible/base/RoleMap.h create mode 100644 accessible/base/SelectionManager.cpp create mode 100644 accessible/base/SelectionManager.h create mode 100644 accessible/base/States.h create mode 100644 accessible/base/Statistics.h create mode 100644 accessible/base/StyleInfo.cpp create mode 100644 accessible/base/StyleInfo.h create mode 100644 accessible/base/TextAttrs.cpp create mode 100644 accessible/base/TextAttrs.h create mode 100644 accessible/base/TextRange-inl.h create mode 100644 accessible/base/TextRange.cpp create mode 100644 accessible/base/TextRange.h create mode 100644 accessible/base/TextUpdater.cpp create mode 100644 accessible/base/TextUpdater.h create mode 100644 accessible/base/TreeWalker.cpp create mode 100644 accessible/base/TreeWalker.h create mode 100644 accessible/base/moz.build create mode 100644 accessible/base/nsAccCache.h create mode 100644 accessible/base/nsAccUtils.cpp create mode 100644 accessible/base/nsAccUtils.h create mode 100644 accessible/base/nsAccessibilityService.cpp create mode 100644 accessible/base/nsAccessibilityService.h create mode 100644 accessible/base/nsAccessiblePivot.cpp create mode 100644 accessible/base/nsAccessiblePivot.h create mode 100644 accessible/base/nsCoreUtils.cpp create mode 100644 accessible/base/nsCoreUtils.h create mode 100644 accessible/base/nsEventShell.cpp create mode 100644 accessible/base/nsEventShell.h create mode 100644 accessible/base/nsTextEquivUtils.cpp create mode 100644 accessible/base/nsTextEquivUtils.h create mode 100644 accessible/generic/ARIAGridAccessible-inl.h create mode 100644 accessible/generic/ARIAGridAccessible.cpp create mode 100644 accessible/generic/ARIAGridAccessible.h create mode 100644 accessible/generic/Accessible-inl.h create mode 100644 accessible/generic/Accessible.cpp create mode 100644 accessible/generic/Accessible.h create mode 100644 accessible/generic/ApplicationAccessible.cpp create mode 100644 accessible/generic/ApplicationAccessible.h create mode 100644 accessible/generic/BaseAccessibles.cpp create mode 100644 accessible/generic/BaseAccessibles.h create mode 100644 accessible/generic/DocAccessible-inl.h create mode 100644 accessible/generic/DocAccessible.cpp create mode 100644 accessible/generic/DocAccessible.h create mode 100644 accessible/generic/FormControlAccessible.cpp create mode 100644 accessible/generic/FormControlAccessible.h create mode 100644 accessible/generic/HyperTextAccessible-inl.h create mode 100644 accessible/generic/HyperTextAccessible.cpp create mode 100644 accessible/generic/HyperTextAccessible.h create mode 100644 accessible/generic/ImageAccessible.cpp create mode 100644 accessible/generic/ImageAccessible.h create mode 100644 accessible/generic/OuterDocAccessible.cpp create mode 100644 accessible/generic/OuterDocAccessible.h create mode 100644 accessible/generic/RootAccessible.cpp create mode 100644 accessible/generic/RootAccessible.h create mode 100644 accessible/generic/TableAccessible.h create mode 100644 accessible/generic/TableCellAccessible.cpp create mode 100644 accessible/generic/TableCellAccessible.h create mode 100644 accessible/generic/TextLeafAccessible.cpp create mode 100644 accessible/generic/TextLeafAccessible.h create mode 100644 accessible/generic/moz.build create mode 100644 accessible/html/HTMLCanvasAccessible.cpp create mode 100644 accessible/html/HTMLCanvasAccessible.h create mode 100644 accessible/html/HTMLElementAccessibles.cpp create mode 100644 accessible/html/HTMLElementAccessibles.h create mode 100644 accessible/html/HTMLFormControlAccessible.cpp create mode 100644 accessible/html/HTMLFormControlAccessible.h create mode 100644 accessible/html/HTMLImageMapAccessible.cpp create mode 100644 accessible/html/HTMLImageMapAccessible.h create mode 100644 accessible/html/HTMLLinkAccessible.cpp create mode 100644 accessible/html/HTMLLinkAccessible.h create mode 100644 accessible/html/HTMLListAccessible.cpp create mode 100644 accessible/html/HTMLListAccessible.h create mode 100644 accessible/html/HTMLSelectAccessible.cpp create mode 100644 accessible/html/HTMLSelectAccessible.h create mode 100644 accessible/html/HTMLTableAccessible.cpp create mode 100644 accessible/html/HTMLTableAccessible.h create mode 100644 accessible/html/moz.build create mode 100644 accessible/interfaces/ia2/IA2Marshal.def create mode 100644 accessible/interfaces/ia2/IA2Marshal.dll.manifest create mode 100644 accessible/interfaces/ia2/IA2Marshal.rc create mode 100644 accessible/interfaces/ia2/IA2Typelib.idl create mode 100644 accessible/interfaces/ia2/Makefile.in create mode 100644 accessible/interfaces/ia2/moz.build create mode 100644 accessible/interfaces/moz.build create mode 100644 accessible/interfaces/msaa/AccessibleMarshal.def create mode 100644 accessible/interfaces/msaa/AccessibleMarshal.rc create mode 100644 accessible/interfaces/msaa/ISimpleDOMDocument.idl create mode 100644 accessible/interfaces/msaa/ISimpleDOMNode.idl create mode 100644 accessible/interfaces/msaa/ISimpleDOMText.idl create mode 100644 accessible/interfaces/msaa/Makefile.in create mode 100644 accessible/interfaces/msaa/moz.build create mode 100644 accessible/interfaces/nsIAccessibilityService.idl create mode 100644 accessible/interfaces/nsIAccessible.idl create mode 100644 accessible/interfaces/nsIAccessibleApplication.idl create mode 100644 accessible/interfaces/nsIAccessibleCaretMoveEvent.idl create mode 100644 accessible/interfaces/nsIAccessibleDocument.idl create mode 100644 accessible/interfaces/nsIAccessibleEditableText.idl create mode 100644 accessible/interfaces/nsIAccessibleEvent.idl create mode 100644 accessible/interfaces/nsIAccessibleHideEvent.idl create mode 100644 accessible/interfaces/nsIAccessibleHyperLink.idl create mode 100644 accessible/interfaces/nsIAccessibleHyperText.idl create mode 100644 accessible/interfaces/nsIAccessibleImage.idl create mode 100644 accessible/interfaces/nsIAccessibleObjectAttributeChangedEvent.idl create mode 100644 accessible/interfaces/nsIAccessiblePivot.idl create mode 100644 accessible/interfaces/nsIAccessibleRelation.idl create mode 100644 accessible/interfaces/nsIAccessibleRole.idl create mode 100644 accessible/interfaces/nsIAccessibleSelectable.idl create mode 100644 accessible/interfaces/nsIAccessibleStateChangeEvent.idl create mode 100644 accessible/interfaces/nsIAccessibleStates.idl create mode 100644 accessible/interfaces/nsIAccessibleTable.idl create mode 100644 accessible/interfaces/nsIAccessibleTableChangeEvent.idl create mode 100644 accessible/interfaces/nsIAccessibleText.idl create mode 100644 accessible/interfaces/nsIAccessibleTextChangeEvent.idl create mode 100644 accessible/interfaces/nsIAccessibleTextRange.idl create mode 100644 accessible/interfaces/nsIAccessibleTypes.idl create mode 100644 accessible/interfaces/nsIAccessibleValue.idl create mode 100644 accessible/interfaces/nsIAccessibleVirtualCursorChangeEvent.idl create mode 100644 accessible/interfaces/nsIXBLAccessible.idl create mode 100644 accessible/ipc/DocAccessibleChildBase.cpp create mode 100644 accessible/ipc/DocAccessibleChildBase.h create mode 100644 accessible/ipc/DocAccessibleParent.cpp create mode 100644 accessible/ipc/DocAccessibleParent.h create mode 100644 accessible/ipc/IPCTypes.h create mode 100644 accessible/ipc/ProxyAccessibleBase.cpp create mode 100644 accessible/ipc/ProxyAccessibleBase.h create mode 100644 accessible/ipc/ProxyAccessibleShared.h create mode 100644 accessible/ipc/moz.build create mode 100644 accessible/ipc/other/DocAccessibleChild.cpp create mode 100644 accessible/ipc/other/DocAccessibleChild.h create mode 100644 accessible/ipc/other/PDocAccessible.ipdl create mode 100644 accessible/ipc/other/ProxyAccessible.cpp create mode 100644 accessible/ipc/other/ProxyAccessible.h create mode 100644 accessible/ipc/other/moz.build create mode 100644 accessible/ipc/win/COMPtrTypes.cpp create mode 100644 accessible/ipc/win/COMPtrTypes.h create mode 100644 accessible/ipc/win/DocAccessibleChild.cpp create mode 100644 accessible/ipc/win/DocAccessibleChild.h create mode 100644 accessible/ipc/win/PDocAccessible.ipdl create mode 100644 accessible/ipc/win/PlatformChild.cpp create mode 100644 accessible/ipc/win/PlatformChild.h create mode 100644 accessible/ipc/win/ProxyAccessible.cpp create mode 100644 accessible/ipc/win/ProxyAccessible.h create mode 100644 accessible/ipc/win/moz.build create mode 100644 accessible/ipc/win/typelib/Accessible.idl create mode 100644 accessible/ipc/win/typelib/Makefile.in create mode 100644 accessible/ipc/win/typelib/moz.build create mode 100644 accessible/jsat/AccessFu.css create mode 100644 accessible/jsat/AccessFu.jsm create mode 100644 accessible/jsat/Constants.jsm create mode 100644 accessible/jsat/ContentControl.jsm create mode 100644 accessible/jsat/EventManager.jsm create mode 100644 accessible/jsat/Gestures.jsm create mode 100644 accessible/jsat/OutputGenerator.jsm create mode 100644 accessible/jsat/PointerAdapter.jsm create mode 100644 accessible/jsat/Presentation.jsm create mode 100644 accessible/jsat/Traversal.jsm create mode 100644 accessible/jsat/Utils.jsm create mode 100644 accessible/jsat/content-script.js create mode 100644 accessible/jsat/jar.mn create mode 100644 accessible/jsat/moz.build create mode 100644 accessible/jsat/sounds/clicked.ogg create mode 100644 accessible/jsat/sounds/virtual_cursor_key.ogg create mode 100644 accessible/jsat/sounds/virtual_cursor_move.ogg create mode 100644 accessible/mac/ARIAGridAccessibleWrap.h create mode 100644 accessible/mac/AccessibleWrap.h create mode 100644 accessible/mac/AccessibleWrap.mm create mode 100644 accessible/mac/ApplicationAccessibleWrap.h create mode 100644 accessible/mac/DocAccessibleWrap.h create mode 100644 accessible/mac/DocAccessibleWrap.mm create mode 100644 accessible/mac/HTMLTableAccessibleWrap.h create mode 100644 accessible/mac/HyperTextAccessibleWrap.h create mode 100644 accessible/mac/ImageAccessibleWrap.h create mode 100644 accessible/mac/MacUtils.h create mode 100644 accessible/mac/MacUtils.mm create mode 100644 accessible/mac/Platform.mm create mode 100644 accessible/mac/RootAccessibleWrap.h create mode 100644 accessible/mac/RootAccessibleWrap.mm create mode 100644 accessible/mac/TextLeafAccessibleWrap.h create mode 100644 accessible/mac/XULListboxAccessibleWrap.h create mode 100644 accessible/mac/XULMenuAccessibleWrap.h create mode 100644 accessible/mac/XULTreeGridAccessibleWrap.h create mode 100644 accessible/mac/moz.build create mode 100644 accessible/mac/mozAccessible.h create mode 100644 accessible/mac/mozAccessible.mm create mode 100644 accessible/mac/mozAccessibleProtocol.h create mode 100644 accessible/mac/mozActionElements.h create mode 100644 accessible/mac/mozActionElements.mm create mode 100644 accessible/mac/mozDocAccessible.h create mode 100644 accessible/mac/mozDocAccessible.mm create mode 100644 accessible/mac/mozHTMLAccessible.h create mode 100644 accessible/mac/mozHTMLAccessible.mm create mode 100644 accessible/mac/mozTableAccessible.h create mode 100644 accessible/mac/mozTableAccessible.mm create mode 100644 accessible/mac/mozTextAccessible.h create mode 100644 accessible/mac/mozTextAccessible.mm create mode 100644 accessible/moz.build create mode 100644 accessible/other/ARIAGridAccessibleWrap.h create mode 100644 accessible/other/AccessibleWrap.cpp create mode 100644 accessible/other/AccessibleWrap.h create mode 100644 accessible/other/ApplicationAccessibleWrap.h create mode 100644 accessible/other/DocAccessibleWrap.h create mode 100644 accessible/other/HTMLTableAccessibleWrap.h create mode 100644 accessible/other/HyperTextAccessibleWrap.h create mode 100644 accessible/other/ImageAccessibleWrap.h create mode 100644 accessible/other/Platform.cpp create mode 100644 accessible/other/RootAccessibleWrap.h create mode 100644 accessible/other/TextLeafAccessibleWrap.h create mode 100644 accessible/other/XULListboxAccessibleWrap.h create mode 100644 accessible/other/XULMenuAccessibleWrap.h create mode 100644 accessible/other/XULTreeGridAccessibleWrap.h create mode 100644 accessible/other/moz.build create mode 100644 accessible/tests/browser/.eslintrc.js create mode 100644 accessible/tests/browser/browser.ini create mode 100644 accessible/tests/browser/browser_shutdown_multi_reference.js create mode 100644 accessible/tests/browser/browser_shutdown_parent_own_reference.js create mode 100644 accessible/tests/browser/browser_shutdown_remote_no_reference.js create mode 100644 accessible/tests/browser/browser_shutdown_remote_only.js create mode 100644 accessible/tests/browser/browser_shutdown_remote_own_reference.js create mode 100644 accessible/tests/browser/browser_shutdown_scope_lifecycle.js create mode 100644 accessible/tests/browser/browser_shutdown_start_restart.js create mode 100644 accessible/tests/browser/e10s/browser.ini create mode 100644 accessible/tests/browser/e10s/browser_caching_attributes.js create mode 100644 accessible/tests/browser/e10s/browser_caching_description.js create mode 100644 accessible/tests/browser/e10s/browser_caching_name.js create mode 100644 accessible/tests/browser/e10s/browser_caching_relations.js create mode 100644 accessible/tests/browser/e10s/browser_caching_states.js create mode 100644 accessible/tests/browser/e10s/browser_caching_value.js create mode 100644 accessible/tests/browser/e10s/browser_events_caretmove.js create mode 100644 accessible/tests/browser/e10s/browser_events_hide.js create mode 100644 accessible/tests/browser/e10s/browser_events_show.js create mode 100644 accessible/tests/browser/e10s/browser_events_statechange.js create mode 100644 accessible/tests/browser/e10s/browser_events_textchange.js create mode 100644 accessible/tests/browser/e10s/browser_treeupdate_ariadialog.js create mode 100644 accessible/tests/browser/e10s/browser_treeupdate_ariaowns.js create mode 100644 accessible/tests/browser/e10s/browser_treeupdate_canvas.js create mode 100644 accessible/tests/browser/e10s/browser_treeupdate_cssoverflow.js create mode 100644 accessible/tests/browser/e10s/browser_treeupdate_doc.js create mode 100644 accessible/tests/browser/e10s/browser_treeupdate_gencontent.js create mode 100644 accessible/tests/browser/e10s/browser_treeupdate_hidden.js create mode 100644 accessible/tests/browser/e10s/browser_treeupdate_imagemap.js create mode 100644 accessible/tests/browser/e10s/browser_treeupdate_list.js create mode 100644 accessible/tests/browser/e10s/browser_treeupdate_list_editabledoc.js create mode 100644 accessible/tests/browser/e10s/browser_treeupdate_listener.js create mode 100644 accessible/tests/browser/e10s/browser_treeupdate_optgroup.js create mode 100644 accessible/tests/browser/e10s/browser_treeupdate_removal.js create mode 100644 accessible/tests/browser/e10s/browser_treeupdate_table.js create mode 100644 accessible/tests/browser/e10s/browser_treeupdate_textleaf.js create mode 100644 accessible/tests/browser/e10s/browser_treeupdate_visibility.js create mode 100644 accessible/tests/browser/e10s/browser_treeupdate_whitespace.js create mode 100644 accessible/tests/browser/e10s/doc_treeupdate_ariadialog.html create mode 100644 accessible/tests/browser/e10s/doc_treeupdate_ariaowns.html create mode 100644 accessible/tests/browser/e10s/doc_treeupdate_imagemap.html create mode 100644 accessible/tests/browser/e10s/doc_treeupdate_removal.xhtml create mode 100644 accessible/tests/browser/e10s/doc_treeupdate_visibility.html create mode 100644 accessible/tests/browser/e10s/doc_treeupdate_whitespace.html create mode 100644 accessible/tests/browser/e10s/events.js create mode 100644 accessible/tests/browser/e10s/head.js create mode 100644 accessible/tests/browser/head.js create mode 100644 accessible/tests/browser/shared-head.js create mode 100644 accessible/tests/crashtests/448064.xhtml create mode 100644 accessible/tests/crashtests/471493.xul create mode 100644 accessible/tests/crashtests/crashtests.list create mode 100644 accessible/tests/mochitest/a11y.ini create mode 100644 accessible/tests/mochitest/actions.js create mode 100644 accessible/tests/mochitest/actions/a11y.ini create mode 100644 accessible/tests/mochitest/actions/test_anchors.html create mode 100644 accessible/tests/mochitest/actions/test_aria.html create mode 100644 accessible/tests/mochitest/actions/test_controls.html create mode 100644 accessible/tests/mochitest/actions/test_general.html create mode 100644 accessible/tests/mochitest/actions/test_general.xul create mode 100644 accessible/tests/mochitest/actions/test_keys.html create mode 100644 accessible/tests/mochitest/actions/test_keys_menu.xul create mode 100644 accessible/tests/mochitest/actions/test_link.html create mode 100644 accessible/tests/mochitest/actions/test_media.html create mode 100644 accessible/tests/mochitest/actions/test_select.html create mode 100644 accessible/tests/mochitest/actions/test_tree.xul create mode 100644 accessible/tests/mochitest/actions/test_treegrid.xul create mode 100644 accessible/tests/mochitest/aom/a11y.ini create mode 100644 accessible/tests/mochitest/aom/test_general.html create mode 100644 accessible/tests/mochitest/attributes.js create mode 100644 accessible/tests/mochitest/attributes/a11y.ini create mode 100644 accessible/tests/mochitest/attributes/test_obj.html create mode 100644 accessible/tests/mochitest/attributes/test_obj_css.html create mode 100644 accessible/tests/mochitest/attributes/test_obj_css.xul create mode 100644 accessible/tests/mochitest/attributes/test_obj_group.html create mode 100644 accessible/tests/mochitest/attributes/test_obj_group.xul create mode 100644 accessible/tests/mochitest/attributes/test_obj_group_tree.xul create mode 100644 accessible/tests/mochitest/attributes/test_tag.html create mode 100644 accessible/tests/mochitest/attributes/test_xml-roles.html create mode 100644 accessible/tests/mochitest/autocomplete.js create mode 100644 accessible/tests/mochitest/bounds/a11y.ini create mode 100644 accessible/tests/mochitest/bounds/test_list.html create mode 100644 accessible/tests/mochitest/bounds/test_select.html create mode 100644 accessible/tests/mochitest/bounds/test_zoom.html create mode 100644 accessible/tests/mochitest/bounds/test_zoom_text.html create mode 100644 accessible/tests/mochitest/browser.js create mode 100644 accessible/tests/mochitest/common.js create mode 100644 accessible/tests/mochitest/dumbfile.zip create mode 100644 accessible/tests/mochitest/editabletext/a11y.ini create mode 100644 accessible/tests/mochitest/editabletext/editabletext.js create mode 100644 accessible/tests/mochitest/editabletext/test_1.html create mode 100644 accessible/tests/mochitest/editabletext/test_2.html create mode 100644 accessible/tests/mochitest/elm/a11y.ini create mode 100644 accessible/tests/mochitest/elm/test_HTMLSpec.html create mode 100644 accessible/tests/mochitest/elm/test_MathMLSpec.html create mode 100644 accessible/tests/mochitest/elm/test_canvas.html create mode 100644 accessible/tests/mochitest/elm/test_figure.html create mode 100644 accessible/tests/mochitest/elm/test_listbox.xul create mode 100644 accessible/tests/mochitest/elm/test_nsApplicationAcc.html create mode 100644 accessible/tests/mochitest/elm/test_plugin.html create mode 100644 accessible/tests/mochitest/elm/test_shadowroot.html create mode 100644 accessible/tests/mochitest/events.js create mode 100644 accessible/tests/mochitest/events/a11y.ini create mode 100644 accessible/tests/mochitest/events/docload_wnd.html create mode 100644 accessible/tests/mochitest/events/focus.html create mode 100644 accessible/tests/mochitest/events/scroll.html create mode 100644 accessible/tests/mochitest/events/test_aria_alert.html create mode 100644 accessible/tests/mochitest/events/test_aria_menu.html create mode 100644 accessible/tests/mochitest/events/test_aria_objattr.html create mode 100644 accessible/tests/mochitest/events/test_aria_owns.html create mode 100644 accessible/tests/mochitest/events/test_aria_statechange.html create mode 100644 accessible/tests/mochitest/events/test_attrs.html create mode 100644 accessible/tests/mochitest/events/test_bug1322593-2.html create mode 100644 accessible/tests/mochitest/events/test_bug1322593.html create mode 100644 accessible/tests/mochitest/events/test_caretmove.html create mode 100644 accessible/tests/mochitest/events/test_caretmove.xul create mode 100644 accessible/tests/mochitest/events/test_coalescence.html create mode 100644 accessible/tests/mochitest/events/test_contextmenu.html create mode 100644 accessible/tests/mochitest/events/test_descrchange.html create mode 100644 accessible/tests/mochitest/events/test_docload.html create mode 100644 accessible/tests/mochitest/events/test_docload.xul create mode 100644 accessible/tests/mochitest/events/test_docload_aria.html create mode 100644 accessible/tests/mochitest/events/test_dragndrop.html create mode 100644 accessible/tests/mochitest/events/test_flush.html create mode 100644 accessible/tests/mochitest/events/test_focus_aria_activedescendant.html create mode 100644 accessible/tests/mochitest/events/test_focus_autocomplete.xul create mode 100644 accessible/tests/mochitest/events/test_focus_browserui.xul create mode 100644 accessible/tests/mochitest/events/test_focus_canvas.html create mode 100644 accessible/tests/mochitest/events/test_focus_contextmenu.xul create mode 100644 accessible/tests/mochitest/events/test_focus_controls.html create mode 100644 accessible/tests/mochitest/events/test_focus_dialog.html create mode 100644 accessible/tests/mochitest/events/test_focus_doc.html create mode 100644 accessible/tests/mochitest/events/test_focus_general.html create mode 100644 accessible/tests/mochitest/events/test_focus_general.xul create mode 100644 accessible/tests/mochitest/events/test_focus_listcontrols.xul create mode 100644 accessible/tests/mochitest/events/test_focus_menu.xul create mode 100644 accessible/tests/mochitest/events/test_focus_name.html create mode 100644 accessible/tests/mochitest/events/test_focus_selects.html create mode 100644 accessible/tests/mochitest/events/test_focus_tabbox.xul create mode 100644 accessible/tests/mochitest/events/test_focus_tree.xul create mode 100644 accessible/tests/mochitest/events/test_fromUserInput.html create mode 100644 accessible/tests/mochitest/events/test_label.xul create mode 100644 accessible/tests/mochitest/events/test_menu.xul create mode 100644 accessible/tests/mochitest/events/test_mutation.html create mode 100644 accessible/tests/mochitest/events/test_mutation.xhtml create mode 100644 accessible/tests/mochitest/events/test_namechange.html create mode 100644 accessible/tests/mochitest/events/test_namechange.xul create mode 100644 accessible/tests/mochitest/events/test_scroll.xul create mode 100644 accessible/tests/mochitest/events/test_scroll_caret.xul create mode 100644 accessible/tests/mochitest/events/test_selection.html create mode 100644 accessible/tests/mochitest/events/test_selection.xul create mode 100644 accessible/tests/mochitest/events/test_selection_aria.html create mode 100644 accessible/tests/mochitest/events/test_statechange.html create mode 100644 accessible/tests/mochitest/events/test_text.html create mode 100644 accessible/tests/mochitest/events/test_text_alg.html create mode 100644 accessible/tests/mochitest/events/test_textattrchange.html create mode 100644 accessible/tests/mochitest/events/test_textselchange.html create mode 100644 accessible/tests/mochitest/events/test_tree.xul create mode 100644 accessible/tests/mochitest/events/test_valuechange.html create mode 100644 accessible/tests/mochitest/focus/a11y.ini create mode 100644 accessible/tests/mochitest/focus/test_focusedChild.html create mode 100644 accessible/tests/mochitest/focus/test_takeFocus.html create mode 100644 accessible/tests/mochitest/focus/test_takeFocus.xul create mode 100644 accessible/tests/mochitest/formimage.png create mode 100644 accessible/tests/mochitest/grid.js create mode 100644 accessible/tests/mochitest/hittest/a11y.ini create mode 100644 accessible/tests/mochitest/hittest/test_browser.html create mode 100644 accessible/tests/mochitest/hittest/test_canvas_hitregion.html create mode 100644 accessible/tests/mochitest/hittest/test_general.html create mode 100644 accessible/tests/mochitest/hittest/test_menu.xul create mode 100644 accessible/tests/mochitest/hittest/test_shadowroot.html create mode 100644 accessible/tests/mochitest/hittest/test_zoom.html create mode 100644 accessible/tests/mochitest/hittest/test_zoom_text.html create mode 100644 accessible/tests/mochitest/hittest/test_zoom_tree.xul create mode 100644 accessible/tests/mochitest/hittest/zoom_tree.xul create mode 100644 accessible/tests/mochitest/hyperlink/a11y.ini create mode 100644 accessible/tests/mochitest/hyperlink/hyperlink.js create mode 100644 accessible/tests/mochitest/hyperlink/test_general.html create mode 100644 accessible/tests/mochitest/hyperlink/test_general.xul create mode 100644 accessible/tests/mochitest/hypertext/a11y.ini create mode 100644 accessible/tests/mochitest/hypertext/test_general.html create mode 100644 accessible/tests/mochitest/hypertext/test_update.html create mode 100644 accessible/tests/mochitest/jsat/a11y.ini create mode 100644 accessible/tests/mochitest/jsat/doc_content_integration.html create mode 100644 accessible/tests/mochitest/jsat/doc_content_text.html create mode 100644 accessible/tests/mochitest/jsat/doc_traversal.html create mode 100644 accessible/tests/mochitest/jsat/dom_helper.js create mode 100644 accessible/tests/mochitest/jsat/gestures.json create mode 100644 accessible/tests/mochitest/jsat/jsatcommon.js create mode 100644 accessible/tests/mochitest/jsat/output.js create mode 100644 accessible/tests/mochitest/jsat/test_alive.html create mode 100644 accessible/tests/mochitest/jsat/test_content_integration.html create mode 100644 accessible/tests/mochitest/jsat/test_content_text.html create mode 100644 accessible/tests/mochitest/jsat/test_explicit_names.html create mode 100644 accessible/tests/mochitest/jsat/test_gesture_tracker.html create mode 100644 accessible/tests/mochitest/jsat/test_hints.html create mode 100644 accessible/tests/mochitest/jsat/test_landmarks.html create mode 100644 accessible/tests/mochitest/jsat/test_live_regions.html create mode 100644 accessible/tests/mochitest/jsat/test_output.html create mode 100644 accessible/tests/mochitest/jsat/test_output_mathml.html create mode 100644 accessible/tests/mochitest/jsat/test_pointer_relay.html create mode 100644 accessible/tests/mochitest/jsat/test_quicknav_modes.html create mode 100644 accessible/tests/mochitest/jsat/test_tables.html create mode 100644 accessible/tests/mochitest/jsat/test_traversal.html create mode 100644 accessible/tests/mochitest/jsat/test_traversal_helper.html create mode 100644 accessible/tests/mochitest/layout.js create mode 100644 accessible/tests/mochitest/letters.gif create mode 100644 accessible/tests/mochitest/longdesc_src.html create mode 100644 accessible/tests/mochitest/moz.build create mode 100644 accessible/tests/mochitest/moz.png create mode 100644 accessible/tests/mochitest/name.js create mode 100644 accessible/tests/mochitest/name/a11y.ini create mode 100644 accessible/tests/mochitest/name/general.css create mode 100644 accessible/tests/mochitest/name/general.xbl create mode 100644 accessible/tests/mochitest/name/markup.js create mode 100644 accessible/tests/mochitest/name/markuprules.xml create mode 100644 accessible/tests/mochitest/name/test_browserui.xul create mode 100644 accessible/tests/mochitest/name/test_counterstyle.html create mode 100644 accessible/tests/mochitest/name/test_general.html create mode 100644 accessible/tests/mochitest/name/test_general.xul create mode 100644 accessible/tests/mochitest/name/test_link.html create mode 100644 accessible/tests/mochitest/name/test_list.html create mode 100644 accessible/tests/mochitest/name/test_markup.html create mode 100644 accessible/tests/mochitest/name/test_svg.html create mode 100644 accessible/tests/mochitest/name/test_toolbaritem.xul create mode 100644 accessible/tests/mochitest/name/test_tree.xul create mode 100644 accessible/tests/mochitest/pivot.js create mode 100644 accessible/tests/mochitest/pivot/a11y.ini create mode 100644 accessible/tests/mochitest/pivot/doc_virtualcursor.html create mode 100644 accessible/tests/mochitest/pivot/doc_virtualcursor_text.html create mode 100644 accessible/tests/mochitest/pivot/test_virtualcursor.html create mode 100644 accessible/tests/mochitest/pivot/test_virtualcursor_text.html create mode 100644 accessible/tests/mochitest/relations.js create mode 100644 accessible/tests/mochitest/relations/a11y.ini create mode 100644 accessible/tests/mochitest/relations/test_bindings.xhtml create mode 100644 accessible/tests/mochitest/relations/test_embeds.xul create mode 100644 accessible/tests/mochitest/relations/test_general.html create mode 100644 accessible/tests/mochitest/relations/test_general.xul create mode 100644 accessible/tests/mochitest/relations/test_tabbrowser.xul create mode 100644 accessible/tests/mochitest/relations/test_tree.xul create mode 100644 accessible/tests/mochitest/relations/test_ui_modalprompt.html create mode 100644 accessible/tests/mochitest/relations/test_update.html create mode 100644 accessible/tests/mochitest/role.js create mode 100644 accessible/tests/mochitest/role/a11y.ini create mode 100644 accessible/tests/mochitest/role/test_aria.html create mode 100644 accessible/tests/mochitest/role/test_aria.xul create mode 100644 accessible/tests/mochitest/role/test_general.html create mode 100644 accessible/tests/mochitest/role/test_general.xul create mode 100644 accessible/tests/mochitest/role/test_svg.html create mode 100644 accessible/tests/mochitest/scroll/a11y.ini create mode 100644 accessible/tests/mochitest/scroll/test_zoom.html create mode 100644 accessible/tests/mochitest/scroll/test_zoom_text.html create mode 100644 accessible/tests/mochitest/selectable.js create mode 100644 accessible/tests/mochitest/selectable/a11y.ini create mode 100644 accessible/tests/mochitest/selectable/test_aria.html create mode 100644 accessible/tests/mochitest/selectable/test_listbox.xul create mode 100644 accessible/tests/mochitest/selectable/test_menu.xul create mode 100644 accessible/tests/mochitest/selectable/test_menulist.xul create mode 100644 accessible/tests/mochitest/selectable/test_select.html create mode 100644 accessible/tests/mochitest/selectable/test_tree.xul create mode 100644 accessible/tests/mochitest/states.js create mode 100644 accessible/tests/mochitest/states/a11y.ini create mode 100644 accessible/tests/mochitest/states/test_aria.html create mode 100644 accessible/tests/mochitest/states/test_aria.xul create mode 100644 accessible/tests/mochitest/states/test_aria_imgmap.html create mode 100644 accessible/tests/mochitest/states/test_aria_widgetitems.html create mode 100644 accessible/tests/mochitest/states/test_buttons.html create mode 100644 accessible/tests/mochitest/states/test_controls.html create mode 100644 accessible/tests/mochitest/states/test_controls.xul create mode 100644 accessible/tests/mochitest/states/test_doc.html create mode 100644 accessible/tests/mochitest/states/test_doc_busy.html create mode 100644 accessible/tests/mochitest/states/test_docarticle.html create mode 100644 accessible/tests/mochitest/states/test_editablebody.html create mode 100644 accessible/tests/mochitest/states/test_expandable.xul create mode 100644 accessible/tests/mochitest/states/test_frames.html create mode 100644 accessible/tests/mochitest/states/test_inputs.html create mode 100644 accessible/tests/mochitest/states/test_link.html create mode 100644 accessible/tests/mochitest/states/test_popup.xul create mode 100644 accessible/tests/mochitest/states/test_selects.html create mode 100644 accessible/tests/mochitest/states/test_stale.html create mode 100644 accessible/tests/mochitest/states/test_tabs.xul create mode 100644 accessible/tests/mochitest/states/test_textbox.xul create mode 100644 accessible/tests/mochitest/states/test_tree.xul create mode 100644 accessible/tests/mochitest/states/test_visibility.html create mode 100644 accessible/tests/mochitest/states/test_visibility.xul create mode 100644 accessible/tests/mochitest/states/z_frames.html create mode 100644 accessible/tests/mochitest/states/z_frames_article.html create mode 100644 accessible/tests/mochitest/states/z_frames_checkbox.html create mode 100644 accessible/tests/mochitest/states/z_frames_textbox.html create mode 100644 accessible/tests/mochitest/states/z_frames_update.html create mode 100644 accessible/tests/mochitest/table.js create mode 100644 accessible/tests/mochitest/table/a11y.ini create mode 100644 accessible/tests/mochitest/table/test_css_tables.html create mode 100644 accessible/tests/mochitest/table/test_headers_ariagrid.html create mode 100644 accessible/tests/mochitest/table/test_headers_ariatable.html create mode 100644 accessible/tests/mochitest/table/test_headers_listbox.xul create mode 100644 accessible/tests/mochitest/table/test_headers_table.html create mode 100644 accessible/tests/mochitest/table/test_headers_tree.xul create mode 100644 accessible/tests/mochitest/table/test_indexes_ariagrid.html create mode 100644 accessible/tests/mochitest/table/test_indexes_listbox.xul create mode 100644 accessible/tests/mochitest/table/test_indexes_table.html create mode 100644 accessible/tests/mochitest/table/test_indexes_tree.xul create mode 100644 accessible/tests/mochitest/table/test_layoutguess.html create mode 100644 accessible/tests/mochitest/table/test_mtable.html create mode 100644 accessible/tests/mochitest/table/test_sels_ariagrid.html create mode 100644 accessible/tests/mochitest/table/test_sels_listbox.xul create mode 100644 accessible/tests/mochitest/table/test_sels_table.html create mode 100644 accessible/tests/mochitest/table/test_sels_tree.xul create mode 100644 accessible/tests/mochitest/table/test_struct_ariagrid.html create mode 100644 accessible/tests/mochitest/table/test_struct_ariatreegrid.html create mode 100644 accessible/tests/mochitest/table/test_struct_listbox.xul create mode 100644 accessible/tests/mochitest/table/test_struct_table.html create mode 100644 accessible/tests/mochitest/table/test_struct_tree.xul create mode 100644 accessible/tests/mochitest/table/test_table_1.html create mode 100644 accessible/tests/mochitest/table/test_table_2.html create mode 100644 accessible/tests/mochitest/test_OuterDocAccessible.html create mode 100644 accessible/tests/mochitest/test_aria_token_attrs.html create mode 100644 accessible/tests/mochitest/test_bug420863.html create mode 100644 accessible/tests/mochitest/test_descr.html create mode 100644 accessible/tests/mochitest/test_nsIAccessibleDocument.html create mode 100644 accessible/tests/mochitest/test_nsIAccessibleImage.html create mode 100644 accessible/tests/mochitest/text.js create mode 100644 accessible/tests/mochitest/text/a11y.ini create mode 100644 accessible/tests/mochitest/text/doc.html create mode 100644 accessible/tests/mochitest/text/test_atcaretoffset.html create mode 100644 accessible/tests/mochitest/text/test_charboundary.html create mode 100644 accessible/tests/mochitest/text/test_doc.html create mode 100644 accessible/tests/mochitest/text/test_dynamic.html create mode 100644 accessible/tests/mochitest/text/test_general.xul create mode 100644 accessible/tests/mochitest/text/test_gettext.html create mode 100644 accessible/tests/mochitest/text/test_hypertext.html create mode 100644 accessible/tests/mochitest/text/test_lineboundary.html create mode 100644 accessible/tests/mochitest/text/test_passwords.html create mode 100644 accessible/tests/mochitest/text/test_selection.html create mode 100644 accessible/tests/mochitest/text/test_wordboundary.html create mode 100644 accessible/tests/mochitest/text/test_words.html create mode 100644 accessible/tests/mochitest/textattrs/a11y.ini create mode 100644 accessible/tests/mochitest/textattrs/test_general.html create mode 100644 accessible/tests/mochitest/textattrs/test_invalid.html create mode 100644 accessible/tests/mochitest/textcaret/a11y.ini create mode 100644 accessible/tests/mochitest/textcaret/test_browserui.xul create mode 100644 accessible/tests/mochitest/textcaret/test_general.html create mode 100644 accessible/tests/mochitest/textrange/a11y.ini create mode 100644 accessible/tests/mochitest/textrange/test_general.html create mode 100644 accessible/tests/mochitest/textrange/test_selection.html create mode 100644 accessible/tests/mochitest/textselection/a11y.ini create mode 100644 accessible/tests/mochitest/textselection/test_general.html create mode 100644 accessible/tests/mochitest/textselection/test_userinput.html create mode 100644 accessible/tests/mochitest/tree/a11y.ini create mode 100644 accessible/tests/mochitest/tree/dockids.html create mode 100644 accessible/tests/mochitest/tree/test_applicationacc.xul create mode 100644 accessible/tests/mochitest/tree/test_aria_globals.html create mode 100644 accessible/tests/mochitest/tree/test_aria_grid.html create mode 100644 accessible/tests/mochitest/tree/test_aria_imgmap.html create mode 100644 accessible/tests/mochitest/tree/test_aria_list.html create mode 100644 accessible/tests/mochitest/tree/test_aria_menu.html create mode 100644 accessible/tests/mochitest/tree/test_aria_owns.html create mode 100644 accessible/tests/mochitest/tree/test_aria_presentation.html create mode 100644 accessible/tests/mochitest/tree/test_aria_table.html create mode 100644 accessible/tests/mochitest/tree/test_brokencontext.html create mode 100644 accessible/tests/mochitest/tree/test_button.xul create mode 100644 accessible/tests/mochitest/tree/test_canvas.html create mode 100644 accessible/tests/mochitest/tree/test_combobox.xul create mode 100644 accessible/tests/mochitest/tree/test_cssflexbox.html create mode 100644 accessible/tests/mochitest/tree/test_cssoverflow.html create mode 100644 accessible/tests/mochitest/tree/test_dochierarchy.html create mode 100644 accessible/tests/mochitest/tree/test_dockids.html create mode 100644 accessible/tests/mochitest/tree/test_filectrl.html create mode 100644 accessible/tests/mochitest/tree/test_formctrl.html create mode 100644 accessible/tests/mochitest/tree/test_formctrl.xul create mode 100644 accessible/tests/mochitest/tree/test_gencontent.html create mode 100644 accessible/tests/mochitest/tree/test_groupbox.xul create mode 100644 accessible/tests/mochitest/tree/test_iframe.html create mode 100644 accessible/tests/mochitest/tree/test_img.html create mode 100644 accessible/tests/mochitest/tree/test_invalid_img.xhtml create mode 100644 accessible/tests/mochitest/tree/test_invalidationlist.html create mode 100644 accessible/tests/mochitest/tree/test_list.html create mode 100644 accessible/tests/mochitest/tree/test_map.html create mode 100644 accessible/tests/mochitest/tree/test_media.html create mode 100644 accessible/tests/mochitest/tree/test_select.html create mode 100644 accessible/tests/mochitest/tree/test_tabbox.xul create mode 100644 accessible/tests/mochitest/tree/test_tabbrowser.xul create mode 100644 accessible/tests/mochitest/tree/test_table.html create mode 100644 accessible/tests/mochitest/tree/test_tree.xul create mode 100644 accessible/tests/mochitest/tree/test_txtcntr.html create mode 100644 accessible/tests/mochitest/tree/test_txtctrl.html create mode 100644 accessible/tests/mochitest/tree/test_txtctrl.xul create mode 100644 accessible/tests/mochitest/tree/wnd.xul create mode 100644 accessible/tests/mochitest/treeupdate/a11y.ini create mode 100644 accessible/tests/mochitest/treeupdate/test_ariadialog.html create mode 100644 accessible/tests/mochitest/treeupdate/test_ariaowns.html create mode 100644 accessible/tests/mochitest/treeupdate/test_bug1040735.html create mode 100644 accessible/tests/mochitest/treeupdate/test_bug1100602.html create mode 100644 accessible/tests/mochitest/treeupdate/test_bug1175913.html create mode 100644 accessible/tests/mochitest/treeupdate/test_bug1189277.html create mode 100644 accessible/tests/mochitest/treeupdate/test_bug1276857.html create mode 100644 accessible/tests/mochitest/treeupdate/test_bug852150.xhtml create mode 100644 accessible/tests/mochitest/treeupdate/test_bug883708.xhtml create mode 100644 accessible/tests/mochitest/treeupdate/test_bug884251.xhtml create mode 100644 accessible/tests/mochitest/treeupdate/test_bug895082.html create mode 100644 accessible/tests/mochitest/treeupdate/test_canvas.html create mode 100644 accessible/tests/mochitest/treeupdate/test_colorpicker.xul create mode 100644 accessible/tests/mochitest/treeupdate/test_contextmenu.xul create mode 100644 accessible/tests/mochitest/treeupdate/test_cssoverflow.html create mode 100644 accessible/tests/mochitest/treeupdate/test_deck.xul create mode 100644 accessible/tests/mochitest/treeupdate/test_doc.html create mode 100644 accessible/tests/mochitest/treeupdate/test_gencontent.html create mode 100644 accessible/tests/mochitest/treeupdate/test_general.html create mode 100644 accessible/tests/mochitest/treeupdate/test_hidden.html create mode 100644 accessible/tests/mochitest/treeupdate/test_imagemap.html create mode 100644 accessible/tests/mochitest/treeupdate/test_list.html create mode 100644 accessible/tests/mochitest/treeupdate/test_list_editabledoc.html create mode 100644 accessible/tests/mochitest/treeupdate/test_listbox.xul create mode 100644 accessible/tests/mochitest/treeupdate/test_menu.xul create mode 100644 accessible/tests/mochitest/treeupdate/test_menubutton.xul create mode 100644 accessible/tests/mochitest/treeupdate/test_optgroup.html create mode 100644 accessible/tests/mochitest/treeupdate/test_recreation.html create mode 100644 accessible/tests/mochitest/treeupdate/test_select.html create mode 100644 accessible/tests/mochitest/treeupdate/test_shutdown.xul create mode 100644 accessible/tests/mochitest/treeupdate/test_table.html create mode 100644 accessible/tests/mochitest/treeupdate/test_textleaf.html create mode 100644 accessible/tests/mochitest/treeupdate/test_visibility.html create mode 100644 accessible/tests/mochitest/treeupdate/test_whitespace.html create mode 100644 accessible/tests/mochitest/treeview.css create mode 100644 accessible/tests/mochitest/treeview.js create mode 100644 accessible/tests/mochitest/value.js create mode 100644 accessible/tests/mochitest/value/a11y.ini create mode 100644 accessible/tests/mochitest/value/test_general.html create mode 100644 accessible/tests/mochitest/value/test_number.html create mode 100644 accessible/tests/mochitest/value/test_progress.html create mode 100644 accessible/tests/mochitest/value/test_progress.xul create mode 100644 accessible/tests/mochitest/value/test_range.html create mode 100644 accessible/windows/ProxyWrappers.h create mode 100644 accessible/windows/ia2/ia2Accessible.cpp create mode 100644 accessible/windows/ia2/ia2Accessible.h create mode 100644 accessible/windows/ia2/ia2AccessibleAction.cpp create mode 100644 accessible/windows/ia2/ia2AccessibleAction.h create mode 100644 accessible/windows/ia2/ia2AccessibleComponent.cpp create mode 100644 accessible/windows/ia2/ia2AccessibleComponent.h create mode 100644 accessible/windows/ia2/ia2AccessibleEditableText.cpp create mode 100644 accessible/windows/ia2/ia2AccessibleEditableText.h create mode 100644 accessible/windows/ia2/ia2AccessibleHyperlink.cpp create mode 100644 accessible/windows/ia2/ia2AccessibleHyperlink.h create mode 100644 accessible/windows/ia2/ia2AccessibleHypertext.cpp create mode 100644 accessible/windows/ia2/ia2AccessibleHypertext.h create mode 100644 accessible/windows/ia2/ia2AccessibleImage.cpp create mode 100644 accessible/windows/ia2/ia2AccessibleImage.h create mode 100644 accessible/windows/ia2/ia2AccessibleRelation.cpp create mode 100644 accessible/windows/ia2/ia2AccessibleRelation.h create mode 100644 accessible/windows/ia2/ia2AccessibleTable.cpp create mode 100644 accessible/windows/ia2/ia2AccessibleTable.h create mode 100644 accessible/windows/ia2/ia2AccessibleTableCell.cpp create mode 100644 accessible/windows/ia2/ia2AccessibleTableCell.h create mode 100644 accessible/windows/ia2/ia2AccessibleText.cpp create mode 100644 accessible/windows/ia2/ia2AccessibleText.h create mode 100644 accessible/windows/ia2/ia2AccessibleValue.cpp create mode 100644 accessible/windows/ia2/ia2AccessibleValue.h create mode 100644 accessible/windows/ia2/moz.build create mode 100644 accessible/windows/moz.build create mode 100644 accessible/windows/msaa/ARIAGridAccessibleWrap.cpp create mode 100644 accessible/windows/msaa/ARIAGridAccessibleWrap.h create mode 100644 accessible/windows/msaa/AccessibleWrap.cpp create mode 100644 accessible/windows/msaa/AccessibleWrap.h create mode 100644 accessible/windows/msaa/ApplicationAccessibleWrap.cpp create mode 100644 accessible/windows/msaa/ApplicationAccessibleWrap.h create mode 100644 accessible/windows/msaa/Compatibility.cpp create mode 100644 accessible/windows/msaa/Compatibility.h create mode 100644 accessible/windows/msaa/DocAccessibleWrap.cpp create mode 100644 accessible/windows/msaa/DocAccessibleWrap.h create mode 100644 accessible/windows/msaa/EnumVariant.cpp create mode 100644 accessible/windows/msaa/EnumVariant.h create mode 100644 accessible/windows/msaa/HTMLTableAccessibleWrap.cpp create mode 100644 accessible/windows/msaa/HTMLTableAccessibleWrap.h create mode 100644 accessible/windows/msaa/HTMLWin32ObjectAccessible.cpp create mode 100644 accessible/windows/msaa/HTMLWin32ObjectAccessible.h create mode 100644 accessible/windows/msaa/HyperTextAccessibleWrap.cpp create mode 100644 accessible/windows/msaa/HyperTextAccessibleWrap.h create mode 100644 accessible/windows/msaa/IDSet.h create mode 100644 accessible/windows/msaa/IUnknownImpl.cpp create mode 100644 accessible/windows/msaa/IUnknownImpl.h create mode 100644 accessible/windows/msaa/ImageAccessibleWrap.cpp create mode 100644 accessible/windows/msaa/ImageAccessibleWrap.h create mode 100644 accessible/windows/msaa/MsaaIdGenerator.cpp create mode 100644 accessible/windows/msaa/MsaaIdGenerator.h create mode 100644 accessible/windows/msaa/Platform.cpp create mode 100644 accessible/windows/msaa/RootAccessibleWrap.cpp create mode 100644 accessible/windows/msaa/RootAccessibleWrap.h create mode 100644 accessible/windows/msaa/ServiceProvider.cpp create mode 100644 accessible/windows/msaa/ServiceProvider.h create mode 100644 accessible/windows/msaa/TextLeafAccessibleWrap.cpp create mode 100644 accessible/windows/msaa/TextLeafAccessibleWrap.h create mode 100644 accessible/windows/msaa/XULListboxAccessibleWrap.cpp create mode 100644 accessible/windows/msaa/XULListboxAccessibleWrap.h create mode 100644 accessible/windows/msaa/XULMenuAccessibleWrap.cpp create mode 100644 accessible/windows/msaa/XULMenuAccessibleWrap.h create mode 100644 accessible/windows/msaa/XULTreeGridAccessibleWrap.cpp create mode 100644 accessible/windows/msaa/XULTreeGridAccessibleWrap.h create mode 100644 accessible/windows/msaa/moz.build create mode 100644 accessible/windows/msaa/nsEventMap.h create mode 100644 accessible/windows/msaa/nsWinUtils.cpp create mode 100644 accessible/windows/msaa/nsWinUtils.h create mode 100644 accessible/windows/sdn/moz.build create mode 100644 accessible/windows/sdn/sdnAccessible-inl.h create mode 100644 accessible/windows/sdn/sdnAccessible.cpp create mode 100644 accessible/windows/sdn/sdnAccessible.h create mode 100644 accessible/windows/sdn/sdnDocAccessible.cpp create mode 100644 accessible/windows/sdn/sdnDocAccessible.h create mode 100644 accessible/windows/sdn/sdnTextAccessible.cpp create mode 100644 accessible/windows/sdn/sdnTextAccessible.h create mode 100644 accessible/windows/uia/moz.build create mode 100644 accessible/windows/uia/uiaRawElmProvider.cpp create mode 100644 accessible/windows/uia/uiaRawElmProvider.h create mode 100755 accessible/xpcom/AccEventGen.py create mode 100644 accessible/xpcom/AccEvents.conf create mode 100644 accessible/xpcom/moz.build create mode 100644 accessible/xpcom/nsAccessibleRelation.cpp create mode 100644 accessible/xpcom/nsAccessibleRelation.h create mode 100644 accessible/xpcom/xpcAccessibilityService.cpp create mode 100644 accessible/xpcom/xpcAccessibilityService.h create mode 100644 accessible/xpcom/xpcAccessible.cpp create mode 100644 accessible/xpcom/xpcAccessible.h create mode 100644 accessible/xpcom/xpcAccessibleApplication.cpp create mode 100644 accessible/xpcom/xpcAccessibleApplication.h create mode 100644 accessible/xpcom/xpcAccessibleDocument.cpp create mode 100644 accessible/xpcom/xpcAccessibleDocument.h create mode 100644 accessible/xpcom/xpcAccessibleGeneric.cpp create mode 100644 accessible/xpcom/xpcAccessibleGeneric.h create mode 100644 accessible/xpcom/xpcAccessibleHyperLink.cpp create mode 100644 accessible/xpcom/xpcAccessibleHyperLink.h create mode 100644 accessible/xpcom/xpcAccessibleHyperText.cpp create mode 100644 accessible/xpcom/xpcAccessibleHyperText.h create mode 100644 accessible/xpcom/xpcAccessibleImage.cpp create mode 100644 accessible/xpcom/xpcAccessibleImage.h create mode 100644 accessible/xpcom/xpcAccessibleSelectable.cpp create mode 100644 accessible/xpcom/xpcAccessibleSelectable.h create mode 100644 accessible/xpcom/xpcAccessibleTable.cpp create mode 100644 accessible/xpcom/xpcAccessibleTable.h create mode 100644 accessible/xpcom/xpcAccessibleTableCell.cpp create mode 100644 accessible/xpcom/xpcAccessibleTableCell.h create mode 100644 accessible/xpcom/xpcAccessibleTextRange.cpp create mode 100644 accessible/xpcom/xpcAccessibleTextRange.h create mode 100644 accessible/xpcom/xpcAccessibleValue.cpp create mode 100644 accessible/xpcom/xpcAccessibleValue.h create mode 100644 accessible/xul/XULAlertAccessible.cpp create mode 100644 accessible/xul/XULAlertAccessible.h create mode 100644 accessible/xul/XULColorPickerAccessible.cpp create mode 100644 accessible/xul/XULColorPickerAccessible.h create mode 100644 accessible/xul/XULComboboxAccessible.cpp create mode 100644 accessible/xul/XULComboboxAccessible.h create mode 100644 accessible/xul/XULElementAccessibles.cpp create mode 100644 accessible/xul/XULElementAccessibles.h create mode 100644 accessible/xul/XULFormControlAccessible.cpp create mode 100644 accessible/xul/XULFormControlAccessible.h create mode 100644 accessible/xul/XULListboxAccessible.cpp create mode 100644 accessible/xul/XULListboxAccessible.h create mode 100644 accessible/xul/XULMenuAccessible.cpp create mode 100644 accessible/xul/XULMenuAccessible.h create mode 100644 accessible/xul/XULSelectControlAccessible.cpp create mode 100644 accessible/xul/XULSelectControlAccessible.h create mode 100644 accessible/xul/XULSliderAccessible.cpp create mode 100644 accessible/xul/XULSliderAccessible.h create mode 100644 accessible/xul/XULTabAccessible.cpp create mode 100644 accessible/xul/XULTabAccessible.h create mode 100644 accessible/xul/XULTreeAccessible.cpp create mode 100644 accessible/xul/XULTreeAccessible.h create mode 100644 accessible/xul/XULTreeGridAccessible.cpp create mode 100644 accessible/xul/XULTreeGridAccessible.h create mode 100644 accessible/xul/moz.build (limited to 'accessible') diff --git a/accessible/.eslintrc.js b/accessible/.eslintrc.js new file mode 100644 index 0000000000..3cd32ed601 --- /dev/null +++ b/accessible/.eslintrc.js @@ -0,0 +1,17 @@ +"use strict"; + +module.exports = { + "extends": [ + "../.eslintrc.js" + ], + "globals": { + "Cc": true, + "Ci": true, + "Components": true, + "console": true, + "Cu": true, + "dump": true, + "Services": true, + "XPCOMUtils": true + } +}; diff --git a/accessible/aom/AccessibleNode.cpp b/accessible/aom/AccessibleNode.cpp new file mode 100644 index 0000000000..dd26c6a29f --- /dev/null +++ b/accessible/aom/AccessibleNode.cpp @@ -0,0 +1,68 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "AccessibleNode.h" +#include "mozilla/dom/AccessibleNodeBinding.h" +#include "mozilla/dom/BindingDeclarations.h" + +#include "Accessible-inl.h" +#include "nsAccessibilityService.h" +#include "DocAccessible.h" + +using namespace mozilla; +using namespace mozilla::a11y; +using namespace mozilla::dom; + +NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_0(AccessibleNode) + +NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(AccessibleNode) + NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY + NS_INTERFACE_MAP_ENTRY(nsISupports) +NS_INTERFACE_MAP_END + +NS_IMPL_CYCLE_COLLECTING_ADDREF(AccessibleNode) +NS_IMPL_CYCLE_COLLECTING_RELEASE(AccessibleNode) + +AccessibleNode::AccessibleNode(nsINode* aNode) : mDOMNode(aNode) +{ + DocAccessible* doc = + GetOrCreateAccService()->GetDocAccessible(mDOMNode->OwnerDoc()); + if (doc) { + mIntl = doc->GetAccessible(mDOMNode); + } +} + +AccessibleNode::~AccessibleNode() +{ +} + +/* virtual */ JSObject* +AccessibleNode::WrapObject(JSContext* aCx, JS::Handle aGivenProto) +{ + return AccessibleNodeBinding::Wrap(aCx, this, aGivenProto); +} + +/* virtual */ ParentObject +AccessibleNode::GetParentObject() const +{ + return mDOMNode->GetParentObject(); +} + +void +AccessibleNode::GetRole(nsAString& aRole) +{ + if (mIntl) { + GetOrCreateAccService()->GetStringRole(mIntl->Role(), aRole); + return; + } + + aRole.AssignLiteral("unknown"); +} + +nsINode* +AccessibleNode::GetDOMNode() +{ + return mDOMNode; +} diff --git a/accessible/aom/AccessibleNode.h b/accessible/aom/AccessibleNode.h new file mode 100644 index 0000000000..355bb395c8 --- /dev/null +++ b/accessible/aom/AccessibleNode.h @@ -0,0 +1,53 @@ +/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */ +/* vim: set ts=2 et sw=2 tw=40: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef A11Y_AOM_ACCESSIBLENODE_H +#define A11Y_AOM_ACCESSIBLENODE_H + +#include "nsWrapperCache.h" +#include "mozilla/RefPtr.h" + +class nsINode; + +namespace mozilla { + +namespace a11y { + class Accessible; +} + +namespace dom { + +struct ParentObject; + +class AccessibleNode : public nsISupports, + public nsWrapperCache +{ +public: + explicit AccessibleNode(nsINode* aNode); + + NS_DECL_CYCLE_COLLECTING_ISUPPORTS; + NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(AccessibleNode); + + virtual JSObject* WrapObject(JSContext* aCx, JS::Handle aGivenProto) override final; + virtual dom::ParentObject GetParentObject() const final; + + void GetRole(nsAString& aRole); + nsINode* GetDOMNode(); + +protected: + AccessibleNode(const AccessibleNode& aCopy) = delete; + AccessibleNode& operator=(const AccessibleNode& aCopy) = delete; + virtual ~AccessibleNode(); + + RefPtr mIntl; + RefPtr mDOMNode; +}; + +} // dom +} // mozilla + + +#endif // A11Y_JSAPI_ACCESSIBLENODE diff --git a/accessible/aom/moz.build b/accessible/aom/moz.build new file mode 100644 index 0000000000..7000812153 --- /dev/null +++ b/accessible/aom/moz.build @@ -0,0 +1,40 @@ +# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*- +# vim: set filetype=python: +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +EXPORTS.mozilla.dom += [ + 'AccessibleNode.h', +] + +UNIFIED_SOURCES += [ + 'AccessibleNode.cpp', +] + +LOCAL_INCLUDES += [ + '/accessible/base', + '/accessible/generic', +] + +if 'gtk' in CONFIG['MOZ_WIDGET_TOOLKIT']: + LOCAL_INCLUDES += [ + '/accessible/atk', + ] +elif CONFIG['MOZ_WIDGET_TOOLKIT'] == 'windows': + LOCAL_INCLUDES += [ + '/accessible/windows/ia2', + '/accessible/windows/msaa', + ] +elif CONFIG['MOZ_WIDGET_TOOLKIT'] == 'cocoa': + LOCAL_INCLUDES += [ + '/accessible/mac', + ] +else: + LOCAL_INCLUDES += [ + '/accessible/other', + ] + +include('/ipc/chromium/chromium-config.mozbuild') + +FINAL_LIBRARY = 'xul' diff --git a/accessible/atk/ARIAGridAccessibleWrap.h b/accessible/atk/ARIAGridAccessibleWrap.h new file mode 100644 index 0000000000..8d53c6eb20 --- /dev/null +++ b/accessible/atk/ARIAGridAccessibleWrap.h @@ -0,0 +1,21 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef MOZILLA_A11Y_ARIAGRIDACCESSIBLEWRAP_H +#define MOZILLA_A11Y_ARIAGRIDACCESSIBLEWRAP_H + +#include "ARIAGridAccessible.h" + +namespace mozilla { +namespace a11y { + +typedef class ARIAGridAccessible ARIAGridAccessibleWrap; +typedef class ARIAGridCellAccessible ARIAGridCellAccessibleWrap; + +} // namespace a11y +} // namespace mozilla + +#endif diff --git a/accessible/atk/AccessibleWrap.cpp b/accessible/atk/AccessibleWrap.cpp new file mode 100644 index 0000000000..cd0f2999a6 --- /dev/null +++ b/accessible/atk/AccessibleWrap.cpp @@ -0,0 +1,1759 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "AccessibleWrap.h" + +#include "Accessible-inl.h" +#include "ApplicationAccessibleWrap.h" +#include "InterfaceInitFuncs.h" +#include "nsAccUtils.h" +#include "mozilla/a11y/PDocAccessible.h" +#include "OuterDocAccessible.h" +#include "ProxyAccessible.h" +#include "RootAccessible.h" +#include "TableAccessible.h" +#include "TableCellAccessible.h" +#include "nsMai.h" +#include "nsMaiHyperlink.h" +#include "nsString.h" +#include "nsStateMap.h" +#include "mozilla/a11y/Platform.h" +#include "Relation.h" +#include "RootAccessible.h" +#include "States.h" +#include "nsISimpleEnumerator.h" + +#include "mozilla/ArrayUtils.h" +#include "mozilla/Sprintf.h" +#include "nsXPCOMStrings.h" +#include "nsComponentManagerUtils.h" +#include "nsIPersistentProperties2.h" + +using namespace mozilla; +using namespace mozilla::a11y; + +MaiAtkObject::EAvailableAtkSignals MaiAtkObject::gAvailableAtkSignals = + eUnknown; + +//defined in ApplicationAccessibleWrap.cpp +extern "C" GType g_atk_hyperlink_impl_type; + +/* MaiAtkObject */ + +enum { + ACTIVATE, + CREATE, + DEACTIVATE, + DESTROY, + MAXIMIZE, + MINIMIZE, + RESIZE, + RESTORE, + LAST_SIGNAL +}; + +enum MaiInterfaceType { + MAI_INTERFACE_COMPONENT, /* 0 */ + MAI_INTERFACE_ACTION, + MAI_INTERFACE_VALUE, + MAI_INTERFACE_EDITABLE_TEXT, + MAI_INTERFACE_HYPERTEXT, + MAI_INTERFACE_HYPERLINK_IMPL, + MAI_INTERFACE_SELECTION, + MAI_INTERFACE_TABLE, + MAI_INTERFACE_TEXT, + MAI_INTERFACE_DOCUMENT, + MAI_INTERFACE_IMAGE, /* 10 */ + MAI_INTERFACE_TABLE_CELL +}; + +static GType GetAtkTypeForMai(MaiInterfaceType type) +{ + switch (type) { + case MAI_INTERFACE_COMPONENT: + return ATK_TYPE_COMPONENT; + case MAI_INTERFACE_ACTION: + return ATK_TYPE_ACTION; + case MAI_INTERFACE_VALUE: + return ATK_TYPE_VALUE; + case MAI_INTERFACE_EDITABLE_TEXT: + return ATK_TYPE_EDITABLE_TEXT; + case MAI_INTERFACE_HYPERTEXT: + return ATK_TYPE_HYPERTEXT; + case MAI_INTERFACE_HYPERLINK_IMPL: + return g_atk_hyperlink_impl_type; + case MAI_INTERFACE_SELECTION: + return ATK_TYPE_SELECTION; + case MAI_INTERFACE_TABLE: + return ATK_TYPE_TABLE; + case MAI_INTERFACE_TEXT: + return ATK_TYPE_TEXT; + case MAI_INTERFACE_DOCUMENT: + return ATK_TYPE_DOCUMENT; + case MAI_INTERFACE_IMAGE: + return ATK_TYPE_IMAGE; + case MAI_INTERFACE_TABLE_CELL: + MOZ_ASSERT(false); + } + return G_TYPE_INVALID; +} + +#define NON_USER_EVENT ":system" + +// The atk interfaces we can expose without checking what version of ATK we are +// dealing with. At the moment AtkTableCell is the only interface we can't +// always expose. +static const GInterfaceInfo atk_if_infos[] = { + {(GInterfaceInitFunc)componentInterfaceInitCB, + (GInterfaceFinalizeFunc) nullptr, nullptr}, + {(GInterfaceInitFunc)actionInterfaceInitCB, + (GInterfaceFinalizeFunc) nullptr, nullptr}, + {(GInterfaceInitFunc)valueInterfaceInitCB, + (GInterfaceFinalizeFunc) nullptr, nullptr}, + {(GInterfaceInitFunc)editableTextInterfaceInitCB, + (GInterfaceFinalizeFunc) nullptr, nullptr}, + {(GInterfaceInitFunc)hypertextInterfaceInitCB, + (GInterfaceFinalizeFunc) nullptr, nullptr}, + {(GInterfaceInitFunc)hyperlinkImplInterfaceInitCB, + (GInterfaceFinalizeFunc) nullptr, nullptr}, + {(GInterfaceInitFunc)selectionInterfaceInitCB, + (GInterfaceFinalizeFunc) nullptr, nullptr}, + {(GInterfaceInitFunc)tableInterfaceInitCB, + (GInterfaceFinalizeFunc) nullptr, nullptr}, + {(GInterfaceInitFunc)textInterfaceInitCB, + (GInterfaceFinalizeFunc) nullptr, nullptr}, + {(GInterfaceInitFunc)documentInterfaceInitCB, + (GInterfaceFinalizeFunc) nullptr, nullptr}, + {(GInterfaceInitFunc)imageInterfaceInitCB, + (GInterfaceFinalizeFunc) nullptr, nullptr} +}; + +static GQuark quark_mai_hyperlink = 0; + +AtkHyperlink* +MaiAtkObject::GetAtkHyperlink() +{ + NS_ASSERTION(quark_mai_hyperlink, "quark_mai_hyperlink not initialized"); + MaiHyperlink* maiHyperlink = + (MaiHyperlink*)g_object_get_qdata(G_OBJECT(this), quark_mai_hyperlink); + if (!maiHyperlink) { + maiHyperlink = new MaiHyperlink(accWrap); + g_object_set_qdata(G_OBJECT(this), quark_mai_hyperlink, maiHyperlink); + } + + return maiHyperlink->GetAtkHyperlink(); +} + +void +MaiAtkObject::Shutdown() +{ + accWrap.SetBits(0); + MaiHyperlink* maiHyperlink = + (MaiHyperlink*)g_object_get_qdata(G_OBJECT(this), quark_mai_hyperlink); + if (maiHyperlink) { + delete maiHyperlink; + g_object_set_qdata(G_OBJECT(this), quark_mai_hyperlink, nullptr); + } +} + +struct MaiAtkObjectClass +{ + AtkObjectClass parent_class; +}; + +static guint mai_atk_object_signals [LAST_SIGNAL] = { 0, }; + +static void MaybeFireNameChange(AtkObject* aAtkObj, const nsString& aNewName); + +G_BEGIN_DECLS +/* callbacks for MaiAtkObject */ +static void classInitCB(AtkObjectClass *aClass); +static void initializeCB(AtkObject *aAtkObj, gpointer aData); +static void finalizeCB(GObject *aObj); + +/* callbacks for AtkObject virtual functions */ +static const gchar* getNameCB (AtkObject *aAtkObj); +/* getDescriptionCB is also used by image interface */ + const gchar* getDescriptionCB (AtkObject *aAtkObj); +static AtkRole getRoleCB(AtkObject *aAtkObj); +static AtkAttributeSet* getAttributesCB(AtkObject *aAtkObj); +static const gchar* GetLocaleCB(AtkObject*); +static AtkObject* getParentCB(AtkObject *aAtkObj); +static gint getChildCountCB(AtkObject *aAtkObj); +static AtkObject* refChildCB(AtkObject *aAtkObj, gint aChildIndex); +static gint getIndexInParentCB(AtkObject *aAtkObj); +static AtkStateSet* refStateSetCB(AtkObject *aAtkObj); +static AtkRelationSet* refRelationSetCB(AtkObject *aAtkObj); + +/* the missing atkobject virtual functions */ +/* + static AtkLayer getLayerCB(AtkObject *aAtkObj); + static gint getMdiZorderCB(AtkObject *aAtkObj); + static void SetNameCB(AtkObject *aAtkObj, + const gchar *name); + static void SetDescriptionCB(AtkObject *aAtkObj, + const gchar *description); + static void SetParentCB(AtkObject *aAtkObj, + AtkObject *parent); + static void SetRoleCB(AtkObject *aAtkObj, + AtkRole role); + static guint ConnectPropertyChangeHandlerCB( + AtkObject *aObj, + AtkPropertyChangeHandler *handler); + static void RemovePropertyChangeHandlerCB( + AtkObject *aAtkObj, + guint handler_id); + static void InitializeCB(AtkObject *aAtkObj, + gpointer data); + static void ChildrenChangedCB(AtkObject *aAtkObj, + guint change_index, + gpointer changed_child); + static void FocusEventCB(AtkObject *aAtkObj, + gboolean focus_in); + static void PropertyChangeCB(AtkObject *aAtkObj, + AtkPropertyValues *values); + static void StateChangeCB(AtkObject *aAtkObj, + const gchar *name, + gboolean state_set); + static void VisibleDataChangedCB(AtkObject *aAtkObj); +*/ +G_END_DECLS + +static GType GetMaiAtkType(uint16_t interfacesBits); +static const char * GetUniqueMaiAtkTypeName(uint16_t interfacesBits); + +static gpointer parent_class = nullptr; + +GType +mai_atk_object_get_type(void) +{ + static GType type = 0; + + if (!type) { + static const GTypeInfo tinfo = { + sizeof(MaiAtkObjectClass), + (GBaseInitFunc)nullptr, + (GBaseFinalizeFunc)nullptr, + (GClassInitFunc)classInitCB, + (GClassFinalizeFunc)nullptr, + nullptr, /* class data */ + sizeof(MaiAtkObject), /* instance size */ + 0, /* nb preallocs */ + (GInstanceInitFunc)nullptr, + nullptr /* value table */ + }; + + type = g_type_register_static(ATK_TYPE_OBJECT, + "MaiAtkObject", &tinfo, GTypeFlags(0)); + quark_mai_hyperlink = g_quark_from_static_string("MaiHyperlink"); + } + return type; +} + +AccessibleWrap:: + AccessibleWrap(nsIContent* aContent, DocAccessible* aDoc) : + Accessible(aContent, aDoc), mAtkObject(nullptr) +{ +} + +AccessibleWrap::~AccessibleWrap() +{ + NS_ASSERTION(!mAtkObject, "ShutdownAtkObject() is not called"); +} + +void +AccessibleWrap::ShutdownAtkObject() +{ + if (!mAtkObject) + return; + + NS_ASSERTION(IS_MAI_OBJECT(mAtkObject), "wrong type of atk object"); + if (IS_MAI_OBJECT(mAtkObject)) + MAI_ATK_OBJECT(mAtkObject)->Shutdown(); + + g_object_unref(mAtkObject); + mAtkObject = nullptr; +} + +void +AccessibleWrap::Shutdown() +{ + ShutdownAtkObject(); + Accessible::Shutdown(); +} + +void +AccessibleWrap::GetNativeInterface(void** aOutAccessible) +{ + *aOutAccessible = nullptr; + + if (!mAtkObject) { + if (IsDefunct() || IsText()) { + // We don't create ATK objects for node which has been shutdown or + // plain text leaves + return; + } + + GType type = GetMaiAtkType(CreateMaiInterfaces()); + if (!type) + return; + + mAtkObject = reinterpret_cast(g_object_new(type, nullptr)); + if (!mAtkObject) + return; + + atk_object_initialize(mAtkObject, this); + mAtkObject->role = ATK_ROLE_INVALID; + mAtkObject->layer = ATK_LAYER_INVALID; + } + + *aOutAccessible = mAtkObject; +} + +AtkObject * +AccessibleWrap::GetAtkObject(void) +{ + void *atkObj = nullptr; + GetNativeInterface(&atkObj); + return static_cast(atkObj); +} + +// Get AtkObject from Accessible interface +/* static */ +AtkObject * +AccessibleWrap::GetAtkObject(Accessible* acc) +{ + void *atkObjPtr = nullptr; + acc->GetNativeInterface(&atkObjPtr); + return atkObjPtr ? ATK_OBJECT(atkObjPtr) : nullptr; +} + +/* private */ +uint16_t +AccessibleWrap::CreateMaiInterfaces(void) +{ + uint16_t interfacesBits = 0; + + // The Component interface is supported by all accessibles. + interfacesBits |= 1 << MAI_INTERFACE_COMPONENT; + + // Add Action interface if the action count is more than zero. + if (ActionCount() > 0) + interfacesBits |= 1 << MAI_INTERFACE_ACTION; + + // Text, Editabletext, and Hypertext interface. + HyperTextAccessible* hyperText = AsHyperText(); + if (hyperText && hyperText->IsTextRole()) { + interfacesBits |= 1 << MAI_INTERFACE_TEXT; + interfacesBits |= 1 << MAI_INTERFACE_EDITABLE_TEXT; + if (!nsAccUtils::MustPrune(this)) + interfacesBits |= 1 << MAI_INTERFACE_HYPERTEXT; + } + + // Value interface. + if (HasNumericValue()) + interfacesBits |= 1 << MAI_INTERFACE_VALUE; + + // Document interface. + if (IsDoc()) + interfacesBits |= 1 << MAI_INTERFACE_DOCUMENT; + + if (IsImage()) + interfacesBits |= 1 << MAI_INTERFACE_IMAGE; + + // HyperLink interface. + if (IsLink()) + interfacesBits |= 1 << MAI_INTERFACE_HYPERLINK_IMPL; + + if (!nsAccUtils::MustPrune(this)) { // These interfaces require children + // Table interface. + if (AsTable()) + interfacesBits |= 1 << MAI_INTERFACE_TABLE; + + if (AsTableCell()) + interfacesBits |= 1 << MAI_INTERFACE_TABLE_CELL; + + // Selection interface. + if (IsSelect()) { + interfacesBits |= 1 << MAI_INTERFACE_SELECTION; + } + } + + return interfacesBits; +} + +static GType +GetMaiAtkType(uint16_t interfacesBits) +{ + GType type; + static const GTypeInfo tinfo = { + sizeof(MaiAtkObjectClass), + (GBaseInitFunc) nullptr, + (GBaseFinalizeFunc) nullptr, + (GClassInitFunc) nullptr, + (GClassFinalizeFunc) nullptr, + nullptr, /* class data */ + sizeof(MaiAtkObject), /* instance size */ + 0, /* nb preallocs */ + (GInstanceInitFunc) nullptr, + nullptr /* value table */ + }; + + /* + * The members we use to register GTypes are GetAtkTypeForMai + * and atk_if_infos, which are constant values to each MaiInterface + * So we can reuse the registered GType when having + * the same MaiInterface types. + */ + const char *atkTypeName = GetUniqueMaiAtkTypeName(interfacesBits); + type = g_type_from_name(atkTypeName); + if (type) { + return type; + } + + /* + * gobject limits the number of types that can directly derive from any + * given object type to 4095. + */ + static uint16_t typeRegCount = 0; + if (typeRegCount++ >= 4095) { + return G_TYPE_INVALID; + } + type = g_type_register_static(MAI_TYPE_ATK_OBJECT, + atkTypeName, + &tinfo, GTypeFlags(0)); + + for (uint32_t index = 0; index < ArrayLength(atk_if_infos); index++) { + if (interfacesBits & (1 << index)) { + g_type_add_interface_static(type, + GetAtkTypeForMai((MaiInterfaceType)index), + &atk_if_infos[index]); + } + } + + // Special case AtkTableCell so we can check what version of Atk we are + // dealing with. + if (IsAtkVersionAtLeast(2, 12) && (interfacesBits & (1 << MAI_INTERFACE_TABLE_CELL))) { + const GInterfaceInfo cellInfo = { + (GInterfaceInitFunc)tableCellInterfaceInitCB, + (GInterfaceFinalizeFunc)nullptr, nullptr}; + g_type_add_interface_static(type, gAtkTableCellGetTypeFunc(), &cellInfo); + } + + return type; +} + +static const char* +GetUniqueMaiAtkTypeName(uint16_t interfacesBits) +{ +#define MAI_ATK_TYPE_NAME_LEN (30) /* 10+sizeof(uint16_t)*8/4+1 < 30 */ + + static gchar namePrefix[] = "MaiAtkType"; /* size = 10 */ + static gchar name[MAI_ATK_TYPE_NAME_LEN + 1]; + + SprintfLiteral(name, "%s%x", namePrefix, interfacesBits); + name[MAI_ATK_TYPE_NAME_LEN] = '\0'; + + return name; +} + +bool +AccessibleWrap::IsValidObject() +{ + // to ensure we are not shut down + return !IsDefunct(); +} + +/* static functions for ATK callbacks */ +void +classInitCB(AtkObjectClass *aClass) +{ + GObjectClass *gobject_class = G_OBJECT_CLASS(aClass); + + parent_class = g_type_class_peek_parent(aClass); + + aClass->get_name = getNameCB; + aClass->get_description = getDescriptionCB; + aClass->get_parent = getParentCB; + aClass->get_n_children = getChildCountCB; + aClass->ref_child = refChildCB; + aClass->get_index_in_parent = getIndexInParentCB; + aClass->get_role = getRoleCB; + aClass->get_attributes = getAttributesCB; + aClass->get_object_locale = GetLocaleCB; + aClass->ref_state_set = refStateSetCB; + aClass->ref_relation_set = refRelationSetCB; + + aClass->initialize = initializeCB; + + gobject_class->finalize = finalizeCB; + + mai_atk_object_signals [ACTIVATE] = + g_signal_new ("activate", + MAI_TYPE_ATK_OBJECT, + G_SIGNAL_RUN_LAST, + 0, /* default signal handler */ + nullptr, nullptr, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, 0); + mai_atk_object_signals [CREATE] = + g_signal_new ("create", + MAI_TYPE_ATK_OBJECT, + G_SIGNAL_RUN_LAST, + 0, /* default signal handler */ + nullptr, nullptr, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, 0); + mai_atk_object_signals [DEACTIVATE] = + g_signal_new ("deactivate", + MAI_TYPE_ATK_OBJECT, + G_SIGNAL_RUN_LAST, + 0, /* default signal handler */ + nullptr, nullptr, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, 0); + mai_atk_object_signals [DESTROY] = + g_signal_new ("destroy", + MAI_TYPE_ATK_OBJECT, + G_SIGNAL_RUN_LAST, + 0, /* default signal handler */ + nullptr, nullptr, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, 0); + mai_atk_object_signals [MAXIMIZE] = + g_signal_new ("maximize", + MAI_TYPE_ATK_OBJECT, + G_SIGNAL_RUN_LAST, + 0, /* default signal handler */ + nullptr, nullptr, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, 0); + mai_atk_object_signals [MINIMIZE] = + g_signal_new ("minimize", + MAI_TYPE_ATK_OBJECT, + G_SIGNAL_RUN_LAST, + 0, /* default signal handler */ + nullptr, nullptr, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, 0); + mai_atk_object_signals [RESIZE] = + g_signal_new ("resize", + MAI_TYPE_ATK_OBJECT, + G_SIGNAL_RUN_LAST, + 0, /* default signal handler */ + nullptr, nullptr, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, 0); + mai_atk_object_signals [RESTORE] = + g_signal_new ("restore", + MAI_TYPE_ATK_OBJECT, + G_SIGNAL_RUN_LAST, + 0, /* default signal handler */ + nullptr, nullptr, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, 0); + +} + +void +initializeCB(AtkObject *aAtkObj, gpointer aData) +{ + NS_ASSERTION((IS_MAI_OBJECT(aAtkObj)), "Invalid AtkObject"); + NS_ASSERTION(aData, "Invalid Data to init AtkObject"); + if (!aAtkObj || !aData) + return; + + /* call parent init function */ + /* AtkObjectClass has not a "initialize" function now, + * maybe it has later + */ + + if (ATK_OBJECT_CLASS(parent_class)->initialize) + ATK_OBJECT_CLASS(parent_class)->initialize(aAtkObj, aData); + + /* initialize object */ + MAI_ATK_OBJECT(aAtkObj)->accWrap.SetBits(reinterpret_cast(aData)); +} + +void +finalizeCB(GObject *aObj) +{ + if (!IS_MAI_OBJECT(aObj)) + return; + NS_ASSERTION(MAI_ATK_OBJECT(aObj)->accWrap.IsNull(), "AccWrap NOT null"); + + // call parent finalize function + // finalize of GObjectClass will unref the accessible parent if has + if (G_OBJECT_CLASS (parent_class)->finalize) + G_OBJECT_CLASS (parent_class)->finalize(aObj); +} + +const gchar* +getNameCB(AtkObject* aAtkObj) +{ + nsAutoString name; + AccessibleWrap* accWrap = GetAccessibleWrap(aAtkObj); + if (accWrap) + accWrap->Name(name); + else if (ProxyAccessible* proxy = GetProxy(aAtkObj)) + proxy->Name(name); + else + return nullptr; + + // XXX Firing an event from here does not seem right + MaybeFireNameChange(aAtkObj, name); + + return aAtkObj->name; +} + +static void +MaybeFireNameChange(AtkObject* aAtkObj, const nsString& aNewName) +{ + NS_ConvertUTF16toUTF8 newNameUTF8(aNewName); + if (aAtkObj->name && !strcmp(aAtkObj->name, newNameUTF8.get())) + return; + + // Below we duplicate the functionality of atk_object_set_name(), + // but without calling atk_object_get_name(). Instead of + // atk_object_get_name() we directly access aAtkObj->name. This is because + // atk_object_get_name() would call getNameCB() which would call + // MaybeFireNameChange() (or atk_object_set_name() before this problem was + // fixed) and we would get an infinite recursion. + // See http://bugzilla.mozilla.org/733712 + + // Do not notify for initial name setting. + // See bug http://bugzilla.gnome.org/665870 + bool notify = !!aAtkObj->name; + + free(aAtkObj->name); + aAtkObj->name = strdup(newNameUTF8.get()); + + if (notify) + g_object_notify(G_OBJECT(aAtkObj), "accessible-name"); +} + +const gchar * +getDescriptionCB(AtkObject *aAtkObj) +{ + nsAutoString uniDesc; + AccessibleWrap* accWrap = GetAccessibleWrap(aAtkObj); + if (accWrap) { + if (accWrap->IsDefunct()) + return nullptr; + + accWrap->Description(uniDesc); + } else if (ProxyAccessible* proxy = GetProxy(aAtkObj)) { + proxy->Description(uniDesc); + } else { + return nullptr; + } + + NS_ConvertUTF8toUTF16 objDesc(aAtkObj->description); + if (!uniDesc.Equals(objDesc)) + atk_object_set_description(aAtkObj, + NS_ConvertUTF16toUTF8(uniDesc).get()); + + return aAtkObj->description; +} + +AtkRole +getRoleCB(AtkObject *aAtkObj) +{ + if (aAtkObj->role != ATK_ROLE_INVALID) + return aAtkObj->role; + + AccessibleOrProxy acc = GetInternalObj(aAtkObj); + if (acc.IsNull()) { + return ATK_ROLE_INVALID; + } + +#ifdef DEBUG + if (AccessibleWrap* accWrap = GetAccessibleWrap(aAtkObj)) { + NS_ASSERTION(nsAccUtils::IsTextInterfaceSupportCorrect(accWrap), + "Does not support Text interface when it should"); + } +#endif + +#define ROLE(geckoRole, stringRole, atkRole, macRole, \ + msaaRole, ia2Role, nameRule) \ + case roles::geckoRole: \ + aAtkObj->role = atkRole; \ + break; + + switch (acc.Role()) { +#include "RoleMap.h" + default: + MOZ_CRASH("Unknown role."); + } + +#undef ROLE + + if (aAtkObj->role == ATK_ROLE_LIST_BOX && !IsAtkVersionAtLeast(2, 1)) + aAtkObj->role = ATK_ROLE_LIST; + else if (aAtkObj->role == ATK_ROLE_TABLE_ROW && !IsAtkVersionAtLeast(2, 1)) + aAtkObj->role = ATK_ROLE_LIST_ITEM; + else if (aAtkObj->role == ATK_ROLE_MATH && !IsAtkVersionAtLeast(2, 12)) + aAtkObj->role = ATK_ROLE_SECTION; + else if (aAtkObj->role == ATK_ROLE_STATIC && !IsAtkVersionAtLeast(2, 16)) + aAtkObj->role = ATK_ROLE_TEXT; + else if ((aAtkObj->role == ATK_ROLE_MATH_FRACTION || + aAtkObj->role == ATK_ROLE_MATH_ROOT) && !IsAtkVersionAtLeast(2, 16)) + aAtkObj->role = ATK_ROLE_SECTION; + + return aAtkObj->role; +} + +static AtkAttributeSet* +ConvertToAtkAttributeSet(nsIPersistentProperties* aAttributes) +{ + if (!aAttributes) + return nullptr; + + AtkAttributeSet *objAttributeSet = nullptr; + nsCOMPtr propEnum; + nsresult rv = aAttributes->Enumerate(getter_AddRefs(propEnum)); + NS_ENSURE_SUCCESS(rv, nullptr); + + bool hasMore; + while (NS_SUCCEEDED(propEnum->HasMoreElements(&hasMore)) && hasMore) { + nsCOMPtr sup; + rv = propEnum->GetNext(getter_AddRefs(sup)); + NS_ENSURE_SUCCESS(rv, objAttributeSet); + + nsCOMPtr propElem(do_QueryInterface(sup)); + NS_ENSURE_TRUE(propElem, objAttributeSet); + + nsAutoCString name; + rv = propElem->GetKey(name); + NS_ENSURE_SUCCESS(rv, objAttributeSet); + + nsAutoString value; + rv = propElem->GetValue(value); + NS_ENSURE_SUCCESS(rv, objAttributeSet); + + AtkAttribute *objAttr = (AtkAttribute *)g_malloc(sizeof(AtkAttribute)); + objAttr->name = g_strdup(name.get()); + objAttr->value = g_strdup(NS_ConvertUTF16toUTF8(value).get()); + objAttributeSet = g_slist_prepend(objAttributeSet, objAttr); + } + + //libspi will free it + return objAttributeSet; +} + +AtkAttributeSet* +GetAttributeSet(Accessible* aAccessible) +{ + nsCOMPtr attributes = aAccessible->Attributes(); + if (attributes) { + // There is no ATK state for haspopup, must use object attribute to expose + // the same info. + if (aAccessible->State() & states::HASPOPUP) { + nsAutoString unused; + attributes->SetStringProperty(NS_LITERAL_CSTRING("haspopup"), + NS_LITERAL_STRING("true"), unused); + } + + return ConvertToAtkAttributeSet(attributes); + } + + return nullptr; +} + +AtkAttributeSet * +getAttributesCB(AtkObject *aAtkObj) +{ + AccessibleWrap* accWrap = GetAccessibleWrap(aAtkObj); + if (accWrap) + return GetAttributeSet(accWrap); + + ProxyAccessible* proxy = GetProxy(aAtkObj); + if (!proxy) + return nullptr; + + AutoTArray attrs; + proxy->Attributes(&attrs); + if (attrs.IsEmpty()) + return nullptr; + + AtkAttributeSet* objAttributeSet = nullptr; + for (uint32_t i = 0; i < attrs.Length(); i++) { + AtkAttribute *objAttr = (AtkAttribute *)g_malloc(sizeof(AtkAttribute)); + objAttr->name = g_strdup(attrs[i].Name().get()); + objAttr->value = g_strdup(NS_ConvertUTF16toUTF8(attrs[i].Value()).get()); + objAttributeSet = g_slist_prepend(objAttributeSet, objAttr); + } + + return objAttributeSet; +} + +const gchar* +GetLocaleCB(AtkObject* aAtkObj) +{ + AccessibleWrap* accWrap = GetAccessibleWrap(aAtkObj); + if (!accWrap) + return nullptr; + + nsAutoString locale; + accWrap->Language(locale); + return AccessibleWrap::ReturnString(locale); +} + +AtkObject * +getParentCB(AtkObject *aAtkObj) +{ + if (aAtkObj->accessible_parent) + return aAtkObj->accessible_parent; + + AccessibleOrProxy acc = GetInternalObj(aAtkObj); + if (acc.IsNull()) { + return nullptr; + } + + AccessibleOrProxy parent = acc.Parent(); + AtkObject* atkParent = !parent.IsNull() ? GetWrapperFor(parent) : nullptr; + if (atkParent) + atk_object_set_parent(aAtkObj, atkParent); + + return aAtkObj->accessible_parent; +} + +gint +getChildCountCB(AtkObject *aAtkObj) +{ + if (AccessibleWrap* accWrap = GetAccessibleWrap(aAtkObj)) { + if (nsAccUtils::MustPrune(accWrap)) { + return 0; + } + + uint32_t count = accWrap->EmbeddedChildCount(); + if (count) { + return static_cast(count); + } + + OuterDocAccessible* outerDoc = accWrap->AsOuterDoc(); + if (outerDoc && outerDoc->RemoteChildDoc()) { + return 1; + } + } + + ProxyAccessible* proxy = GetProxy(aAtkObj); + if (proxy && !proxy->MustPruneChildren()) { + return proxy->EmbeddedChildCount(); + } + + return 0; +} + +AtkObject * +refChildCB(AtkObject *aAtkObj, gint aChildIndex) +{ + // aChildIndex should not be less than zero + if (aChildIndex < 0) { + return nullptr; + } + + AtkObject* childAtkObj = nullptr; + AccessibleWrap* accWrap = GetAccessibleWrap(aAtkObj); + if (accWrap) { + if (nsAccUtils::MustPrune(accWrap)) { + return nullptr; + } + + Accessible* accChild = accWrap->GetEmbeddedChildAt(aChildIndex); + if (accChild) { + childAtkObj = AccessibleWrap::GetAtkObject(accChild); + } else { + OuterDocAccessible* docOwner = accWrap->AsOuterDoc(); + if (docOwner) { + ProxyAccessible* proxyDoc = docOwner->RemoteChildDoc(); + if (proxyDoc) + childAtkObj = GetWrapperFor(proxyDoc); + } + } + } else if (ProxyAccessible* proxy = GetProxy(aAtkObj)) { + if (proxy->MustPruneChildren()) + return nullptr; + + ProxyAccessible* child = proxy->EmbeddedChildAt(aChildIndex); + if (child) + childAtkObj = GetWrapperFor(child); + } else { + return nullptr; + } + + NS_ASSERTION(childAtkObj, "Fail to get AtkObj"); + if (!childAtkObj) + return nullptr; + + g_object_ref(childAtkObj); + + if (aAtkObj != childAtkObj->accessible_parent) + atk_object_set_parent(childAtkObj, aAtkObj); + + return childAtkObj; +} + +gint +getIndexInParentCB(AtkObject* aAtkObj) +{ + // We don't use Accessible::IndexInParent() because we don't include text + // leaf nodes as children in ATK. + if (ProxyAccessible* proxy = GetProxy(aAtkObj)) { + if (ProxyAccessible* parent = proxy->Parent()) + return parent->IndexOfEmbeddedChild(proxy); + + if (proxy->OuterDocOfRemoteBrowser()) + return 0; + + return -1; + } + + AccessibleWrap* accWrap = GetAccessibleWrap(aAtkObj); + if (!accWrap) { + return -1; + } + + Accessible* parent = accWrap->Parent(); + if (!parent) + return -1; // No parent + + return parent->GetIndexOfEmbeddedChild(accWrap); +} + +static void +TranslateStates(uint64_t aState, AtkStateSet* aStateSet) +{ + // atk doesn't have a read only state so read only things shouldn't be + // editable. + if (aState & states::READONLY) + aState &= ~states::EDITABLE; + + // Convert every state to an entry in AtkStateMap + uint32_t stateIndex = 0; + uint64_t bitMask = 1; + while (gAtkStateMap[stateIndex].stateMapEntryType != kNoSuchState) { + if (gAtkStateMap[stateIndex].atkState) { // There's potentially an ATK state for this + bool isStateOn = (aState & bitMask) != 0; + if (gAtkStateMap[stateIndex].stateMapEntryType == kMapOpposite) { + isStateOn = !isStateOn; + } + if (isStateOn) { + atk_state_set_add_state(aStateSet, gAtkStateMap[stateIndex].atkState); + } + } + bitMask <<= 1; + ++ stateIndex; + } +} + +AtkStateSet * +refStateSetCB(AtkObject *aAtkObj) +{ + AtkStateSet *state_set = nullptr; + state_set = ATK_OBJECT_CLASS(parent_class)->ref_state_set(aAtkObj); + + AccessibleWrap* accWrap = GetAccessibleWrap(aAtkObj); + if (accWrap) + TranslateStates(accWrap->State(), state_set); + else if (ProxyAccessible* proxy = GetProxy(aAtkObj)) + TranslateStates(proxy->State(), state_set); + else + TranslateStates(states::DEFUNCT, state_set); + + return state_set; +} + +static void +UpdateAtkRelation(RelationType aType, Accessible* aAcc, + AtkRelationType aAtkType, AtkRelationSet* aAtkSet) +{ + if (aAtkType == ATK_RELATION_NULL) + return; + + AtkRelation* atkRelation = + atk_relation_set_get_relation_by_type(aAtkSet, aAtkType); + if (atkRelation) + atk_relation_set_remove(aAtkSet, atkRelation); + + Relation rel(aAcc->RelationByType(aType)); + nsTArray targets; + Accessible* tempAcc = nullptr; + while ((tempAcc = rel.Next())) + targets.AppendElement(AccessibleWrap::GetAtkObject(tempAcc)); + + if (aType == RelationType::EMBEDS && aAcc->IsRoot()) { + if (ProxyAccessible* proxyDoc = + aAcc->AsRoot()->GetPrimaryRemoteTopLevelContentDoc()) { + targets.AppendElement(GetWrapperFor(proxyDoc)); + } + } + + if (targets.Length()) { + atkRelation = atk_relation_new(targets.Elements(), + targets.Length(), aAtkType); + atk_relation_set_add(aAtkSet, atkRelation); + g_object_unref(atkRelation); + } +} + +AtkRelationSet * +refRelationSetCB(AtkObject *aAtkObj) +{ + AtkRelationSet* relation_set = + ATK_OBJECT_CLASS(parent_class)->ref_relation_set(aAtkObj); + + const AtkRelationType typeMap[] = { +#define RELATIONTYPE(gecko, s, atk, m, i) atk, +#include "RelationTypeMap.h" +#undef RELATIONTYPE + }; + + if (ProxyAccessible* proxy = GetProxy(aAtkObj)) { + nsTArray types; + nsTArray> targetSets; + proxy->Relations(&types, &targetSets); + + size_t relationCount = types.Length(); + for (size_t i = 0; i < relationCount; i++) { + if (typeMap[static_cast(types[i])] == ATK_RELATION_NULL) + continue; + + size_t targetCount = targetSets[i].Length(); + AutoTArray wrappers; + for (size_t j = 0; j < targetCount; j++) + wrappers.AppendElement(GetWrapperFor(targetSets[i][j])); + + AtkRelationType atkType = typeMap[static_cast(types[i])]; + AtkRelation* atkRelation = + atk_relation_set_get_relation_by_type(relation_set, atkType); + if (atkRelation) + atk_relation_set_remove(relation_set, atkRelation); + + atkRelation = atk_relation_new(wrappers.Elements(), wrappers.Length(), + atkType); + atk_relation_set_add(relation_set, atkRelation); + g_object_unref(atkRelation); + } + } + + AccessibleWrap* accWrap = GetAccessibleWrap(aAtkObj); + if (!accWrap) + return relation_set; + +#define RELATIONTYPE(geckoType, geckoTypeName, atkType, msaaType, ia2Type) \ + UpdateAtkRelation(RelationType::geckoType, accWrap, atkType, relation_set); + +#include "RelationTypeMap.h" + +#undef RELATIONTYPE + + return relation_set; +} + +// Check if aAtkObj is a valid MaiAtkObject, and return the AccessibleWrap +// for it. +AccessibleWrap* +GetAccessibleWrap(AtkObject* aAtkObj) +{ + bool isMAIObject = IS_MAI_OBJECT(aAtkObj); + NS_ENSURE_TRUE(isMAIObject || MAI_IS_ATK_SOCKET(aAtkObj), + nullptr); + + AccessibleWrap* accWrap = nullptr; + if (isMAIObject) { + Accessible* acc = MAI_ATK_OBJECT(aAtkObj)->accWrap.AsAccessible(); + accWrap = static_cast(acc); + } else { + accWrap = MAI_ATK_SOCKET(aAtkObj)->accWrap; + } + + // Check if the accessible was deconstructed. + if (!accWrap) + return nullptr; + + NS_ENSURE_TRUE(accWrap->GetAtkObject() == aAtkObj, nullptr); + + AccessibleWrap* appAccWrap = ApplicationAcc(); + if (appAccWrap != accWrap && !accWrap->IsValidObject()) + return nullptr; + + return accWrap; +} + +ProxyAccessible* +GetProxy(AtkObject* aObj) +{ + return GetInternalObj(aObj).AsProxy(); +} + +AccessibleOrProxy +GetInternalObj(AtkObject* aObj) +{ + if (!aObj || !IS_MAI_OBJECT(aObj)) + return nullptr; + + return MAI_ATK_OBJECT(aObj)->accWrap; +} + +AtkObject* +GetWrapperFor(ProxyAccessible* aProxy) +{ + return reinterpret_cast(aProxy->GetWrapper() & ~IS_PROXY); +} + +AtkObject* +GetWrapperFor(AccessibleOrProxy aObj) +{ + if (aObj.IsProxy()) { + return GetWrapperFor(aObj.AsProxy()); + } + + return AccessibleWrap::GetAtkObject(aObj.AsAccessible()); +} + +static uint16_t +GetInterfacesForProxy(ProxyAccessible* aProxy, uint32_t aInterfaces) +{ + uint16_t interfaces = 1 << MAI_INTERFACE_COMPONENT; + if (aInterfaces & Interfaces::HYPERTEXT) + interfaces |= (1 << MAI_INTERFACE_HYPERTEXT) | (1 << MAI_INTERFACE_TEXT) + | (1 << MAI_INTERFACE_EDITABLE_TEXT); + + if (aInterfaces & Interfaces::HYPERLINK) + interfaces |= 1 << MAI_INTERFACE_HYPERLINK_IMPL; + + if (aInterfaces & Interfaces::VALUE) + interfaces |= 1 << MAI_INTERFACE_VALUE; + + if (aInterfaces & Interfaces::TABLE) + interfaces |= 1 << MAI_INTERFACE_TABLE; + + if (aInterfaces & Interfaces::TABLECELL) + interfaces |= 1 << MAI_INTERFACE_TABLE_CELL; + + if (aInterfaces & Interfaces::IMAGE) + interfaces |= 1 << MAI_INTERFACE_IMAGE; + + if (aInterfaces & Interfaces::DOCUMENT) + interfaces |= 1 << MAI_INTERFACE_DOCUMENT; + + if (aInterfaces & Interfaces::SELECTION) { + interfaces |= 1 << MAI_INTERFACE_SELECTION; + } + + if (aInterfaces & Interfaces::ACTION) { + interfaces |= 1 << MAI_INTERFACE_ACTION; + } + + return interfaces; +} + +void +a11y::ProxyCreated(ProxyAccessible* aProxy, uint32_t aInterfaces) +{ + GType type = GetMaiAtkType(GetInterfacesForProxy(aProxy, aInterfaces)); + NS_ASSERTION(type, "why don't we have a type!"); + + AtkObject* obj = + reinterpret_cast + (g_object_new(type, nullptr)); + if (!obj) + return; + + uintptr_t inner = reinterpret_cast(aProxy) | IS_PROXY; + atk_object_initialize(obj, reinterpret_cast(inner)); + obj->role = ATK_ROLE_INVALID; + obj->layer = ATK_LAYER_INVALID; + aProxy->SetWrapper(reinterpret_cast(obj) | IS_PROXY); +} + +void +a11y::ProxyDestroyed(ProxyAccessible* aProxy) +{ + auto obj = reinterpret_cast(aProxy->GetWrapper() & ~IS_PROXY); + if (!obj) { + return; + } + + obj->Shutdown(); + g_object_unref(obj); + aProxy->SetWrapper(0); +} + +nsresult +AccessibleWrap::HandleAccEvent(AccEvent* aEvent) +{ + nsresult rv = Accessible::HandleAccEvent(aEvent); + NS_ENSURE_SUCCESS(rv, rv); + + if (IPCAccessibilityActive()) { + return NS_OK; + } + + Accessible* accessible = aEvent->GetAccessible(); + NS_ENSURE_TRUE(accessible, NS_ERROR_FAILURE); + + // The accessible can become defunct if we have an xpcom event listener + // which decides it would be fun to change the DOM and flush layout. + if (accessible->IsDefunct()) + return NS_OK; + + uint32_t type = aEvent->GetEventType(); + + AtkObject* atkObj = AccessibleWrap::GetAtkObject(accessible); + + // We don't create ATK objects for plain text leaves, just return NS_OK in + // such case. + if (!atkObj) { + NS_ASSERTION(type == nsIAccessibleEvent::EVENT_SHOW || + type == nsIAccessibleEvent::EVENT_HIDE, + "Event other than SHOW and HIDE fired for plain text leaves"); + return NS_OK; + } + + AccessibleWrap* accWrap = GetAccessibleWrap(atkObj); + if (!accWrap) { + return NS_OK; // Node is shut down + } + + switch (type) { + case nsIAccessibleEvent::EVENT_STATE_CHANGE: + { + AccStateChangeEvent* event = downcast_accEvent(aEvent); + MAI_ATK_OBJECT(atkObj)->FireStateChangeEvent(event->GetState(), + event->IsStateEnabled()); + break; + } + + case nsIAccessibleEvent::EVENT_TEXT_REMOVED: + case nsIAccessibleEvent::EVENT_TEXT_INSERTED: + { + AccTextChangeEvent* event = downcast_accEvent(aEvent); + NS_ENSURE_TRUE(event, NS_ERROR_FAILURE); + + MAI_ATK_OBJECT(atkObj)-> FireTextChangeEvent(event->ModifiedText(), + event->GetStartOffset(), + event->GetLength(), + event->IsTextInserted(), + event->IsFromUserInput()); + + return NS_OK; + } + + case nsIAccessibleEvent::EVENT_FOCUS: + { + a11y::RootAccessible* rootAccWrap = accWrap->RootAccessible(); + if (rootAccWrap && rootAccWrap->mActivated) { + atk_focus_tracker_notify(atkObj); + // Fire state change event for focus + atk_object_notify_state_change(atkObj, ATK_STATE_FOCUSED, true); + return NS_OK; + } + } break; + + case nsIAccessibleEvent::EVENT_NAME_CHANGE: + { + nsAutoString newName; + accessible->Name(newName); + + MaybeFireNameChange(atkObj, newName); + + break; + } + + case nsIAccessibleEvent::EVENT_VALUE_CHANGE: + case nsIAccessibleEvent::EVENT_TEXT_VALUE_CHANGE: + if (accessible->HasNumericValue()) { + // Make sure this is a numeric value. Don't fire for string value changes + // (e.g. text editing) ATK values are always numeric. + g_object_notify((GObject*)atkObj, "accessible-value"); + } + break; + + case nsIAccessibleEvent::EVENT_SELECTION: + case nsIAccessibleEvent::EVENT_SELECTION_ADD: + case nsIAccessibleEvent::EVENT_SELECTION_REMOVE: + { + // XXX: dupe events may be fired + AccSelChangeEvent* selChangeEvent = downcast_accEvent(aEvent); + g_signal_emit_by_name(AccessibleWrap::GetAtkObject(selChangeEvent->Widget()), + "selection_changed"); + break; + } + + case nsIAccessibleEvent::EVENT_SELECTION_WITHIN: + { + g_signal_emit_by_name(atkObj, "selection_changed"); + break; + } + + case nsIAccessibleEvent::EVENT_ALERT: + // A hack using state change showing events as alert events. + atk_object_notify_state_change(atkObj, ATK_STATE_SHOWING, true); + break; + + case nsIAccessibleEvent::EVENT_TEXT_SELECTION_CHANGED: + g_signal_emit_by_name(atkObj, "text_selection_changed"); + break; + + case nsIAccessibleEvent::EVENT_TEXT_CARET_MOVED: + { + AccCaretMoveEvent* caretMoveEvent = downcast_accEvent(aEvent); + NS_ASSERTION(caretMoveEvent, "Event needs event data"); + if (!caretMoveEvent) + break; + + int32_t caretOffset = caretMoveEvent->GetCaretOffset(); + g_signal_emit_by_name(atkObj, "text_caret_moved", caretOffset); + } break; + + case nsIAccessibleEvent::EVENT_TEXT_ATTRIBUTE_CHANGED: + g_signal_emit_by_name(atkObj, "text-attributes-changed"); + break; + + case nsIAccessibleEvent::EVENT_TABLE_MODEL_CHANGED: + g_signal_emit_by_name(atkObj, "model_changed"); + break; + + case nsIAccessibleEvent::EVENT_TABLE_ROW_INSERT: + { + AccTableChangeEvent* tableEvent = downcast_accEvent(aEvent); + NS_ENSURE_TRUE(tableEvent, NS_ERROR_FAILURE); + + int32_t rowIndex = tableEvent->GetIndex(); + int32_t numRows = tableEvent->GetCount(); + + g_signal_emit_by_name(atkObj, "row_inserted", rowIndex, numRows); + } break; + + case nsIAccessibleEvent::EVENT_TABLE_ROW_DELETE: + { + AccTableChangeEvent* tableEvent = downcast_accEvent(aEvent); + NS_ENSURE_TRUE(tableEvent, NS_ERROR_FAILURE); + + int32_t rowIndex = tableEvent->GetIndex(); + int32_t numRows = tableEvent->GetCount(); + + g_signal_emit_by_name(atkObj, "row_deleted", rowIndex, numRows); + } break; + + case nsIAccessibleEvent::EVENT_TABLE_ROW_REORDER: + { + g_signal_emit_by_name(atkObj, "row_reordered"); + break; + } + + case nsIAccessibleEvent::EVENT_TABLE_COLUMN_INSERT: + { + AccTableChangeEvent* tableEvent = downcast_accEvent(aEvent); + NS_ENSURE_TRUE(tableEvent, NS_ERROR_FAILURE); + + int32_t colIndex = tableEvent->GetIndex(); + int32_t numCols = tableEvent->GetCount(); + g_signal_emit_by_name(atkObj, "column_inserted", colIndex, numCols); + } break; + + case nsIAccessibleEvent::EVENT_TABLE_COLUMN_DELETE: + { + AccTableChangeEvent* tableEvent = downcast_accEvent(aEvent); + NS_ENSURE_TRUE(tableEvent, NS_ERROR_FAILURE); + + int32_t colIndex = tableEvent->GetIndex(); + int32_t numCols = tableEvent->GetCount(); + g_signal_emit_by_name(atkObj, "column_deleted", colIndex, numCols); + } break; + + case nsIAccessibleEvent::EVENT_TABLE_COLUMN_REORDER: + g_signal_emit_by_name(atkObj, "column_reordered"); + break; + + case nsIAccessibleEvent::EVENT_SECTION_CHANGED: + g_signal_emit_by_name(atkObj, "visible_data_changed"); + break; + + case nsIAccessibleEvent::EVENT_SHOW: + { + AccMutationEvent* event = downcast_accEvent(aEvent); + Accessible* parentAcc = event ? event->Parent() : accessible->Parent(); + AtkObject* parent = AccessibleWrap::GetAtkObject(parentAcc); + NS_ENSURE_STATE(parent); + auto obj = reinterpret_cast(atkObj); + obj->FireAtkShowHideEvent(parent, true, aEvent->IsFromUserInput()); + return NS_OK; + } + + case nsIAccessibleEvent::EVENT_HIDE: + { + // XXX - Handle native dialog accessibles. + if (!accessible->IsRoot() && accessible->HasARIARole() && + accessible->ARIARole() == roles::DIALOG) { + guint id = g_signal_lookup("deactivate", MAI_TYPE_ATK_OBJECT); + g_signal_emit(atkObj, id, 0); + } + + AccMutationEvent* event = downcast_accEvent(aEvent); + Accessible* parentAcc = event ? event->Parent() : accessible->Parent(); + AtkObject* parent = AccessibleWrap::GetAtkObject(parentAcc); + NS_ENSURE_STATE(parent); + auto obj = reinterpret_cast(atkObj); + obj->FireAtkShowHideEvent(parent, false, aEvent->IsFromUserInput()); + return NS_OK; + } + + /* + * Because dealing with menu is very different between nsIAccessible + * and ATK, and the menu activity is important, specially transfer the + * following two event. + * Need more verification by AT test. + */ + case nsIAccessibleEvent::EVENT_MENU_START: + case nsIAccessibleEvent::EVENT_MENU_END: + break; + + case nsIAccessibleEvent::EVENT_WINDOW_ACTIVATE: + { + accessible->AsRoot()->mActivated = true; + guint id = g_signal_lookup("activate", MAI_TYPE_ATK_OBJECT); + g_signal_emit(atkObj, id, 0); + + // Always fire a current focus event after activation. + FocusMgr()->ForceFocusEvent(); + } break; + + case nsIAccessibleEvent::EVENT_WINDOW_DEACTIVATE: + { + accessible->AsRoot()->mActivated = false; + guint id = g_signal_lookup("deactivate", MAI_TYPE_ATK_OBJECT); + g_signal_emit(atkObj, id, 0); + } break; + + case nsIAccessibleEvent::EVENT_WINDOW_MAXIMIZE: + { + guint id = g_signal_lookup("maximize", MAI_TYPE_ATK_OBJECT); + g_signal_emit(atkObj, id, 0); + } break; + + case nsIAccessibleEvent::EVENT_WINDOW_MINIMIZE: + { + guint id = g_signal_lookup("minimize", MAI_TYPE_ATK_OBJECT); + g_signal_emit(atkObj, id, 0); + } break; + + case nsIAccessibleEvent::EVENT_WINDOW_RESTORE: + { + guint id = g_signal_lookup("restore", MAI_TYPE_ATK_OBJECT); + g_signal_emit(atkObj, id, 0); + } break; + + case nsIAccessibleEvent::EVENT_DOCUMENT_LOAD_COMPLETE: + g_signal_emit_by_name (atkObj, "load_complete"); + // XXX - Handle native dialog accessibles. + if (!accessible->IsRoot() && accessible->HasARIARole() && + accessible->ARIARole() == roles::DIALOG) { + guint id = g_signal_lookup("activate", MAI_TYPE_ATK_OBJECT); + g_signal_emit(atkObj, id, 0); + } + break; + + case nsIAccessibleEvent::EVENT_DOCUMENT_RELOAD: + g_signal_emit_by_name (atkObj, "reload"); + break; + + case nsIAccessibleEvent::EVENT_DOCUMENT_LOAD_STOPPED: + g_signal_emit_by_name (atkObj, "load_stopped"); + break; + + case nsIAccessibleEvent::EVENT_MENUPOPUP_START: + atk_focus_tracker_notify(atkObj); // fire extra focus event + atk_object_notify_state_change(atkObj, ATK_STATE_VISIBLE, true); + atk_object_notify_state_change(atkObj, ATK_STATE_SHOWING, true); + break; + + case nsIAccessibleEvent::EVENT_MENUPOPUP_END: + atk_object_notify_state_change(atkObj, ATK_STATE_VISIBLE, false); + atk_object_notify_state_change(atkObj, ATK_STATE_SHOWING, false); + break; + } + + return NS_OK; +} + +void +a11y::ProxyEvent(ProxyAccessible* aTarget, uint32_t aEventType) +{ + AtkObject* wrapper = GetWrapperFor(aTarget); + + switch (aEventType) { + case nsIAccessibleEvent::EVENT_FOCUS: + atk_focus_tracker_notify(wrapper); + atk_object_notify_state_change(wrapper, ATK_STATE_FOCUSED, true); + break; + case nsIAccessibleEvent::EVENT_DOCUMENT_LOAD_COMPLETE: + g_signal_emit_by_name(wrapper, "load_complete"); + break; + case nsIAccessibleEvent::EVENT_DOCUMENT_RELOAD: + g_signal_emit_by_name(wrapper, "reload"); + break; + case nsIAccessibleEvent::EVENT_DOCUMENT_LOAD_STOPPED: + g_signal_emit_by_name(wrapper, "load_stopped"); + break; + case nsIAccessibleEvent::EVENT_MENUPOPUP_START: + atk_focus_tracker_notify(wrapper); // fire extra focus event + atk_object_notify_state_change(wrapper, ATK_STATE_VISIBLE, true); + atk_object_notify_state_change(wrapper, ATK_STATE_SHOWING, true); + break; + case nsIAccessibleEvent::EVENT_MENUPOPUP_END: + atk_object_notify_state_change(wrapper, ATK_STATE_VISIBLE, false); + atk_object_notify_state_change(wrapper, ATK_STATE_SHOWING, false); + break; + case nsIAccessibleEvent::EVENT_ALERT: + // A hack using state change showing events as alert events. + atk_object_notify_state_change(wrapper, ATK_STATE_SHOWING, true); + break; + case nsIAccessibleEvent::EVENT_VALUE_CHANGE: + g_object_notify((GObject*)wrapper, "accessible-value"); + break; + case nsIAccessibleEvent::EVENT_TEXT_SELECTION_CHANGED: + case nsIAccessibleEvent::EVENT_SELECTION_WITHIN: + g_signal_emit_by_name(wrapper, "selection_changed"); + break; + } +} + +void +a11y::ProxyStateChangeEvent(ProxyAccessible* aTarget, uint64_t aState, + bool aEnabled) +{ + MaiAtkObject* atkObj = MAI_ATK_OBJECT(GetWrapperFor(aTarget)); + atkObj->FireStateChangeEvent(aState, aEnabled); +} + +void +a11y::ProxyCaretMoveEvent(ProxyAccessible* aTarget, int32_t aOffset) +{ + AtkObject* wrapper = GetWrapperFor(aTarget); + g_signal_emit_by_name(wrapper, "text_caret_moved", aOffset); +} + +void +MaiAtkObject::FireStateChangeEvent(uint64_t aState, bool aEnabled) +{ + int32_t stateIndex = AtkStateMap::GetStateIndexFor(aState); + if (stateIndex >= 0) { + NS_ASSERTION(gAtkStateMap[stateIndex].stateMapEntryType != kNoSuchState, + "No such state"); + + if (gAtkStateMap[stateIndex].atkState != kNone) { + NS_ASSERTION(gAtkStateMap[stateIndex].stateMapEntryType != kNoStateChange, + "State changes should not fired for this state"); + + if (gAtkStateMap[stateIndex].stateMapEntryType == kMapOpposite) + aEnabled = !aEnabled; + + // Fire state change for first state if there is one to map + atk_object_notify_state_change(&parent, + gAtkStateMap[stateIndex].atkState, + aEnabled); + } + } +} + +void +a11y::ProxyTextChangeEvent(ProxyAccessible* aTarget, const nsString& aStr, + int32_t aStart, uint32_t aLen, bool aIsInsert, + bool aFromUser) +{ + MaiAtkObject* atkObj = MAI_ATK_OBJECT(GetWrapperFor(aTarget)); + atkObj->FireTextChangeEvent(aStr, aStart, aLen, aIsInsert, aFromUser); +} + +#define OLD_TEXT_INSERTED "text_changed::insert" +#define OLD_TEXT_REMOVED "text_changed::delete" +static const char* oldTextChangeStrings[2][2] = { + { OLD_TEXT_REMOVED NON_USER_EVENT, OLD_TEXT_INSERTED NON_USER_EVENT }, + { OLD_TEXT_REMOVED, OLD_TEXT_INSERTED } +}; + +#define TEXT_INSERTED "text-insert" +#define TEXT_REMOVED "text-remove" +#define NON_USER_DETAIL "::system" +static const char* textChangedStrings[2][2] = { + { TEXT_REMOVED NON_USER_DETAIL, TEXT_INSERTED NON_USER_DETAIL }, + { TEXT_REMOVED, TEXT_INSERTED} +}; + +void +MaiAtkObject::FireTextChangeEvent(const nsString& aStr, int32_t aStart, + uint32_t aLen, bool aIsInsert, + bool aFromUser) +{ + if (gAvailableAtkSignals == eUnknown) + gAvailableAtkSignals = + g_signal_lookup("text-insert", G_OBJECT_TYPE(this)) ? + eHaveNewAtkTextSignals : eNoNewAtkSignals; + + if (gAvailableAtkSignals == eNoNewAtkSignals) { + // XXX remove this code and the gHaveNewTextSignals check when we can + // stop supporting old atk since it doesn't really work anyway + // see bug 619002 + const char* signal_name = + oldTextChangeStrings[aFromUser][aIsInsert]; + g_signal_emit_by_name(this, signal_name, aStart, aLen); + } else { + const char* signal_name = + textChangedStrings[aFromUser][aIsInsert]; + g_signal_emit_by_name(this, signal_name, aStart, aLen, + NS_ConvertUTF16toUTF8(aStr).get()); + } +} + +void +a11y::ProxyShowHideEvent(ProxyAccessible* aTarget, ProxyAccessible* aParent, + bool aInsert, bool aFromUser) +{ + MaiAtkObject* obj = MAI_ATK_OBJECT(GetWrapperFor(aTarget)); + obj->FireAtkShowHideEvent(GetWrapperFor(aParent), aInsert, aFromUser); +} + +#define ADD_EVENT "children_changed::add" +#define HIDE_EVENT "children_changed::remove" + +static const char *kMutationStrings[2][2] = { + { HIDE_EVENT NON_USER_EVENT, ADD_EVENT NON_USER_EVENT }, + { HIDE_EVENT, ADD_EVENT }, +}; + +void +MaiAtkObject::FireAtkShowHideEvent(AtkObject* aParent, bool aIsAdded, + bool aFromUser) +{ + int32_t indexInParent = getIndexInParentCB(&this->parent); + const char *signal_name = kMutationStrings[aFromUser][aIsAdded]; + g_signal_emit_by_name(aParent, signal_name, indexInParent, this, nullptr); +} + +void +a11y::ProxySelectionEvent(ProxyAccessible*, ProxyAccessible* aWidget, uint32_t) +{ + MaiAtkObject* obj = MAI_ATK_OBJECT(GetWrapperFor(aWidget)); + g_signal_emit_by_name(obj, "selection_changed"); +} + +// static +void +AccessibleWrap::GetKeyBinding(Accessible* aAccessible, nsAString& aResult) +{ + // Return all key bindings including access key and keyboard shortcut. + + // Get access key. + nsAutoString keyBindingsStr; + KeyBinding keyBinding = aAccessible->AccessKey(); + if (!keyBinding.IsEmpty()) { + keyBinding.AppendToString(keyBindingsStr, KeyBinding::eAtkFormat); + + Accessible* parent = aAccessible->Parent(); + roles::Role role = parent ? parent->Role() : roles::NOTHING; + if (role == roles::PARENT_MENUITEM || role == roles::MENUITEM || + role == roles::RADIO_MENU_ITEM || role == roles::CHECK_MENU_ITEM) { + // It is submenu, expose keyboard shortcuts from menu hierarchy like + // "s;f:s" + nsAutoString keysInHierarchyStr = keyBindingsStr; + do { + KeyBinding parentKeyBinding = parent->AccessKey(); + if (!parentKeyBinding.IsEmpty()) { + nsAutoString str; + parentKeyBinding.ToString(str, KeyBinding::eAtkFormat); + str.Append(':'); + + keysInHierarchyStr.Insert(str, 0); + } + } while ((parent = parent->Parent()) && parent->Role() != roles::MENUBAR); + + keyBindingsStr.Append(';'); + keyBindingsStr.Append(keysInHierarchyStr); + } + } else { + // No access key, add ';' to point this. + keyBindingsStr.Append(';'); + } + + // Get keyboard shortcut. + keyBindingsStr.Append(';'); + keyBinding = aAccessible->KeyboardShortcut(); + if (!keyBinding.IsEmpty()) { + keyBinding.AppendToString(keyBindingsStr, KeyBinding::eAtkFormat); + } + aResult = keyBindingsStr; +} + +// static +Accessible* +AccessibleWrap::GetColumnHeader(TableAccessible* aAccessible, int32_t aColIdx) +{ + if (!aAccessible) { + return nullptr; + } + + Accessible* cell = aAccessible->CellAt(0, aColIdx); + if (!cell) { + return nullptr; + } + + // If the cell at the first row is column header then assume it is column + // header for all rows, + if (cell->Role() == roles::COLUMNHEADER) { + return cell; + } + + // otherwise get column header for the data cell at the first row. + TableCellAccessible* tableCell = cell->AsTableCell(); + if (!tableCell) { + return nullptr; + } + + AutoTArray headerCells; + tableCell->ColHeaderCells(&headerCells); + if (headerCells.IsEmpty()) { + return nullptr; + } + + return headerCells[0]; +} + +// static +Accessible* +AccessibleWrap::GetRowHeader(TableAccessible* aAccessible, int32_t aRowIdx) +{ + if (!aAccessible) { + return nullptr; + } + + Accessible* cell = aAccessible->CellAt(aRowIdx, 0); + if (!cell) { + return nullptr; + } + + // If the cell at the first column is row header then assume it is row + // header for all columns, + if (cell->Role() == roles::ROWHEADER) { + return cell; + } + + // otherwise get row header for the data cell at the first column. + TableCellAccessible* tableCell = cell->AsTableCell(); + if (!tableCell) { + return nullptr; + } + + AutoTArray headerCells; + tableCell->RowHeaderCells(&headerCells); + if (headerCells.IsEmpty()) { + return nullptr; + } + + return headerCells[0]; +} diff --git a/accessible/atk/AccessibleWrap.h b/accessible/atk/AccessibleWrap.h new file mode 100644 index 0000000000..f73d2f0f48 --- /dev/null +++ b/accessible/atk/AccessibleWrap.h @@ -0,0 +1,92 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef __NS_ACCESSIBLE_WRAP_H__ +#define __NS_ACCESSIBLE_WRAP_H__ + +#include "nsCOMPtr.h" +#include "Accessible.h" + +struct _AtkObject; +typedef struct _AtkObject AtkObject; + +enum AtkProperty { + PROP_0, // gobject convention + PROP_NAME, + PROP_DESCRIPTION, + PROP_PARENT, // ancestry has changed + PROP_ROLE, + PROP_LAYER, + PROP_MDI_ZORDER, + PROP_TABLE_CAPTION, + PROP_TABLE_COLUMN_DESCRIPTION, + PROP_TABLE_COLUMN_HEADER, + PROP_TABLE_ROW_DESCRIPTION, + PROP_TABLE_ROW_HEADER, + PROP_TABLE_SUMMARY, + PROP_LAST // gobject convention +}; + +struct AtkPropertyChange { + int32_t type; // property type as listed above + void *oldvalue; + void *newvalue; +}; + +namespace mozilla { +namespace a11y { + +class MaiHyperlink; + +/** + * AccessibleWrap, and its descendents in atk directory provide the + * implementation of AtkObject. + */ +class AccessibleWrap : public Accessible +{ +public: + AccessibleWrap(nsIContent* aContent, DocAccessible* aDoc); + virtual ~AccessibleWrap(); + void ShutdownAtkObject(); + + virtual void Shutdown() override; + + // return the atk object for this AccessibleWrap + virtual void GetNativeInterface(void** aOutAccessible) override; + virtual nsresult HandleAccEvent(AccEvent* aEvent) override; + + AtkObject * GetAtkObject(void); + static AtkObject* GetAtkObject(Accessible* aAccessible); + + bool IsValidObject(); + + static const char * ReturnString(nsAString &aString) { + static nsCString returnedString; + returnedString = NS_ConvertUTF16toUTF8(aString); + return returnedString.get(); + } + + static void GetKeyBinding(Accessible* aAccessible, nsAString& aResult); + + static Accessible* GetColumnHeader(TableAccessible* aAccessible, + int32_t aColIdx); + static Accessible* GetRowHeader(TableAccessible* aAccessible, + int32_t aRowIdx); +protected: + + nsresult FireAtkStateChangeEvent(AccEvent* aEvent, AtkObject *aObject); + nsresult FireAtkTextChangedEvent(AccEvent* aEvent, AtkObject *aObject); + + AtkObject *mAtkObject; + +private: + uint16_t CreateMaiInterfaces(); +}; + +} // namespace a11y +} // namespace mozilla + +#endif /* __NS_ACCESSIBLE_WRAP_H__ */ diff --git a/accessible/atk/ApplicationAccessibleWrap.cpp b/accessible/atk/ApplicationAccessibleWrap.cpp new file mode 100644 index 0000000000..011881023c --- /dev/null +++ b/accessible/atk/ApplicationAccessibleWrap.cpp @@ -0,0 +1,167 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "ApplicationAccessibleWrap.h" + +#include "nsCOMPtr.h" +#include "nsMai.h" +#include "nsAccessibilityService.h" + +#include +#include + +using namespace mozilla; +using namespace mozilla::a11y; + + +// ApplicationAccessibleWrap + +ApplicationAccessibleWrap::ApplicationAccessibleWrap(): + ApplicationAccessible() +{ +} + +ApplicationAccessibleWrap::~ApplicationAccessibleWrap() +{ + AccessibleWrap::ShutdownAtkObject(); +} + +gboolean +toplevel_event_watcher(GSignalInvocationHint* ihint, + guint n_param_values, + const GValue* param_values, + gpointer data) +{ + static GQuark sQuark_gecko_acc_obj = 0; + + if (!sQuark_gecko_acc_obj) + sQuark_gecko_acc_obj = g_quark_from_static_string("GeckoAccObj"); + + if (nsAccessibilityService::IsShutdown()) + return TRUE; + + GObject* object = reinterpret_cast(g_value_get_object(param_values)); + if (!GTK_IS_WINDOW(object)) + return TRUE; + + AtkObject* child = gtk_widget_get_accessible(GTK_WIDGET(object)); + + // GTK native dialog + if (!IS_MAI_OBJECT(child) && + (atk_object_get_role(child) == ATK_ROLE_DIALOG)) { + + if (data == reinterpret_cast(nsIAccessibleEvent::EVENT_SHOW)) { + + // Attach the dialog accessible to app accessible tree + Accessible* windowAcc = GetAccService()->AddNativeRootAccessible(child); + g_object_set_qdata(G_OBJECT(child), sQuark_gecko_acc_obj, + reinterpret_cast(windowAcc)); + + } else { + + // Deattach the dialog accessible + Accessible* windowAcc = + reinterpret_cast + (g_object_get_qdata(G_OBJECT(child), sQuark_gecko_acc_obj)); + if (windowAcc) { + GetAccService()->RemoveNativeRootAccessible(windowAcc); + g_object_set_qdata(G_OBJECT(child), sQuark_gecko_acc_obj, nullptr); + } + + } + } + + return TRUE; +} + +ENameValueFlag +ApplicationAccessibleWrap::Name(nsString& aName) +{ + // ATK doesn't provide a way to obtain an application name (for example, + // Firefox or Thunderbird) like IA2 does. Thus let's return an application + // name as accessible name that was used to get a branding name (for example, + // Minefield aka nightly Firefox or Daily aka nightly Thunderbird). + AppName(aName); + return eNameOK; +} + +void +ApplicationAccessibleWrap::GetNativeInterface(void** aOutAccessible) +{ + *aOutAccessible = nullptr; + + if (!mAtkObject) { + mAtkObject = + reinterpret_cast(g_object_new(MAI_TYPE_ATK_OBJECT, nullptr)); + if (!mAtkObject) + return; + + atk_object_initialize(mAtkObject, this); + mAtkObject->role = ATK_ROLE_INVALID; + mAtkObject->layer = ATK_LAYER_INVALID; + } + + *aOutAccessible = mAtkObject; +} + +struct AtkRootAccessibleAddedEvent { + AtkObject *app_accessible; + AtkObject *root_accessible; + uint32_t index; +}; + +gboolean fireRootAccessibleAddedCB(gpointer data) +{ + AtkRootAccessibleAddedEvent* eventData = (AtkRootAccessibleAddedEvent*)data; + g_signal_emit_by_name(eventData->app_accessible, "children_changed::add", + eventData->index, eventData->root_accessible, nullptr); + g_object_unref(eventData->app_accessible); + g_object_unref(eventData->root_accessible); + free(data); + + return FALSE; +} + +bool +ApplicationAccessibleWrap::InsertChildAt(uint32_t aIdx, Accessible* aChild) +{ + if (!ApplicationAccessible::InsertChildAt(aIdx, aChild)) + return false; + + AtkObject* atkAccessible = AccessibleWrap::GetAtkObject(aChild); + atk_object_set_parent(atkAccessible, mAtkObject); + + uint32_t count = mChildren.Length(); + + // Emit children_changed::add in a timeout + // to make sure aRootAccWrap is fully initialized. + AtkRootAccessibleAddedEvent* eventData = (AtkRootAccessibleAddedEvent*) + malloc(sizeof(AtkRootAccessibleAddedEvent)); + if (eventData) { + eventData->app_accessible = mAtkObject; + eventData->root_accessible = atkAccessible; + eventData->index = count -1; + g_object_ref(mAtkObject); + g_object_ref(atkAccessible); + g_timeout_add(0, fireRootAccessibleAddedCB, eventData); + } + + return true; +} + +bool +ApplicationAccessibleWrap::RemoveChild(Accessible* aChild) +{ + int32_t index = aChild->IndexInParent(); + + AtkObject* atkAccessible = AccessibleWrap::GetAtkObject(aChild); + atk_object_set_parent(atkAccessible, nullptr); + g_signal_emit_by_name(mAtkObject, "children_changed::remove", index, + atkAccessible, nullptr); + + return ApplicationAccessible::RemoveChild(aChild); +} + diff --git a/accessible/atk/ApplicationAccessibleWrap.h b/accessible/atk/ApplicationAccessibleWrap.h new file mode 100644 index 0000000000..468616b6cc --- /dev/null +++ b/accessible/atk/ApplicationAccessibleWrap.h @@ -0,0 +1,35 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef mozilla_a11y_ApplicationAccessibleWrap_h__ +#define mozilla_a11y_ApplicationAccessibleWrap_h__ + +#include "ApplicationAccessible.h" + +namespace mozilla { +namespace a11y { + +class ApplicationAccessibleWrap: public ApplicationAccessible +{ +public: + ApplicationAccessibleWrap(); + virtual ~ApplicationAccessibleWrap(); + + // Accessible + virtual mozilla::a11y::ENameValueFlag Name(nsString& aName) override; + virtual bool InsertChildAt(uint32_t aIdx, Accessible* aChild) override; + virtual bool RemoveChild(Accessible* aChild) override; + + /** + * Return the atk object for app root accessible. + */ + virtual void GetNativeInterface(void** aOutAccessible) override; +}; + +} // namespace a11y +} // namespace mozilla + +#endif /* __NS_APP_ROOT_ACCESSIBLE_H__ */ diff --git a/accessible/atk/AtkSocketAccessible.cpp b/accessible/atk/AtkSocketAccessible.cpp new file mode 100644 index 0000000000..95c3075e80 --- /dev/null +++ b/accessible/atk/AtkSocketAccessible.cpp @@ -0,0 +1,126 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include +#include "AtkSocketAccessible.h" + +#include "InterfaceInitFuncs.h" +#include "nsMai.h" +#include "mozilla/Likely.h" + +using namespace mozilla::a11y; + +AtkSocketEmbedType AtkSocketAccessible::g_atk_socket_embed = nullptr; +GType AtkSocketAccessible::g_atk_socket_type = G_TYPE_INVALID; +const char* AtkSocketAccessible::sATKSocketEmbedSymbol = "atk_socket_embed"; +const char* AtkSocketAccessible::sATKSocketGetTypeSymbol = "atk_socket_get_type"; + +bool AtkSocketAccessible::gCanEmbed = FALSE; + +extern "C" void mai_atk_component_iface_init(AtkComponentIface* aIface); + +G_DEFINE_TYPE_EXTENDED(MaiAtkSocket, mai_atk_socket, + AtkSocketAccessible::g_atk_socket_type, 0, + G_IMPLEMENT_INTERFACE(ATK_TYPE_COMPONENT, + mai_atk_component_iface_init)) + +void +mai_atk_socket_class_init(MaiAtkSocketClass* aAcc) +{ +} + +void +mai_atk_socket_init(MaiAtkSocket* aAcc) +{ +} + +static AtkObject* +mai_atk_socket_new(AccessibleWrap* aAccWrap) +{ + NS_ENSURE_TRUE(aAccWrap, nullptr); + + MaiAtkSocket* acc = nullptr; + acc = static_cast(g_object_new(MAI_TYPE_ATK_SOCKET, nullptr)); + NS_ENSURE_TRUE(acc, nullptr); + + acc->accWrap = aAccWrap; + return ATK_OBJECT(acc); +} + +extern "C" { +static AtkObject* +RefAccessibleAtPoint(AtkComponent* aComponent, gint aX, gint aY, + AtkCoordType aCoordType) +{ + NS_ENSURE_TRUE(MAI_IS_ATK_SOCKET(aComponent), nullptr); + + return refAccessibleAtPointHelper(ATK_OBJECT(MAI_ATK_SOCKET(aComponent)), + aX, aY, aCoordType); +} + +static void +GetExtents(AtkComponent* aComponent, gint* aX, gint* aY, gint* aWidth, + gint* aHeight, AtkCoordType aCoordType) +{ + *aX = *aY = *aWidth = *aHeight = 0; + + if (!MAI_IS_ATK_SOCKET(aComponent)) + return; + + getExtentsHelper(ATK_OBJECT(MAI_ATK_SOCKET(aComponent)), + aX, aY, aWidth, aHeight, aCoordType); +} +} + +void +mai_atk_component_iface_init(AtkComponentIface* aIface) +{ + NS_ASSERTION(aIface, "Invalid Interface"); + if (MOZ_UNLIKELY(!aIface)) + return; + + aIface->ref_accessible_at_point = RefAccessibleAtPoint; + aIface->get_extents = GetExtents; +} + +AtkSocketAccessible::AtkSocketAccessible(nsIContent* aContent, + DocAccessible* aDoc, + const nsCString& aPlugId) : + AccessibleWrap(aContent, aDoc) +{ + mAtkObject = mai_atk_socket_new(this); + if (!mAtkObject) + return; + + // Embeds the children of an AtkPlug, specified by plugId, as the children of + // this socket. + // Using G_TYPE macros instead of ATK_SOCKET macros to avoid undefined + // symbols. + if (gCanEmbed && G_TYPE_CHECK_INSTANCE_TYPE(mAtkObject, g_atk_socket_type) && + !aPlugId.IsVoid()) { + AtkSocket* accSocket = + G_TYPE_CHECK_INSTANCE_CAST(mAtkObject, g_atk_socket_type, AtkSocket); + g_atk_socket_embed(accSocket, (gchar*)aPlugId.get()); + } +} + +void +AtkSocketAccessible::GetNativeInterface(void** aOutAccessible) +{ + *aOutAccessible = mAtkObject; +} + +void +AtkSocketAccessible::Shutdown() +{ + if (mAtkObject) { + if (MAI_IS_ATK_SOCKET(mAtkObject)) + MAI_ATK_SOCKET(mAtkObject)->accWrap = nullptr; + g_object_unref(mAtkObject); + mAtkObject = nullptr; + } + AccessibleWrap::Shutdown(); +} diff --git a/accessible/atk/AtkSocketAccessible.h b/accessible/atk/AtkSocketAccessible.h new file mode 100644 index 0000000000..3b63a8e730 --- /dev/null +++ b/accessible/atk/AtkSocketAccessible.h @@ -0,0 +1,56 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef _AtkSocketAccessible_H_ +#define _AtkSocketAccessible_H_ + +#include "AccessibleWrap.h" + +// This file gets included by nsAccessibilityService.cpp, which can't include +// atk.h (or glib.h), so we can't rely on it being included. +#ifdef __ATK_H__ +extern "C" typedef void (*AtkSocketEmbedType) (AtkSocket*, gchar*); +#else +extern "C" typedef void (*AtkSocketEmbedType) (void*, void*); +#endif + +namespace mozilla { +namespace a11y { + +/** + * Provides a AccessibleWrap wrapper around AtkSocket for out-of-process + * accessibles. + */ +class AtkSocketAccessible : public AccessibleWrap +{ +public: + + // Soft references to AtkSocket + static AtkSocketEmbedType g_atk_socket_embed; +#ifdef __ATK_H__ + static GType g_atk_socket_type; +#endif + static const char* sATKSocketEmbedSymbol; + static const char* sATKSocketGetTypeSymbol; + + /* + * True if the current Atk version supports AtkSocket and it was correctly + * loaded. + */ + static bool gCanEmbed; + + AtkSocketAccessible(nsIContent* aContent, DocAccessible* aDoc, + const nsCString& aPlugId); + + virtual void Shutdown() override; + + virtual void GetNativeInterface(void** aOutAccessible) override; +}; + +} // namespace a11y +} // namespace mozilla + +#endif diff --git a/accessible/atk/DocAccessibleWrap.cpp b/accessible/atk/DocAccessibleWrap.cpp new file mode 100644 index 0000000000..d78d724b43 --- /dev/null +++ b/accessible/atk/DocAccessibleWrap.cpp @@ -0,0 +1,25 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "nsMai.h" +#include "DocAccessibleWrap.h" + +using namespace mozilla::a11y; + +//////////////////////////////////////////////////////////////////////////////// +// DocAccessibleWrap +//////////////////////////////////////////////////////////////////////////////// + +DocAccessibleWrap:: + DocAccessibleWrap(nsIDocument* aDocument, nsIPresShell* aPresShell) : + DocAccessible(aDocument, aPresShell), mActivated(false) +{ +} + +DocAccessibleWrap::~DocAccessibleWrap() +{ +} + diff --git a/accessible/atk/DocAccessibleWrap.h b/accessible/atk/DocAccessibleWrap.h new file mode 100644 index 0000000000..e5fc8e5e47 --- /dev/null +++ b/accessible/atk/DocAccessibleWrap.h @@ -0,0 +1,31 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +/* For documentation of the accessibility architecture, + * see http://lxr.mozilla.org/seamonkey/source/accessible/accessible-docs.html + */ + +#ifndef mozilla_a11y_DocAccessibleWrap_h__ +#define mozilla_a11y_DocAccessibleWrap_h__ + +#include "DocAccessible.h" + +namespace mozilla { +namespace a11y { + +class DocAccessibleWrap : public DocAccessible +{ +public: + DocAccessibleWrap(nsIDocument* aDocument, nsIPresShell* aPresShell); + virtual ~DocAccessibleWrap(); + + bool mActivated; +}; + +} // namespace a11y +} // namespace mozilla + +#endif diff --git a/accessible/atk/HTMLTableAccessibleWrap.h b/accessible/atk/HTMLTableAccessibleWrap.h new file mode 100644 index 0000000000..88d40cc2e6 --- /dev/null +++ b/accessible/atk/HTMLTableAccessibleWrap.h @@ -0,0 +1,23 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef mozilla_a11y_HTMLTableAccessibleWrap_h__ +#define mozilla_a11y_HTMLTableAccessibleWrap_h__ + +#include "HTMLTableAccessible.h" + +namespace mozilla { +namespace a11y { + +typedef class HTMLTableAccessible HTMLTableAccessibleWrap; +typedef class HTMLTableCellAccessible HTMLTableCellAccessibleWrap; +typedef class HTMLTableHeaderCellAccessible HTMLTableHeaderCellAccessibleWrap; + +} // namespace a11y +} // namespace mozilla + +#endif + diff --git a/accessible/atk/HyperTextAccessibleWrap.h b/accessible/atk/HyperTextAccessibleWrap.h new file mode 100644 index 0000000000..a43fe65cf8 --- /dev/null +++ b/accessible/atk/HyperTextAccessibleWrap.h @@ -0,0 +1,21 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef mozilla_a11y_HyperTextAccessibleWrap_h__ +#define mozilla_a11y_HyperTextAccessibleWrap_h__ + +#include "HyperTextAccessible.h" + +namespace mozilla { +namespace a11y { + +typedef class HyperTextAccessible HyperTextAccessibleWrap; + +} // namespace a11y +} // namespace mozilla + +#endif + diff --git a/accessible/atk/ImageAccessibleWrap.h b/accessible/atk/ImageAccessibleWrap.h new file mode 100644 index 0000000000..7f1620a599 --- /dev/null +++ b/accessible/atk/ImageAccessibleWrap.h @@ -0,0 +1,21 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef mozilla_a11y_ImageAccessibleWrap_h__ +#define mozilla_a11y_ImageAccessibleWrap_h__ + +#include "ImageAccessible.h" + +namespace mozilla { +namespace a11y { + +typedef class ImageAccessible ImageAccessibleWrap; + +} // namespace a11y +} // namespace mozilla + +#endif + diff --git a/accessible/atk/InterfaceInitFuncs.h b/accessible/atk/InterfaceInitFuncs.h new file mode 100644 index 0000000000..c604a99fc2 --- /dev/null +++ b/accessible/atk/InterfaceInitFuncs.h @@ -0,0 +1,44 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef ATK_INTERFACE_INIT_FUNCS_H_ +#define ATK_INTERFACE_INIT_FUNCS_H_ + +#include + +namespace mozilla { +namespace a11y { + +class AccessibleWrap; + +} // namespace a11y +} // namespace mozilla + +extern "C" { +void actionInterfaceInitCB(AtkActionIface* aIface); +void componentInterfaceInitCB(AtkComponentIface* aIface); +void documentInterfaceInitCB(AtkDocumentIface *aIface); +void editableTextInterfaceInitCB(AtkEditableTextIface* aIface); +void hyperlinkImplInterfaceInitCB(AtkHyperlinkImplIface *aIface); +void hypertextInterfaceInitCB(AtkHypertextIface* aIface); +void imageInterfaceInitCB(AtkImageIface* aIface); +void selectionInterfaceInitCB(AtkSelectionIface* aIface); +void tableInterfaceInitCB(AtkTableIface *aIface); +void tableCellInterfaceInitCB(AtkTableCellIface *aIface); +void textInterfaceInitCB(AtkTextIface* aIface); +void valueInterfaceInitCB(AtkValueIface *aIface); +} + +/** + * XXX these should live in a file of utils for atk. + */ +AtkObject* refAccessibleAtPointHelper(AtkObject* aAtkObj, + gint aX, gint aY, AtkCoordType aCoordType); +void getExtentsHelper(AtkObject* aAtkObj, + gint* aX, gint* aY, gint* aWidth, gint* aHeight, + AtkCoordType aCoordType); + +#endif // ATK_INTERFACE_INIT_FUNCS_H_ diff --git a/accessible/atk/Platform.cpp b/accessible/atk/Platform.cpp new file mode 100644 index 0000000000..e64084f5a0 --- /dev/null +++ b/accessible/atk/Platform.cpp @@ -0,0 +1,377 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "Platform.h" + +#include "nsIAccessibleEvent.h" +#include "nsIGConfService.h" +#include "nsIServiceManager.h" +#include "nsMai.h" +#include "AtkSocketAccessible.h" +#include "prenv.h" +#include "prlink.h" + +#ifdef MOZ_ENABLE_DBUS +#include +#endif +#include + +#if (MOZ_WIDGET_GTK == 3) +extern "C" __attribute__((weak,visibility("default"))) int atk_bridge_adaptor_init(int*, char **[]); +#endif + +using namespace mozilla; +using namespace mozilla::a11y; + +int atkMajorVersion = 1, atkMinorVersion = 12; + +GType (*gAtkTableCellGetTypeFunc)(); + +extern "C" { +typedef GType (* AtkGetTypeType) (void); +typedef void (*GnomeAccessibilityInit) (void); +typedef void (*GnomeAccessibilityShutdown) (void); +} + +static PRLibrary* sATKLib = nullptr; +static const char sATKLibName[] = "libatk-1.0.so.0"; +static const char sATKHyperlinkImplGetTypeSymbol[] = + "atk_hyperlink_impl_get_type"; + +gboolean toplevel_event_watcher(GSignalInvocationHint*, guint, const GValue*, + gpointer); +static bool sToplevel_event_hook_added = false; +static gulong sToplevel_show_hook = 0; +static gulong sToplevel_hide_hook = 0; + +GType g_atk_hyperlink_impl_type = G_TYPE_INVALID; + +struct GnomeAccessibilityModule +{ + const char *libName; + PRLibrary *lib; + const char *initName; + GnomeAccessibilityInit init; + const char *shutdownName; + GnomeAccessibilityShutdown shutdown; +}; + +static GnomeAccessibilityModule sAtkBridge = { +#ifdef AIX + "libatk-bridge.a(libatk-bridge.so.0)", nullptr, +#else + "libatk-bridge.so", nullptr, +#endif + "gnome_accessibility_module_init", nullptr, + "gnome_accessibility_module_shutdown", nullptr +}; + +#if (MOZ_WIDGET_GTK == 2) +static GnomeAccessibilityModule sGail = { + "libgail.so", nullptr, + "gnome_accessibility_module_init", nullptr, + "gnome_accessibility_module_shutdown", nullptr +}; +#endif + +static nsresult +LoadGtkModule(GnomeAccessibilityModule& aModule) +{ + NS_ENSURE_ARG(aModule.libName); + + if (!(aModule.lib = PR_LoadLibrary(aModule.libName))) { + //try to load the module with "gtk-2.0/modules" appended + char *curLibPath = PR_GetLibraryPath(); + nsAutoCString libPath(curLibPath); +#if defined(LINUX) && defined(__x86_64__) + libPath.AppendLiteral(":/usr/lib64:/usr/lib"); +#else + libPath.AppendLiteral(":/usr/lib"); +#endif + PR_FreeLibraryName(curLibPath); + + int16_t loc1 = 0, loc2 = 0; + int16_t subLen = 0; + while (loc2 >= 0) { + loc2 = libPath.FindChar(':', loc1); + if (loc2 < 0) + subLen = libPath.Length() - loc1; + else + subLen = loc2 - loc1; + nsAutoCString sub(Substring(libPath, loc1, subLen)); +#if (MOZ_WIDGET_GTK == 2) + sub.AppendLiteral("/gtk-2.0/modules/"); +#else + sub.AppendLiteral("/gtk-3.0/modules/"); +#endif + sub.Append(aModule.libName); + aModule.lib = PR_LoadLibrary(sub.get()); + if (aModule.lib) + break; + + loc1 = loc2+1; + } + if (!aModule.lib) + return NS_ERROR_FAILURE; + } + + //we have loaded the library, try to get the function ptrs + if (!(aModule.init = PR_FindFunctionSymbol(aModule.lib, + aModule.initName)) || + !(aModule.shutdown = PR_FindFunctionSymbol(aModule.lib, + aModule.shutdownName))) { + + //fail, :( + PR_UnloadLibrary(aModule.lib); + aModule.lib = nullptr; + return NS_ERROR_FAILURE; + } + return NS_OK; +} + +void +a11y::PlatformInit() +{ + if (!ShouldA11yBeEnabled()) + return; + + sATKLib = PR_LoadLibrary(sATKLibName); + if (!sATKLib) + return; + + AtkGetTypeType pfn_atk_hyperlink_impl_get_type = + (AtkGetTypeType) PR_FindFunctionSymbol(sATKLib, sATKHyperlinkImplGetTypeSymbol); + if (pfn_atk_hyperlink_impl_get_type) + g_atk_hyperlink_impl_type = pfn_atk_hyperlink_impl_get_type(); + + AtkGetTypeType pfn_atk_socket_get_type = (AtkGetTypeType) + PR_FindFunctionSymbol(sATKLib, AtkSocketAccessible::sATKSocketGetTypeSymbol); + if (pfn_atk_socket_get_type) { + AtkSocketAccessible::g_atk_socket_type = pfn_atk_socket_get_type(); + AtkSocketAccessible::g_atk_socket_embed = (AtkSocketEmbedType) + PR_FindFunctionSymbol(sATKLib, AtkSocketAccessible ::sATKSocketEmbedSymbol); + AtkSocketAccessible::gCanEmbed = + AtkSocketAccessible::g_atk_socket_type != G_TYPE_INVALID && + AtkSocketAccessible::g_atk_socket_embed; + } + + gAtkTableCellGetTypeFunc = (GType (*)()) + PR_FindFunctionSymbol(sATKLib, "atk_table_cell_get_type"); + + const char* (*atkGetVersion)() = + (const char* (*)()) PR_FindFunctionSymbol(sATKLib, "atk_get_version"); + if (atkGetVersion) { + const char* version = atkGetVersion(); + if (version) { + char* endPtr = nullptr; + atkMajorVersion = strtol(version, &endPtr, 10); + if (*endPtr == '.') + atkMinorVersion = strtol(endPtr + 1, &endPtr, 10); + } + } + +#if (MOZ_WIDGET_GTK == 2) + // Load and initialize gail library. + nsresult rv = LoadGtkModule(sGail); + if (NS_SUCCEEDED(rv)) + (*sGail.init)(); +#endif + + // Initialize the MAI Utility class, it will overwrite gail_util. + g_type_class_unref(g_type_class_ref(mai_util_get_type())); + + // Init atk-bridge now + PR_SetEnv("NO_AT_BRIDGE=0"); +#if (MOZ_WIDGET_GTK == 3) + if (atk_bridge_adaptor_init) { + atk_bridge_adaptor_init(nullptr, nullptr); + } else +#endif + { + nsresult rv = LoadGtkModule(sAtkBridge); + if (NS_SUCCEEDED(rv)) { + (*sAtkBridge.init)(); + } + } + + if (!sToplevel_event_hook_added) { + sToplevel_event_hook_added = true; + sToplevel_show_hook = + g_signal_add_emission_hook(g_signal_lookup("show", GTK_TYPE_WINDOW), + 0, toplevel_event_watcher, + reinterpret_cast(nsIAccessibleEvent::EVENT_SHOW), + nullptr); + sToplevel_hide_hook = + g_signal_add_emission_hook(g_signal_lookup("hide", GTK_TYPE_WINDOW), 0, + toplevel_event_watcher, + reinterpret_cast(nsIAccessibleEvent::EVENT_HIDE), + nullptr); + } +} + +void +a11y::PlatformShutdown() +{ + if (sToplevel_event_hook_added) { + sToplevel_event_hook_added = false; + g_signal_remove_emission_hook(g_signal_lookup("show", GTK_TYPE_WINDOW), + sToplevel_show_hook); + g_signal_remove_emission_hook(g_signal_lookup("hide", GTK_TYPE_WINDOW), + sToplevel_hide_hook); + } + + if (sAtkBridge.lib) { + // Do not shutdown/unload atk-bridge, + // an exit function registered will take care of it + // if (sAtkBridge.shutdown) + // (*sAtkBridge.shutdown)(); + // PR_UnloadLibrary(sAtkBridge.lib); + sAtkBridge.lib = nullptr; + sAtkBridge.init = nullptr; + sAtkBridge.shutdown = nullptr; + } +#if (MOZ_WIDGET_GTK == 2) + if (sGail.lib) { + // Do not shutdown gail because + // 1) Maybe it's not init-ed by us. e.g. GtkEmbed + // 2) We need it to avoid assert in spi_atk_tidy_windows + // if (sGail.shutdown) + // (*sGail.shutdown)(); + // PR_UnloadLibrary(sGail.lib); + sGail.lib = nullptr; + sGail.init = nullptr; + sGail.shutdown = nullptr; + } +#endif + // if (sATKLib) { + // PR_UnloadLibrary(sATKLib); + // sATKLib = nullptr; + // } +} + + static const char sAccEnv [] = "GNOME_ACCESSIBILITY"; +#ifdef MOZ_ENABLE_DBUS +static DBusPendingCall *sPendingCall = nullptr; +#endif + +void +a11y::PreInit() +{ +#ifdef MOZ_ENABLE_DBUS + static bool sChecked = FALSE; + if (sChecked) + return; + + sChecked = TRUE; + + // dbus is only checked if GNOME_ACCESSIBILITY is unset + // also make sure that a session bus address is available to prevent dbus from + // starting a new one. Dbus confuses the test harness when it creates a new + // process (see bug 693343) + if (PR_GetEnv(sAccEnv) || !PR_GetEnv("DBUS_SESSION_BUS_ADDRESS")) + return; + + DBusConnection* bus = dbus_bus_get(DBUS_BUS_SESSION, nullptr); + if (!bus) + return; + + dbus_connection_set_exit_on_disconnect(bus, FALSE); + + static const char* iface = "org.a11y.Status"; + static const char* member = "IsEnabled"; + DBusMessage *message; + message = dbus_message_new_method_call("org.a11y.Bus", "/org/a11y/bus", + "org.freedesktop.DBus.Properties", + "Get"); + if (!message) + goto dbus_done; + + dbus_message_append_args(message, DBUS_TYPE_STRING, &iface, + DBUS_TYPE_STRING, &member, DBUS_TYPE_INVALID); + dbus_connection_send_with_reply(bus, message, &sPendingCall, 1000); + dbus_message_unref(message); + +dbus_done: + dbus_connection_unref(bus); +#endif +} + +bool +a11y::ShouldA11yBeEnabled() +{ + static bool sChecked = false, sShouldEnable = false; + if (sChecked) + return sShouldEnable; + + sChecked = true; + + EPlatformDisabledState disabledState = PlatformDisabledState(); + if (disabledState == ePlatformIsDisabled) + return sShouldEnable = false; + + // check if accessibility enabled/disabled by environment variable + const char* envValue = PR_GetEnv(sAccEnv); + if (envValue) + return sShouldEnable = !!atoi(envValue); + +#ifdef MOZ_ENABLE_DBUS + PreInit(); + bool dbusSuccess = false; + DBusMessage *reply = nullptr; + if (!sPendingCall) + goto dbus_done; + + dbus_pending_call_block(sPendingCall); + reply = dbus_pending_call_steal_reply(sPendingCall); + dbus_pending_call_unref(sPendingCall); + sPendingCall = nullptr; + if (!reply || + dbus_message_get_type(reply) != DBUS_MESSAGE_TYPE_METHOD_RETURN || + strcmp(dbus_message_get_signature (reply), DBUS_TYPE_VARIANT_AS_STRING)) + goto dbus_done; + + DBusMessageIter iter, iter_variant, iter_struct; + dbus_bool_t dResult; + dbus_message_iter_init(reply, &iter); + dbus_message_iter_recurse (&iter, &iter_variant); + switch (dbus_message_iter_get_arg_type(&iter_variant)) { + case DBUS_TYPE_STRUCT: + // at-spi2-core 2.2.0-2.2.1 had a bug where it returned a struct + dbus_message_iter_recurse(&iter_variant, &iter_struct); + if (dbus_message_iter_get_arg_type(&iter_struct) == DBUS_TYPE_BOOLEAN) { + dbus_message_iter_get_basic(&iter_struct, &dResult); + sShouldEnable = dResult; + dbusSuccess = true; + } + + break; + case DBUS_TYPE_BOOLEAN: + dbus_message_iter_get_basic(&iter_variant, &dResult); + sShouldEnable = dResult; + dbusSuccess = true; + break; + default: + break; + } + +dbus_done: + if (reply) + dbus_message_unref(reply); + + if (dbusSuccess) + return sShouldEnable; +#endif + + //check gconf-2 setting +#define GCONF_A11Y_KEY "/desktop/gnome/interface/accessibility" + nsresult rv = NS_OK; + nsCOMPtr gconf = + do_GetService(NS_GCONFSERVICE_CONTRACTID, &rv); + if (NS_SUCCEEDED(rv) && gconf) + gconf->GetBool(NS_LITERAL_CSTRING(GCONF_A11Y_KEY), &sShouldEnable); + + return sShouldEnable; +} diff --git a/accessible/atk/RootAccessibleWrap.cpp b/accessible/atk/RootAccessibleWrap.cpp new file mode 100644 index 0000000000..e1142e1613 --- /dev/null +++ b/accessible/atk/RootAccessibleWrap.cpp @@ -0,0 +1,24 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "RootAccessibleWrap.h" + +#include "nsMai.h" + +using namespace mozilla::a11y; + +GtkWindowAccessible::GtkWindowAccessible(AtkObject* aAccessible) : + DummyAccessible() +{ + g_object_ref(aAccessible); + mAtkObject = aAccessible; +} + +GtkWindowAccessible::~GtkWindowAccessible() +{ + g_object_unref(mAtkObject); + mAtkObject = nullptr; +} diff --git a/accessible/atk/RootAccessibleWrap.h b/accessible/atk/RootAccessibleWrap.h new file mode 100644 index 0000000000..cf4b5c18ce --- /dev/null +++ b/accessible/atk/RootAccessibleWrap.h @@ -0,0 +1,34 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef mozilla_a11y_RootAccessibleWrap_h__ +#define mozilla_a11y_RootAccessibleWrap_h__ + +#include "BaseAccessibles.h" +#include "RootAccessible.h" + +namespace mozilla { +namespace a11y { + +typedef RootAccessible RootAccessibleWrap; + +/* GtkWindowAccessible is the accessible class for gtk+ native window. + * The instance of GtkWindowAccessible is a child of MaiAppRoot instance. + * It is added into root when the toplevel window is created, and removed + * from root when the toplevel window is destroyed. + */ +class GtkWindowAccessible final : public DummyAccessible +{ +public: + explicit GtkWindowAccessible(AtkObject* aAccessible); + virtual ~GtkWindowAccessible(); +}; + +} // namespace a11y +} // namespace mozilla + +#endif /* mozilla_a11y_Root_Accessible_Wrap_h__ */ + diff --git a/accessible/atk/TextLeafAccessibleWrap.h b/accessible/atk/TextLeafAccessibleWrap.h new file mode 100644 index 0000000000..726feff01a --- /dev/null +++ b/accessible/atk/TextLeafAccessibleWrap.h @@ -0,0 +1,20 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef mozilla_a11y_TextLeafAccessibleWrap_h__ +#define mozilla_a11y_TextLeafAccessibleWrap_h__ + +#include "TextLeafAccessible.h" + +namespace mozilla { +namespace a11y { + +typedef class TextLeafAccessible TextLeafAccessibleWrap; + +} // namespace a11y +} // namespace mozilla + +#endif diff --git a/accessible/atk/UtilInterface.cpp b/accessible/atk/UtilInterface.cpp new file mode 100644 index 0000000000..a2ab00141d --- /dev/null +++ b/accessible/atk/UtilInterface.cpp @@ -0,0 +1,411 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "ApplicationAccessibleWrap.h" +#include "mozilla/Likely.h" +#include "nsAccessibilityService.h" +#include "nsMai.h" + +#include +#include +#include + +using namespace mozilla; +using namespace mozilla::a11y; + +typedef AtkUtil MaiUtil; +typedef AtkUtilClass MaiUtilClass; + +#define MAI_VERSION MOZILLA_VERSION +#define MAI_NAME "Gecko" + +extern "C" { +static guint (*gail_add_global_event_listener)(GSignalEmissionHook listener, + const gchar* event_type); +static void (*gail_remove_global_event_listener) (guint remove_listener); +static void (*gail_remove_key_event_listener) (guint remove_listener); +static AtkObject* (*gail_get_root)(); +} + +struct MaiUtilListenerInfo +{ + gint key; + guint signal_id; + gulong hook_id; + // For window create/destory/minimize/maximize/restore/activate/deactivate + // events, we'll chain gail_util's add/remove_global_event_listener. + // So we store the listenerid returned by gail's add_global_event_listener + // in this structure to call gail's remove_global_event_listener later. + guint gail_listenerid; +}; + +static GHashTable* sListener_list = nullptr; +static gint sListener_idx = 1; + +extern "C" { +static guint +add_listener (GSignalEmissionHook listener, + const gchar *object_type, + const gchar *signal, + const gchar *hook_data, + guint gail_listenerid = 0) +{ + GType type; + guint signal_id; + gint rc = 0; + + type = g_type_from_name(object_type); + if (type) { + signal_id = g_signal_lookup(signal, type); + if (signal_id > 0) { + MaiUtilListenerInfo *listener_info; + + rc = sListener_idx; + + listener_info = (MaiUtilListenerInfo *) + g_malloc(sizeof(MaiUtilListenerInfo)); + listener_info->key = sListener_idx; + listener_info->hook_id = + g_signal_add_emission_hook(signal_id, 0, listener, + g_strdup(hook_data), + (GDestroyNotify)g_free); + listener_info->signal_id = signal_id; + listener_info->gail_listenerid = gail_listenerid; + + g_hash_table_insert(sListener_list, &(listener_info->key), + listener_info); + sListener_idx++; + } + else { + g_warning("Invalid signal type %s\n", signal); + } + } + else { + g_warning("Invalid object type %s\n", object_type); + } + return rc; +} + +static guint +mai_util_add_global_event_listener(GSignalEmissionHook listener, + const gchar *event_type) +{ + guint rc = 0; + gchar **split_string; + + split_string = g_strsplit (event_type, ":", 3); + + if (split_string) { + if (!strcmp ("window", split_string[0])) { + guint gail_listenerid = 0; + if (gail_add_global_event_listener) { + // call gail's function to track gtk native window events + gail_listenerid = + gail_add_global_event_listener(listener, event_type); + } + + rc = add_listener (listener, "MaiAtkObject", split_string[1], + event_type, gail_listenerid); + } + else { + rc = add_listener (listener, split_string[1], split_string[2], + event_type); + } + g_strfreev(split_string); + } + return rc; +} + +static void +mai_util_remove_global_event_listener(guint remove_listener) +{ + if (remove_listener > 0) { + MaiUtilListenerInfo *listener_info; + gint tmp_idx = remove_listener; + + listener_info = (MaiUtilListenerInfo *) + g_hash_table_lookup(sListener_list, &tmp_idx); + + if (listener_info != nullptr) { + if (gail_remove_global_event_listener && + listener_info->gail_listenerid) { + gail_remove_global_event_listener(listener_info->gail_listenerid); + } + + /* Hook id of 0 and signal id of 0 are invalid */ + if (listener_info->hook_id != 0 && listener_info->signal_id != 0) { + /* Remove the emission hook */ + g_signal_remove_emission_hook(listener_info->signal_id, + listener_info->hook_id); + + /* Remove the element from the hash */ + g_hash_table_remove(sListener_list, &tmp_idx); + } + else { + g_warning("Invalid listener hook_id %ld or signal_id %d\n", + listener_info->hook_id, listener_info->signal_id); + } + } + else { + // atk-bridge is initialized with gail (e.g. yelp) + // try gail_remove_global_event_listener + if (gail_remove_global_event_listener) { + return gail_remove_global_event_listener(remove_listener); + } + + g_warning("No listener with the specified listener id %d", + remove_listener); + } + } + else { + g_warning("Invalid listener_id %d", remove_listener); + } +} + +static AtkKeyEventStruct * +atk_key_event_from_gdk_event_key (GdkEventKey *key) +{ + AtkKeyEventStruct *event = g_new0(AtkKeyEventStruct, 1); + switch (key->type) { + case GDK_KEY_PRESS: + event->type = ATK_KEY_EVENT_PRESS; + break; + case GDK_KEY_RELEASE: + event->type = ATK_KEY_EVENT_RELEASE; + break; + default: + g_assert_not_reached (); + return nullptr; + } + event->state = key->state; + event->keyval = key->keyval; + event->length = key->length; + if (key->string && key->string [0] && + (key->state & GDK_CONTROL_MASK || + g_unichar_isgraph (g_utf8_get_char (key->string)))) { + event->string = key->string; + } + else if (key->type == GDK_KEY_PRESS || + key->type == GDK_KEY_RELEASE) { + event->string = gdk_keyval_name (key->keyval); + } + event->keycode = key->hardware_keycode; + event->timestamp = key->time; + + return event; +} + +struct MaiKeyEventInfo +{ + AtkKeyEventStruct *key_event; + gpointer func_data; +}; + +union AtkKeySnoopFuncPointer +{ + AtkKeySnoopFunc func_ptr; + gpointer data; +}; + +static gboolean +notify_hf(gpointer key, gpointer value, gpointer data) +{ + MaiKeyEventInfo *info = (MaiKeyEventInfo *)data; + AtkKeySnoopFuncPointer atkKeySnoop; + atkKeySnoop.data = value; + return (atkKeySnoop.func_ptr)(info->key_event, info->func_data) ? TRUE : FALSE; +} + +static void +insert_hf(gpointer key, gpointer value, gpointer data) +{ + GHashTable *new_table = (GHashTable *) data; + g_hash_table_insert (new_table, key, value); +} + +static GHashTable* sKey_listener_list = nullptr; + +static gint +mai_key_snooper(GtkWidget *the_widget, GdkEventKey *event, gpointer func_data) +{ + /* notify each AtkKeySnoopFunc in turn... */ + + MaiKeyEventInfo *info = g_new0(MaiKeyEventInfo, 1); + gint consumed = 0; + if (sKey_listener_list) { + GHashTable *new_hash = g_hash_table_new(nullptr, nullptr); + g_hash_table_foreach (sKey_listener_list, insert_hf, new_hash); + info->key_event = atk_key_event_from_gdk_event_key (event); + info->func_data = func_data; + consumed = g_hash_table_foreach_steal (new_hash, notify_hf, info); + g_hash_table_destroy (new_hash); + g_free(info->key_event); + } + g_free(info); + return (consumed ? 1 : 0); +} + +static guint sKey_snooper_id = 0; + +static guint +mai_util_add_key_event_listener(AtkKeySnoopFunc listener, gpointer data) +{ + if (MOZ_UNLIKELY(!listener)) { + return 0; + } + + static guint key = 0; + + if (!sKey_listener_list) { + sKey_listener_list = g_hash_table_new(nullptr, nullptr); + } + + // If we have no registered event listeners then we need to (re)install the + // key event snooper. + if (g_hash_table_size(sKey_listener_list) == 0) { + sKey_snooper_id = gtk_key_snooper_install(mai_key_snooper, data); + } + + AtkKeySnoopFuncPointer atkKeySnoop; + atkKeySnoop.func_ptr = listener; + key++; + g_hash_table_insert(sKey_listener_list, GUINT_TO_POINTER(key), + atkKeySnoop.data); + return key; +} + +static void +mai_util_remove_key_event_listener (guint remove_listener) +{ + if (!sKey_listener_list) { + // atk-bridge is initialized with gail (e.g. yelp) + // try gail_remove_key_event_listener + return gail_remove_key_event_listener(remove_listener); + } + + g_hash_table_remove(sKey_listener_list, GUINT_TO_POINTER (remove_listener)); + if (g_hash_table_size(sKey_listener_list) == 0) { + gtk_key_snooper_remove(sKey_snooper_id); + } +} + +static AtkObject* +mai_util_get_root() +{ + ApplicationAccessible* app = ApplicationAcc(); + if (app) + return app->GetAtkObject(); + + // We've shutdown, try to use gail instead + // (to avoid assert in spi_atk_tidy_windows()) + // XXX tbsaunde then why didn't we replace the gail atk_util impl? + if (gail_get_root) + return gail_get_root(); + + return nullptr; +} + +static const gchar* +mai_util_get_toolkit_name() +{ + return MAI_NAME; +} + +static const gchar* +mai_util_get_toolkit_version() +{ + return MAI_VERSION; +} + +static void +_listener_info_destroy(gpointer data) +{ + g_free(data); +} + +static void +window_added (AtkObject *atk_obj, + guint index, + AtkObject *child) +{ + if (!IS_MAI_OBJECT(child)) + return; + + static guint id = g_signal_lookup ("create", MAI_TYPE_ATK_OBJECT); + g_signal_emit (child, id, 0); +} + +static void +window_removed (AtkObject *atk_obj, + guint index, + AtkObject *child) +{ + if (!IS_MAI_OBJECT(child)) + return; + + static guint id = g_signal_lookup ("destroy", MAI_TYPE_ATK_OBJECT); + g_signal_emit (child, id, 0); +} + + static void +UtilInterfaceInit(MaiUtilClass* klass) +{ + AtkUtilClass *atk_class; + gpointer data; + + data = g_type_class_peek(ATK_TYPE_UTIL); + atk_class = ATK_UTIL_CLASS(data); + + // save gail function pointer + gail_add_global_event_listener = atk_class->add_global_event_listener; + gail_remove_global_event_listener = atk_class->remove_global_event_listener; + gail_remove_key_event_listener = atk_class->remove_key_event_listener; + gail_get_root = atk_class->get_root; + + atk_class->add_global_event_listener = + mai_util_add_global_event_listener; + atk_class->remove_global_event_listener = + mai_util_remove_global_event_listener; + atk_class->add_key_event_listener = mai_util_add_key_event_listener; + atk_class->remove_key_event_listener = mai_util_remove_key_event_listener; + atk_class->get_root = mai_util_get_root; + atk_class->get_toolkit_name = mai_util_get_toolkit_name; + atk_class->get_toolkit_version = mai_util_get_toolkit_version; + + sListener_list = g_hash_table_new_full(g_int_hash, g_int_equal, nullptr, + _listener_info_destroy); + // Keep track of added/removed windows. + AtkObject *root = atk_get_root (); + g_signal_connect (root, "children-changed::add", (GCallback) window_added, nullptr); + g_signal_connect (root, "children-changed::remove", (GCallback) window_removed, nullptr); +} +} + +GType +mai_util_get_type() +{ + static GType type = 0; + + if (!type) { + static const GTypeInfo tinfo = { + sizeof(MaiUtilClass), + (GBaseInitFunc) nullptr, /* base init */ + (GBaseFinalizeFunc) nullptr, /* base finalize */ + (GClassInitFunc) UtilInterfaceInit, /* class init */ + (GClassFinalizeFunc) nullptr, /* class finalize */ + nullptr, /* class data */ + sizeof(MaiUtil), /* instance size */ + 0, /* nb preallocs */ + (GInstanceInitFunc) nullptr, /* instance init */ + nullptr /* value table */ + }; + + type = g_type_register_static(ATK_TYPE_UTIL, + "MaiUtil", &tinfo, GTypeFlags(0)); + } + return type; +} + diff --git a/accessible/atk/XULListboxAccessibleWrap.h b/accessible/atk/XULListboxAccessibleWrap.h new file mode 100644 index 0000000000..c0a7594527 --- /dev/null +++ b/accessible/atk/XULListboxAccessibleWrap.h @@ -0,0 +1,21 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef mozilla_a11y_XULListboxAccessibleWrap_h__ +#define mozilla_a11y_XULListboxAccessibleWrap_h__ + +#include "XULListboxAccessible.h" + +namespace mozilla { +namespace a11y { + +typedef class XULListboxAccessible XULListboxAccessibleWrap; +typedef class XULListCellAccessible XULListCellAccessibleWrap; + +} // namespace a11y +} // namespace mozilla + +#endif diff --git a/accessible/atk/XULMenuAccessibleWrap.h b/accessible/atk/XULMenuAccessibleWrap.h new file mode 100644 index 0000000000..d9e325053d --- /dev/null +++ b/accessible/atk/XULMenuAccessibleWrap.h @@ -0,0 +1,20 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef mozilla_a11y_XULMenuAccessibleWrap_h__ +#define mozilla_a11y_XULMenuAccessibleWrap_h__ + +#include "XULMenuAccessible.h" + +namespace mozilla { +namespace a11y { + +typedef class XULMenuitemAccessible XULMenuitemAccessibleWrap; + +} // namespace a11y +} // namespace mozilla + +#endif diff --git a/accessible/atk/XULTreeGridAccessibleWrap.h b/accessible/atk/XULTreeGridAccessibleWrap.h new file mode 100644 index 0000000000..b7f23434bf --- /dev/null +++ b/accessible/atk/XULTreeGridAccessibleWrap.h @@ -0,0 +1,22 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef mozilla_a11y_XULTreeGridAccessibleWrap_h__ +#define mozilla_a11y_XULTreeGridAccessibleWrap_h__ + +#include "XULTreeGridAccessible.h" + +namespace mozilla { +namespace a11y { + +typedef class XULTreeGridAccessible XULTreeGridAccessibleWrap; +typedef class XULTreeGridCellAccessible XULTreeGridCellAccessibleWrap; + +} // namespace a11y +} // namespace mozilla + +#endif + diff --git a/accessible/atk/moz.build b/accessible/atk/moz.build new file mode 100644 index 0000000000..0d6ff9bbe6 --- /dev/null +++ b/accessible/atk/moz.build @@ -0,0 +1,63 @@ +# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*- +# vim: set filetype=python: +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +EXPORTS.mozilla.a11y += [ + 'AccessibleWrap.h', + 'HyperTextAccessibleWrap.h', +] + +SOURCES += [ + 'AccessibleWrap.cpp', + 'ApplicationAccessibleWrap.cpp', + 'AtkSocketAccessible.cpp', + 'DocAccessibleWrap.cpp', + 'nsMaiHyperlink.cpp', + 'nsMaiInterfaceAction.cpp', + 'nsMaiInterfaceComponent.cpp', + 'nsMaiInterfaceDocument.cpp', + 'nsMaiInterfaceEditableText.cpp', + 'nsMaiInterfaceHyperlinkImpl.cpp', + 'nsMaiInterfaceHypertext.cpp', + 'nsMaiInterfaceImage.cpp', + 'nsMaiInterfaceSelection.cpp', + 'nsMaiInterfaceTable.cpp', + 'nsMaiInterfaceTableCell.cpp', + 'nsMaiInterfaceText.cpp', + 'nsMaiInterfaceValue.cpp', + 'Platform.cpp', + 'RootAccessibleWrap.cpp', + 'UtilInterface.cpp', +] + +LOCAL_INCLUDES += [ + '/accessible/base', + '/accessible/generic', + '/accessible/html', + '/accessible/ipc', + '/accessible/ipc/other', + '/accessible/xpcom', + '/accessible/xul', + '/other-licenses/atk-1.0', +] + +FINAL_LIBRARY = 'xul' + +if 'gtk' in CONFIG['MOZ_WIDGET_TOOLKIT']: + CFLAGS += CONFIG['TK_CFLAGS'] + CXXFLAGS += CONFIG['TK_CFLAGS'] + +if CONFIG['MOZ_ENABLE_DBUS']: + CXXFLAGS += CONFIG['MOZ_DBUS_CFLAGS'] + +include('/ipc/chromium/chromium-config.mozbuild') + +if CONFIG['CLANG_CXX'] or CONFIG['GNU_CXX']: + # Used in G_DEFINE_TYPE_EXTENDED macro, probably fixed in newer glib / + # gobject headers. See bug 1243331 comment 3. + CXXFLAGS += [ + '-Wno-error=shadow', + '-Wno-unused-local-typedefs', + ] diff --git a/accessible/atk/nsMai.h b/accessible/atk/nsMai.h new file mode 100644 index 0000000000..1a9082e99b --- /dev/null +++ b/accessible/atk/nsMai.h @@ -0,0 +1,149 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef __NS_MAI_H__ +#define __NS_MAI_H__ + +#include +#include +#include + +#include "AccessibleOrProxy.h" +#include "AccessibleWrap.h" + +namespace mozilla { +namespace a11y { +class ProxyAccessible; +} +} + +#define MAI_TYPE_ATK_OBJECT (mai_atk_object_get_type ()) +#define MAI_ATK_OBJECT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), \ + MAI_TYPE_ATK_OBJECT, MaiAtkObject)) +#define MAI_ATK_OBJECT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), \ + MAI_TYPE_ATK_OBJECT, \ + MaiAtkObjectClass)) +#define IS_MAI_OBJECT(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), \ + MAI_TYPE_ATK_OBJECT)) +#define IS_MAI_OBJECT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), \ + MAI_TYPE_ATK_OBJECT)) +#define MAI_ATK_OBJECT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), \ + MAI_TYPE_ATK_OBJECT, \ + MaiAtkObjectClass)) +GType mai_atk_object_get_type(void); +GType mai_util_get_type(); +extern "C" GType mai_atk_socket_get_type(void); + +/* MaiAtkSocket */ + +#define MAI_TYPE_ATK_SOCKET (mai_atk_socket_get_type ()) +#define MAI_ATK_SOCKET(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj),\ + MAI_TYPE_ATK_SOCKET, MaiAtkSocket)) +#define MAI_IS_ATK_SOCKET(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj),\ + MAI_TYPE_ATK_SOCKET)) +#define MAI_ATK_SOCKET_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass),\ + MAI_TYPE_ATK_SOCKET,\ + MaiAtkSocketClass)) +#define MAI_IS_ATK_SOCKET_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass),\ + MAI_TYPE_ATK_SOCKET)) +#define MAI_ATK_SOCKET_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj),\ + MAI_TYPE_ATK_SOCKET,\ + MaiAtkSocketClass)) + +typedef struct _MaiAtkSocket +{ + AtkSocket parent; + + mozilla::a11y::AccessibleWrap* accWrap; +} MaiAtkSocket; + +typedef struct _MaiAtkSocketClass +{ + AtkSocketClass parent_class; +} MaiAtkSocketClass; + +// This is a pointer to the atk_table_cell_get_type function if we are using +// a version of atk that defines that. +extern "C" GType (*gAtkTableCellGetTypeFunc)(); + +mozilla::a11y::AccessibleWrap* GetAccessibleWrap(AtkObject* aAtkObj); +mozilla::a11y::ProxyAccessible* GetProxy(AtkObject* aAtkObj); +mozilla::a11y::AccessibleOrProxy GetInternalObj(AtkObject* aObj); +AtkObject* GetWrapperFor(mozilla::a11y::ProxyAccessible* aProxy); +AtkObject* GetWrapperFor(mozilla::a11y::AccessibleOrProxy aObj); + +extern int atkMajorVersion, atkMinorVersion; + +/** + * Return true if the loaded version of libatk-1.0.so is at least + * aMajor.aMinor.0. + */ +static inline bool +IsAtkVersionAtLeast(int aMajor, int aMinor) +{ + return aMajor < atkMajorVersion || + (aMajor == atkMajorVersion && aMinor <= atkMinorVersion); +} + +// This is or'd with the pointer in MaiAtkObject::accWrap if the wrap-ee is a +// proxy. +static const uintptr_t IS_PROXY = 1; + +/** + * This MaiAtkObject is a thin wrapper, in the MAI namespace, for AtkObject + */ +struct MaiAtkObject +{ + AtkObject parent; + /* + * The AccessibleWrap whose properties and features are exported + * via this object instance. + */ + mozilla::a11y::AccessibleOrProxy accWrap; + + /* + * Get the AtkHyperlink for this atk object. + */ + AtkHyperlink* GetAtkHyperlink(); + + /* + * Shutdown this AtkObject. + */ + void Shutdown(); + + /* + * Notify atk of a state change on this AtkObject. + */ + void FireStateChangeEvent(uint64_t aState, bool aEnabled); + + /* + * Notify ATK of a text change within this ATK object. + */ + void FireTextChangeEvent(const nsString& aStr, int32_t aStart, uint32_t aLen, + bool aIsInsert, bool aIsFromUser); + + /** + * Notify ATK of a shown or hidden subtree rooted at aObject whose parent is + * aParent + */ + void FireAtkShowHideEvent(AtkObject* aParent, bool aIsAdded, bool aFromUser); + +private: + /* + * do we have text-remove and text-insert signals if not we need to use + * text-changed see AccessibleWrap::FireAtkTextChangedEvent() and + * bug 619002 + */ + enum EAvailableAtkSignals { + eUnknown, + eHaveNewAtkTextSignals, + eNoNewAtkSignals + }; + + static EAvailableAtkSignals gAvailableAtkSignals; +}; + +#endif /* __NS_MAI_H__ */ diff --git a/accessible/atk/nsMaiHyperlink.cpp b/accessible/atk/nsMaiHyperlink.cpp new file mode 100644 index 0000000000..9d33f6665a --- /dev/null +++ b/accessible/atk/nsMaiHyperlink.cpp @@ -0,0 +1,262 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "nsIURI.h" +#include "nsMaiHyperlink.h" +#include "mozilla/a11y/ProxyAccessible.h" + +using namespace mozilla::a11y; + +/* MaiAtkHyperlink */ + +#define MAI_TYPE_ATK_HYPERLINK (mai_atk_hyperlink_get_type ()) +#define MAI_ATK_HYPERLINK(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj),\ + MAI_TYPE_ATK_HYPERLINK, MaiAtkHyperlink)) +#define MAI_ATK_HYPERLINK_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass),\ + MAI_TYPE_ATK_HYPERLINK, MaiAtkHyperlinkClass)) +#define MAI_IS_ATK_HYPERLINK(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj),\ + MAI_TYPE_ATK_HYPERLINK)) +#define MAI_IS_ATK_HYPERLINK_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass),\ + MAI_TYPE_ATK_HYPERLINK)) +#define MAI_ATK_HYPERLINK_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj),\ + MAI_TYPE_ATK_HYPERLINK, MaiAtkHyperlinkClass)) + +/** + * This MaiAtkHyperlink is a thin wrapper, in the MAI namespace, + * for AtkHyperlink + */ + +struct MaiAtkHyperlink +{ + AtkHyperlink parent; + + /* + * The MaiHyperlink whose properties and features are exported via this + * hyperlink instance. + */ + MaiHyperlink *maiHyperlink; +}; + +struct MaiAtkHyperlinkClass +{ + AtkHyperlinkClass parent_class; +}; + +GType mai_atk_hyperlink_get_type(void); + +G_BEGIN_DECLS +/* callbacks for AtkHyperlink */ +static void classInitCB(AtkHyperlinkClass *aClass); +static void finalizeCB(GObject *aObj); + +/* callbacks for AtkHyperlink virtual functions */ +static gchar *getUriCB(AtkHyperlink *aLink, gint aLinkIndex); +static AtkObject *getObjectCB(AtkHyperlink *aLink, gint aLinkIndex); +static gint getEndIndexCB(AtkHyperlink *aLink); +static gint getStartIndexCB(AtkHyperlink *aLink); +static gboolean isValidCB(AtkHyperlink *aLink); +static gint getAnchorCountCB(AtkHyperlink *aLink); +G_END_DECLS + +static gpointer parent_class = nullptr; + +static MaiHyperlink* +GetMaiHyperlink(AtkHyperlink *aHyperlink) +{ + NS_ENSURE_TRUE(MAI_IS_ATK_HYPERLINK(aHyperlink), nullptr); + MaiHyperlink * maiHyperlink = + MAI_ATK_HYPERLINK(aHyperlink)->maiHyperlink; + NS_ENSURE_TRUE(maiHyperlink != nullptr, nullptr); + NS_ENSURE_TRUE(maiHyperlink->GetAtkHyperlink() == aHyperlink, nullptr); + return maiHyperlink; +} + +GType +mai_atk_hyperlink_get_type(void) +{ + static GType type = 0; + + if (!type) { + static const GTypeInfo tinfo = { + sizeof(MaiAtkHyperlinkClass), + (GBaseInitFunc)nullptr, + (GBaseFinalizeFunc)nullptr, + (GClassInitFunc)classInitCB, + (GClassFinalizeFunc)nullptr, + nullptr, /* class data */ + sizeof(MaiAtkHyperlink), /* instance size */ + 0, /* nb preallocs */ + (GInstanceInitFunc)nullptr, + nullptr /* value table */ + }; + + type = g_type_register_static(ATK_TYPE_HYPERLINK, + "MaiAtkHyperlink", + &tinfo, GTypeFlags(0)); + } + return type; +} + +MaiHyperlink::MaiHyperlink(AccessibleOrProxy aHyperLink) : + mHyperlink(aHyperLink), + mMaiAtkHyperlink(nullptr) +{ + mMaiAtkHyperlink = + reinterpret_cast + (g_object_new(mai_atk_hyperlink_get_type(), nullptr)); + NS_ASSERTION(mMaiAtkHyperlink, "OUT OF MEMORY"); + if (!mMaiAtkHyperlink) + return; + + MAI_ATK_HYPERLINK(mMaiAtkHyperlink)->maiHyperlink = this; +} + +MaiHyperlink::~MaiHyperlink() +{ + if (mMaiAtkHyperlink) { + MAI_ATK_HYPERLINK(mMaiAtkHyperlink)->maiHyperlink = nullptr; + g_object_unref(mMaiAtkHyperlink); + } +} + + +/* static functions for ATK callbacks */ + +void +classInitCB(AtkHyperlinkClass *aClass) +{ + GObjectClass *gobject_class = G_OBJECT_CLASS(aClass); + + parent_class = g_type_class_peek_parent(aClass); + + aClass->get_uri = getUriCB; + aClass->get_object = getObjectCB; + aClass->get_end_index = getEndIndexCB; + aClass->get_start_index = getStartIndexCB; + aClass->is_valid = isValidCB; + aClass->get_n_anchors = getAnchorCountCB; + + gobject_class->finalize = finalizeCB; +} + +void +finalizeCB(GObject *aObj) +{ + NS_ASSERTION(MAI_IS_ATK_HYPERLINK(aObj), "Invalid MaiAtkHyperlink"); + if (!MAI_IS_ATK_HYPERLINK(aObj)) + return; + + MaiAtkHyperlink *maiAtkHyperlink = MAI_ATK_HYPERLINK(aObj); + maiAtkHyperlink->maiHyperlink = nullptr; + + /* call parent finalize function */ + if (G_OBJECT_CLASS (parent_class)->finalize) + G_OBJECT_CLASS (parent_class)->finalize(aObj); +} + +gchar * +getUriCB(AtkHyperlink *aLink, gint aLinkIndex) +{ + MaiHyperlink* maiLink = GetMaiHyperlink(aLink); + if (!maiLink) + return nullptr; + + nsAutoCString cautoStr; + if (Accessible* hyperlink = maiLink->GetAccHyperlink()) { + nsCOMPtr uri = hyperlink->AnchorURIAt(aLinkIndex); + if (!uri) + return nullptr; + + nsresult rv = uri->GetSpec(cautoStr); + NS_ENSURE_SUCCESS(rv, nullptr); + + return g_strdup(cautoStr.get()); + } + + bool valid; + maiLink->Proxy()->AnchorURIAt(aLinkIndex, cautoStr, &valid); + if (!valid) + return nullptr; + + return g_strdup(cautoStr.get()); +} + +AtkObject * +getObjectCB(AtkHyperlink *aLink, gint aLinkIndex) +{ + MaiHyperlink* maiLink = GetMaiHyperlink(aLink); + if (!maiLink) { + return nullptr; + } + + if (Accessible* hyperlink = maiLink->GetAccHyperlink()) { + Accessible* anchor = hyperlink->AnchorAt(aLinkIndex); + NS_ENSURE_TRUE(anchor, nullptr); + + return AccessibleWrap::GetAtkObject(anchor); + } + + ProxyAccessible* anchor = maiLink->Proxy()->AnchorAt(aLinkIndex); + return anchor ? GetWrapperFor(anchor) : nullptr; +} + +gint +getEndIndexCB(AtkHyperlink *aLink) +{ + MaiHyperlink* maiLink = GetMaiHyperlink(aLink); + if (!maiLink) + return false; + + if (Accessible* hyperlink = maiLink->GetAccHyperlink()) + return static_cast(hyperlink->EndOffset()); + + bool valid = false; + uint32_t endIdx = maiLink->Proxy()->EndOffset(&valid); + return valid ? static_cast(endIdx) : -1; +} + +gint +getStartIndexCB(AtkHyperlink *aLink) +{ + MaiHyperlink* maiLink = GetMaiHyperlink(aLink); + if (!maiLink) + return -1; + + if (Accessible* hyperlink = maiLink->GetAccHyperlink()) + return static_cast(hyperlink->StartOffset()); + + bool valid = false; + uint32_t startIdx = maiLink->Proxy()->StartOffset(&valid); + return valid ? static_cast(startIdx) : -1; +} + +gboolean +isValidCB(AtkHyperlink *aLink) +{ + MaiHyperlink* maiLink = GetMaiHyperlink(aLink); + if (!maiLink) + return false; + + if (Accessible* hyperlink = maiLink->GetAccHyperlink()) + return static_cast(hyperlink->IsLinkValid()); + + return static_cast(maiLink->Proxy()->IsLinkValid()); +} + +gint +getAnchorCountCB(AtkHyperlink *aLink) +{ + MaiHyperlink* maiLink = GetMaiHyperlink(aLink); + if (!maiLink) + return -1; + + if (Accessible* hyperlink = maiLink->GetAccHyperlink()) + return static_cast(hyperlink->AnchorCount()); + + bool valid = false; + uint32_t anchorCount = maiLink->Proxy()->AnchorCount(&valid); + return valid ? static_cast(anchorCount) : -1; +} diff --git a/accessible/atk/nsMaiHyperlink.h b/accessible/atk/nsMaiHyperlink.h new file mode 100644 index 0000000000..7dc1b73551 --- /dev/null +++ b/accessible/atk/nsMaiHyperlink.h @@ -0,0 +1,55 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef __MAI_HYPERLINK_H__ +#define __MAI_HYPERLINK_H__ + +#include "nsMai.h" +#include "Accessible.h" + +struct _AtkHyperlink; +typedef struct _AtkHyperlink AtkHyperlink; + +namespace mozilla { +namespace a11y { + +/* + * MaiHyperlink is a auxiliary class for MaiInterfaceHyperText. + */ + +class MaiHyperlink +{ +public: + explicit MaiHyperlink(AccessibleOrProxy aHyperLink); + ~MaiHyperlink(); + +public: + AtkHyperlink* GetAtkHyperlink() const { return mMaiAtkHyperlink; } + Accessible* GetAccHyperlink() + { + if (!mHyperlink.IsAccessible()) + return nullptr; + + Accessible* link = mHyperlink.AsAccessible(); + if (!link) { + return nullptr; + } + + NS_ASSERTION(link->IsLink(), "Why isn't it a link!"); + return link; + } + + ProxyAccessible* Proxy() const { return mHyperlink.AsProxy(); } + +protected: + AccessibleOrProxy mHyperlink; + AtkHyperlink* mMaiAtkHyperlink; +}; + +} // namespace a11y +} // namespace mozilla + +#endif /* __MAI_HYPERLINK_H__ */ diff --git a/accessible/atk/nsMaiInterfaceAction.cpp b/accessible/atk/nsMaiInterfaceAction.cpp new file mode 100644 index 0000000000..9ba1216658 --- /dev/null +++ b/accessible/atk/nsMaiInterfaceAction.cpp @@ -0,0 +1,105 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "InterfaceInitFuncs.h" + +#include "Accessible-inl.h" +#include "nsMai.h" +#include "Role.h" +#include "mozilla/Likely.h" +#include "ProxyAccessible.h" +#include "nsString.h" + +using namespace mozilla::a11y; + +extern "C" { + +static gboolean +doActionCB(AtkAction *aAction, gint aActionIndex) +{ + AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aAction)); + if (accWrap) { + return accWrap->DoAction(aActionIndex); + } + + ProxyAccessible* proxy = GetProxy(ATK_OBJECT(aAction)); + return proxy && proxy->DoAction(aActionIndex); +} + +static gint +getActionCountCB(AtkAction *aAction) +{ + AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aAction)); + if (accWrap) { + return accWrap->ActionCount(); + } + + ProxyAccessible* proxy = GetProxy(ATK_OBJECT(aAction)); + return proxy ? proxy->ActionCount() : 0; +} + +static const gchar* +getActionDescriptionCB(AtkAction *aAction, gint aActionIndex) +{ + nsAutoString description; + AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aAction)); + if (accWrap) { + accWrap->ActionDescriptionAt(aActionIndex, description); + } else if (ProxyAccessible* proxy = GetProxy(ATK_OBJECT(aAction))) { + proxy->ActionDescriptionAt(aActionIndex, description); + } else { + return nullptr; + } + + return AccessibleWrap::ReturnString(description); +} + +static const gchar* +getActionNameCB(AtkAction *aAction, gint aActionIndex) +{ + nsAutoString autoStr; + AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aAction)); + if (accWrap) { + accWrap->ActionNameAt(aActionIndex, autoStr); + } else if (ProxyAccessible* proxy = GetProxy(ATK_OBJECT(aAction))) { + proxy->ActionNameAt(aActionIndex, autoStr); + } else { + return nullptr; + } + + return AccessibleWrap::ReturnString(autoStr); +} + +static const gchar* +getKeyBindingCB(AtkAction *aAction, gint aActionIndex) +{ + nsAutoString keyBindingsStr; + AccessibleWrap* acc = GetAccessibleWrap(ATK_OBJECT(aAction)); + if (acc) { + AccessibleWrap::GetKeyBinding(acc, keyBindingsStr); + } else if (ProxyAccessible* proxy = GetProxy(ATK_OBJECT(aAction))) { + proxy->AtkKeyBinding(keyBindingsStr); + } else { + return nullptr; + } + + return AccessibleWrap::ReturnString(keyBindingsStr); +} +} + +void +actionInterfaceInitCB(AtkActionIface* aIface) +{ + NS_ASSERTION(aIface, "Invalid aIface"); + if (MOZ_UNLIKELY(!aIface)) + return; + + aIface->do_action = doActionCB; + aIface->get_n_actions = getActionCountCB; + aIface->get_description = getActionDescriptionCB; + aIface->get_keybinding = getKeyBindingCB; + aIface->get_name = getActionNameCB; +} diff --git a/accessible/atk/nsMaiInterfaceComponent.cpp b/accessible/atk/nsMaiInterfaceComponent.cpp new file mode 100644 index 0000000000..efd8eb65cd --- /dev/null +++ b/accessible/atk/nsMaiInterfaceComponent.cpp @@ -0,0 +1,151 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "InterfaceInitFuncs.h" + +#include "AccessibleWrap.h" +#include "nsAccUtils.h" +#include "nsCoreUtils.h" +#include "nsMai.h" +#include "mozilla/Likely.h" +#include "mozilla/a11y/ProxyAccessible.h" + +using namespace mozilla::a11y; + +extern "C" { + +static AtkObject* +refAccessibleAtPointCB(AtkComponent* aComponent, gint aAccX, gint aAccY, + AtkCoordType aCoordType) +{ + return refAccessibleAtPointHelper(ATK_OBJECT(aComponent), + aAccX, aAccY, aCoordType); +} + +static void +getExtentsCB(AtkComponent* aComponent, gint* aX, gint* aY, + gint* aWidth, gint* aHeight, AtkCoordType aCoordType) +{ + getExtentsHelper(ATK_OBJECT(aComponent), + aX, aY, aWidth, aHeight, aCoordType); +} + +static gboolean +grabFocusCB(AtkComponent* aComponent) +{ + AtkObject* atkObject = ATK_OBJECT(aComponent); + AccessibleWrap* accWrap = GetAccessibleWrap(atkObject); + if (accWrap) { + accWrap->TakeFocus(); + return TRUE; + } + + ProxyAccessible* proxy = GetProxy(atkObject); + if (proxy) { + proxy->TakeFocus(); + return TRUE; + } + + return FALSE; +} +} + +AtkObject* +refAccessibleAtPointHelper(AtkObject* aAtkObj, gint aX, gint aY, + AtkCoordType aCoordType) +{ + AccessibleWrap* accWrap = GetAccessibleWrap(aAtkObj); + if (accWrap) { + if (accWrap->IsDefunct() || nsAccUtils::MustPrune(accWrap)) { + return nullptr; + } + + // Accessible::ChildAtPoint(x,y) is in screen pixels. + if (aCoordType == ATK_XY_WINDOW) { + nsIntPoint winCoords = + nsCoreUtils::GetScreenCoordsForWindow(accWrap->GetNode()); + aX += winCoords.x; + aY += winCoords.y; + } + + Accessible* accAtPoint = accWrap->ChildAtPoint(aX, aY, + Accessible::eDirectChild); + if (!accAtPoint) { + return nullptr; + } + + AtkObject* atkObj = AccessibleWrap::GetAtkObject(accAtPoint); + if (atkObj) { + g_object_ref(atkObj); + } + + return atkObj; + } + + if (ProxyAccessible* proxy = GetProxy(aAtkObj)) { + ProxyAccessible* result = + proxy->AccessibleAtPoint(aX, aY, aCoordType == ATK_XY_WINDOW); + AtkObject* atkObj = result ? GetWrapperFor(result) : nullptr; + if (atkObj) { + g_object_ref(atkObj); + } + return atkObj; + } + + return nullptr; +} + +void +getExtentsHelper(AtkObject* aAtkObj, + gint* aX, gint* aY, gint* aWidth, gint* aHeight, + AtkCoordType aCoordType) +{ + AccessibleWrap* accWrap = GetAccessibleWrap(aAtkObj); + *aX = *aY = *aWidth = *aHeight = 0; + + if (accWrap) { + if (accWrap->IsDefunct()) { + return; + } + + nsIntRect screenRect = accWrap->Bounds(); + if (screenRect.IsEmpty()) + return; + + if (aCoordType == ATK_XY_WINDOW) { + nsIntPoint winCoords = + nsCoreUtils::GetScreenCoordsForWindow(accWrap->GetNode()); + screenRect.x -= winCoords.x; + screenRect.y -= winCoords.y; + } + + *aX = screenRect.x; + *aY = screenRect.y; + *aWidth = screenRect.width; + *aHeight = screenRect.height; + return; + } + + if (ProxyAccessible* proxy = GetProxy(aAtkObj)) { + proxy->Extents(aCoordType == ATK_XY_WINDOW, aX, aY, aWidth, aHeight); + } +} + +void +componentInterfaceInitCB(AtkComponentIface* aIface) +{ + NS_ASSERTION(aIface, "Invalid Interface"); + if(MOZ_UNLIKELY(!aIface)) + return; + + /* + * Use default implementation in atk for contains, get_position, + * and get_size + */ + aIface->ref_accessible_at_point = refAccessibleAtPointCB; + aIface->get_extents = getExtentsCB; + aIface->grab_focus = grabFocusCB; +} diff --git a/accessible/atk/nsMaiInterfaceDocument.cpp b/accessible/atk/nsMaiInterfaceDocument.cpp new file mode 100644 index 0000000000..801028f9c3 --- /dev/null +++ b/accessible/atk/nsMaiInterfaceDocument.cpp @@ -0,0 +1,151 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "InterfaceInitFuncs.h" + +#include "Accessible-inl.h" +#include "AccessibleWrap.h" +#include "DocAccessible.h" +#include "nsMai.h" +#include "ProxyAccessible.h" +#include "mozilla/Likely.h" + +using namespace mozilla::a11y; + +static const char* const kDocTypeName = "W3C-doctype"; +static const char* const kDocUrlName = "DocURL"; +static const char* const kMimeTypeName = "MimeType"; + +// below functions are vfuncs on an ATK interface so they need to be C call +extern "C" { + +static const gchar* getDocumentLocaleCB(AtkDocument* aDocument); +static AtkAttributeSet* getDocumentAttributesCB(AtkDocument* aDocument); +static const gchar* getDocumentAttributeValueCB(AtkDocument* aDocument, + const gchar* aAttrName); + +void +documentInterfaceInitCB(AtkDocumentIface *aIface) +{ + NS_ASSERTION(aIface, "Invalid Interface"); + if(MOZ_UNLIKELY(!aIface)) + return; + + /* + * We don't support get_document or set_attribute right now. + * get_document_type is deprecated, we return DocType in + * get_document_attribute_value and get_document_attributes instead. + */ + aIface->get_document_attributes = getDocumentAttributesCB; + aIface->get_document_attribute_value = getDocumentAttributeValueCB; + aIface->get_document_locale = getDocumentLocaleCB; +} + +const gchar * +getDocumentLocaleCB(AtkDocument *aDocument) +{ + nsAutoString locale; + AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aDocument)); + if (accWrap) { + accWrap->Language(locale); + } else if (ProxyAccessible* proxy = GetProxy(ATK_OBJECT(aDocument))) { + proxy->Language(locale); + } + + return locale.IsEmpty() ? nullptr : AccessibleWrap::ReturnString(locale); +} + +static inline GSList * +prependToList(GSList *aList, const char *const aName, const nsAutoString &aValue) +{ + if (aValue.IsEmpty()) { + return aList; + } + + // libspi will free these + AtkAttribute *atkAttr = (AtkAttribute *)g_malloc(sizeof(AtkAttribute)); + atkAttr->name = g_strdup(aName); + atkAttr->value = g_strdup(NS_ConvertUTF16toUTF8(aValue).get()); + return g_slist_prepend(aList, atkAttr); +} + +AtkAttributeSet * +getDocumentAttributesCB(AtkDocument *aDocument) +{ + nsAutoString url; + nsAutoString w3cDocType; + nsAutoString mimeType; + AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aDocument)); + if (accWrap) { + if (!accWrap->IsDoc()) { + return nullptr; + } + + DocAccessible* document = accWrap->AsDoc(); + document->URL(url); + document->DocType(w3cDocType); + document->MimeType(mimeType); + } else if (ProxyAccessible* proxy = GetProxy(ATK_OBJECT(aDocument))) { + proxy->URLDocTypeMimeType(url, w3cDocType, mimeType); + } else { + return nullptr; + } + + // according to atkobject.h, AtkAttributeSet is a GSList + GSList* attributes = nullptr; + attributes = prependToList(attributes, kDocUrlName, url); + attributes = prependToList(attributes, kDocTypeName, w3cDocType); + attributes = prependToList(attributes, kMimeTypeName, mimeType); + + return attributes; +} + +const gchar * +getDocumentAttributeValueCB(AtkDocument *aDocument, + const gchar *aAttrName) +{ + ProxyAccessible* proxy = nullptr; + DocAccessible* document = nullptr; + AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aDocument)); + if (accWrap) { + if (!accWrap->IsDoc()) { + return nullptr; + } + + document = accWrap->AsDoc(); + } else { + proxy = GetProxy(ATK_OBJECT(aDocument)); + if (!proxy) { + return nullptr; + } + } + + nsAutoString attrValue; + if (!strcasecmp(aAttrName, kDocTypeName)) { + if (document) { + document->DocType(attrValue); + } else { + proxy->DocType(attrValue); + } + } else if (!strcasecmp(aAttrName, kDocUrlName)) { + if (document) { + document->URL(attrValue); + } else { + proxy->URL(attrValue); + } + } else if (!strcasecmp(aAttrName, kMimeTypeName)) { + if (document) { + document->MimeType(attrValue); + } else { + proxy->MimeType(attrValue); + } + } else { + return nullptr; + } + + return attrValue.IsEmpty() ? nullptr : AccessibleWrap::ReturnString(attrValue); +} +} diff --git a/accessible/atk/nsMaiInterfaceEditableText.cpp b/accessible/atk/nsMaiInterfaceEditableText.cpp new file mode 100644 index 0000000000..18a1b6f422 --- /dev/null +++ b/accessible/atk/nsMaiInterfaceEditableText.cpp @@ -0,0 +1,134 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "InterfaceInitFuncs.h" + +#include "Accessible-inl.h" +#include "HyperTextAccessible-inl.h" +#include "nsMai.h" +#include "ProxyAccessible.h" +#include "nsString.h" +#include "mozilla/Likely.h" + +using namespace mozilla::a11y; + +extern "C" { +static void +setTextContentsCB(AtkEditableText *aText, const gchar *aString) +{ + AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aText)); + if (accWrap) { + HyperTextAccessible* text = accWrap->AsHyperText(); + if (!text || !text->IsTextRole()) { + return; + } + + NS_ConvertUTF8toUTF16 strContent(aString); + text->ReplaceText(strContent); + } else if (ProxyAccessible* proxy = GetProxy(ATK_OBJECT(aText))) { + NS_ConvertUTF8toUTF16 strContent(aString); + proxy->ReplaceText(strContent); + } +} + +static void +insertTextCB(AtkEditableText *aText, + const gchar *aString, gint aLength, gint *aPosition) +{ + AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aText)); + if (accWrap) { + HyperTextAccessible* text = accWrap->AsHyperText(); + if (!text || !text->IsTextRole()) { + return; + } + + NS_ConvertUTF8toUTF16 strContent(aString); + text->InsertText(strContent, *aPosition); + } else if (ProxyAccessible* proxy = GetProxy(ATK_OBJECT(aText))) { + NS_ConvertUTF8toUTF16 strContent(aString); + proxy->InsertText(strContent, *aPosition); + } +} + +static void +copyTextCB(AtkEditableText *aText, gint aStartPos, gint aEndPos) +{ + AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aText)); + if (accWrap) { + HyperTextAccessible* text = accWrap->AsHyperText(); + if (!text || !text->IsTextRole()) { + return; + } + + text->CopyText(aStartPos, aEndPos); + } else if (ProxyAccessible* proxy = GetProxy(ATK_OBJECT(aText))) { + proxy->CopyText(aStartPos, aEndPos); + } +} + +static void +cutTextCB(AtkEditableText *aText, gint aStartPos, gint aEndPos) +{ + AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aText)); + if (accWrap) { + HyperTextAccessible* text = accWrap->AsHyperText(); + if (!text || !text->IsTextRole()) { + return; + } + + text->CutText(aStartPos, aEndPos); + } else if (ProxyAccessible* proxy = GetProxy(ATK_OBJECT(aText))) { + proxy->CutText(aStartPos, aEndPos); + } +} + +static void +deleteTextCB(AtkEditableText *aText, gint aStartPos, gint aEndPos) +{ + AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aText)); + if (accWrap) { + HyperTextAccessible* text = accWrap->AsHyperText(); + if (!text || !text->IsTextRole()) { + return; + } + + text->DeleteText(aStartPos, aEndPos); + } else if (ProxyAccessible* proxy = GetProxy(ATK_OBJECT(aText))) { + proxy->DeleteText(aStartPos, aEndPos); + } +} + +static void +pasteTextCB(AtkEditableText *aText, gint aPosition) +{ + AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aText)); + if (accWrap) { + HyperTextAccessible* text = accWrap->AsHyperText(); + if (!text || !text->IsTextRole()) { + return; + } + + text->PasteText(aPosition); + } else if (ProxyAccessible* proxy = GetProxy(ATK_OBJECT(aText))) { + proxy->PasteText(aPosition); + } +} +} + +void +editableTextInterfaceInitCB(AtkEditableTextIface* aIface) +{ + NS_ASSERTION(aIface, "Invalid aIface"); + if (MOZ_UNLIKELY(!aIface)) + return; + + aIface->set_text_contents = setTextContentsCB; + aIface->insert_text = insertTextCB; + aIface->copy_text = copyTextCB; + aIface->cut_text = cutTextCB; + aIface->delete_text = deleteTextCB; + aIface->paste_text = pasteTextCB; +} diff --git a/accessible/atk/nsMaiInterfaceHyperlinkImpl.cpp b/accessible/atk/nsMaiInterfaceHyperlinkImpl.cpp new file mode 100644 index 0000000000..f8cfd6fc16 --- /dev/null +++ b/accessible/atk/nsMaiInterfaceHyperlinkImpl.cpp @@ -0,0 +1,37 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "InterfaceInitFuncs.h" + +#include "nsMaiHyperlink.h" +#include "mozilla/Likely.h" + +using namespace mozilla::a11y; + +extern "C" { +static AtkHyperlink* +getHyperlinkCB(AtkHyperlinkImpl* aImpl) +{ + AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aImpl)); + if (!accWrap && !GetProxy(ATK_OBJECT(aImpl))) + return nullptr; + + if (accWrap) + NS_ASSERTION(accWrap->IsLink(), "why isn't it a link!"); + + return MAI_ATK_OBJECT(aImpl)->GetAtkHyperlink(); +} +} + +void +hyperlinkImplInterfaceInitCB(AtkHyperlinkImplIface *aIface) +{ + NS_ASSERTION(aIface, "no interface!"); + if (MOZ_UNLIKELY(!aIface)) + return; + + aIface->get_hyperlink = getHyperlinkCB; +} diff --git a/accessible/atk/nsMaiInterfaceHypertext.cpp b/accessible/atk/nsMaiInterfaceHypertext.cpp new file mode 100644 index 0000000000..d6b3ee8f47 --- /dev/null +++ b/accessible/atk/nsMaiInterfaceHypertext.cpp @@ -0,0 +1,94 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "InterfaceInitFuncs.h" + +#include "Accessible-inl.h" +#include "HyperTextAccessible.h" +#include "nsMai.h" +#include "nsMaiHyperlink.h" +#include "ProxyAccessible.h" +#include "mozilla/Likely.h" + + +using namespace mozilla::a11y; + +extern "C" { + +static AtkHyperlink* +getLinkCB(AtkHypertext *aText, gint aLinkIndex) +{ + AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aText)); + AtkObject* atkHyperLink = nullptr; + if (accWrap) { + HyperTextAccessible* hyperText = accWrap->AsHyperText(); + NS_ENSURE_TRUE(hyperText, nullptr); + + Accessible* hyperLink = hyperText->LinkAt(aLinkIndex); + if (!hyperLink || !hyperLink->IsLink()) { + return nullptr; + } + + atkHyperLink = AccessibleWrap::GetAtkObject(hyperLink); + } else if (ProxyAccessible* proxy = GetProxy(ATK_OBJECT(aText))) { + ProxyAccessible* proxyLink = proxy->LinkAt(aLinkIndex); + if (!proxyLink) + return nullptr; + + atkHyperLink = GetWrapperFor(proxyLink); + } + + NS_ENSURE_TRUE(IS_MAI_OBJECT(atkHyperLink), nullptr); + return MAI_ATK_OBJECT(atkHyperLink)->GetAtkHyperlink(); +} + +static gint +getLinkCountCB(AtkHypertext *aText) +{ + AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aText)); + if (accWrap) { + HyperTextAccessible* hyperText = accWrap->AsHyperText(); + NS_ENSURE_TRUE(hyperText, -1); + return hyperText->LinkCount(); + } + + if (ProxyAccessible* proxy = GetProxy(ATK_OBJECT(aText))) { + return proxy->LinkCount(); + } + + return -1; +} + +static gint +getLinkIndexCB(AtkHypertext *aText, gint aCharIndex) +{ + AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aText)); + if (accWrap) { + HyperTextAccessible* hyperText = accWrap->AsHyperText(); + NS_ENSURE_TRUE(hyperText, -1); + + return hyperText->LinkIndexAtOffset(aCharIndex); + } + + if (ProxyAccessible* proxy = GetProxy(ATK_OBJECT(aText))) { + return proxy->LinkIndexAtOffset(aCharIndex); + } + + return -1; +} +} + +void +hypertextInterfaceInitCB(AtkHypertextIface* aIface) +{ + NS_ASSERTION(aIface, "no interface!"); + if (MOZ_UNLIKELY(!aIface)) + return; + + aIface->get_link = getLinkCB; + aIface->get_n_links = getLinkCountCB; + aIface->get_link_index = getLinkIndexCB; +} diff --git a/accessible/atk/nsMaiInterfaceImage.cpp b/accessible/atk/nsMaiInterfaceImage.cpp new file mode 100644 index 0000000000..64a3beaab3 --- /dev/null +++ b/accessible/atk/nsMaiInterfaceImage.cpp @@ -0,0 +1,77 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "InterfaceInitFuncs.h" + +#include "AccessibleWrap.h" +#include "ImageAccessible.h" +#include "mozilla/Likely.h" +#include "nsMai.h" +#include "nsIAccessibleTypes.h" +#include "nsIURI.h" +#include "ProxyAccessible.h" + +using namespace mozilla; +using namespace mozilla::a11y; + +extern "C" { +const gchar* getDescriptionCB(AtkObject* aAtkObj); + +static void +getImagePositionCB(AtkImage* aImage, gint* aAccX, gint* aAccY, + AtkCoordType aCoordType) +{ + nsIntPoint pos; + uint32_t geckoCoordType = (aCoordType == ATK_XY_WINDOW) ? + nsIAccessibleCoordinateType::COORDTYPE_WINDOW_RELATIVE : + nsIAccessibleCoordinateType::COORDTYPE_SCREEN_RELATIVE; + + AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aImage)); + if (accWrap && accWrap->IsImage()) { + ImageAccessible* image = accWrap->AsImage(); + pos = image->Position(geckoCoordType); + } else if (ProxyAccessible* proxy = GetProxy(ATK_OBJECT(aImage))) { + pos = proxy->ImagePosition(geckoCoordType); + } + + *aAccX = pos.x; + *aAccY = pos.y; +} + +static const gchar* +getImageDescriptionCB(AtkImage* aImage) +{ + return getDescriptionCB(ATK_OBJECT(aImage)); +} + +static void +getImageSizeCB(AtkImage* aImage, gint* aAccWidth, gint* aAccHeight) +{ + nsIntSize size; + AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aImage)); + if (accWrap && accWrap->IsImage()) { + size = accWrap->AsImage()->Size(); + } else if (ProxyAccessible* proxy = GetProxy(ATK_OBJECT(aImage))) { + size = proxy->ImageSize(); + } + + *aAccWidth = size.width; + *aAccHeight = size.height; +} + +} // extern "C" + +void +imageInterfaceInitCB(AtkImageIface* aIface) +{ + NS_ASSERTION(aIface, "no interface!"); + if (MOZ_UNLIKELY(!aIface)) + return; + + aIface->get_image_position = getImagePositionCB; + aIface->get_image_description = getImageDescriptionCB; + aIface->get_image_size = getImageSizeCB; +} diff --git a/accessible/atk/nsMaiInterfaceSelection.cpp b/accessible/atk/nsMaiInterfaceSelection.cpp new file mode 100644 index 0000000000..2ce63a4513 --- /dev/null +++ b/accessible/atk/nsMaiInterfaceSelection.cpp @@ -0,0 +1,152 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "InterfaceInitFuncs.h" + +#include "Accessible-inl.h" +#include "AccessibleWrap.h" +#include "nsMai.h" +#include "ProxyAccessible.h" +#include "mozilla/Likely.h" + +#include + +using namespace mozilla::a11y; + +extern "C" { + +static gboolean +addSelectionCB(AtkSelection *aSelection, gint i) +{ + AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aSelection)); + if (accWrap && accWrap->IsSelect()) { + return accWrap->AddItemToSelection(i); + } + + if (ProxyAccessible* proxy = GetProxy(ATK_OBJECT(aSelection))) { + return proxy->AddItemToSelection(i); + } + + return FALSE; +} + +static gboolean +clearSelectionCB(AtkSelection *aSelection) +{ + AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aSelection)); + if (accWrap && accWrap->IsSelect()) { + return accWrap->UnselectAll(); + } + + if (ProxyAccessible* proxy = GetProxy(ATK_OBJECT(aSelection))) { + return proxy->UnselectAll(); + } + + return FALSE; +} + +static AtkObject* +refSelectionCB(AtkSelection *aSelection, gint i) +{ + AtkObject* atkObj = nullptr; + AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aSelection)); + if (accWrap && accWrap->IsSelect()) { + Accessible* selectedItem = accWrap->GetSelectedItem(i); + if (!selectedItem) { + return nullptr; + } + + atkObj = AccessibleWrap::GetAtkObject(selectedItem); + } else if (ProxyAccessible* proxy = GetProxy(ATK_OBJECT(aSelection))) { + ProxyAccessible* selectedItem = proxy->GetSelectedItem(i); + if (selectedItem) { + atkObj = GetWrapperFor(selectedItem); + } + } + + if (atkObj) { + g_object_ref(atkObj); + } + + return atkObj; +} + +static gint +getSelectionCountCB(AtkSelection *aSelection) +{ + AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aSelection)); + if (accWrap && accWrap->IsSelect()) { + return accWrap->SelectedItemCount(); + } + + if (ProxyAccessible* proxy = GetProxy(ATK_OBJECT(aSelection))) { + return proxy->SelectedItemCount(); + } + + return -1; +} + +static gboolean +isChildSelectedCB(AtkSelection *aSelection, gint i) +{ + AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aSelection)); + if (accWrap && accWrap->IsSelect()) { + return accWrap->IsItemSelected(i); + } + + if (ProxyAccessible* proxy = GetProxy(ATK_OBJECT(aSelection))) { + return proxy->IsItemSelected(i); + } + + return FALSE; +} + +static gboolean +removeSelectionCB(AtkSelection *aSelection, gint i) +{ + AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aSelection)); + if (accWrap && accWrap->IsSelect()) { + return accWrap->RemoveItemFromSelection(i); + } + + if (ProxyAccessible* proxy = GetProxy(ATK_OBJECT(aSelection))) { + return proxy->RemoveItemFromSelection(i); + } + + return FALSE; +} + +static gboolean +selectAllSelectionCB(AtkSelection *aSelection) +{ + AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aSelection)); + if (accWrap && accWrap->IsSelect()) { + return accWrap->SelectAll(); + } + + if (ProxyAccessible* proxy = GetProxy(ATK_OBJECT(aSelection))) { + return proxy->SelectAll(); + } + + return FALSE; +} +} + +void +selectionInterfaceInitCB(AtkSelectionIface* aIface) +{ + NS_ASSERTION(aIface, "Invalid aIface"); + if (MOZ_UNLIKELY(!aIface)) + return; + + aIface->add_selection = addSelectionCB; + aIface->clear_selection = clearSelectionCB; + aIface->ref_selection = refSelectionCB; + aIface->get_selection_count = getSelectionCountCB; + aIface->is_child_selected = isChildSelectedCB; + aIface->remove_selection = removeSelectionCB; + aIface->select_all_selection = selectAllSelectionCB; +} diff --git a/accessible/atk/nsMaiInterfaceTable.cpp b/accessible/atk/nsMaiInterfaceTable.cpp new file mode 100644 index 0000000000..c94815f3c8 --- /dev/null +++ b/accessible/atk/nsMaiInterfaceTable.cpp @@ -0,0 +1,391 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "InterfaceInitFuncs.h" + +#include "Accessible-inl.h" +#include "AccessibleWrap.h" +#include "nsAccUtils.h" +#include "TableAccessible.h" +#include "TableCellAccessible.h" +#include "nsMai.h" +#include "ProxyAccessible.h" +#include "nsArrayUtils.h" + +#include "mozilla/Likely.h" + +using namespace mozilla::a11y; + +extern "C" { +static AtkObject* +refAtCB(AtkTable* aTable, gint aRowIdx, gint aColIdx) +{ + if (aRowIdx < 0 || aColIdx < 0) { + return nullptr; + } + + AtkObject* cellAtkObj = nullptr; + AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aTable)); + if (accWrap) { + Accessible* cell = accWrap->AsTable()->CellAt(aRowIdx, aColIdx); + if (!cell) { + return nullptr; + } + + cellAtkObj = AccessibleWrap::GetAtkObject(cell); + } else if (ProxyAccessible* proxy = GetProxy(ATK_OBJECT(aTable))) { + ProxyAccessible* cell = proxy->TableCellAt(aRowIdx, aColIdx); + if (!cell) { + return nullptr; + } + + cellAtkObj = GetWrapperFor(cell); + } + + if (cellAtkObj) { + g_object_ref(cellAtkObj); + } + + return cellAtkObj; +} + +static gint +getIndexAtCB(AtkTable* aTable, gint aRowIdx, gint aColIdx) +{ + if (aRowIdx < 0 || aColIdx < 0) { + return -1; + } + + AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aTable)); + if (accWrap) { + return static_cast(accWrap->AsTable()->CellIndexAt(aRowIdx, aColIdx)); + } + + if (ProxyAccessible* proxy = GetProxy(ATK_OBJECT(aTable))) { + return static_cast(proxy->TableCellIndexAt(aRowIdx, aColIdx)); + } + + return -1; +} + +static gint +getColumnAtIndexCB(AtkTable *aTable, gint aIdx) +{ + if (aIdx < 0) { + return -1; + } + + AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aTable)); + if (accWrap) { + return static_cast(accWrap->AsTable()->ColIndexAt(aIdx)); + } + + if (ProxyAccessible* proxy = GetProxy(ATK_OBJECT(aTable))) { + return static_cast(proxy->TableColumnIndexAt(aIdx)); + } + + return -1; +} + +static gint +getRowAtIndexCB(AtkTable *aTable, gint aIdx) +{ + if (aIdx < 0) { + return -1; + } + + AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aTable)); + if (accWrap) { + return static_cast(accWrap->AsTable()->RowIndexAt(aIdx)); + } + + if (ProxyAccessible* proxy = GetProxy(ATK_OBJECT(aTable))) { + return static_cast(proxy->TableRowIndexAt(aIdx)); + } + + return -1; +} + +static gint +getColumnCountCB(AtkTable *aTable) +{ + AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aTable)); + if (accWrap) { + return static_cast(accWrap->AsTable()->ColCount()); + } + + if (ProxyAccessible* proxy = GetProxy(ATK_OBJECT(aTable))) { + return static_cast(proxy->TableColumnCount()); + } + + return -1; +} + +static gint +getRowCountCB(AtkTable *aTable) +{ + AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aTable)); + if (accWrap) { + return static_cast(accWrap->AsTable()->RowCount()); + } + + if (ProxyAccessible* proxy = GetProxy(ATK_OBJECT(aTable))) { + return static_cast(proxy->TableRowCount()); + } + + return -1; +} + +static gint +getColumnExtentAtCB(AtkTable *aTable, gint aRowIdx, gint aColIdx) +{ + if (aRowIdx < 0 || aColIdx < 0) { + return -1; + } + + AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aTable)); + if (accWrap) { + return static_cast(accWrap->AsTable()->ColExtentAt(aRowIdx, aColIdx)); + } + + if (ProxyAccessible* proxy = GetProxy(ATK_OBJECT(aTable))) { + return static_cast(proxy->TableColumnExtentAt(aRowIdx, aColIdx)); + } + + return -1; +} + +static gint +getRowExtentAtCB(AtkTable *aTable, gint aRowIdx, gint aColIdx) +{ + AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aTable)); + if (accWrap) { + return static_cast(accWrap->AsTable()->RowExtentAt(aRowIdx, aColIdx)); + } + + if (ProxyAccessible* proxy = GetProxy(ATK_OBJECT(aTable))) { + return static_cast(proxy->TableRowExtentAt(aRowIdx, aColIdx)); + } + + return -1; +} + +static AtkObject* +getCaptionCB(AtkTable* aTable) +{ + AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aTable)); + if (accWrap) { + Accessible* caption = accWrap->AsTable()->Caption(); + return caption ? AccessibleWrap::GetAtkObject(caption) : nullptr; + } + + if (ProxyAccessible* proxy = GetProxy(ATK_OBJECT(aTable))) { + ProxyAccessible* caption = proxy->TableCaption(); + return caption ? GetWrapperFor(caption) : nullptr; + } + + return nullptr; +} + +static const gchar* +getColumnDescriptionCB(AtkTable *aTable, gint aColumn) +{ + nsAutoString autoStr; + AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aTable)); + if (accWrap) { + accWrap->AsTable()->ColDescription(aColumn, autoStr); + } else if (ProxyAccessible* proxy = GetProxy(ATK_OBJECT(aTable))) { + proxy->TableColumnDescription(aColumn, autoStr); + } else { + return nullptr; + } + + return AccessibleWrap::ReturnString(autoStr); +} + +static AtkObject* +getColumnHeaderCB(AtkTable *aTable, gint aColIdx) +{ + AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aTable)); + if (accWrap) { + Accessible* header = + AccessibleWrap::GetColumnHeader(accWrap->AsTable(), aColIdx); + return header ? AccessibleWrap::GetAtkObject(header) : nullptr; + } + + if (ProxyAccessible* proxy = GetProxy(ATK_OBJECT(aTable))) { + ProxyAccessible* header = proxy->AtkTableColumnHeader(aColIdx); + return header ? GetWrapperFor(header) : nullptr; + } + + return nullptr; +} + +static const gchar* +getRowDescriptionCB(AtkTable *aTable, gint aRow) +{ + nsAutoString autoStr; + AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aTable)); + if (accWrap) { + accWrap->AsTable()->RowDescription(aRow, autoStr); + } else if (ProxyAccessible* proxy = GetProxy(ATK_OBJECT(aTable))) { + proxy->TableRowDescription(aRow, autoStr); + } else { + return nullptr; + } + + return AccessibleWrap::ReturnString(autoStr); +} + +static AtkObject* +getRowHeaderCB(AtkTable *aTable, gint aRowIdx) +{ + AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aTable)); + if (accWrap) { + Accessible* header = + AccessibleWrap::GetRowHeader(accWrap->AsTable(), aRowIdx); + return header ? AccessibleWrap::GetAtkObject(header) : nullptr; + } + + if (ProxyAccessible* proxy = GetProxy(ATK_OBJECT(aTable))) { + ProxyAccessible* header = proxy->AtkTableRowHeader(aRowIdx); + return header ? GetWrapperFor(header) : nullptr; + } + + return nullptr; +} + +static AtkObject* +getSummaryCB(AtkTable *aTable) +{ + // Neither html:table nor xul:tree nor ARIA grid/tree have an ability to + // link an accessible object to specify a summary. There is closes method + // in TableAccessible::summary to get a summary as a string which is not + // mapped directly to ATK. + return nullptr; +} + +static gint +getSelectedColumnsCB(AtkTable *aTable, gint** aSelected) +{ + *aSelected = nullptr; + + AutoTArray cols; + AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aTable)); + if (accWrap) { + accWrap->AsTable()->SelectedColIndices(&cols); + } else if (ProxyAccessible* proxy = GetProxy(ATK_OBJECT(aTable))) { + proxy->TableSelectedColumnIndices(&cols); + } else { + return 0; + } + + if (cols.IsEmpty()) + return 0; + + gint* atkColumns = g_new(gint, cols.Length()); + if (!atkColumns) { + NS_WARNING("OUT OF MEMORY"); + return 0; + } + + memcpy(atkColumns, cols.Elements(), cols.Length() * sizeof(uint32_t)); + *aSelected = atkColumns; + return cols.Length(); +} + +static gint +getSelectedRowsCB(AtkTable *aTable, gint **aSelected) +{ + AutoTArray rows; + AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aTable)); + if (accWrap) { + accWrap->AsTable()->SelectedRowIndices(&rows); + } else if (ProxyAccessible* proxy = GetProxy(ATK_OBJECT(aTable))) { + proxy->TableSelectedRowIndices(&rows); + } else { + return 0; + } + + gint* atkRows = g_new(gint, rows.Length()); + if (!atkRows) { + NS_WARNING("OUT OF MEMORY"); + return 0; + } + + memcpy(atkRows, rows.Elements(), rows.Length() * sizeof(uint32_t)); + *aSelected = atkRows; + return rows.Length(); +} + +static gboolean +isColumnSelectedCB(AtkTable *aTable, gint aColIdx) +{ + AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aTable)); + if (accWrap) { + return static_cast(accWrap->AsTable()->IsColSelected(aColIdx)); + } else if (ProxyAccessible* proxy = GetProxy(ATK_OBJECT(aTable))) { + return static_cast(proxy->TableColumnSelected(aColIdx)); + } + + return FALSE; +} + +static gboolean +isRowSelectedCB(AtkTable *aTable, gint aRowIdx) +{ + AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aTable)); + if (accWrap) { + return static_cast(accWrap->AsTable()->IsRowSelected(aRowIdx)); + } else if (ProxyAccessible* proxy = GetProxy(ATK_OBJECT(aTable))) { + return static_cast(proxy->TableRowSelected(aRowIdx)); + } + + return FALSE; +} + +static gboolean +isCellSelectedCB(AtkTable *aTable, gint aRowIdx, gint aColIdx) +{ + AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aTable)); + if (accWrap) { + return static_cast(accWrap->AsTable()-> + IsCellSelected(aRowIdx, aColIdx)); + } else if (ProxyAccessible* proxy = GetProxy(ATK_OBJECT(aTable))) { + return static_cast(proxy->TableCellSelected(aRowIdx, aColIdx)); + } + + return FALSE; +} +} + +void +tableInterfaceInitCB(AtkTableIface* aIface) +{ + NS_ASSERTION(aIface, "no interface!"); + if (MOZ_UNLIKELY(!aIface)) + return; + + aIface->ref_at = refAtCB; + aIface->get_index_at = getIndexAtCB; + aIface->get_column_at_index = getColumnAtIndexCB; + aIface->get_row_at_index = getRowAtIndexCB; + aIface->get_n_columns = getColumnCountCB; + aIface->get_n_rows = getRowCountCB; + aIface->get_column_extent_at = getColumnExtentAtCB; + aIface->get_row_extent_at = getRowExtentAtCB; + aIface->get_caption = getCaptionCB; + aIface->get_column_description = getColumnDescriptionCB; + aIface->get_column_header = getColumnHeaderCB; + aIface->get_row_description = getRowDescriptionCB; + aIface->get_row_header = getRowHeaderCB; + aIface->get_summary = getSummaryCB; + aIface->get_selected_columns = getSelectedColumnsCB; + aIface->get_selected_rows = getSelectedRowsCB; + aIface->is_column_selected = isColumnSelectedCB; + aIface->is_row_selected = isRowSelectedCB; + aIface->is_selected = isCellSelectedCB; +} diff --git a/accessible/atk/nsMaiInterfaceTableCell.cpp b/accessible/atk/nsMaiInterfaceTableCell.cpp new file mode 100644 index 0000000000..39bdd40677 --- /dev/null +++ b/accessible/atk/nsMaiInterfaceTableCell.cpp @@ -0,0 +1,216 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "InterfaceInitFuncs.h" + +#include "Accessible-inl.h" +#include "AccessibleWrap.h" +#include "nsAccUtils.h" +#include "TableAccessible.h" +#include "TableCellAccessible.h" +#include "nsMai.h" +#include "ProxyAccessible.h" +#include "nsArrayUtils.h" + +#include "mozilla/Likely.h" + +using namespace mozilla::a11y; + +extern "C" { +static gint +GetColumnSpanCB(AtkTableCell* aCell) +{ + AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aCell)); + if (accWrap) { + return accWrap->AsTableCell()->ColExtent(); + } + + if (ProxyAccessible* proxy = GetProxy(ATK_OBJECT(aCell))) { + return proxy->ColExtent(); + } + + return 0; +} + +static gboolean +GetRowSpanCB(AtkTableCell* aCell) +{ + AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aCell)); + if (accWrap) { + return accWrap->AsTableCell()->RowExtent(); + } + + if (ProxyAccessible* proxy = GetProxy(ATK_OBJECT(aCell))) { + return proxy->RowExtent(); + } + + return 0; +} + +static gboolean +GetPositionCB(AtkTableCell* aCell, gint* aRow, gint* aCol) +{ + if (AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aCell))) { + TableCellAccessible* cell = accWrap->AsTableCell(); + *aRow = cell->RowIdx(); + *aCol = cell->ColIdx(); + return true; + } + + if (ProxyAccessible* proxy = GetProxy(ATK_OBJECT(aCell))) { + uint32_t rowIdx = 0, colIdx = 0; + proxy->GetPosition(&rowIdx, &colIdx); + *aCol = colIdx; + *aRow = rowIdx; + return true; + } + + return false; +} + +static gboolean +GetColumnRowSpanCB(AtkTableCell* aCell, gint* aCol, gint* aRow, + gint* aColExtent, gint* aRowExtent) { + if (AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aCell))) { + TableCellAccessible* cellAcc = accWrap->AsTableCell(); + *aCol = cellAcc->ColIdx(); + *aRow = cellAcc->RowIdx(); + *aColExtent = cellAcc->ColExtent(); + *aRowExtent = cellAcc->ColExtent(); + return true; + } + + if (ProxyAccessible* proxy = GetProxy(ATK_OBJECT(aCell))) { + uint32_t colIdx = 0, rowIdx = 0, colExtent = 0, rowExtent = 0; + proxy->GetColRowExtents(&colIdx, &rowIdx, &colExtent, &rowExtent); + *aCol = colIdx; + *aRow = rowIdx; + *aColExtent = colExtent; + *aRowExtent = rowExtent; + return true; + } + + return false; +} + +static AtkObject* +GetTableCB(AtkTableCell* aTableCell) +{ + AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aTableCell)); + if (accWrap) { + TableAccessible* table = accWrap->AsTableCell()->Table(); + if (!table) { + return nullptr; + } + + Accessible* tableAcc = table->AsAccessible(); + return tableAcc ? AccessibleWrap::GetAtkObject(tableAcc) : nullptr; + } + + if (ProxyAccessible* proxy = GetProxy(ATK_OBJECT(aTableCell))) { + ProxyAccessible* table = proxy->TableOfACell(); + return table ? GetWrapperFor(table) : nullptr; + } + + return nullptr; +} + +static GPtrArray* +GetColumnHeaderCellsCB(AtkTableCell* aCell) +{ + if (AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aCell))) { + AutoTArray headers; + accWrap->AsTableCell()->ColHeaderCells(&headers); + if (headers.IsEmpty()) { + return nullptr; + } + + GPtrArray* atkHeaders = g_ptr_array_sized_new(headers.Length()); + for (Accessible* header: headers) { + AtkObject* atkHeader = AccessibleWrap::GetAtkObject(header); + g_object_ref(atkHeader); + g_ptr_array_add(atkHeaders, atkHeader); + } + + return atkHeaders; + } + + if (ProxyAccessible* proxy = GetProxy(ATK_OBJECT(aCell))) { + AutoTArray headers; + proxy->ColHeaderCells(&headers); + if (headers.IsEmpty()) { + return nullptr; + } + + GPtrArray* atkHeaders = g_ptr_array_sized_new(headers.Length()); + for (ProxyAccessible* header: headers) { + AtkObject* atkHeader = GetWrapperFor(header); + g_object_ref(atkHeader); + g_ptr_array_add(atkHeaders, atkHeader); + } + + return atkHeaders; + } + + return nullptr; +} + +static GPtrArray* +GetRowHeaderCellsCB(AtkTableCell* aCell) +{ + if (AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aCell))) { + AutoTArray headers; + accWrap->AsTableCell()->RowHeaderCells(&headers); + if (headers.IsEmpty()) { + return nullptr; + } + + GPtrArray* atkHeaders = g_ptr_array_sized_new(headers.Length()); + for (Accessible* header: headers) { + AtkObject* atkHeader = AccessibleWrap::GetAtkObject(header); + g_object_ref(atkHeader); + g_ptr_array_add(atkHeaders, atkHeader); + } + + return atkHeaders; + } + + if (ProxyAccessible* proxy = GetProxy(ATK_OBJECT(aCell))) { + AutoTArray headers; + proxy->RowHeaderCells(&headers); + if (headers.IsEmpty()) { + return nullptr; + } + + GPtrArray* atkHeaders = g_ptr_array_sized_new(headers.Length()); + for (ProxyAccessible* header: headers) { + AtkObject* atkHeader = GetWrapperFor(header); + g_object_ref(atkHeader); + g_ptr_array_add(atkHeaders, atkHeader); + } + + return atkHeaders; + } + + return nullptr; +} +} + +void +tableCellInterfaceInitCB(AtkTableCellIface* aIface) +{ + NS_ASSERTION(aIface, "no interface!"); + if (MOZ_UNLIKELY(!aIface)) + return; + + aIface->get_column_span = GetColumnSpanCB; + aIface->get_column_header_cells = GetColumnHeaderCellsCB; + aIface->get_position = GetPositionCB; + aIface->get_row_span = GetRowSpanCB; + aIface->get_row_header_cells = GetRowHeaderCellsCB; + aIface->get_row_column_span = GetColumnRowSpanCB; + aIface->get_table = GetTableCB; +} diff --git a/accessible/atk/nsMaiInterfaceText.cpp b/accessible/atk/nsMaiInterfaceText.cpp new file mode 100644 index 0000000000..1982f37309 --- /dev/null +++ b/accessible/atk/nsMaiInterfaceText.cpp @@ -0,0 +1,629 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "InterfaceInitFuncs.h" +#include "mozilla/a11y/PDocAccessible.h" +#include "Accessible-inl.h" +#include "HyperTextAccessible-inl.h" +#include "nsMai.h" +#include "ProxyAccessible.h" + +#include "nsIAccessibleTypes.h" +#include "nsIPersistentProperties2.h" +#include "nsISimpleEnumerator.h" + +#include "mozilla/Likely.h" + +using namespace mozilla; +using namespace mozilla::a11y; + +static const char* sAtkTextAttrNames[ATK_TEXT_ATTR_LAST_DEFINED]; + +void +ConvertTextAttributeToAtkAttribute(const nsACString& aName, + const nsAString& aValue, + AtkAttributeSet** aAttributeSet) +{ + // Handle attributes where atk has its own name. + const char* atkName = nullptr; + nsAutoString atkValue; + if (aName.EqualsLiteral("color")) { + // The format of the atk attribute is r,g,b and the gecko one is + // rgb(r, g, b). + atkValue = Substring(aValue, 4, aValue.Length() - 5); + atkValue.StripWhitespace(); + atkName = sAtkTextAttrNames[ATK_TEXT_ATTR_FG_COLOR]; + } else if (aName.EqualsLiteral("background-color")) { + // The format of the atk attribute is r,g,b and the gecko one is + // rgb(r, g, b). + atkValue = Substring(aValue, 4, aValue.Length() - 5); + atkValue.StripWhitespace(); + atkName = sAtkTextAttrNames[ATK_TEXT_ATTR_BG_COLOR]; + } else if (aName.EqualsLiteral("font-family")) { + atkValue = aValue; + atkName = sAtkTextAttrNames[ATK_TEXT_ATTR_FAMILY_NAME]; + } else if (aName.EqualsLiteral("font-size")) { + // ATK wants the number of pixels without px at the end. + atkValue = StringHead(aValue, aValue.Length() - 2); + atkName = sAtkTextAttrNames[ATK_TEXT_ATTR_SIZE]; + } else if (aName.EqualsLiteral("font-weight")) { + atkValue = aValue; + atkName = sAtkTextAttrNames[ATK_TEXT_ATTR_WEIGHT]; + } else if (aName.EqualsLiteral("invalid")) { + atkValue = aValue; + atkName = sAtkTextAttrNames[ATK_TEXT_ATTR_INVALID]; + } + + if (atkName) { + AtkAttribute* objAttr = + static_cast(g_malloc(sizeof(AtkAttribute))); + objAttr->name = g_strdup(atkName); + objAttr->value = g_strdup(NS_ConvertUTF16toUTF8(atkValue).get()); + *aAttributeSet = g_slist_prepend(*aAttributeSet, objAttr); + } +} + +static AtkAttributeSet* +ConvertToAtkTextAttributeSet(nsTArray& aAttributes) +{ + AtkAttributeSet* objAttributeSet = nullptr; + for (size_t i = 0; i < aAttributes.Length(); ++i) { + AtkAttribute* objAttr = (AtkAttribute *)g_malloc(sizeof(AtkAttribute)); + objAttr->name = g_strdup(aAttributes[i].Name().get()); + objAttr->value = + g_strdup(NS_ConvertUTF16toUTF8(aAttributes[i].Value()).get()); + objAttributeSet = g_slist_prepend(objAttributeSet, objAttr); + ConvertTextAttributeToAtkAttribute(aAttributes[i].Name(), + aAttributes[i].Value(), + &objAttributeSet); + } + return objAttributeSet; +} + +static AtkAttributeSet* +ConvertToAtkTextAttributeSet(nsIPersistentProperties* aAttributes) +{ + if (!aAttributes) + return nullptr; + + AtkAttributeSet* objAttributeSet = nullptr; + nsCOMPtr propEnum; + nsresult rv = aAttributes->Enumerate(getter_AddRefs(propEnum)); + NS_ENSURE_SUCCESS(rv, nullptr); + + bool hasMore = false; + while (NS_SUCCEEDED(propEnum->HasMoreElements(&hasMore)) && hasMore) { + nsCOMPtr sup; + rv = propEnum->GetNext(getter_AddRefs(sup)); + NS_ENSURE_SUCCESS(rv, objAttributeSet); + + nsCOMPtr propElem(do_QueryInterface(sup)); + NS_ENSURE_TRUE(propElem, objAttributeSet); + + nsAutoCString name; + rv = propElem->GetKey(name); + NS_ENSURE_SUCCESS(rv, objAttributeSet); + + nsAutoString value; + rv = propElem->GetValue(value); + NS_ENSURE_SUCCESS(rv, objAttributeSet); + + AtkAttribute* objAttr = (AtkAttribute*)g_malloc(sizeof(AtkAttribute)); + objAttr->name = g_strdup(name.get()); + objAttr->value = g_strdup(NS_ConvertUTF16toUTF8(value).get()); + objAttributeSet = g_slist_prepend(objAttributeSet, objAttr); + + ConvertTextAttributeToAtkAttribute(name, value, &objAttributeSet); + } + + // libatk-adaptor will free it + return objAttributeSet; +} + +static void +ConvertTexttoAsterisks(AccessibleWrap* accWrap, nsAString& aString) +{ + // convert each char to "*" when it's "password text" + if (accWrap->NativeRole() == roles::PASSWORD_TEXT) { + for (uint32_t i = 0; i < aString.Length(); i++) + aString.Replace(i, 1, NS_LITERAL_STRING("*")); + } +} + +extern "C" { + +static gchar* +getTextCB(AtkText *aText, gint aStartOffset, gint aEndOffset) +{ + AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aText)); + nsAutoString autoStr; + if (accWrap) { + HyperTextAccessible* text = accWrap->AsHyperText(); + if (!text || !text->IsTextRole()) + return nullptr; + + text->TextSubstring(aStartOffset, aEndOffset, autoStr); + + ConvertTexttoAsterisks(accWrap, autoStr); + } else if (ProxyAccessible* proxy = GetProxy(ATK_OBJECT(aText))) { + proxy->TextSubstring(aStartOffset, aEndOffset, autoStr); + } + + NS_ConvertUTF16toUTF8 cautoStr(autoStr); + + //copy and return, libspi will free it. + return (cautoStr.get()) ? g_strdup(cautoStr.get()) : nullptr; +} + +static gchar* +getTextAfterOffsetCB(AtkText *aText, gint aOffset, + AtkTextBoundary aBoundaryType, + gint *aStartOffset, gint *aEndOffset) +{ + nsAutoString autoStr; + int32_t startOffset = 0, endOffset = 0; + AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aText)); + if (accWrap) { + HyperTextAccessible* text = accWrap->AsHyperText(); + if (!text || !text->IsTextRole()) + return nullptr; + + text->TextAfterOffset(aOffset, aBoundaryType, &startOffset, &endOffset, autoStr); + ConvertTexttoAsterisks(accWrap, autoStr); + } else if (ProxyAccessible* proxy = GetProxy(ATK_OBJECT(aText))) { + proxy->GetTextAfterOffset(aOffset, aBoundaryType, autoStr, &startOffset, + &endOffset); + } + + *aStartOffset = startOffset; + *aEndOffset = endOffset; + + NS_ConvertUTF16toUTF8 cautoStr(autoStr); + return (cautoStr.get()) ? g_strdup(cautoStr.get()) : nullptr; +} + +static gchar* +getTextAtOffsetCB(AtkText *aText, gint aOffset, + AtkTextBoundary aBoundaryType, + gint *aStartOffset, gint *aEndOffset) +{ + nsAutoString autoStr; + int32_t startOffset = 0, endOffset = 0; + AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aText)); + if (accWrap) { + HyperTextAccessible* text = accWrap->AsHyperText(); + if (!text || !text->IsTextRole()) + return nullptr; + + text->TextAtOffset(aOffset, aBoundaryType, &startOffset, &endOffset, autoStr); + ConvertTexttoAsterisks(accWrap, autoStr); + } else if (ProxyAccessible* proxy = GetProxy(ATK_OBJECT(aText))) { + proxy->GetTextAtOffset(aOffset, aBoundaryType, autoStr, &startOffset, + &endOffset); + } + + *aStartOffset = startOffset; + *aEndOffset = endOffset; + + NS_ConvertUTF16toUTF8 cautoStr(autoStr); + return (cautoStr.get()) ? g_strdup(cautoStr.get()) : nullptr; +} + +static gunichar +getCharacterAtOffsetCB(AtkText* aText, gint aOffset) +{ + AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aText)); + if (accWrap) { + HyperTextAccessible* text = accWrap->AsHyperText(); + if (!text || !text->IsTextRole()) { + return 0; + } + + // char16_t is unsigned short in Mozilla, gnuichar is guint32 in glib. + return static_cast(text->CharAt(aOffset)); + } + + if (ProxyAccessible* proxy = GetProxy(ATK_OBJECT(aText))) { + return static_cast(proxy->CharAt(aOffset)); + } + + return 0; +} + +static gchar* +getTextBeforeOffsetCB(AtkText *aText, gint aOffset, + AtkTextBoundary aBoundaryType, + gint *aStartOffset, gint *aEndOffset) +{ + nsAutoString autoStr; + int32_t startOffset = 0, endOffset = 0; + AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aText)); + if (accWrap) { + HyperTextAccessible* text = accWrap->AsHyperText(); + if (!text || !text->IsTextRole()) + return nullptr; + + text->TextBeforeOffset(aOffset, aBoundaryType, + &startOffset, &endOffset, autoStr); + ConvertTexttoAsterisks(accWrap, autoStr); + } else if (ProxyAccessible* proxy = GetProxy(ATK_OBJECT(aText))) { + proxy->GetTextBeforeOffset(aOffset, aBoundaryType, autoStr, &startOffset, + &endOffset); + } + + *aStartOffset = startOffset; + *aEndOffset = endOffset; + + NS_ConvertUTF16toUTF8 cautoStr(autoStr); + return (cautoStr.get()) ? g_strdup(cautoStr.get()) : nullptr; +} + +static gint +getCaretOffsetCB(AtkText *aText) +{ + AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aText)); + if (accWrap) { + HyperTextAccessible* text = accWrap->AsHyperText(); + if (!text || !text->IsTextRole()) { + return 0; + } + + return static_cast(text->CaretOffset()); + } + + if (ProxyAccessible* proxy = GetProxy(ATK_OBJECT(aText))) { + return static_cast(proxy->CaretOffset()); + } + + return 0; +} + +static AtkAttributeSet* +getRunAttributesCB(AtkText *aText, gint aOffset, + gint *aStartOffset, + gint *aEndOffset) +{ + *aStartOffset = -1; + *aEndOffset = -1; + int32_t startOffset = 0, endOffset = 0; + + AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aText)); + if (accWrap) { + HyperTextAccessible* text = accWrap->AsHyperText(); + if (!text || !text->IsTextRole()) { + return nullptr; + } + + nsCOMPtr attributes = + text->TextAttributes(false, aOffset, &startOffset, &endOffset); + + *aStartOffset = startOffset; + *aEndOffset = endOffset; + + return ConvertToAtkTextAttributeSet(attributes); + } + + ProxyAccessible* proxy = GetProxy(ATK_OBJECT(aText)); + if (!proxy) { + return nullptr; + } + + AutoTArray attrs; + proxy->TextAttributes(false, aOffset, &attrs, &startOffset, &endOffset); + *aStartOffset = startOffset; + *aEndOffset = endOffset; + return ConvertToAtkTextAttributeSet(attrs); +} + +static AtkAttributeSet* +getDefaultAttributesCB(AtkText *aText) +{ + AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aText)); + if (accWrap) { + HyperTextAccessible* text = accWrap->AsHyperText(); + if (!text || !text->IsTextRole()) { + return nullptr; + } + + nsCOMPtr attributes = text->DefaultTextAttributes(); + return ConvertToAtkTextAttributeSet(attributes); + } + + ProxyAccessible* proxy = GetProxy(ATK_OBJECT(aText)); + if (!proxy) { + return nullptr; + } + + AutoTArray attrs; + proxy->DefaultTextAttributes(&attrs); + return ConvertToAtkTextAttributeSet(attrs); +} + +static void +getCharacterExtentsCB(AtkText *aText, gint aOffset, + gint *aX, gint *aY, + gint *aWidth, gint *aHeight, + AtkCoordType aCoords) +{ + if(!aX || !aY || !aWidth || !aHeight) { + return; + } + + nsIntRect rect; + uint32_t geckoCoordType; + if (aCoords == ATK_XY_SCREEN) { + geckoCoordType = nsIAccessibleCoordinateType::COORDTYPE_SCREEN_RELATIVE; + } else { + geckoCoordType = nsIAccessibleCoordinateType::COORDTYPE_WINDOW_RELATIVE; + } + + AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aText)); + if (accWrap) { + HyperTextAccessible* text = accWrap->AsHyperText(); + if (!text || !text->IsTextRole()) { + return; + } + + rect = text->CharBounds(aOffset, geckoCoordType); + } else if (ProxyAccessible* proxy = GetProxy(ATK_OBJECT(aText))) { + rect = proxy->CharBounds(aOffset, geckoCoordType); + } else { + return; + } + + *aX = rect.x; + *aY = rect.y; + *aWidth = rect.width; + *aHeight = rect.height; +} + +static void +getRangeExtentsCB(AtkText *aText, gint aStartOffset, gint aEndOffset, + AtkCoordType aCoords, AtkTextRectangle *aRect) +{ + if (!aRect) { + return; + } + + nsIntRect rect; + uint32_t geckoCoordType; + if (aCoords == ATK_XY_SCREEN) { + geckoCoordType = nsIAccessibleCoordinateType::COORDTYPE_SCREEN_RELATIVE; + } else { + geckoCoordType = nsIAccessibleCoordinateType::COORDTYPE_WINDOW_RELATIVE; + } + + AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aText)); + if(accWrap) { + HyperTextAccessible* text = accWrap->AsHyperText(); + if (!text || !text->IsTextRole()) { + return; + } + + rect = text->TextBounds(aStartOffset, aEndOffset, geckoCoordType); + } else if (ProxyAccessible* proxy = GetProxy(ATK_OBJECT(aText))) { + rect = proxy->TextBounds(aStartOffset, aEndOffset, geckoCoordType); + } else { + return; + } + + aRect->x = rect.x; + aRect->y = rect.y; + aRect->width = rect.width; + aRect->height = rect.height; +} + +static gint +getCharacterCountCB(AtkText *aText) +{ + AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aText)); + if (accWrap) { + HyperTextAccessible* textAcc = accWrap->AsHyperText(); + return + textAcc->IsDefunct() ? 0 : static_cast(textAcc->CharacterCount()); + } + + if (ProxyAccessible* proxy = GetProxy(ATK_OBJECT(aText))) { + return proxy->CharacterCount(); + } + + return 0; +} + +static gint +getOffsetAtPointCB(AtkText *aText, + gint aX, gint aY, + AtkCoordType aCoords) +{ + AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aText)); + if (accWrap) { + HyperTextAccessible* text = accWrap->AsHyperText(); + if (!text || !text->IsTextRole()) { + return -1; + } + + return static_cast( + text->OffsetAtPoint(aX, aY, + (aCoords == ATK_XY_SCREEN ? + nsIAccessibleCoordinateType::COORDTYPE_SCREEN_RELATIVE : + nsIAccessibleCoordinateType::COORDTYPE_WINDOW_RELATIVE))); + } + + if (ProxyAccessible* proxy = GetProxy(ATK_OBJECT(aText))) { + return static_cast( + proxy->OffsetAtPoint(aX, aY, + (aCoords == ATK_XY_SCREEN ? + nsIAccessibleCoordinateType::COORDTYPE_SCREEN_RELATIVE : + nsIAccessibleCoordinateType::COORDTYPE_WINDOW_RELATIVE))); + } + + return -1; +} + +static gint +getTextSelectionCountCB(AtkText *aText) +{ + AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aText)); + if (accWrap) { + HyperTextAccessible* text = accWrap->AsHyperText(); + if (!text || !text->IsTextRole()) { + return 0; + } + + return text->SelectionCount(); + } + + if (ProxyAccessible* proxy = GetProxy(ATK_OBJECT(aText))) { + return proxy->SelectionCount(); + } + + return 0; +} + +static gchar* +getTextSelectionCB(AtkText *aText, gint aSelectionNum, + gint *aStartOffset, gint *aEndOffset) +{ + AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aText)); + int32_t startOffset = 0, endOffset = 0; + if (accWrap) { + HyperTextAccessible* text = accWrap->AsHyperText(); + if (!text || !text->IsTextRole()) { + return nullptr; + } + + text->SelectionBoundsAt(aSelectionNum, &startOffset, &endOffset); + *aStartOffset = startOffset; + *aEndOffset = endOffset; + + return getTextCB(aText, *aStartOffset, *aEndOffset); + } else if (ProxyAccessible* proxy = GetProxy(ATK_OBJECT(aText))) { + nsString data; + proxy->SelectionBoundsAt(aSelectionNum, data, &startOffset, &endOffset); + *aStartOffset = startOffset; + *aEndOffset = endOffset; + + NS_ConvertUTF16toUTF8 dataAsUTF8(data); + return (dataAsUTF8.get()) ? g_strdup(dataAsUTF8.get()) : nullptr; + } + return nullptr; +} + +// set methods +static gboolean +addTextSelectionCB(AtkText *aText, + gint aStartOffset, + gint aEndOffset) +{ + AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aText)); + if (accWrap) { + HyperTextAccessible* text = accWrap->AsHyperText(); + if (!text || !text->IsTextRole()) { + return FALSE; + } + + return text->AddToSelection(aStartOffset, aEndOffset); + } else if (ProxyAccessible* proxy = GetProxy(ATK_OBJECT(aText))) { + return proxy->AddToSelection(aStartOffset, aEndOffset); + } + + return FALSE; +} + +static gboolean +removeTextSelectionCB(AtkText *aText, + gint aSelectionNum) +{ + AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aText)); + if (accWrap) { + HyperTextAccessible* text = accWrap->AsHyperText(); + if (!text || !text->IsTextRole()) { + return FALSE; + } + + return text->RemoveFromSelection(aSelectionNum); + } else if (ProxyAccessible* proxy = GetProxy(ATK_OBJECT(aText))) { + return proxy->RemoveFromSelection(aSelectionNum); + } + + return FALSE; +} + +static gboolean +setTextSelectionCB(AtkText *aText, gint aSelectionNum, + gint aStartOffset, gint aEndOffset) +{ + AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aText)); + if (accWrap) { + HyperTextAccessible* text = accWrap->AsHyperText(); + if (!text || !text->IsTextRole()) { + return FALSE; + } + + return text->SetSelectionBoundsAt(aSelectionNum, aStartOffset, aEndOffset); + } else if (ProxyAccessible* proxy = GetProxy(ATK_OBJECT(aText))) { + return proxy->SetSelectionBoundsAt(aSelectionNum, aStartOffset, aEndOffset); + } + + return FALSE; +} + +static gboolean +setCaretOffsetCB(AtkText *aText, gint aOffset) +{ + AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aText)); + if (accWrap) { + HyperTextAccessible* text = accWrap->AsHyperText(); + if (!text || !text->IsTextRole() || !text->IsValidOffset(aOffset)) { + return FALSE; + } + + text->SetCaretOffset(aOffset); + return TRUE; + } + + if (ProxyAccessible* proxy = GetProxy(ATK_OBJECT(aText))) { + proxy->SetCaretOffset(aOffset); + return TRUE; + } + + return FALSE; +} +} + +void +textInterfaceInitCB(AtkTextIface* aIface) +{ + NS_ASSERTION(aIface, "Invalid aIface"); + if (MOZ_UNLIKELY(!aIface)) + return; + + aIface->get_text = getTextCB; + aIface->get_text_after_offset = getTextAfterOffsetCB; + aIface->get_text_at_offset = getTextAtOffsetCB; + aIface->get_character_at_offset = getCharacterAtOffsetCB; + aIface->get_text_before_offset = getTextBeforeOffsetCB; + aIface->get_caret_offset = getCaretOffsetCB; + aIface->get_run_attributes = getRunAttributesCB; + aIface->get_default_attributes = getDefaultAttributesCB; + aIface->get_character_extents = getCharacterExtentsCB; + aIface->get_range_extents = getRangeExtentsCB; + aIface->get_character_count = getCharacterCountCB; + aIface->get_offset_at_point = getOffsetAtPointCB; + aIface->get_n_selections = getTextSelectionCountCB; + aIface->get_selection = getTextSelectionCB; + + // set methods + aIface->add_selection = addTextSelectionCB; + aIface->remove_selection = removeTextSelectionCB; + aIface->set_selection = setTextSelectionCB; + aIface->set_caret_offset = setCaretOffsetCB; + + // Cache the string values of the atk text attribute names. + for (uint32_t i = 0; i < ArrayLength(sAtkTextAttrNames); i++) + sAtkTextAttrNames[i] = + atk_text_attribute_get_name(static_cast(i)); +} diff --git a/accessible/atk/nsMaiInterfaceValue.cpp b/accessible/atk/nsMaiInterfaceValue.cpp new file mode 100644 index 0000000000..016b3b672c --- /dev/null +++ b/accessible/atk/nsMaiInterfaceValue.cpp @@ -0,0 +1,133 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "InterfaceInitFuncs.h" + +#include "AccessibleWrap.h" +#include "nsMai.h" +#include "ProxyAccessible.h" +#include "mozilla/FloatingPoint.h" +#include "mozilla/Likely.h" + +using namespace mozilla; +using namespace mozilla::a11y; + +extern "C" { + +static void +getCurrentValueCB(AtkValue *obj, GValue *value) +{ + ProxyAccessible* proxy = nullptr; + AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(obj)); + if (!accWrap) { + proxy = GetProxy(ATK_OBJECT(obj)); + if (!proxy) { + return; + } + } + + memset (value, 0, sizeof (GValue)); + double accValue = accWrap ? accWrap->CurValue() : proxy->CurValue(); + if (IsNaN(accValue)) + return; + + g_value_init (value, G_TYPE_DOUBLE); + g_value_set_double (value, accValue); +} + +static void +getMaximumValueCB(AtkValue *obj, GValue *value) +{ + ProxyAccessible* proxy = nullptr; + AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(obj)); + if (!accWrap) { + proxy = GetProxy(ATK_OBJECT(obj)); + if (!proxy) { + return; + } + } + + memset(value, 0, sizeof (GValue)); + double accValue = accWrap ? accWrap->MaxValue() : proxy->MaxValue(); + if (IsNaN(accValue)) + return; + + g_value_init(value, G_TYPE_DOUBLE); + g_value_set_double(value, accValue); +} + +static void +getMinimumValueCB(AtkValue *obj, GValue *value) +{ + ProxyAccessible* proxy = nullptr; + AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(obj)); + if (!accWrap) { + proxy = GetProxy(ATK_OBJECT(obj)); + if (!proxy) { + return; + } + } + + memset(value, 0, sizeof (GValue)); + double accValue = accWrap ? accWrap->MinValue() : proxy->MinValue(); + if (IsNaN(accValue)) + return; + + g_value_init(value, G_TYPE_DOUBLE); + g_value_set_double(value, accValue); +} + +static void +getMinimumIncrementCB(AtkValue *obj, GValue *minimumIncrement) +{ + ProxyAccessible* proxy = nullptr; + AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(obj)); + if (!accWrap) { + proxy = GetProxy(ATK_OBJECT(obj)); + if (!proxy) { + return; + } + } + + memset(minimumIncrement, 0, sizeof (GValue)); + double accValue = accWrap ? accWrap->Step() : proxy->Step(); + if (IsNaN(accValue)) + accValue = 0; // zero if the minimum increment is undefined + + g_value_init(minimumIncrement, G_TYPE_DOUBLE); + g_value_set_double(minimumIncrement, accValue); +} + +static gboolean +setCurrentValueCB(AtkValue *obj, const GValue *value) +{ + ProxyAccessible* proxy = nullptr; + AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(obj)); + if (!accWrap) { + proxy = GetProxy(ATK_OBJECT(obj)); + if (!proxy) { + return FALSE; + } + } + + double accValue =g_value_get_double(value); + return accWrap ? accWrap->SetCurValue(accValue) : proxy->SetCurValue(accValue); +} +} + +void +valueInterfaceInitCB(AtkValueIface* aIface) +{ + NS_ASSERTION(aIface, "Invalid aIface"); + if (MOZ_UNLIKELY(!aIface)) + return; + + aIface->get_current_value = getCurrentValueCB; + aIface->get_maximum_value = getMaximumValueCB; + aIface->get_minimum_value = getMinimumValueCB; + aIface->get_minimum_increment = getMinimumIncrementCB; + aIface->set_current_value = setCurrentValueCB; +} diff --git a/accessible/atk/nsStateMap.h b/accessible/atk/nsStateMap.h new file mode 100644 index 0000000000..2f3cde2407 --- /dev/null +++ b/accessible/atk/nsStateMap.h @@ -0,0 +1,117 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include +#include "AccessibleWrap.h" + +/****************************************************************************** +The following accessible states aren't translated, just ignored: + STATE_READONLY: Supported indirectly via EXT_STATE_EDITABLE + STATE_HOTTRACKED: No ATK equivalent. No known use case. + The nsIAccessible state is not currently supported. + STATE_FLOATING: No ATK equivalent. No known use case. + The nsIAccessible state is not currently supported. + STATE_MOVEABLE: No ATK equivalent. No known use case. + The nsIAccessible state is not currently supported. + STATE_SELFVOICING: No ATK equivalent -- the object has self-TTS. + The nsIAccessible state is not currently supported. + STATE_LINKED: The object is formatted as a hyperlink. Supported via ATK_ROLE_LINK. + STATE_EXTSELECTABLE: Indicates that an object extends its selection. + This is supported via STATE_MULTISELECTABLE. + STATE_PROTECTED: The object is a password-protected edit control. + Supported via ATK_ROLE_PASSWORD_TEXT + STATE_HASPOPUP: Object displays a pop-up menu or window when invoked. + No ATK equivalent. The accessible state is not + currently supported. + STATE_PINNED: The object is pinned, usually indicating it is fixed in + place and has permanence. No ATK equivalent. The + accessible state is not currently supported. + +The following ATK states are not supported: + ATK_STATE_ARMED: No clear use case, used briefly when button is activated + ATK_STATE_HAS_TOOLTIP: No clear use case, no IA2 equivalent + ATK_STATE_ICONIFIED: Mozilla does not have elements which are collapsable into icons + ATK_STATE_TRUNCATED: No clear use case. Indicates that an object's onscreen content is truncated, + e.g. a text value in a spreadsheet cell. No IA2 state. +******************************************************************************/ + +enum EStateMapEntryType { + kMapDirectly, + kMapOpposite, // For example, UNAVAILABLE is the opposite of ENABLED + kNoStateChange, // Don't fire state change event + kNoSuchState +}; + +const AtkStateType kNone = ATK_STATE_INVALID; + +struct AtkStateMap { + AtkStateType atkState; + EStateMapEntryType stateMapEntryType; + + static int32_t GetStateIndexFor(uint64_t aState) + { + int32_t stateIndex = -1; + while (aState > 0) { + ++ stateIndex; + aState >>= 1; + } + return stateIndex; // Returns -1 if not mapped + } +}; + + +// Map array from cross platform states to ATK states +static const AtkStateMap gAtkStateMap[] = { // Cross Platform States + { kNone, kMapOpposite }, // states::UNAVAILABLE = 1 << 0 + { ATK_STATE_SELECTED, kMapDirectly }, // states::SELECTED = 1 << 1 + { ATK_STATE_FOCUSED, kMapDirectly }, // states::FOCUSED = 1 << 2 + { ATK_STATE_PRESSED, kMapDirectly }, // states::PRESSED = 1 << 3 + { ATK_STATE_CHECKED, kMapDirectly }, // states::CHECKED = 1 << 4 + { ATK_STATE_INDETERMINATE, kMapDirectly }, // states::MIXED = 1 << 5 + { kNone, kMapDirectly }, // states::READONLY = 1 << 6 + { kNone, kMapDirectly }, // states::HOTTRACKED = 1 << 7 + { ATK_STATE_DEFAULT, kMapDirectly }, // states::DEFAULT = 1 << 8 + { ATK_STATE_EXPANDED, kMapDirectly }, // states::EXPANDED = 1 << 9 + { kNone, kNoStateChange }, // states::COLLAPSED = 1 << 10 + { ATK_STATE_BUSY, kMapDirectly }, // states::BUSY = 1 << 11 + { kNone, kMapDirectly }, // states::FLOATING = 1 << 12 + { ATK_STATE_CHECKABLE, kMapDirectly }, // states::CHECKABLE = 1 << 13 + { ATK_STATE_ANIMATED, kMapDirectly }, // states::ANIMATED = 1 << 14 + { ATK_STATE_VISIBLE, kMapOpposite }, // states::INVISIBLE = 1 << 15 + { ATK_STATE_SHOWING, kMapOpposite }, // states::OFFSCREEN = 1 << 16 + { ATK_STATE_RESIZABLE, kMapDirectly }, // states::SIZEABLE = 1 << 17 + { kNone, kMapDirectly }, // states::MOVEABLE = 1 << 18 + { kNone, kMapDirectly }, // states::SELFVOICING = 1 << 19 + { ATK_STATE_FOCUSABLE, kMapDirectly }, // states::FOCUSABLE = 1 << 20 + { ATK_STATE_SELECTABLE, kMapDirectly }, // states::SELECTABLE = 1 << 21 + { kNone, kMapDirectly }, // states::LINKED = 1 << 22 + { ATK_STATE_VISITED, kMapDirectly }, // states::TRAVERSED = 1 << 23 + { ATK_STATE_MULTISELECTABLE, kMapDirectly }, // states::MULTISELECTABLE = 1 << 24 + { kNone, kMapDirectly }, // states::EXTSELECTABLE = 1 << 25 + { ATK_STATE_REQUIRED, kMapDirectly }, // states::STATE_REQUIRED = 1 << 26 + { kNone, kMapDirectly }, // states::ALERT_MEDIUM = 1 << 27 + { ATK_STATE_INVALID_ENTRY, kMapDirectly }, // states::INVALID = 1 << 28 + { kNone, kMapDirectly }, // states::PROTECTED = 1 << 29 + { kNone, kMapDirectly }, // states::HASPOPUP = 1 << 30 + { ATK_STATE_SUPPORTS_AUTOCOMPLETION, kMapDirectly }, // states::SUPPORTS_AUTOCOMPLETION = 1 << 31 + { ATK_STATE_DEFUNCT, kMapDirectly }, // states::DEFUNCT = 1 << 32 + { ATK_STATE_SELECTABLE_TEXT, kMapDirectly }, // states::SELECTABLE_TEXT = 1 << 33 + { ATK_STATE_EDITABLE, kMapDirectly }, // states::EDITABLE = 1 << 34 + { ATK_STATE_ACTIVE, kMapDirectly }, // states::ACTIVE = 1 << 35 + { ATK_STATE_MODAL, kMapDirectly }, // states::MODAL = 1 << 36 + { ATK_STATE_MULTI_LINE, kMapDirectly }, // states::MULTI_LINE = 1 << 37 + { ATK_STATE_HORIZONTAL, kMapDirectly }, // states::HORIZONTAL = 1 << 38 + { ATK_STATE_OPAQUE, kMapDirectly }, // states::OPAQUE = 1 << 39 + { ATK_STATE_SINGLE_LINE, kMapDirectly }, // states::SINGLE_LINE = 1 << 40 + { ATK_STATE_TRANSIENT, kMapDirectly }, // states::TRANSIENT = 1 << 41 + { ATK_STATE_VERTICAL, kMapDirectly }, // states::VERTICAL = 1 << 42 + { ATK_STATE_STALE, kMapDirectly }, // states::STALE = 1 << 43 + { ATK_STATE_ENABLED, kMapDirectly }, // states::ENABLED = 1 << 44 + { ATK_STATE_SENSITIVE, kMapDirectly }, // states::SENSITIVE = 1 << 45 + { ATK_STATE_EXPANDABLE, kMapDirectly }, // states::EXPANDABLE = 1 << 46 + { kNone, kMapDirectly }, // states::PINNED = 1 << 47 + { kNone, kNoSuchState }, // = 1 << 48 +}; diff --git a/accessible/base/ARIAMap.cpp b/accessible/base/ARIAMap.cpp new file mode 100644 index 0000000000..c29d37873c --- /dev/null +++ b/accessible/base/ARIAMap.cpp @@ -0,0 +1,1008 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim:expandtab:shiftwidth=2:tabstop=2: + */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "ARIAMap.h" + +#include "nsAccUtils.h" +#include "nsCoreUtils.h" +#include "Role.h" +#include "States.h" + +#include "nsAttrName.h" +#include "nsWhitespaceTokenizer.h" + +#include "mozilla/BinarySearch.h" +#include "mozilla/dom/Element.h" + +using namespace mozilla; +using namespace mozilla::a11y; +using namespace mozilla::a11y::aria; + +static const uint32_t kGenericAccType = 0; + +/** + * This list of WAI-defined roles are currently hardcoded. + * Eventually we will most likely be loading an RDF resource that contains this information + * Using RDF will also allow for role extensibility. See bug 280138. + * + * Definition of nsRoleMapEntry contains comments explaining this table. + * + * When no Role enum mapping exists for an ARIA role, the role will be exposed + * via the object attribute "xml-roles". + */ + +static const nsRoleMapEntry sWAIRoleMaps[] = +{ + { // alert + &nsGkAtoms::alert, + roles::ALERT, + kUseMapRole, + eNoValue, + eNoAction, + eNoLiveAttr, + eAlert, + kNoReqStates + }, + { // alertdialog + &nsGkAtoms::alertdialog, + roles::DIALOG, + kUseMapRole, + eNoValue, + eNoAction, + eNoLiveAttr, + kGenericAccType, + kNoReqStates + }, + { // application + &nsGkAtoms::application, + roles::APPLICATION, + kUseMapRole, + eNoValue, + eNoAction, + eNoLiveAttr, + eLandmark, + kNoReqStates + }, + { // article + &nsGkAtoms::article, + roles::DOCUMENT, + kUseMapRole, + eNoValue, + eNoAction, + eNoLiveAttr, + kGenericAccType, + kNoReqStates, + eReadonlyUntilEditable + }, + { // banner + &nsGkAtoms::banner, + roles::NOTHING, + kUseNativeRole, + eNoValue, + eNoAction, + eNoLiveAttr, + eLandmark, + kNoReqStates + }, + { // button + &nsGkAtoms::button, + roles::PUSHBUTTON, + kUseMapRole, + eNoValue, + ePressAction, + eNoLiveAttr, + eButton, + kNoReqStates + // eARIAPressed is auto applied on any button + }, + { // cell + &nsGkAtoms::cell, + roles::CELL, + kUseMapRole, + eNoValue, + eNoAction, + eNoLiveAttr, + eTableCell, + kNoReqStates + }, + { // checkbox + &nsGkAtoms::checkbox, + roles::CHECKBUTTON, + kUseMapRole, + eNoValue, + eCheckUncheckAction, + eNoLiveAttr, + kGenericAccType, + kNoReqStates, + eARIACheckableMixed, + eARIAReadonly + }, + { // columnheader + &nsGkAtoms::columnheader, + roles::COLUMNHEADER, + kUseMapRole, + eNoValue, + eSortAction, + eNoLiveAttr, + eTableCell, + kNoReqStates, + eARIASelectableIfDefined, + eARIAReadonlyOrEditableIfDefined + }, + { // combobox + &nsGkAtoms::combobox, + roles::COMBOBOX, + kUseMapRole, + eNoValue, + eOpenCloseAction, + eNoLiveAttr, + kGenericAccType, + states::COLLAPSED | states::HASPOPUP | states::VERTICAL, + eARIAAutoComplete, + eARIAReadonly, + eARIAOrientation + }, + { // complementary + &nsGkAtoms::complementary, + roles::NOTHING, + kUseNativeRole, + eNoValue, + eNoAction, + eNoLiveAttr, + eLandmark, + kNoReqStates + }, + { // contentinfo + &nsGkAtoms::contentinfo, + roles::NOTHING, + kUseNativeRole, + eNoValue, + eNoAction, + eNoLiveAttr, + eLandmark, + kNoReqStates + }, + { // dialog + &nsGkAtoms::dialog, + roles::DIALOG, + kUseMapRole, + eNoValue, + eNoAction, + eNoLiveAttr, + kGenericAccType, + kNoReqStates + }, + { // directory + &nsGkAtoms::directory, + roles::LIST, + kUseMapRole, + eNoValue, + eNoAction, + eNoLiveAttr, + eList, + kNoReqStates + }, + { // document + &nsGkAtoms::document, + roles::DOCUMENT, + kUseMapRole, + eNoValue, + eNoAction, + eNoLiveAttr, + kGenericAccType, + kNoReqStates, + eReadonlyUntilEditable + }, + { // feed + &nsGkAtoms::feed, + roles::GROUPING, + kUseMapRole, + eNoValue, + eNoAction, + eNoLiveAttr, + kGenericAccType, + kNoReqStates + }, + { // form + &nsGkAtoms::form, + roles::FORM, + kUseMapRole, + eNoValue, + eNoAction, + eNoLiveAttr, + eLandmark, + kNoReqStates + }, + { // grid + &nsGkAtoms::grid, + roles::TABLE, + kUseMapRole, + eNoValue, + eNoAction, + eNoLiveAttr, + eSelect | eTable, + kNoReqStates, + eARIAMultiSelectable, + eARIAReadonlyOrEditable, + eFocusableUntilDisabled + }, + { // gridcell + &nsGkAtoms::gridcell, + roles::GRID_CELL, + kUseMapRole, + eNoValue, + eNoAction, + eNoLiveAttr, + eTableCell, + kNoReqStates, + eARIASelectable, + eARIAReadonlyOrEditableIfDefined + }, + { // group + &nsGkAtoms::group, + roles::GROUPING, + kUseMapRole, + eNoValue, + eNoAction, + eNoLiveAttr, + kGenericAccType, + kNoReqStates + }, + { // heading + &nsGkAtoms::heading, + roles::HEADING, + kUseMapRole, + eNoValue, + eNoAction, + eNoLiveAttr, + kGenericAccType, + kNoReqStates + }, + { // img + &nsGkAtoms::img, + roles::GRAPHIC, + kUseMapRole, + eNoValue, + eNoAction, + eNoLiveAttr, + kGenericAccType, + kNoReqStates + }, + { // key + &nsGkAtoms::key, + roles::KEY, + kUseMapRole, + eNoValue, + ePressAction, + eNoLiveAttr, + kGenericAccType, + kNoReqStates, + eARIAPressed + }, + { // link + &nsGkAtoms::link, + roles::LINK, + kUseMapRole, + eNoValue, + eJumpAction, + eNoLiveAttr, + kGenericAccType, + states::LINKED + }, + { // list + &nsGkAtoms::list, + roles::LIST, + kUseMapRole, + eNoValue, + eNoAction, + eNoLiveAttr, + eList, + states::READONLY + }, + { // listbox + &nsGkAtoms::listbox, + roles::LISTBOX, + kUseMapRole, + eNoValue, + eNoAction, + eNoLiveAttr, + eListControl | eSelect, + states::VERTICAL, + eARIAMultiSelectable, + eARIAReadonly, + eFocusableUntilDisabled, + eARIAOrientation + }, + { // listitem + &nsGkAtoms::listitem, + roles::LISTITEM, + kUseMapRole, + eNoValue, + eNoAction, // XXX: should depend on state, parent accessible + eNoLiveAttr, + kGenericAccType, + states::READONLY + }, + { // log + &nsGkAtoms::log_, + roles::NOTHING, + kUseNativeRole, + eNoValue, + eNoAction, + ePoliteLiveAttr, + kGenericAccType, + kNoReqStates + }, + { // main + &nsGkAtoms::main, + roles::NOTHING, + kUseNativeRole, + eNoValue, + eNoAction, + eNoLiveAttr, + eLandmark, + kNoReqStates + }, + { // marquee + &nsGkAtoms::marquee, + roles::ANIMATION, + kUseMapRole, + eNoValue, + eNoAction, + eOffLiveAttr, + kGenericAccType, + kNoReqStates + }, + { // math + &nsGkAtoms::math, + roles::FLAT_EQUATION, + kUseMapRole, + eNoValue, + eNoAction, + eNoLiveAttr, + kGenericAccType, + kNoReqStates + }, + { // menu + &nsGkAtoms::menu, + roles::MENUPOPUP, + kUseMapRole, + eNoValue, + eNoAction, // XXX: technically accessibles of menupopup role haven't + // any action, but menu can be open or close. + eNoLiveAttr, + kGenericAccType, + states::VERTICAL, + eARIAOrientation + }, + { // menubar + &nsGkAtoms::menubar, + roles::MENUBAR, + kUseMapRole, + eNoValue, + eNoAction, + eNoLiveAttr, + kGenericAccType, + states::HORIZONTAL, + eARIAOrientation + }, + { // menuitem + &nsGkAtoms::menuitem, + roles::MENUITEM, + kUseMapRole, + eNoValue, + eClickAction, + eNoLiveAttr, + kGenericAccType, + kNoReqStates, + eARIACheckedMixed + }, + { // menuitemcheckbox + &nsGkAtoms::menuitemcheckbox, + roles::CHECK_MENU_ITEM, + kUseMapRole, + eNoValue, + eClickAction, + eNoLiveAttr, + kGenericAccType, + kNoReqStates, + eARIACheckableMixed + }, + { // menuitemradio + &nsGkAtoms::menuitemradio, + roles::RADIO_MENU_ITEM, + kUseMapRole, + eNoValue, + eClickAction, + eNoLiveAttr, + kGenericAccType, + kNoReqStates, + eARIACheckableBool + }, + { // navigation + &nsGkAtoms::navigation, + roles::NOTHING, + kUseNativeRole, + eNoValue, + eNoAction, + eNoLiveAttr, + eLandmark, + kNoReqStates + }, + { // none + &nsGkAtoms::none, + roles::NOTHING, + kUseMapRole, + eNoValue, + eNoAction, + eNoLiveAttr, + kGenericAccType, + kNoReqStates + }, + { // note + &nsGkAtoms::note_, + roles::NOTE, + kUseMapRole, + eNoValue, + eNoAction, + eNoLiveAttr, + kGenericAccType, + kNoReqStates + }, + { // option + &nsGkAtoms::option, + roles::OPTION, + kUseMapRole, + eNoValue, + eSelectAction, + eNoLiveAttr, + kGenericAccType, + kNoReqStates, + eARIASelectable, + eARIACheckedMixed + }, + { // presentation + &nsGkAtoms::presentation, + roles::NOTHING, + kUseMapRole, + eNoValue, + eNoAction, + eNoLiveAttr, + kGenericAccType, + kNoReqStates + }, + { // progressbar + &nsGkAtoms::progressbar, + roles::PROGRESSBAR, + kUseMapRole, + eHasValueMinMax, + eNoAction, + eNoLiveAttr, + kGenericAccType, + states::READONLY, + eIndeterminateIfNoValue + }, + { // radio + &nsGkAtoms::radio, + roles::RADIOBUTTON, + kUseMapRole, + eNoValue, + eSelectAction, + eNoLiveAttr, + kGenericAccType, + kNoReqStates, + eARIACheckableBool + }, + { // radiogroup + &nsGkAtoms::radiogroup, + roles::RADIO_GROUP, + kUseMapRole, + eNoValue, + eNoAction, + eNoLiveAttr, + kGenericAccType, + kNoReqStates, + eARIAOrientation + }, + { // region + &nsGkAtoms::region, + roles::PANE, + kUseMapRole, + eNoValue, + eNoAction, + eNoLiveAttr, + kGenericAccType, + kNoReqStates + }, + { // row + &nsGkAtoms::row, + roles::ROW, + kUseMapRole, + eNoValue, + eNoAction, + eNoLiveAttr, + eTableRow, + kNoReqStates, + eARIASelectable + }, + { // rowgroup + &nsGkAtoms::rowgroup, + roles::GROUPING, + kUseMapRole, + eNoValue, + eNoAction, + eNoLiveAttr, + kGenericAccType, + kNoReqStates + }, + { // rowheader + &nsGkAtoms::rowheader, + roles::ROWHEADER, + kUseMapRole, + eNoValue, + eSortAction, + eNoLiveAttr, + eTableCell, + kNoReqStates, + eARIASelectableIfDefined, + eARIAReadonlyOrEditableIfDefined + }, + { // scrollbar + &nsGkAtoms::scrollbar, + roles::SCROLLBAR, + kUseMapRole, + eHasValueMinMax, + eNoAction, + eNoLiveAttr, + kGenericAccType, + states::VERTICAL, + eARIAOrientation, + eARIAReadonly + }, + { // search + &nsGkAtoms::search, + roles::NOTHING, + kUseNativeRole, + eNoValue, + eNoAction, + eNoLiveAttr, + eLandmark, + kNoReqStates + }, + { // searchbox + &nsGkAtoms::searchbox, + roles::ENTRY, + kUseMapRole, + eNoValue, + eActivateAction, + eNoLiveAttr, + kGenericAccType, + kNoReqStates, + eARIAAutoComplete, + eARIAMultiline, + eARIAReadonlyOrEditable + }, + { // separator + &nsGkAtoms::separator_, + roles::SEPARATOR, + kUseMapRole, + eNoValue, + eNoAction, + eNoLiveAttr, + kGenericAccType, + states::HORIZONTAL, + eARIAOrientation + }, + { // slider + &nsGkAtoms::slider, + roles::SLIDER, + kUseMapRole, + eHasValueMinMax, + eNoAction, + eNoLiveAttr, + kGenericAccType, + states::HORIZONTAL, + eARIAOrientation, + eARIAReadonly + }, + { // spinbutton + &nsGkAtoms::spinbutton, + roles::SPINBUTTON, + kUseMapRole, + eHasValueMinMax, + eNoAction, + eNoLiveAttr, + kGenericAccType, + kNoReqStates, + eARIAReadonly + }, + { // status + &nsGkAtoms::status, + roles::STATUSBAR, + kUseMapRole, + eNoValue, + eNoAction, + ePoliteLiveAttr, + kGenericAccType, + kNoReqStates + }, + { // switch + &nsGkAtoms::_switch, + roles::SWITCH, + kUseMapRole, + eNoValue, + eCheckUncheckAction, + eNoLiveAttr, + kGenericAccType, + kNoReqStates, + eARIACheckableBool + }, + { // tab + &nsGkAtoms::tab, + roles::PAGETAB, + kUseMapRole, + eNoValue, + eSwitchAction, + eNoLiveAttr, + kGenericAccType, + kNoReqStates, + eARIASelectable + }, + { // table + &nsGkAtoms::table, + roles::TABLE, + kUseMapRole, + eNoValue, + eNoAction, + eNoLiveAttr, + eTable, + kNoReqStates, + eARIASelectable + }, + { // tablist + &nsGkAtoms::tablist, + roles::PAGETABLIST, + kUseMapRole, + eNoValue, + eNoAction, + eNoLiveAttr, + eSelect, + states::HORIZONTAL, + eARIAOrientation + }, + { // tabpanel + &nsGkAtoms::tabpanel, + roles::PROPERTYPAGE, + kUseMapRole, + eNoValue, + eNoAction, + eNoLiveAttr, + kGenericAccType, + kNoReqStates + }, + { // textbox + &nsGkAtoms::textbox, + roles::ENTRY, + kUseMapRole, + eNoValue, + eActivateAction, + eNoLiveAttr, + kGenericAccType, + kNoReqStates, + eARIAAutoComplete, + eARIAMultiline, + eARIAReadonlyOrEditable + }, + { // timer + &nsGkAtoms::timer, + roles::NOTHING, + kUseNativeRole, + eNoValue, + eNoAction, + eOffLiveAttr, + kNoReqStates + }, + { // toolbar + &nsGkAtoms::toolbar, + roles::TOOLBAR, + kUseMapRole, + eNoValue, + eNoAction, + eNoLiveAttr, + kGenericAccType, + states::HORIZONTAL, + eARIAOrientation + }, + { // tooltip + &nsGkAtoms::tooltip, + roles::TOOLTIP, + kUseMapRole, + eNoValue, + eNoAction, + eNoLiveAttr, + kGenericAccType, + kNoReqStates + }, + { // tree + &nsGkAtoms::tree, + roles::OUTLINE, + kUseMapRole, + eNoValue, + eNoAction, + eNoLiveAttr, + eSelect, + states::VERTICAL, + eARIAReadonly, + eARIAMultiSelectable, + eFocusableUntilDisabled, + eARIAOrientation + }, + { // treegrid + &nsGkAtoms::treegrid, + roles::TREE_TABLE, + kUseMapRole, + eNoValue, + eNoAction, + eNoLiveAttr, + eSelect | eTable, + states::VERTICAL, + eARIAReadonlyOrEditable, + eARIAMultiSelectable, + eFocusableUntilDisabled, + eARIAOrientation + }, + { // treeitem + &nsGkAtoms::treeitem, + roles::OUTLINEITEM, + kUseMapRole, + eNoValue, + eActivateAction, // XXX: should expose second 'expand/collapse' action based + // on states + eNoLiveAttr, + kGenericAccType, + kNoReqStates, + eARIASelectable, + eARIACheckedMixed + } +}; + +static const nsRoleMapEntry sLandmarkRoleMap = { + &nsGkAtoms::_empty, + roles::NOTHING, + kUseNativeRole, + eNoValue, + eNoAction, + eNoLiveAttr, + kGenericAccType, + kNoReqStates +}; + +nsRoleMapEntry aria::gEmptyRoleMap = { + &nsGkAtoms::_empty, + roles::NOTHING, + kUseMapRole, + eNoValue, + eNoAction, + eNoLiveAttr, + kGenericAccType, + kNoReqStates +}; + +/** + * Universal (Global) states: + * The following state rules are applied to any accessible element, + * whether there is an ARIA role or not: + */ +static const EStateRule sWAIUnivStateMap[] = { + eARIABusy, + eARIADisabled, + eARIAExpanded, // Currently under spec review but precedent exists + eARIAHasPopup, // Note this is technically a "property" + eARIAInvalid, + eARIAModal, + eARIARequired, // XXX not global, Bug 553117 + eARIANone +}; + + +/** + * ARIA attribute map for attribute characteristics. + * @note ARIA attributes that don't have any flags are not included here. + */ + +struct AttrCharacteristics +{ + nsIAtom** attributeName; + const uint8_t characteristics; +}; + +static const AttrCharacteristics gWAIUnivAttrMap[] = { + {&nsGkAtoms::aria_activedescendant, ATTR_BYPASSOBJ }, + {&nsGkAtoms::aria_atomic, ATTR_BYPASSOBJ_IF_FALSE | ATTR_VALTOKEN | ATTR_GLOBAL }, + {&nsGkAtoms::aria_busy, ATTR_VALTOKEN | ATTR_GLOBAL }, + {&nsGkAtoms::aria_checked, ATTR_BYPASSOBJ | ATTR_VALTOKEN }, /* exposes checkable obj attr */ + {&nsGkAtoms::aria_controls, ATTR_BYPASSOBJ | ATTR_GLOBAL }, + {&nsGkAtoms::aria_describedby, ATTR_BYPASSOBJ | ATTR_GLOBAL }, + {&nsGkAtoms::aria_details, ATTR_BYPASSOBJ | ATTR_GLOBAL }, + {&nsGkAtoms::aria_disabled, ATTR_BYPASSOBJ | ATTR_VALTOKEN | ATTR_GLOBAL }, + {&nsGkAtoms::aria_dropeffect, ATTR_VALTOKEN | ATTR_GLOBAL }, + {&nsGkAtoms::aria_errormessage, ATTR_BYPASSOBJ | ATTR_GLOBAL }, + {&nsGkAtoms::aria_expanded, ATTR_BYPASSOBJ | ATTR_VALTOKEN }, + {&nsGkAtoms::aria_flowto, ATTR_BYPASSOBJ | ATTR_GLOBAL }, + {&nsGkAtoms::aria_grabbed, ATTR_VALTOKEN | ATTR_GLOBAL }, + {&nsGkAtoms::aria_haspopup, ATTR_BYPASSOBJ | ATTR_VALTOKEN | ATTR_GLOBAL }, + {&nsGkAtoms::aria_hidden, ATTR_BYPASSOBJ | ATTR_VALTOKEN | ATTR_GLOBAL }, /* handled special way */ + {&nsGkAtoms::aria_invalid, ATTR_BYPASSOBJ | ATTR_VALTOKEN | ATTR_GLOBAL }, + {&nsGkAtoms::aria_label, ATTR_BYPASSOBJ | ATTR_GLOBAL }, + {&nsGkAtoms::aria_labelledby, ATTR_BYPASSOBJ | ATTR_GLOBAL }, + {&nsGkAtoms::aria_level, ATTR_BYPASSOBJ }, /* handled via groupPosition */ + {&nsGkAtoms::aria_live, ATTR_VALTOKEN | ATTR_GLOBAL }, + {&nsGkAtoms::aria_modal, ATTR_BYPASSOBJ | ATTR_VALTOKEN | ATTR_GLOBAL }, + {&nsGkAtoms::aria_multiline, ATTR_BYPASSOBJ | ATTR_VALTOKEN }, + {&nsGkAtoms::aria_multiselectable, ATTR_BYPASSOBJ | ATTR_VALTOKEN }, + {&nsGkAtoms::aria_owns, ATTR_BYPASSOBJ | ATTR_GLOBAL }, + {&nsGkAtoms::aria_orientation, ATTR_VALTOKEN }, + {&nsGkAtoms::aria_posinset, ATTR_BYPASSOBJ }, /* handled via groupPosition */ + {&nsGkAtoms::aria_pressed, ATTR_BYPASSOBJ | ATTR_VALTOKEN }, + {&nsGkAtoms::aria_readonly, ATTR_BYPASSOBJ | ATTR_VALTOKEN }, + {&nsGkAtoms::aria_relevant, ATTR_BYPASSOBJ | ATTR_GLOBAL }, + {&nsGkAtoms::aria_required, ATTR_BYPASSOBJ | ATTR_VALTOKEN }, + {&nsGkAtoms::aria_selected, ATTR_BYPASSOBJ | ATTR_VALTOKEN }, + {&nsGkAtoms::aria_setsize, ATTR_BYPASSOBJ }, /* handled via groupPosition */ + {&nsGkAtoms::aria_sort, ATTR_VALTOKEN }, + {&nsGkAtoms::aria_valuenow, ATTR_BYPASSOBJ }, + {&nsGkAtoms::aria_valuemin, ATTR_BYPASSOBJ }, + {&nsGkAtoms::aria_valuemax, ATTR_BYPASSOBJ }, + {&nsGkAtoms::aria_valuetext, ATTR_BYPASSOBJ } +}; + +namespace { + +struct RoleComparator +{ + const nsDependentSubstring& mRole; + explicit RoleComparator(const nsDependentSubstring& aRole) : mRole(aRole) {} + int operator()(const nsRoleMapEntry& aEntry) const { + return Compare(mRole, aEntry.ARIARoleString()); + } +}; + +} + +const nsRoleMapEntry* +aria::GetRoleMap(dom::Element* aEl) +{ + return GetRoleMapFromIndex(GetRoleMapIndex(aEl)); +} + +uint8_t +aria::GetRoleMapIndex(dom::Element* aEl) +{ + nsAutoString roles; + if (!aEl || !aEl->GetAttr(kNameSpaceID_None, nsGkAtoms::role, roles) || + roles.IsEmpty()) { + // We treat role="" as if the role attribute is absent (per aria spec:8.1.1) + return NO_ROLE_MAP_ENTRY_INDEX; + } + + nsWhitespaceTokenizer tokenizer(roles); + while (tokenizer.hasMoreTokens()) { + // Do a binary search through table for the next role in role list + const nsDependentSubstring role = tokenizer.nextToken(); + size_t idx; + if (BinarySearchIf(sWAIRoleMaps, 0, ArrayLength(sWAIRoleMaps), + RoleComparator(role), &idx)) { + return idx; + } + } + + // Always use some entry index if there is a non-empty role string + // To ensure an accessible object is created + return LANDMARK_ROLE_MAP_ENTRY_INDEX; +} + + +const nsRoleMapEntry* +aria::GetRoleMapFromIndex(uint8_t aRoleMapIndex) +{ + switch (aRoleMapIndex) { + case NO_ROLE_MAP_ENTRY_INDEX: + return nullptr; + case EMPTY_ROLE_MAP_ENTRY_INDEX: + return &gEmptyRoleMap; + case LANDMARK_ROLE_MAP_ENTRY_INDEX: + return &sLandmarkRoleMap; + default: + return sWAIRoleMaps + aRoleMapIndex; + } +} + +uint8_t +aria::GetIndexFromRoleMap(const nsRoleMapEntry* aRoleMapEntry) +{ + if (aRoleMapEntry == nullptr) { + return NO_ROLE_MAP_ENTRY_INDEX; + } else if (aRoleMapEntry == &gEmptyRoleMap) { + return EMPTY_ROLE_MAP_ENTRY_INDEX; + } else if (aRoleMapEntry == &sLandmarkRoleMap) { + return LANDMARK_ROLE_MAP_ENTRY_INDEX; + } else { + return aRoleMapEntry - sWAIRoleMaps; + } +} + +uint64_t +aria::UniversalStatesFor(mozilla::dom::Element* aElement) +{ + uint64_t state = 0; + uint32_t index = 0; + while (MapToState(sWAIUnivStateMap[index], aElement, &state)) + index++; + + return state; +} + +uint8_t +aria::AttrCharacteristicsFor(nsIAtom* aAtom) +{ + for (uint32_t i = 0; i < ArrayLength(gWAIUnivAttrMap); i++) + if (*gWAIUnivAttrMap[i].attributeName == aAtom) + return gWAIUnivAttrMap[i].characteristics; + + return 0; +} + +bool +aria::HasDefinedARIAHidden(nsIContent* aContent) +{ + return aContent && + nsAccUtils::HasDefinedARIAToken(aContent, nsGkAtoms::aria_hidden) && + !aContent->AttrValueIs(kNameSpaceID_None, nsGkAtoms::aria_hidden, + nsGkAtoms::_false, eCaseMatters); +} + +//////////////////////////////////////////////////////////////////////////////// +// AttrIterator class + +bool +AttrIterator::Next(nsAString& aAttrName, nsAString& aAttrValue) +{ + while (mAttrIdx < mAttrCount) { + const nsAttrName* attr = mContent->GetAttrNameAt(mAttrIdx); + mAttrIdx++; + if (attr->NamespaceEquals(kNameSpaceID_None)) { + nsIAtom* attrAtom = attr->Atom(); + nsDependentAtomString attrStr(attrAtom); + if (!StringBeginsWith(attrStr, NS_LITERAL_STRING("aria-"))) + continue; // Not ARIA + + uint8_t attrFlags = aria::AttrCharacteristicsFor(attrAtom); + if (attrFlags & ATTR_BYPASSOBJ) + continue; // No need to handle exposing as obj attribute here + + if ((attrFlags & ATTR_VALTOKEN) && + !nsAccUtils::HasDefinedARIAToken(mContent, attrAtom)) + continue; // only expose token based attributes if they are defined + + if ((attrFlags & ATTR_BYPASSOBJ_IF_FALSE) && + mContent->AttrValueIs(kNameSpaceID_None, attrAtom, + nsGkAtoms::_false, eCaseMatters)) { + continue; // only expose token based attribute if value is not 'false'. + } + + nsAutoString value; + if (mContent->GetAttr(kNameSpaceID_None, attrAtom, value)) { + aAttrName.Assign(Substring(attrStr, 5)); + aAttrValue.Assign(value); + return true; + } + } + } + + return false; +} + diff --git a/accessible/base/ARIAMap.h b/accessible/base/ARIAMap.h new file mode 100644 index 0000000000..4d603c04bb --- /dev/null +++ b/accessible/base/ARIAMap.h @@ -0,0 +1,305 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim:expandtab:shiftwidth=2:tabstop=2: + */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef mozilla_a11y_aria_ARIAMap_h_ +#define mozilla_a11y_aria_ARIAMap_h_ + +#include "ARIAStateMap.h" +#include "mozilla/a11y/AccTypes.h" +#include "mozilla/a11y/Role.h" + +#include "nsIAtom.h" +#include "nsIContent.h" + +class nsINode; + +//////////////////////////////////////////////////////////////////////////////// +// Value constants + +/** + * Used to define if role requires to expose Value interface. + */ +enum EValueRule +{ + /** + * Value interface isn't exposed. + */ + eNoValue, + + /** + * Value interface is implemented, supports value, min and max from + * aria-valuenow, aria-valuemin and aria-valuemax. + */ + eHasValueMinMax +}; + + +//////////////////////////////////////////////////////////////////////////////// +// Action constants + +/** + * Used to define if the role requires to expose action. + */ +enum EActionRule +{ + eNoAction, + eActivateAction, + eClickAction, + ePressAction, + eCheckUncheckAction, + eExpandAction, + eJumpAction, + eOpenCloseAction, + eSelectAction, + eSortAction, + eSwitchAction +}; + + +//////////////////////////////////////////////////////////////////////////////// +// Live region constants + +/** + * Used to define if role exposes default value of aria-live attribute. + */ +enum ELiveAttrRule +{ + eNoLiveAttr, + eOffLiveAttr, + ePoliteLiveAttr +}; + + +//////////////////////////////////////////////////////////////////////////////// +// Role constants + +/** + * ARIA role overrides role from native markup. + */ +const bool kUseMapRole = true; + +/** + * ARIA role doesn't override the role from native markup. + */ +const bool kUseNativeRole = false; + + +//////////////////////////////////////////////////////////////////////////////// +// ARIA attribute characteristic masks + +/** + * This mask indicates the attribute should not be exposed as an object + * attribute via the catch-all logic in Accessible::Attributes(). + * This means it either isn't mean't to be exposed as an object attribute, or + * that it should, but is already handled in other code. + */ +const uint8_t ATTR_BYPASSOBJ = 0x1 << 0; +const uint8_t ATTR_BYPASSOBJ_IF_FALSE = 0x1 << 1; + +/** + * This mask indicates the attribute is expected to have an NMTOKEN or bool value. + * (See for example usage in Accessible::Attributes()) + */ +const uint8_t ATTR_VALTOKEN = 0x1 << 2; + +/** + * Indicate the attribute is global state or property (refer to + * http://www.w3.org/TR/wai-aria/states_and_properties#global_states). + */ +const uint8_t ATTR_GLOBAL = 0x1 << 3; + +//////////////////////////////////////////////////////////////////////////////// +// State map entry + +/** + * Used in nsRoleMapEntry.state if no nsIAccessibleStates are automatic for + * a given role. + */ +#define kNoReqStates 0 + +//////////////////////////////////////////////////////////////////////////////// +// Role map entry + +/** + * For each ARIA role, this maps the nsIAccessible information. + */ +struct nsRoleMapEntry +{ + /** + * Return true if matches to the given ARIA role. + */ + bool Is(nsIAtom* aARIARole) const + { return *roleAtom == aARIARole; } + + /** + * Return true if ARIA role has the given accessible type. + */ + bool IsOfType(mozilla::a11y::AccGenericType aType) const + { return accTypes & aType; } + + /** + * Return ARIA role. + */ + const nsDependentAtomString ARIARoleString() const + { return nsDependentAtomString(*roleAtom); } + + // ARIA role: string representation such as "button" + nsIAtom** roleAtom; + + // Role mapping rule: maps to enum Role + mozilla::a11y::role role; + + // Role rule: whether to use mapped role or native semantics + bool roleRule; + + // Value mapping rule: how to compute accessible value + EValueRule valueRule; + + // Action mapping rule, how to expose accessible action + EActionRule actionRule; + + // 'live' and 'container-live' object attributes mapping rule: how to expose + // these object attributes if ARIA 'live' attribute is missed. + ELiveAttrRule liveAttRule; + + // Accessible types this role belongs to. + uint32_t accTypes; + + // Automatic state mapping rule: always include in states + uint64_t state; // or kNoReqStates if no default state for this role + + // ARIA properties supported for this role (in other words, the aria-foo + // attribute to accessible states mapping rules). + // Currently you cannot have unlimited mappings, because + // a variable sized array would not allow the use of + // C++'s struct initialization feature. + mozilla::a11y::aria::EStateRule attributeMap1; + mozilla::a11y::aria::EStateRule attributeMap2; + mozilla::a11y::aria::EStateRule attributeMap3; + mozilla::a11y::aria::EStateRule attributeMap4; +}; + + +//////////////////////////////////////////////////////////////////////////////// +// ARIA map + +/** + * These provide the mappings for WAI-ARIA roles, states and properties using + * the structs defined in this file and ARIAStateMap files. + */ +namespace mozilla { +namespace a11y { +namespace aria { + +/** + * Empty role map entry. Used by accessibility service to create an accessible + * if the accessible can't use role of used accessible class. For example, + * it is used for table cells that aren't contained by table. + */ +extern nsRoleMapEntry gEmptyRoleMap; + +/** + * Constants for the role map entry index to indicate that the role map entry + * isn't in sWAIRoleMaps, but rather is a special entry: nullptr, + * gEmptyRoleMap, and sLandmarkRoleMap + */ +const uint8_t NO_ROLE_MAP_ENTRY_INDEX = UINT8_MAX - 2; +const uint8_t EMPTY_ROLE_MAP_ENTRY_INDEX = UINT8_MAX - 1; +const uint8_t LANDMARK_ROLE_MAP_ENTRY_INDEX = UINT8_MAX; + +/** + * Get the role map entry for a given DOM node. This will use the first + * ARIA role if the role attribute provides a space delimited list of roles. + * + * @param aEl [in] the DOM node to get the role map entry for + * @return a pointer to the role map entry for the ARIA role, or nullptr + * if none + */ +const nsRoleMapEntry* GetRoleMap(dom::Element* aEl); + +/** + * Get the role map entry pointer's index for a given DOM node. This will use + * the first ARIA role if the role attribute provides a space delimited list of + * roles. + * + * @param aEl [in] the DOM node to get the role map entry for + * @return the index of the pointer to the role map entry for the ARIA + * role, or NO_ROLE_MAP_ENTRY_INDEX if none + */ +uint8_t GetRoleMapIndex(dom::Element* aEl); + +/** + * Get the role map entry pointer for a given role map entry index. + * + * @param aRoleMapIndex [in] the role map index to get the role map entry + * pointer for + * @return a pointer to the role map entry for the ARIA role, + * or nullptr, if none + */ +const nsRoleMapEntry* GetRoleMapFromIndex(uint8_t aRoleMapIndex); + +/** + * Get the role map entry index for a given role map entry pointer. If the role + * map entry is within sWAIRoleMaps, return the index within that array, + * otherwise return one of the special index constants listed above. + * + * @param aRoleMap [in] the role map entry pointer to get the index for + * @return the index of the pointer to the role map entry, or + * NO_ROLE_MAP_ENTRY_INDEX if none + */ +uint8_t GetIndexFromRoleMap(const nsRoleMapEntry* aRoleMap); + +/** + * Return accessible state from ARIA universal states applied to the given + * element. + */ +uint64_t UniversalStatesFor(mozilla::dom::Element* aElement); + +/** + * Get the ARIA attribute characteristics for a given ARIA attribute. + * + * @param aAtom ARIA attribute + * @return A bitflag representing the attribute characteristics + * (see above for possible bit masks, prefixed "ATTR_") + */ +uint8_t AttrCharacteristicsFor(nsIAtom* aAtom); + +/** + * Return true if the element has defined aria-hidden. + */ +bool HasDefinedARIAHidden(nsIContent* aContent); + + /** + * Represents a simple enumerator for iterating through ARIA attributes + * exposed as object attributes on a given accessible. + */ +class AttrIterator +{ +public: + explicit AttrIterator(nsIContent* aContent) : + mContent(aContent), mAttrIdx(0) + { + mAttrCount = mContent->GetAttrCount(); + } + + bool Next(nsAString& aAttrName, nsAString& aAttrValue); + +private: + AttrIterator() = delete; + AttrIterator(const AttrIterator&) = delete; + AttrIterator& operator= (const AttrIterator&) = delete; + + nsIContent* mContent; + uint32_t mAttrIdx; + uint32_t mAttrCount; +}; + +} // namespace aria +} // namespace a11y +} // namespace mozilla + +#endif diff --git a/accessible/base/ARIAStateMap.cpp b/accessible/base/ARIAStateMap.cpp new file mode 100644 index 0000000000..f121835d11 --- /dev/null +++ b/accessible/base/ARIAStateMap.cpp @@ -0,0 +1,376 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "ARIAMap.h" +#include "nsAccUtils.h" +#include "States.h" + +#include "mozilla/dom/Element.h" + +using namespace mozilla; +using namespace mozilla::a11y; +using namespace mozilla::a11y::aria; + +/** + * Used to store state map rule data for ARIA attribute of enum type. + */ +struct EnumTypeData +{ + // ARIA attribute name. + nsIAtom* const mAttrName; + + // States if the attribute value is matched to the enum value. Used as + // nsIContent::AttrValuesArray, last item must be nullptr. + nsIAtom* const* const mValues[4]; + + // States applied if corresponding enum values are matched. + const uint64_t mStates[3]; + + // States to clear in case of match. + const uint64_t mClearState; +}; + +enum ETokenType +{ + eBoolType = 0, + eMixedType = 1, // can take 'mixed' value + eDefinedIfAbsent = 2 // permanent and false state are applied if absent +}; + +/** + * Used to store state map rule data for ARIA attribute of token type (including + * mixed value). + */ +struct TokenTypeData +{ + TokenTypeData(nsIAtom* aAttrName, uint32_t aType, + uint64_t aPermanentState, + uint64_t aTrueState, + uint64_t aFalseState = 0) : + mAttrName(aAttrName), mType(aType), mPermanentState(aPermanentState), + mTrueState(aTrueState), mFalseState(aFalseState) + { } + + // ARIA attribute name. + nsIAtom* const mAttrName; + + // Type. + const uint32_t mType; + + // State applied if the attribute is defined or mType doesn't have + // eDefinedIfAbsent flag set. + const uint64_t mPermanentState; + + // States applied if the attribute value is true/false. + const uint64_t mTrueState; + const uint64_t mFalseState; +}; + +/** + * Map enum type attribute value to accessible state. + */ +static void MapEnumType(dom::Element* aElement, uint64_t* aState, + const EnumTypeData& aData); + +/** + * Map token type attribute value to states. + */ +static void MapTokenType(dom::Element* aContent, uint64_t* aState, + const TokenTypeData& aData); + +bool +aria::MapToState(EStateRule aRule, dom::Element* aElement, uint64_t* aState) +{ + switch (aRule) { + case eARIAAutoComplete: + { + static const EnumTypeData data = { + nsGkAtoms::aria_autocomplete, + { &nsGkAtoms::inlinevalue, + &nsGkAtoms::list, + &nsGkAtoms::both, nullptr }, + { states::SUPPORTS_AUTOCOMPLETION, + states::HASPOPUP | states::SUPPORTS_AUTOCOMPLETION, + states::HASPOPUP | states::SUPPORTS_AUTOCOMPLETION }, 0 + }; + + MapEnumType(aElement, aState, data); + return true; + } + + case eARIABusy: + { + static const EnumTypeData data = { + nsGkAtoms::aria_busy, + { &nsGkAtoms::_true, + &nsGkAtoms::error, nullptr }, + { states::BUSY, + states::INVALID }, 0 + }; + + MapEnumType(aElement, aState, data); + return true; + } + + case eARIACheckableBool: + { + static const TokenTypeData data( + nsGkAtoms::aria_checked, eBoolType | eDefinedIfAbsent, + states::CHECKABLE, states::CHECKED); + + MapTokenType(aElement, aState, data); + return true; + } + + case eARIACheckableMixed: + { + static const TokenTypeData data( + nsGkAtoms::aria_checked, eMixedType | eDefinedIfAbsent, + states::CHECKABLE, states::CHECKED); + + MapTokenType(aElement, aState, data); + return true; + } + + case eARIACheckedMixed: + { + static const TokenTypeData data( + nsGkAtoms::aria_checked, eMixedType, + states::CHECKABLE, states::CHECKED); + + MapTokenType(aElement, aState, data); + return true; + } + + case eARIADisabled: + { + static const TokenTypeData data( + nsGkAtoms::aria_disabled, eBoolType, + 0, states::UNAVAILABLE); + + MapTokenType(aElement, aState, data); + return true; + } + + case eARIAExpanded: + { + static const TokenTypeData data( + nsGkAtoms::aria_expanded, eBoolType, + 0, states::EXPANDED, states::COLLAPSED); + + MapTokenType(aElement, aState, data); + return true; + } + + case eARIAHasPopup: + { + static const TokenTypeData data( + nsGkAtoms::aria_haspopup, eBoolType, + 0, states::HASPOPUP); + + MapTokenType(aElement, aState, data); + return true; + } + + case eARIAInvalid: + { + static const TokenTypeData data( + nsGkAtoms::aria_invalid, eBoolType, + 0, states::INVALID); + + MapTokenType(aElement, aState, data); + return true; + } + + case eARIAModal: + { + static const TokenTypeData data( + nsGkAtoms::aria_modal, eBoolType, + 0, states::MODAL); + + MapTokenType(aElement, aState, data); + return true; + } + + case eARIAMultiline: + { + static const TokenTypeData data( + nsGkAtoms::aria_multiline, eBoolType | eDefinedIfAbsent, + 0, states::MULTI_LINE, states::SINGLE_LINE); + + MapTokenType(aElement, aState, data); + return true; + } + + case eARIAMultiSelectable: + { + static const TokenTypeData data( + nsGkAtoms::aria_multiselectable, eBoolType, + 0, states::MULTISELECTABLE | states::EXTSELECTABLE); + + MapTokenType(aElement, aState, data); + return true; + } + + case eARIAOrientation: + { + static const EnumTypeData data = { + nsGkAtoms::aria_orientation, + { &nsGkAtoms::horizontal, + &nsGkAtoms::vertical, nullptr }, + { states::HORIZONTAL, + states::VERTICAL }, + states::HORIZONTAL | states::VERTICAL + }; + + MapEnumType(aElement, aState, data); + return true; + } + + case eARIAPressed: + { + static const TokenTypeData data( + nsGkAtoms::aria_pressed, eMixedType, + 0, states::PRESSED); + + MapTokenType(aElement, aState, data); + return true; + } + + case eARIAReadonly: + { + static const TokenTypeData data( + nsGkAtoms::aria_readonly, eBoolType, + 0, states::READONLY); + + MapTokenType(aElement, aState, data); + return true; + } + + case eARIAReadonlyOrEditable: + { + static const TokenTypeData data( + nsGkAtoms::aria_readonly, eBoolType | eDefinedIfAbsent, + 0, states::READONLY, states::EDITABLE); + + MapTokenType(aElement, aState, data); + return true; + } + + case eARIAReadonlyOrEditableIfDefined: + { + static const TokenTypeData data( + nsGkAtoms::aria_readonly, eBoolType, + 0, states::READONLY, states::EDITABLE); + + MapTokenType(aElement, aState, data); + return true; + } + + case eARIARequired: + { + static const TokenTypeData data( + nsGkAtoms::aria_required, eBoolType, + 0, states::REQUIRED); + + MapTokenType(aElement, aState, data); + return true; + } + + case eARIASelectable: + { + static const TokenTypeData data( + nsGkAtoms::aria_selected, eBoolType | eDefinedIfAbsent, + states::SELECTABLE, states::SELECTED); + + MapTokenType(aElement, aState, data); + return true; + } + + case eARIASelectableIfDefined: + { + static const TokenTypeData data( + nsGkAtoms::aria_selected, eBoolType, + states::SELECTABLE, states::SELECTED); + + MapTokenType(aElement, aState, data); + return true; + } + + case eReadonlyUntilEditable: + { + if (!(*aState & states::EDITABLE)) + *aState |= states::READONLY; + + return true; + } + + case eIndeterminateIfNoValue: + { + if (!aElement->HasAttr(kNameSpaceID_None, nsGkAtoms::aria_valuenow) && + !aElement->HasAttr(kNameSpaceID_None, nsGkAtoms::aria_valuetext)) + *aState |= states::MIXED; + + return true; + } + + case eFocusableUntilDisabled: + { + if (!nsAccUtils::HasDefinedARIAToken(aElement, nsGkAtoms::aria_disabled) || + aElement->AttrValueIs(kNameSpaceID_None, nsGkAtoms::aria_disabled, + nsGkAtoms::_false, eCaseMatters)) + *aState |= states::FOCUSABLE; + + return true; + } + + default: + return false; + } +} + +static void +MapEnumType(dom::Element* aElement, uint64_t* aState, const EnumTypeData& aData) +{ + switch (aElement->FindAttrValueIn(kNameSpaceID_None, aData.mAttrName, + aData.mValues, eCaseMatters)) { + case 0: + *aState = (*aState & ~aData.mClearState) | aData.mStates[0]; + return; + case 1: + *aState = (*aState & ~aData.mClearState) | aData.mStates[1]; + return; + case 2: + *aState = (*aState & ~aData.mClearState) | aData.mStates[2]; + return; + } +} + +static void +MapTokenType(dom::Element* aElement, uint64_t* aState, + const TokenTypeData& aData) +{ + if (nsAccUtils::HasDefinedARIAToken(aElement, aData.mAttrName)) { + if ((aData.mType & eMixedType) && + aElement->AttrValueIs(kNameSpaceID_None, aData.mAttrName, + nsGkAtoms::mixed, eCaseMatters)) { + *aState |= aData.mPermanentState | states::MIXED; + return; + } + + if (aElement->AttrValueIs(kNameSpaceID_None, aData.mAttrName, + nsGkAtoms::_false, eCaseMatters)) { + *aState |= aData.mPermanentState | aData.mFalseState; + return; + } + + *aState |= aData.mPermanentState | aData.mTrueState; + return; + } + + if (aData.mType & eDefinedIfAbsent) + *aState |= aData.mPermanentState | aData.mFalseState; +} diff --git a/accessible/base/ARIAStateMap.h b/accessible/base/ARIAStateMap.h new file mode 100644 index 0000000000..41626fcafa --- /dev/null +++ b/accessible/base/ARIAStateMap.h @@ -0,0 +1,67 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef _mozilla_a11y_aria_ARIAStateMap_h_ +#define _mozilla_a11y_aria_ARIAStateMap_h_ + +#include + +namespace mozilla { + +namespace dom { +class Element; +} + +namespace a11y { +namespace aria { + +/** + * List of the ARIA state mapping rules. + */ +enum EStateRule +{ + eARIANone, + eARIAAutoComplete, + eARIABusy, + eARIACheckableBool, + eARIACheckableMixed, + eARIACheckedMixed, + eARIADisabled, + eARIAExpanded, + eARIAHasPopup, + eARIAInvalid, + eARIAModal, + eARIAMultiline, + eARIAMultiSelectable, + eARIAOrientation, + eARIAPressed, + eARIAReadonly, + eARIAReadonlyOrEditable, + eARIAReadonlyOrEditableIfDefined, + eARIARequired, + eARIASelectable, + eARIASelectableIfDefined, + eReadonlyUntilEditable, + eIndeterminateIfNoValue, + eFocusableUntilDisabled +}; + +/** + * Expose the accessible states for the given element accordingly to state + * mapping rule. + * + * @param aRule [in] state mapping rule ID + * @param aElement [in] node of the accessible + * @param aState [in/out] accessible states + * @return true if state map rule ID is valid + */ +bool MapToState(EStateRule aRule, dom::Element* aElement, uint64_t* aState); + +} // namespace aria +} // namespace a11y +} // namespace mozilla + +#endif diff --git a/accessible/base/AccEvent.cpp b/accessible/base/AccEvent.cpp new file mode 100644 index 0000000000..a27ceacb9f --- /dev/null +++ b/accessible/base/AccEvent.cpp @@ -0,0 +1,271 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "AccEvent.h" + +#include "nsAccUtils.h" +#include "DocAccessible.h" +#include "xpcAccEvents.h" +#include "States.h" +#include "xpcAccessibleDocument.h" + +#include "mozilla/EventStateManager.h" +#include "mozilla/dom/Selection.h" + +using namespace mozilla; +using namespace mozilla::a11y; + +static_assert(static_cast(eNoUserInput) == false && + static_cast(eFromUserInput) == true, + "EIsFromUserInput cannot be casted to bool"); + +//////////////////////////////////////////////////////////////////////////////// +// AccEvent +//////////////////////////////////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////////////////////////// +// AccEvent constructors + +AccEvent::AccEvent(uint32_t aEventType, Accessible* aAccessible, + EIsFromUserInput aIsFromUserInput, EEventRule aEventRule) : + mEventType(aEventType), mEventRule(aEventRule), mAccessible(aAccessible) +{ + if (aIsFromUserInput == eAutoDetect) + mIsFromUserInput = EventStateManager::IsHandlingUserInput(); + else + mIsFromUserInput = aIsFromUserInput == eFromUserInput ? true : false; +} + +//////////////////////////////////////////////////////////////////////////////// +// AccEvent cycle collection + +NS_IMPL_CYCLE_COLLECTION_CLASS(AccEvent) + +NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(AccEvent) + NS_IMPL_CYCLE_COLLECTION_UNLINK(mAccessible) + if (AccTreeMutationEvent* tmEvent = downcast_accEvent(tmp)) { + tmEvent->SetNextEvent(nullptr); + tmEvent->SetPrevEvent(nullptr); + } +NS_IMPL_CYCLE_COLLECTION_UNLINK_END + +NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(AccEvent) + NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mAccessible) + if (AccTreeMutationEvent* tmEvent = downcast_accEvent(tmp)) { + CycleCollectionNoteChild(cb, tmEvent->NextEvent(), "mNext"); + CycleCollectionNoteChild(cb, tmEvent->PrevEvent(), "mPrevEvent"); + } +NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END + +NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(AccEvent, AddRef) +NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(AccEvent, Release) + +//////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// +// AccTextChangeEvent +//////////////////////////////////////////////////////////////////////////////// + +// Note: we pass in eAllowDupes to the base class because we don't support text +// events coalescence. We fire delayed text change events in DocAccessible but +// we continue to base the event off the accessible object rather than just the +// node. This means we won't try to create an accessible based on the node when +// we are ready to fire the event and so we will no longer assert at that point +// if the node was removed from the document. Either way, the AT won't work with +// a defunct accessible so the behaviour should be equivalent. +AccTextChangeEvent:: + AccTextChangeEvent(Accessible* aAccessible, int32_t aStart, + const nsAString& aModifiedText, bool aIsInserted, + EIsFromUserInput aIsFromUserInput) + : AccEvent(aIsInserted ? + static_cast(nsIAccessibleEvent::EVENT_TEXT_INSERTED) : + static_cast(nsIAccessibleEvent::EVENT_TEXT_REMOVED), + aAccessible, aIsFromUserInput, eAllowDupes) + , mStart(aStart) + , mIsInserted(aIsInserted) + , mModifiedText(aModifiedText) +{ + // XXX We should use IsFromUserInput here, but that isn't always correct + // when the text change isn't related to content insertion or removal. + mIsFromUserInput = mAccessible->State() & + (states::FOCUSED | states::EDITABLE); +} + +//////////////////////////////////////////////////////////////////////////////// +// AccHideEvent +//////////////////////////////////////////////////////////////////////////////// + +AccHideEvent:: + AccHideEvent(Accessible* aTarget, bool aNeedsShutdown) : + AccMutationEvent(::nsIAccessibleEvent::EVENT_HIDE, aTarget), + mNeedsShutdown(aNeedsShutdown) +{ + mNextSibling = mAccessible->NextSibling(); + mPrevSibling = mAccessible->PrevSibling(); +} + + +//////////////////////////////////////////////////////////////////////////////// +// AccShowEvent +//////////////////////////////////////////////////////////////////////////////// + +AccShowEvent:: + AccShowEvent(Accessible* aTarget) : + AccMutationEvent(::nsIAccessibleEvent::EVENT_SHOW, aTarget) +{ + int32_t idx = aTarget->IndexInParent(); + MOZ_ASSERT(idx >= 0); + mInsertionIndex = idx; +} + + +//////////////////////////////////////////////////////////////////////////////// +// AccTextSelChangeEvent +//////////////////////////////////////////////////////////////////////////////// + +AccTextSelChangeEvent::AccTextSelChangeEvent(HyperTextAccessible* aTarget, + dom::Selection* aSelection, + int32_t aReason) : + AccEvent(nsIAccessibleEvent::EVENT_TEXT_SELECTION_CHANGED, aTarget, + eAutoDetect, eCoalesceTextSelChange), + mSel(aSelection), mReason(aReason) {} + +AccTextSelChangeEvent::~AccTextSelChangeEvent() { } + +bool +AccTextSelChangeEvent::IsCaretMoveOnly() const +{ + return mSel->RangeCount() == 1 && mSel->IsCollapsed() && + ((mReason & (nsISelectionListener::COLLAPSETOSTART_REASON | + nsISelectionListener::COLLAPSETOEND_REASON)) == 0); +} + +//////////////////////////////////////////////////////////////////////////////// +// AccSelChangeEvent +//////////////////////////////////////////////////////////////////////////////// + +AccSelChangeEvent:: + AccSelChangeEvent(Accessible* aWidget, Accessible* aItem, + SelChangeType aSelChangeType) : + AccEvent(0, aItem, eAutoDetect, eCoalesceSelectionChange), + mWidget(aWidget), mItem(aItem), mSelChangeType(aSelChangeType), + mPreceedingCount(0), mPackedEvent(nullptr) +{ + if (aSelChangeType == eSelectionAdd) { + if (mWidget->GetSelectedItem(1)) + mEventType = nsIAccessibleEvent::EVENT_SELECTION_ADD; + else + mEventType = nsIAccessibleEvent::EVENT_SELECTION; + } else { + mEventType = nsIAccessibleEvent::EVENT_SELECTION_REMOVE; + } +} + + +//////////////////////////////////////////////////////////////////////////////// +// AccTableChangeEvent +//////////////////////////////////////////////////////////////////////////////// + +AccTableChangeEvent:: + AccTableChangeEvent(Accessible* aAccessible, uint32_t aEventType, + int32_t aRowOrColIndex, int32_t aNumRowsOrCols) : + AccEvent(aEventType, aAccessible), + mRowOrColIndex(aRowOrColIndex), mNumRowsOrCols(aNumRowsOrCols) +{ +} + + +//////////////////////////////////////////////////////////////////////////////// +// AccVCChangeEvent +//////////////////////////////////////////////////////////////////////////////// + +AccVCChangeEvent:: + AccVCChangeEvent(Accessible* aAccessible, + Accessible* aOldAccessible, + int32_t aOldStart, int32_t aOldEnd, + int16_t aReason, EIsFromUserInput aIsFromUserInput) : + AccEvent(::nsIAccessibleEvent::EVENT_VIRTUALCURSOR_CHANGED, aAccessible, + aIsFromUserInput), + mOldAccessible(aOldAccessible), mOldStart(aOldStart), mOldEnd(aOldEnd), + mReason(aReason) +{ +} + +already_AddRefed +a11y::MakeXPCEvent(AccEvent* aEvent) +{ + DocAccessible* doc = aEvent->Document(); + Accessible* acc = aEvent->GetAccessible(); + nsINode* node = acc->GetNode(); + nsIDOMNode* domNode = node ? node->AsDOMNode() : nullptr; + bool fromUser = aEvent->IsFromUserInput(); + uint32_t type = aEvent->GetEventType(); + uint32_t eventGroup = aEvent->GetEventGroups(); + nsCOMPtr xpEvent; + + if (eventGroup & (1 << AccEvent::eStateChangeEvent)) { + AccStateChangeEvent* sc = downcast_accEvent(aEvent); + bool extra = false; + uint32_t state = nsAccUtils::To32States(sc->GetState(), &extra); + xpEvent = new xpcAccStateChangeEvent(type, ToXPC(acc), ToXPCDocument(doc), + domNode, fromUser, + state, extra, sc->IsStateEnabled()); + return xpEvent.forget(); + } + + if (eventGroup & (1 << AccEvent::eTextChangeEvent)) { + AccTextChangeEvent* tc = downcast_accEvent(aEvent); + nsString text; + tc->GetModifiedText(text); + xpEvent = new xpcAccTextChangeEvent(type, ToXPC(acc), ToXPCDocument(doc), + domNode, fromUser, + tc->GetStartOffset(), tc->GetLength(), + tc->IsTextInserted(), text); + return xpEvent.forget(); + } + + if (eventGroup & (1 << AccEvent::eHideEvent)) { + AccHideEvent* hideEvent = downcast_accEvent(aEvent); + xpEvent = new xpcAccHideEvent(type, ToXPC(acc), ToXPCDocument(doc), + domNode, fromUser, + ToXPC(hideEvent->TargetParent()), + ToXPC(hideEvent->TargetNextSibling()), + ToXPC(hideEvent->TargetPrevSibling())); + return xpEvent.forget(); + } + + if (eventGroup & (1 << AccEvent::eCaretMoveEvent)) { + AccCaretMoveEvent* cm = downcast_accEvent(aEvent); + xpEvent = new xpcAccCaretMoveEvent(type, ToXPC(acc), ToXPCDocument(doc), + domNode, fromUser, + cm->GetCaretOffset()); + return xpEvent.forget(); + } + + if (eventGroup & (1 << AccEvent::eVirtualCursorChangeEvent)) { + AccVCChangeEvent* vcc = downcast_accEvent(aEvent); + xpEvent = new xpcAccVirtualCursorChangeEvent(type, + ToXPC(acc), ToXPCDocument(doc), + domNode, fromUser, + ToXPC(vcc->OldAccessible()), + vcc->OldStartOffset(), + vcc->OldEndOffset(), + vcc->Reason()); + return xpEvent.forget(); + } + + if (eventGroup & (1 << AccEvent::eObjectAttrChangedEvent)) { + AccObjectAttrChangedEvent* oac = downcast_accEvent(aEvent); + xpEvent = new xpcAccObjectAttributeChangedEvent(type, + ToXPC(acc), + ToXPCDocument(doc), domNode, + fromUser, + oac->GetAttribute()); + return xpEvent.forget(); + } + + xpEvent = new xpcAccEvent(type, ToXPC(acc), ToXPCDocument(doc), domNode, fromUser); + return xpEvent.forget(); + } diff --git a/accessible/base/AccEvent.h b/accessible/base/AccEvent.h new file mode 100644 index 0000000000..4162242789 --- /dev/null +++ b/accessible/base/AccEvent.h @@ -0,0 +1,570 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef _AccEvent_H_ +#define _AccEvent_H_ + +#include "nsIAccessibleEvent.h" + +#include "mozilla/a11y/Accessible.h" + +class nsEventShell; +namespace mozilla { + +namespace dom { +class Selection; +} + +namespace a11y { + +class DocAccessible; + +// Constants used to point whether the event is from user input. +enum EIsFromUserInput +{ + // eNoUserInput: event is not from user input + eNoUserInput = 0, + // eFromUserInput: event is from user input + eFromUserInput = 1, + // eAutoDetect: the value should be obtained from event state manager + eAutoDetect = -1 +}; + +/** + * Generic accessible event. + */ +class AccEvent +{ +public: + + // Rule for accessible events. + // The rule will be applied when flushing pending events. + enum EEventRule { + // eAllowDupes : More than one event of the same type is allowed. + // This event will always be emitted. This flag is used for events that + // don't support coalescence. + eAllowDupes, + + // eCoalesceReorder : For reorder events from the same subtree or the same + // node, only the umbrella event on the ancestor will be emitted. + eCoalesceReorder, + + // eCoalesceOfSameType : For events of the same type, only the newest event + // will be processed. + eCoalesceOfSameType, + + // eCoalesceSelectionChange: coalescence of selection change events. + eCoalesceSelectionChange, + + // eCoalesceStateChange: coalesce state change events. + eCoalesceStateChange, + + // eCoalesceTextSelChange: coalescence of text selection change events. + eCoalesceTextSelChange, + + // eRemoveDupes : For repeat events, only the newest event in queue + // will be emitted. + eRemoveDupes, + + // eDoNotEmit : This event is confirmed as a duplicate, do not emit it. + eDoNotEmit + }; + + // Initialize with an accessible. + AccEvent(uint32_t aEventType, Accessible* aAccessible, + EIsFromUserInput aIsFromUserInput = eAutoDetect, + EEventRule aEventRule = eRemoveDupes); + + // AccEvent + uint32_t GetEventType() const { return mEventType; } + EEventRule GetEventRule() const { return mEventRule; } + bool IsFromUserInput() const { return mIsFromUserInput; } + EIsFromUserInput FromUserInput() const + { return static_cast(mIsFromUserInput); } + + Accessible* GetAccessible() const { return mAccessible; } + DocAccessible* Document() const { return mAccessible->Document(); } + + /** + * Down casting. + */ + enum EventGroup { + eGenericEvent, + eStateChangeEvent, + eTextChangeEvent, + eTreeMutationEvent, + eMutationEvent, + eReorderEvent, + eHideEvent, + eShowEvent, + eCaretMoveEvent, + eTextSelChangeEvent, + eSelectionChangeEvent, + eTableChangeEvent, + eVirtualCursorChangeEvent, + eObjectAttrChangedEvent + }; + + static const EventGroup kEventGroup = eGenericEvent; + virtual unsigned int GetEventGroups() const + { + return 1U << eGenericEvent; + } + + /** + * Reference counting and cycle collection. + */ + NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(AccEvent) + NS_DECL_CYCLE_COLLECTION_NATIVE_CLASS(AccEvent) + +protected: + virtual ~AccEvent() {} + + bool mIsFromUserInput; + uint32_t mEventType; + EEventRule mEventRule; + RefPtr mAccessible; + + friend class EventQueue; + friend class EventTree; + friend class ::nsEventShell; + friend class NotificationController; +}; + + +/** + * Accessible state change event. + */ +class AccStateChangeEvent: public AccEvent +{ +public: + AccStateChangeEvent(Accessible* aAccessible, uint64_t aState, + bool aIsEnabled, + EIsFromUserInput aIsFromUserInput = eAutoDetect) : + AccEvent(nsIAccessibleEvent::EVENT_STATE_CHANGE, aAccessible, + aIsFromUserInput, eCoalesceStateChange), + mState(aState), mIsEnabled(aIsEnabled) { } + + AccStateChangeEvent(Accessible* aAccessible, uint64_t aState) : + AccEvent(::nsIAccessibleEvent::EVENT_STATE_CHANGE, aAccessible, + eAutoDetect, eCoalesceStateChange), mState(aState) + { mIsEnabled = (mAccessible->State() & mState) != 0; } + + // AccEvent + static const EventGroup kEventGroup = eStateChangeEvent; + virtual unsigned int GetEventGroups() const override + { + return AccEvent::GetEventGroups() | (1U << eStateChangeEvent); + } + + // AccStateChangeEvent + uint64_t GetState() const { return mState; } + bool IsStateEnabled() const { return mIsEnabled; } + +private: + uint64_t mState; + bool mIsEnabled; + + friend class EventQueue; +}; + + +/** + * Accessible text change event. + */ +class AccTextChangeEvent: public AccEvent +{ +public: + AccTextChangeEvent(Accessible* aAccessible, int32_t aStart, + const nsAString& aModifiedText, bool aIsInserted, + EIsFromUserInput aIsFromUserInput = eAutoDetect); + + // AccEvent + static const EventGroup kEventGroup = eTextChangeEvent; + virtual unsigned int GetEventGroups() const override + { + return AccEvent::GetEventGroups() | (1U << eTextChangeEvent); + } + + // AccTextChangeEvent + int32_t GetStartOffset() const { return mStart; } + uint32_t GetLength() const { return mModifiedText.Length(); } + bool IsTextInserted() const { return mIsInserted; } + void GetModifiedText(nsAString& aModifiedText) + { aModifiedText = mModifiedText; } + const nsString& ModifiedText() const { return mModifiedText; } + +private: + int32_t mStart; + bool mIsInserted; + nsString mModifiedText; + + friend class EventTree; + friend class NotificationController; +}; + +/** + * A base class for events related to tree mutation, either an AccMutation + * event, or an AccReorderEvent. + */ +class AccTreeMutationEvent : public AccEvent +{ +public: + AccTreeMutationEvent(uint32_t aEventType, Accessible* aTarget) : + AccEvent(aEventType, aTarget, eAutoDetect, eCoalesceReorder), mGeneration(0) {} + + // Event + static const EventGroup kEventGroup = eTreeMutationEvent; + virtual unsigned int GetEventGroups() const override + { + return AccEvent::GetEventGroups() | (1U << eTreeMutationEvent); + } + + void SetNextEvent(AccTreeMutationEvent* aNext) { mNextEvent = aNext; } + void SetPrevEvent(AccTreeMutationEvent* aPrev) { mPrevEvent = aPrev; } + AccTreeMutationEvent* NextEvent() const { return mNextEvent; } + AccTreeMutationEvent* PrevEvent() const { return mPrevEvent; } + + /** + * A sequence number to know when this event was fired. + */ + uint32_t EventGeneration() const { return mGeneration; } + void SetEventGeneration(uint32_t aGeneration) { mGeneration = aGeneration; } + +private: + RefPtr mNextEvent; + RefPtr mPrevEvent; + uint32_t mGeneration; +}; + +/** + * Base class for show and hide accessible events. + */ +class AccMutationEvent: public AccTreeMutationEvent +{ +public: + AccMutationEvent(uint32_t aEventType, Accessible* aTarget) : + AccTreeMutationEvent(aEventType, aTarget) + { + // Don't coalesce these since they are coalesced by reorder event. Coalesce + // contained text change events. + mParent = mAccessible->Parent(); + } + virtual ~AccMutationEvent() { } + + // Event + static const EventGroup kEventGroup = eMutationEvent; + virtual unsigned int GetEventGroups() const override + { + return AccTreeMutationEvent::GetEventGroups() | (1U << eMutationEvent); + } + + // MutationEvent + bool IsShow() const { return mEventType == nsIAccessibleEvent::EVENT_SHOW; } + bool IsHide() const { return mEventType == nsIAccessibleEvent::EVENT_HIDE; } + + Accessible* Parent() const { return mParent; } + +protected: + nsCOMPtr mNode; + RefPtr mParent; + RefPtr mTextChangeEvent; + + friend class EventTree; + friend class NotificationController; +}; + + +/** + * Accessible hide event. + */ +class AccHideEvent: public AccMutationEvent +{ +public: + explicit AccHideEvent(Accessible* aTarget, bool aNeedsShutdown = true); + + // Event + static const EventGroup kEventGroup = eHideEvent; + virtual unsigned int GetEventGroups() const override + { + return AccMutationEvent::GetEventGroups() | (1U << eHideEvent); + } + + // AccHideEvent + Accessible* TargetParent() const { return mParent; } + Accessible* TargetNextSibling() const { return mNextSibling; } + Accessible* TargetPrevSibling() const { return mPrevSibling; } + bool NeedsShutdown() const { return mNeedsShutdown; } + +protected: + bool mNeedsShutdown; + RefPtr mNextSibling; + RefPtr mPrevSibling; + + friend class EventTree; + friend class NotificationController; +}; + + +/** + * Accessible show event. + */ +class AccShowEvent: public AccMutationEvent +{ +public: + explicit AccShowEvent(Accessible* aTarget); + + // Event + static const EventGroup kEventGroup = eShowEvent; + virtual unsigned int GetEventGroups() const override + { + return AccMutationEvent::GetEventGroups() | (1U << eShowEvent); + } + + uint32_t InsertionIndex() const { return mInsertionIndex; } + +private: + nsTArray> mPrecedingEvents; + uint32_t mInsertionIndex; + + friend class EventTree; +}; + + +/** + * Class for reorder accessible event. Takes care about + */ +class AccReorderEvent : public AccTreeMutationEvent +{ +public: + explicit AccReorderEvent(Accessible* aTarget) : + AccTreeMutationEvent(::nsIAccessibleEvent::EVENT_REORDER, aTarget) { } + virtual ~AccReorderEvent() { } + + // Event + static const EventGroup kEventGroup = eReorderEvent; + virtual unsigned int GetEventGroups() const override + { + return AccTreeMutationEvent::GetEventGroups() | (1U << eReorderEvent); + } +}; + + +/** + * Accessible caret move event. + */ +class AccCaretMoveEvent: public AccEvent +{ +public: + AccCaretMoveEvent(Accessible* aAccessible, int32_t aCaretOffset, + EIsFromUserInput aIsFromUserInput = eAutoDetect) : + AccEvent(::nsIAccessibleEvent::EVENT_TEXT_CARET_MOVED, aAccessible, + aIsFromUserInput), + mCaretOffset(aCaretOffset) { } + virtual ~AccCaretMoveEvent() { } + + // AccEvent + static const EventGroup kEventGroup = eCaretMoveEvent; + virtual unsigned int GetEventGroups() const override + { + return AccEvent::GetEventGroups() | (1U << eCaretMoveEvent); + } + + // AccCaretMoveEvent + int32_t GetCaretOffset() const { return mCaretOffset; } + +private: + int32_t mCaretOffset; +}; + + +/** + * Accessible text selection change event. + */ +class AccTextSelChangeEvent : public AccEvent +{ +public: + AccTextSelChangeEvent(HyperTextAccessible* aTarget, + dom::Selection* aSelection, + int32_t aReason); + virtual ~AccTextSelChangeEvent(); + + // AccEvent + static const EventGroup kEventGroup = eTextSelChangeEvent; + virtual unsigned int GetEventGroups() const override + { + return AccEvent::GetEventGroups() | (1U << eTextSelChangeEvent); + } + + // AccTextSelChangeEvent + + /** + * Return true if the text selection change wasn't caused by pure caret move. + */ + bool IsCaretMoveOnly() const; + +private: + RefPtr mSel; + int32_t mReason; + + friend class EventQueue; + friend class SelectionManager; +}; + + +/** + * Accessible widget selection change event. + */ +class AccSelChangeEvent : public AccEvent +{ +public: + enum SelChangeType { + eSelectionAdd, + eSelectionRemove + }; + + AccSelChangeEvent(Accessible* aWidget, Accessible* aItem, + SelChangeType aSelChangeType); + + virtual ~AccSelChangeEvent() { } + + // AccEvent + static const EventGroup kEventGroup = eSelectionChangeEvent; + virtual unsigned int GetEventGroups() const override + { + return AccEvent::GetEventGroups() | (1U << eSelectionChangeEvent); + } + + // AccSelChangeEvent + Accessible* Widget() const { return mWidget; } + +private: + RefPtr mWidget; + RefPtr mItem; + SelChangeType mSelChangeType; + uint32_t mPreceedingCount; + AccSelChangeEvent* mPackedEvent; + + friend class EventQueue; +}; + + +/** + * Accessible table change event. + */ +class AccTableChangeEvent : public AccEvent +{ +public: + AccTableChangeEvent(Accessible* aAccessible, uint32_t aEventType, + int32_t aRowOrColIndex, int32_t aNumRowsOrCols); + + // AccEvent + static const EventGroup kEventGroup = eTableChangeEvent; + virtual unsigned int GetEventGroups() const override + { + return AccEvent::GetEventGroups() | (1U << eTableChangeEvent); + } + + // AccTableChangeEvent + uint32_t GetIndex() const { return mRowOrColIndex; } + uint32_t GetCount() const { return mNumRowsOrCols; } + +private: + uint32_t mRowOrColIndex; // the start row/column after which the rows are inserted/deleted. + uint32_t mNumRowsOrCols; // the number of inserted/deleted rows/columns +}; + +/** + * Accessible virtual cursor change event. + */ +class AccVCChangeEvent : public AccEvent +{ +public: + AccVCChangeEvent(Accessible* aAccessible, + Accessible* aOldAccessible, + int32_t aOldStart, int32_t aOldEnd, + int16_t aReason, + EIsFromUserInput aIsFromUserInput = eFromUserInput); + + virtual ~AccVCChangeEvent() { } + + // AccEvent + static const EventGroup kEventGroup = eVirtualCursorChangeEvent; + virtual unsigned int GetEventGroups() const override + { + return AccEvent::GetEventGroups() | (1U << eVirtualCursorChangeEvent); + } + + // AccTableChangeEvent + Accessible* OldAccessible() const { return mOldAccessible; } + int32_t OldStartOffset() const { return mOldStart; } + int32_t OldEndOffset() const { return mOldEnd; } + int32_t Reason() const { return mReason; } + +private: + RefPtr mOldAccessible; + int32_t mOldStart; + int32_t mOldEnd; + int16_t mReason; +}; + +/** + * Accessible object attribute changed event. + */ +class AccObjectAttrChangedEvent: public AccEvent +{ +public: + AccObjectAttrChangedEvent(Accessible* aAccessible, nsIAtom* aAttribute) : + AccEvent(::nsIAccessibleEvent::EVENT_OBJECT_ATTRIBUTE_CHANGED, aAccessible), + mAttribute(aAttribute) { } + + // AccEvent + static const EventGroup kEventGroup = eObjectAttrChangedEvent; + virtual unsigned int GetEventGroups() const override + { + return AccEvent::GetEventGroups() | (1U << eObjectAttrChangedEvent); + } + + // AccObjectAttrChangedEvent + nsIAtom* GetAttribute() const { return mAttribute; } + +private: + nsCOMPtr mAttribute; + + virtual ~AccObjectAttrChangedEvent() { } +}; + +/** + * Downcast the generic accessible event object to derived type. + */ +class downcast_accEvent +{ +public: + explicit downcast_accEvent(AccEvent* e) : mRawPtr(e) { } + + template + operator Destination*() { + if (!mRawPtr) + return nullptr; + + return mRawPtr->GetEventGroups() & (1U << Destination::kEventGroup) ? + static_cast(mRawPtr) : nullptr; + } + +private: + AccEvent* mRawPtr; +}; + +/** + * Return a new xpcom accessible event for the given internal one. + */ +already_AddRefed +MakeXPCEvent(AccEvent* aEvent); + +} // namespace a11y +} // namespace mozilla + +#endif + diff --git a/accessible/base/AccGroupInfo.cpp b/accessible/base/AccGroupInfo.cpp new file mode 100644 index 0000000000..bef7078870 --- /dev/null +++ b/accessible/base/AccGroupInfo.cpp @@ -0,0 +1,227 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "AccGroupInfo.h" +#include "nsAccUtils.h" + +#include "Role.h" +#include "States.h" + +using namespace mozilla::a11y; + +AccGroupInfo::AccGroupInfo(Accessible* aItem, role aRole) : + mPosInSet(0), mSetSize(0), mParent(nullptr), mItem(aItem), mRole(aRole) +{ + MOZ_COUNT_CTOR(AccGroupInfo); + Update(); +} + +void +AccGroupInfo::Update() +{ + Accessible* parent = mItem->Parent(); + if (!parent) + return; + + int32_t indexInParent = mItem->IndexInParent(); + uint32_t siblingCount = parent->ChildCount(); + if (indexInParent == -1 || + indexInParent >= static_cast(siblingCount)) { + NS_ERROR("Wrong index in parent! Tree invalidation problem."); + return; + } + + int32_t level = nsAccUtils::GetARIAOrDefaultLevel(mItem); + + // Compute position in set. + mPosInSet = 1; + for (int32_t idx = indexInParent - 1; idx >= 0 ; idx--) { + Accessible* sibling = parent->GetChildAt(idx); + roles::Role siblingRole = sibling->Role(); + + // If the sibling is separator then the group is ended. + if (siblingRole == roles::SEPARATOR) + break; + + // If sibling is not visible and hasn't the same base role. + if (BaseRole(siblingRole) != mRole || sibling->State() & states::INVISIBLE) + continue; + + // Check if it's hierarchical flatten structure, i.e. if the sibling + // level is lesser than this one then group is ended, if the sibling level + // is greater than this one then the group is split by some child elements + // (group will be continued). + int32_t siblingLevel = nsAccUtils::GetARIAOrDefaultLevel(sibling); + if (siblingLevel < level) { + mParent = sibling; + break; + } + + // Skip subset. + if (siblingLevel > level) + continue; + + // If the previous item in the group has calculated group information then + // build group information for this item based on found one. + if (sibling->mBits.groupInfo) { + mPosInSet += sibling->mBits.groupInfo->mPosInSet; + mParent = sibling->mBits.groupInfo->mParent; + mSetSize = sibling->mBits.groupInfo->mSetSize; + return; + } + + mPosInSet++; + } + + // Compute set size. + mSetSize = mPosInSet; + + for (uint32_t idx = indexInParent + 1; idx < siblingCount; idx++) { + Accessible* sibling = parent->GetChildAt(idx); + + roles::Role siblingRole = sibling->Role(); + + // If the sibling is separator then the group is ended. + if (siblingRole == roles::SEPARATOR) + break; + + // If sibling is visible and has the same base role + if (BaseRole(siblingRole) != mRole || sibling->State() & states::INVISIBLE) + continue; + + // and check if it's hierarchical flatten structure. + int32_t siblingLevel = nsAccUtils::GetARIAOrDefaultLevel(sibling); + if (siblingLevel < level) + break; + + // Skip subset. + if (siblingLevel > level) + continue; + + // If the next item in the group has calculated group information then + // build group information for this item based on found one. + if (sibling->mBits.groupInfo) { + mParent = sibling->mBits.groupInfo->mParent; + mSetSize = sibling->mBits.groupInfo->mSetSize; + return; + } + + mSetSize++; + } + + if (mParent) + return; + + roles::Role parentRole = parent->Role(); + if (ShouldReportRelations(mRole, parentRole)) + mParent = parent; + + // ARIA tree and list can be arranged by using ARIA groups to organize levels. + if (parentRole != roles::GROUPING) + return; + + // Way #1 for ARIA tree (not ARIA treegrid): previous sibling of a group is a + // parent. In other words the parent of the tree item will be a group and + // the previous tree item of the group is a conceptual parent of the tree + // item. + if (mRole == roles::OUTLINEITEM) { + Accessible* parentPrevSibling = parent->PrevSibling(); + if (parentPrevSibling && parentPrevSibling->Role() == mRole) { + mParent = parentPrevSibling; + return; + } + } + + // Way #2 for ARIA list and tree: group is a child of an item. In other words + // the parent of the item will be a group and containing item of the group is + // a conceptual parent of the item. + if (mRole == roles::LISTITEM || mRole == roles::OUTLINEITEM) { + Accessible* grandParent = parent->Parent(); + if (grandParent && grandParent->Role() == mRole) + mParent = grandParent; + } +} + +Accessible* +AccGroupInfo::FirstItemOf(Accessible* aContainer) +{ + // ARIA tree can be arranged by ARIA groups case #1 (previous sibling of a + // group is a parent) or by aria-level. + a11y::role containerRole = aContainer->Role(); + Accessible* item = aContainer->NextSibling(); + if (item) { + if (containerRole == roles::OUTLINEITEM && item->Role() == roles::GROUPING) + item = item->FirstChild(); + + if (item) { + AccGroupInfo* itemGroupInfo = item->GetGroupInfo(); + if (itemGroupInfo && itemGroupInfo->ConceptualParent() == aContainer) + return item; + } + } + + // ARIA list and tree can be arranged by ARIA groups case #2 (group is + // a child of an item). + item = aContainer->LastChild(); + if (!item) + return nullptr; + + if (item->Role() == roles::GROUPING && + (containerRole == roles::LISTITEM || containerRole == roles::OUTLINEITEM)) { + item = item->FirstChild(); + if (item) { + AccGroupInfo* itemGroupInfo = item->GetGroupInfo(); + if (itemGroupInfo && itemGroupInfo->ConceptualParent() == aContainer) + return item; + } + } + + // Otherwise, it can be a direct child if the container is a list or tree. + item = aContainer->FirstChild(); + if (ShouldReportRelations(item->Role(), containerRole)) + return item; + + return nullptr; +} + +Accessible* +AccGroupInfo::NextItemTo(Accessible* aItem) +{ + AccGroupInfo* groupInfo = aItem->GetGroupInfo(); + if (!groupInfo) + return nullptr; + + // If the item in middle of the group then search next item in siblings. + if (groupInfo->PosInSet() >= groupInfo->SetSize()) + return nullptr; + + Accessible* parent = aItem->Parent(); + uint32_t childCount = parent->ChildCount(); + for (uint32_t idx = aItem->IndexInParent() + 1; idx < childCount; idx++) { + Accessible* nextItem = parent->GetChildAt(idx); + AccGroupInfo* nextGroupInfo = nextItem->GetGroupInfo(); + if (nextGroupInfo && + nextGroupInfo->ConceptualParent() == groupInfo->ConceptualParent()) { + return nextItem; + } + } + + NS_NOTREACHED("Item in the middle of the group but there's no next item!"); + return nullptr; +} + +bool +AccGroupInfo::ShouldReportRelations(role aRole, role aParentRole) +{ + // We only want to report hierarchy-based node relations for items in tree or + // list form. ARIA level/owns relations are always reported. + if (aParentRole == roles::OUTLINE && aRole == roles::OUTLINEITEM) + return true; + if (aParentRole == roles::TREE_TABLE && aRole == roles::ROW) + return true; + if (aParentRole == roles::LIST && aRole == roles::LISTITEM) + return true; + + return false; +} diff --git a/accessible/base/AccGroupInfo.h b/accessible/base/AccGroupInfo.h new file mode 100644 index 0000000000..0932580709 --- /dev/null +++ b/accessible/base/AccGroupInfo.h @@ -0,0 +1,114 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef AccGroupInfo_h_ +#define AccGroupInfo_h_ + +#include "Accessible-inl.h" + +namespace mozilla { +namespace a11y { + +/** + * Calculate and store group information. + */ +class AccGroupInfo +{ +public: + ~AccGroupInfo() { MOZ_COUNT_DTOR(AccGroupInfo); } + + /** + * Return 1-based position in the group. + */ + uint32_t PosInSet() const { return mPosInSet; } + + /** + * Return a number of items in the group. + */ + uint32_t SetSize() const { return mSetSize; } + + /** + * Return a direct or logical parent of the accessible that this group info is + * created for. + */ + Accessible* ConceptualParent() const { return mParent; } + + /** + * Update group information. + */ + void Update(); + + /** + * Create group info. + */ + static AccGroupInfo* CreateGroupInfo(Accessible* aAccessible) + { + mozilla::a11y::role role = aAccessible->Role(); + if (role != mozilla::a11y::roles::ROW && + role != mozilla::a11y::roles::OUTLINEITEM && + role != mozilla::a11y::roles::OPTION && + role != mozilla::a11y::roles::LISTITEM && + role != mozilla::a11y::roles::MENUITEM && + role != mozilla::a11y::roles::COMBOBOX_OPTION && + role != mozilla::a11y::roles::RICH_OPTION && + role != mozilla::a11y::roles::CHECK_RICH_OPTION && + role != mozilla::a11y::roles::PARENT_MENUITEM && + role != mozilla::a11y::roles::CHECK_MENU_ITEM && + role != mozilla::a11y::roles::RADIO_MENU_ITEM && + role != mozilla::a11y::roles::RADIOBUTTON && + role != mozilla::a11y::roles::PAGETAB) + return nullptr; + + AccGroupInfo* info = new AccGroupInfo(aAccessible, BaseRole(role)); + return info; + } + + /** + * Return a first item for the given container. + */ + static Accessible* FirstItemOf(Accessible* aContainer); + + /** + * Return next item of the same group to the given item. + */ + static Accessible* NextItemTo(Accessible* aItem); + +protected: + AccGroupInfo(Accessible* aItem, a11y::role aRole); + +private: + AccGroupInfo() = delete; + AccGroupInfo(const AccGroupInfo&) = delete; + AccGroupInfo& operator =(const AccGroupInfo&) = delete; + + static mozilla::a11y::role BaseRole(mozilla::a11y::role aRole) + { + if (aRole == mozilla::a11y::roles::CHECK_MENU_ITEM || + aRole == mozilla::a11y::roles::PARENT_MENUITEM || + aRole == mozilla::a11y::roles::RADIO_MENU_ITEM) + return mozilla::a11y::roles::MENUITEM; + + if (aRole == mozilla::a11y::roles::CHECK_RICH_OPTION) + return mozilla::a11y::roles::RICH_OPTION; + + return aRole; + } + + /** + * Return true if the given parent and child roles should have their node + * relations reported. + */ + static bool ShouldReportRelations(a11y::role aRole, a11y::role aParentRole); + + uint32_t mPosInSet; + uint32_t mSetSize; + Accessible* mParent; + Accessible* mItem; + a11y::role mRole; +}; + +} // namespace mozilla +} // namespace a11y + +#endif diff --git a/accessible/base/AccIterator.cpp b/accessible/base/AccIterator.cpp new file mode 100644 index 0000000000..f6e890c502 --- /dev/null +++ b/accessible/base/AccIterator.cpp @@ -0,0 +1,414 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "AccIterator.h" + +#include "AccGroupInfo.h" +#ifdef MOZ_XUL +#include "XULTreeAccessible.h" +#endif + +#include "mozilla/dom/HTMLLabelElement.h" + +using namespace mozilla; +using namespace mozilla::a11y; + +//////////////////////////////////////////////////////////////////////////////// +// AccIterator +//////////////////////////////////////////////////////////////////////////////// + +AccIterator::AccIterator(Accessible* aAccessible, + filters::FilterFuncPtr aFilterFunc) : + mFilterFunc(aFilterFunc) +{ + mState = new IteratorState(aAccessible); +} + +AccIterator::~AccIterator() +{ + while (mState) { + IteratorState *tmp = mState; + mState = tmp->mParentState; + delete tmp; + } +} + +Accessible* +AccIterator::Next() +{ + while (mState) { + Accessible* child = mState->mParent->GetChildAt(mState->mIndex++); + if (!child) { + IteratorState* tmp = mState; + mState = mState->mParentState; + delete tmp; + + continue; + } + + uint32_t result = mFilterFunc(child); + if (result & filters::eMatch) + return child; + + if (!(result & filters::eSkipSubtree)) { + IteratorState* childState = new IteratorState(child, mState); + mState = childState; + } + } + + return nullptr; +} + +//////////////////////////////////////////////////////////////////////////////// +// nsAccIterator::IteratorState + +AccIterator::IteratorState::IteratorState(Accessible* aParent, + IteratorState *mParentState) : + mParent(aParent), mIndex(0), mParentState(mParentState) +{ +} + + +//////////////////////////////////////////////////////////////////////////////// +// RelatedAccIterator +//////////////////////////////////////////////////////////////////////////////// + +RelatedAccIterator:: + RelatedAccIterator(DocAccessible* aDocument, nsIContent* aDependentContent, + nsIAtom* aRelAttr) : + mDocument(aDocument), mRelAttr(aRelAttr), mProviders(nullptr), + mBindingParent(nullptr), mIndex(0) +{ + mBindingParent = aDependentContent->GetBindingParent(); + nsIAtom* IDAttr = mBindingParent ? + nsGkAtoms::anonid : nsGkAtoms::id; + + nsAutoString id; + if (aDependentContent->GetAttr(kNameSpaceID_None, IDAttr, id)) + mProviders = mDocument->mDependentIDsHash.Get(id); +} + +Accessible* +RelatedAccIterator::Next() +{ + if (!mProviders) + return nullptr; + + while (mIndex < mProviders->Length()) { + DocAccessible::AttrRelProvider* provider = (*mProviders)[mIndex++]; + + // Return related accessible for the given attribute and if the provider + // content is in the same binding in the case of XBL usage. + if (provider->mRelAttr == mRelAttr) { + nsIContent* bindingParent = provider->mContent->GetBindingParent(); + bool inScope = mBindingParent == bindingParent || + mBindingParent == provider->mContent; + + if (inScope) { + Accessible* related = mDocument->GetAccessible(provider->mContent); + if (related) + return related; + + // If the document content is pointed by relation then return the document + // itself. + if (provider->mContent == mDocument->GetContent()) + return mDocument; + } + } + } + + return nullptr; +} + + +//////////////////////////////////////////////////////////////////////////////// +// HTMLLabelIterator +//////////////////////////////////////////////////////////////////////////////// + +HTMLLabelIterator:: + HTMLLabelIterator(DocAccessible* aDocument, const Accessible* aAccessible, + LabelFilter aFilter) : + mRelIter(aDocument, aAccessible->GetContent(), nsGkAtoms::_for), + mAcc(aAccessible), mLabelFilter(aFilter) +{ +} + +bool +HTMLLabelIterator::IsLabel(Accessible* aLabel) +{ + dom::HTMLLabelElement* labelEl = + dom::HTMLLabelElement::FromContent(aLabel->GetContent()); + return labelEl && labelEl->GetControl() == mAcc->GetContent(); +} + +Accessible* +HTMLLabelIterator::Next() +{ + // Get either