mirror of
https://github.com/Feodor2/Mypal68.git
synced 2025-06-18 06:45:44 -04:00
68.14.8 - everything else
This commit is contained in:
parent
95cbc1282f
commit
18be06a872
@ -60,7 +60,6 @@ xpcom/reflect/xptcall/md/unix/.*
|
||||
browser/components/translation/cld2/.*
|
||||
browser/extensions/mortar/ppapi/.*
|
||||
devtools/client/shared/sourceeditor/codemirror/.*
|
||||
devtools/client/shared/sourceeditor/tern/.*
|
||||
dom/canvas/test/webgl-conf/checkout/closure-library/.*
|
||||
dom/media/gmp/rlz/.*
|
||||
dom/media/platforms/ffmpeg/ffmpeg57/.*
|
||||
|
@ -125,7 +125,6 @@ devtools/client/shared/source-map/
|
||||
devtools/client/shared/vendor/
|
||||
devtools/client/shared/sourceeditor/codemirror/*.js
|
||||
devtools/client/shared/sourceeditor/codemirror/**/*.js
|
||||
devtools/client/shared/sourceeditor/tern/
|
||||
devtools/client/shared/sourceeditor/test/cm_mode_ruby.js
|
||||
devtools/client/shared/sourceeditor/test/codemirror/
|
||||
devtools/server/actors/utils/automation-timeline.js
|
||||
@ -326,9 +325,6 @@ toolkit/components/reader/JSDOMParser.js
|
||||
# Uses preprocessing
|
||||
toolkit/components/reader/Readerable.jsm
|
||||
|
||||
# Should be going away soon
|
||||
toolkit/content/widgets/wizard.xml
|
||||
|
||||
# Uses preprocessing
|
||||
toolkit/mozapps/update/tests/data/xpcshellConstantsPP.js
|
||||
toolkit/modules/AppConstants.jsm
|
||||
|
452
.eslintrc.js
452
.eslintrc.js
@ -135,6 +135,7 @@ module.exports = {
|
||||
"no-array-constructor": "off",
|
||||
"no-undef": "off",
|
||||
"no-unused-vars": "off",
|
||||
"no-useless-concat": "off",
|
||||
"no-redeclare": "off",
|
||||
"no-global-assign": "off",
|
||||
}
|
||||
@ -187,6 +188,8 @@ module.exports = {
|
||||
"mozilla/reject-importGlobalProperties": "off",
|
||||
"mozilla/no-arbitrary-setTimeout": "off",
|
||||
"mozilla/no-define-cc-etc": "off",
|
||||
"mozilla/no-useless-parameters": "off",
|
||||
"mozilla/no-useless-removeEventListener": "off",
|
||||
"mozilla/use-chromeutils-generateqi": "off",
|
||||
"mozilla/use-default-preference-values": "off",
|
||||
"mozilla/use-includes-instead-of-indexOf": "off",
|
||||
@ -209,6 +212,7 @@ module.exports = {
|
||||
"no-restricted-globals": "off",
|
||||
"no-return-await": "off",
|
||||
"no-sequences": "off",
|
||||
"no-shadow": "off",
|
||||
"no-throw-literal": "off",
|
||||
"no-useless-concat": "off",
|
||||
"no-undef": "off",
|
||||
@ -259,10 +263,10 @@ module.exports = {
|
||||
"dom/websocket/**",
|
||||
"dom/workers/**",
|
||||
"dom/worklet/**",
|
||||
"dom/xbl/**",
|
||||
"dom/xml/**",
|
||||
"dom/xslt/**",
|
||||
"dom/xul/**",
|
||||
"dom/ipc/test.xhtml",
|
||||
],
|
||||
"rules": {
|
||||
"consistent-return": "off",
|
||||
@ -359,5 +363,451 @@ module.exports = {
|
||||
"rules": {
|
||||
"no-async-promise-executor": "off",
|
||||
}
|
||||
}, {
|
||||
"files": [
|
||||
"browser/base/content/test/chrome/test_aboutCrashed.xhtml",
|
||||
"browser/base/content/test/chrome/test_aboutRestartRequired.xhtml",
|
||||
"browser/base/content/test/general/browser_tab_dragdrop2_frame1.xhtml",
|
||||
"browser/components/places/tests/chrome/test_0_bug510634.xhtml",
|
||||
"browser/components/places/tests/chrome/test_bug1163447_selectItems_through_shortcut.xhtml",
|
||||
"browser/components/places/tests/chrome/test_0_bug510634.xhtml",
|
||||
"browser/components/places/tests/chrome/test_bug1163447_selectItems_through_shortcut.xhtml",
|
||||
"browser/components/places/tests/chrome/test_bug549192.xhtml",
|
||||
"browser/components/places/tests/chrome/test_bug549491.xhtml",
|
||||
"browser/components/places/tests/chrome/test_selectItems_on_nested_tree.xhtml",
|
||||
"browser/components/places/tests/chrome/test_treeview_date.xhtml",
|
||||
],
|
||||
"rules": {
|
||||
"mozilla/no-arbitrary-setTimeout": "off",
|
||||
"object-shorthand": "off",
|
||||
"no-undef": "off",
|
||||
"no-unused-vars": "off",
|
||||
}
|
||||
}, {
|
||||
"files": [
|
||||
"accessible/tests/mochitest/actions/test_keys_menu.xhtml",
|
||||
"accessible/tests/mochitest/elm/test_listbox.xhtml",
|
||||
"accessible/tests/mochitest/events/test_focus_autocomplete.xhtml",
|
||||
"accessible/tests/mochitest/events/test_focus_contextmenu.xhtml",
|
||||
"accessible/tests/mochitest/events/test_tree.xhtml",
|
||||
"accessible/tests/mochitest/hittest/test_zoom_tree.xhtml",
|
||||
"accessible/tests/mochitest/name/test_general.xhtml",
|
||||
"accessible/tests/mochitest/name/test_tree.xhtml",
|
||||
"accessible/tests/mochitest/selectable/test_listbox.xhtml",
|
||||
"accessible/tests/mochitest/states/test_expandable.xhtml",
|
||||
"accessible/tests/mochitest/tree/test_button.xhtml",
|
||||
"accessible/tests/mochitest/tree/test_tree.xhtml",
|
||||
"accessible/tests/mochitest/treeupdate/test_contextmenu.xhtml",
|
||||
"accessible/tests/mochitest/treeupdate/test_menu.xhtml",
|
||||
],
|
||||
"rules": {
|
||||
"object-shorthand": "off",
|
||||
"mozilla/no-compare-against-boolean-literals": "off",
|
||||
"mozilla/use-cc-etc": "off",
|
||||
"consistent-return": "off",
|
||||
"no-redeclare": "off",
|
||||
"no-sequences": "off",
|
||||
"no-shadow": "off",
|
||||
"no-unused-vars": "off",
|
||||
"no-useless-call": "off",
|
||||
}
|
||||
}, {
|
||||
"files": [
|
||||
"testing/mochitest/browser-harness.xhtml",
|
||||
"testing/mochitest/chrome/test_chromeGetTestFile.xhtml",
|
||||
"testing/mochitest/chrome/test_sanityEventUtils.xhtml",
|
||||
"testing/mochitest/chrome/test_sanityException.xhtml",
|
||||
"testing/mochitest/chrome/test_sanityException2.xhtml",
|
||||
"testing/mochitest/harness.xhtml",
|
||||
],
|
||||
"rules": {
|
||||
"dot-notation": "off",
|
||||
"object-shorthand": "off",
|
||||
"mozilla/use-services": "off",
|
||||
"mozilla/no-compare-against-boolean-literals": "off",
|
||||
"mozilla/no-useless-parameters": "off",
|
||||
"mozilla/no-useless-removeEventListener": "off",
|
||||
"mozilla/use-cc-etc": "off",
|
||||
"consistent-return": "off",
|
||||
"no-fallthrough": "off",
|
||||
"no-nested-ternary": "off",
|
||||
"no-redeclare": "off",
|
||||
"no-sequences": "off",
|
||||
"no-shadow": "off",
|
||||
"no-throw-literal": "off",
|
||||
"no-undef": "off",
|
||||
"no-unsanitized/property": "off",
|
||||
"no-unused-vars": "off",
|
||||
"no-useless-call": "off",
|
||||
}
|
||||
}, {
|
||||
"files": [
|
||||
"docshell/test/chrome/bug113934_window.xhtml",
|
||||
"docshell/test/chrome/bug215405_window.xhtml",
|
||||
"docshell/test/chrome/bug293235_window.xhtml",
|
||||
"docshell/test/chrome/bug294258_window.xhtml",
|
||||
"docshell/test/chrome/bug298622_window.xhtml",
|
||||
"docshell/test/chrome/bug301397_window.xhtml",
|
||||
"docshell/test/chrome/bug303267_window.xhtml",
|
||||
"docshell/test/chrome/bug311007_window.xhtml",
|
||||
"docshell/test/chrome/bug321671_window.xhtml",
|
||||
"docshell/test/chrome/bug360511_window.xhtml",
|
||||
"docshell/test/chrome/bug396519_window.xhtml",
|
||||
"docshell/test/chrome/bug396649_window.xhtml",
|
||||
"docshell/test/chrome/bug449778_window.xhtml",
|
||||
"docshell/test/chrome/bug449780_window.xhtml",
|
||||
"docshell/test/chrome/bug582176_window.xhtml",
|
||||
"docshell/test/chrome/bug662200_window.xhtml",
|
||||
"docshell/test/chrome/bug690056_window.xhtml",
|
||||
"docshell/test/chrome/bug89419_window.xhtml",
|
||||
"docshell/test/chrome/mozFrameType_window.xhtml",
|
||||
"docshell/test/chrome/test_bug453650.xhtml",
|
||||
"docshell/test/chrome/test_bug454235.xhtml",
|
||||
"docshell/test/chrome/test_bug565388.xhtml",
|
||||
"docshell/test/chrome/test_bug608669.xhtml",
|
||||
"docshell/test/chrome/test_bug789773.xhtml",
|
||||
"docshell/test/chrome/test_bug846906.xhtml",
|
||||
"docshell/test/chrome/test_docRedirect.xhtml",
|
||||
"docshell/test/chrome/test_principalInherit.xhtml",
|
||||
"docshell/test/chrome/test_viewsource_forbidden_in_iframe.xhtml",
|
||||
],
|
||||
"rules": {
|
||||
"dot-notation": "off",
|
||||
"no-global-assign": "off",
|
||||
"no-octal": "off",
|
||||
"object-shorthand": "off",
|
||||
"mozilla/consistent-if-bracing": "off",
|
||||
"mozilla/no-compare-against-boolean-literals": "off",
|
||||
"mozilla/no-useless-parameters": "off",
|
||||
"mozilla/no-useless-removeEventListener": "off",
|
||||
"mozilla/use-cc-etc": "off",
|
||||
"mozilla/use-services": "off",
|
||||
"mozilla/use-chromeutils-generateqi": "off",
|
||||
"consistent-return": "off",
|
||||
"no-delete-var": "off",
|
||||
"no-redeclare": "off",
|
||||
"no-sequences": "off",
|
||||
"no-shadow": "off",
|
||||
"no-undef": "off",
|
||||
"no-unused-vars": "off",
|
||||
"no-useless-call": "off",
|
||||
}
|
||||
}, {
|
||||
"files": [
|
||||
"editor/composer/test/test_bug434998.xhtml",
|
||||
"editor/libeditor/tests/test_bug607584.xhtml",
|
||||
"editor/libeditor/tests/test_bug616590.xhtml",
|
||||
"editor/libeditor/tests/test_bug780908.xhtml",
|
||||
],
|
||||
"rules": {
|
||||
"object-shorthand": "off",
|
||||
"no-undef": "off",
|
||||
}
|
||||
}, {
|
||||
"files": [
|
||||
"widget/tests/native_menus_window.xhtml",
|
||||
"widget/tests/native_mouse_mac_window.xhtml",
|
||||
"widget/tests/standalone_native_menu_window.xhtml",
|
||||
"widget/tests/system_font_changes.xhtml",
|
||||
"widget/tests/taskbar_previews.xhtml",
|
||||
"widget/tests/test_bug1123480.xhtml",
|
||||
"widget/tests/test_bug343416.xhtml",
|
||||
"widget/tests/test_bug428405.xhtml",
|
||||
"widget/tests/test_bug429954.xhtml",
|
||||
"widget/tests/test_bug466599.xhtml",
|
||||
"widget/tests/test_bug485118.xhtml",
|
||||
"widget/tests/test_bug517396.xhtml",
|
||||
"widget/tests/test_bug538242.xhtml",
|
||||
"widget/tests/test_bug596600.xhtml",
|
||||
"widget/tests/test_bug673301.xhtml",
|
||||
"widget/tests/test_bug760802.xhtml",
|
||||
"widget/tests/test_chrome_context_menus_win.xhtml",
|
||||
"widget/tests/test_clipboard.xhtml",
|
||||
"widget/tests/test_input_events_on_deactive_window.xhtml",
|
||||
"widget/tests/test_key_event_counts.xhtml",
|
||||
"widget/tests/test_keycodes.xhtml",
|
||||
"widget/tests/test_panel_mouse_coords.xhtml",
|
||||
"widget/tests/test_position_on_resize.xhtml",
|
||||
"widget/tests/test_sizemode_events.xhtml",
|
||||
"widget/tests/test_taskbar_progress.xhtml",
|
||||
"widget/tests/test_transferable_overflow.xhtml",
|
||||
"widget/tests/window_bug429954.xhtml",
|
||||
"widget/tests/window_bug478536.xhtml",
|
||||
"widget/tests/window_composition_text_querycontent.xhtml",
|
||||
"widget/tests/window_state_windows.xhtml",
|
||||
"widget/tests/window_wheeltransaction.xhtml",
|
||||
],
|
||||
"rules": {
|
||||
"complexity": "off",
|
||||
"consistent-return": "off",
|
||||
"dot-notation": "off",
|
||||
"mozilla/prefer-boolean-length-check": "off",
|
||||
"mozilla/no-useless-parameters": "off",
|
||||
"mozilla/no-useless-removeEventListener": "off",
|
||||
"mozilla/use-cc-etc": "off",
|
||||
"mozilla/use-chromeutils-generateqi": "off",
|
||||
"mozilla/use-services": "off",
|
||||
"object-shorthand": "off",
|
||||
"no-caller": "off",
|
||||
"no-delete-var": "off",
|
||||
"no-nested-ternary": "off",
|
||||
"no-new-object": "off",
|
||||
"no-redeclare": "off",
|
||||
"no-sequences": "off",
|
||||
"no-shadow": "off",
|
||||
"no-undef": "off",
|
||||
"no-unsafe-finally": "off",
|
||||
"no-unsanitized/property": "off",
|
||||
"no-unused-vars": "off",
|
||||
"no-useless-return": "off",
|
||||
}
|
||||
}, {
|
||||
"files": [
|
||||
"dom/base/test/chrome/file_bug1139964.xhtml",
|
||||
"dom/base/test/chrome/file_bug549682.xhtml",
|
||||
"dom/base/test/chrome/file_bug616841.xhtml",
|
||||
"dom/base/test/chrome/file_bug990812-1.xhtml",
|
||||
"dom/base/test/chrome/file_bug990812-2.xhtml",
|
||||
"dom/base/test/chrome/file_bug990812-3.xhtml",
|
||||
"dom/base/test/chrome/file_bug990812-4.xhtml",
|
||||
"dom/base/test/chrome/file_bug990812-5.xhtml",
|
||||
"dom/base/test/chrome/file_bug990812.xhtml",
|
||||
"dom/base/test/chrome/test_bug1098074_throw_from_ReceiveMessage.xhtml",
|
||||
"dom/base/test/chrome/test_bug339494.xhtml",
|
||||
"dom/base/test/chrome/test_bug429785.xhtml",
|
||||
"dom/base/test/chrome/test_bug467123.xhtml",
|
||||
"dom/base/test/chrome/test_bug683852.xhtml",
|
||||
"dom/base/test/chrome/test_bug780529.xhtml",
|
||||
"dom/base/test/chrome/test_bug800386.xhtml",
|
||||
"dom/base/test/chrome/test_bug814638.xhtml",
|
||||
"dom/base/test/chrome/test_bug884693.xhtml",
|
||||
"dom/base/test/chrome/test_document-element-inserted.xhtml",
|
||||
"dom/base/test/chrome/test_domparsing.xhtml",
|
||||
"dom/base/test/chrome/test_fileconstructor.xhtml",
|
||||
"dom/base/test/chrome/title_window.xhtml",
|
||||
"dom/base/test/chrome/window_nsITextInputProcessor.xhtml",
|
||||
"dom/base/test/chrome/window_swapFrameLoaders.xhtml",
|
||||
"dom/base/test/test_domrequesthelper.xhtml",
|
||||
"dom/bindings/test/test_bug1123516_maplikesetlikechrome.xhtml",
|
||||
"dom/console/tests/test_jsm.xhtml",
|
||||
"dom/events/test/test_bug1412775.xhtml",
|
||||
"dom/events/test/test_bug336682_2.xhtml",
|
||||
"dom/events/test/test_bug415498.xhtml",
|
||||
"dom/events/test/test_bug602962.xhtml",
|
||||
"dom/events/test/test_bug617528.xhtml",
|
||||
"dom/events/test/test_bug679494.xhtml",
|
||||
"dom/indexedDB/test/test_globalObjects_chrome.xhtml",
|
||||
"dom/indexedDB/test/test_wrappedArray.xhtml",
|
||||
"dom/ipc/test.xhtml",
|
||||
"dom/ipc/tests/test_process_error.xhtml",
|
||||
"dom/notification/test/chrome/test_notification_system_principal.xhtml",
|
||||
"dom/plugins/test/mochitest/test_busy_hang.xhtml",
|
||||
"dom/plugins/test/mochitest/test_convertpoint.xhtml",
|
||||
"dom/plugins/test/mochitest/test_crash_notify.xhtml",
|
||||
"dom/plugins/test/mochitest/test_crash_notify_no_report.xhtml",
|
||||
"dom/plugins/test/mochitest/test_crash_submit.xhtml",
|
||||
"dom/plugins/test/mochitest/test_hang_submit.xhtml",
|
||||
"dom/plugins/test/mochitest/test_hangui.xhtml",
|
||||
"dom/plugins/test/mochitest/test_idle_hang.xhtml",
|
||||
"dom/plugins/test/mochitest/test_xulbrowser_plugin_visibility.xhtml",
|
||||
"dom/plugins/test/mochitest/xulbrowser_plugin_visibility.xhtml",
|
||||
"dom/security/test/general/test_bug1277803.xhtml",
|
||||
"dom/serviceworkers/test/test_serviceworkerinfo.xhtml",
|
||||
"dom/serviceworkers/test/test_serviceworkermanager.xhtml",
|
||||
"dom/system/tests/test_constants.xhtml",
|
||||
"dom/tests/mochitest/chrome/DOMWindowCreated_chrome.xhtml",
|
||||
"dom/tests/mochitest/chrome/MozDomFullscreen_chrome.xhtml",
|
||||
"dom/tests/mochitest/chrome/sizemode_attribute.xhtml",
|
||||
"dom/tests/mochitest/chrome/test_cyclecollector.xhtml",
|
||||
"dom/tests/mochitest/chrome/test_docshell_swap.xhtml",
|
||||
"dom/tests/mochitest/chrome/window_focus.xhtml",
|
||||
"dom/url/tests/test_bug883784.xhtml",
|
||||
"dom/workers/test/test_WorkerDebugger.xhtml",
|
||||
"dom/workers/test/test_WorkerDebugger_console.xhtml",
|
||||
"dom/workers/test/test_fileReadSlice.xhtml",
|
||||
"dom/workers/test/test_fileReaderSync.xhtml",
|
||||
"dom/workers/test/test_fileSlice.xhtml",
|
||||
],
|
||||
"rules": {
|
||||
"mozilla/no-useless-parameters": "off",
|
||||
"mozilla/no-useless-removeEventListener": "off",
|
||||
"mozilla/use-chromeutils-generateqi": "off",
|
||||
"mozilla/use-services": "off",
|
||||
"complexity": "off",
|
||||
"no-array-constructor": "off",
|
||||
"no-caller": "off",
|
||||
"no-empty": "off",
|
||||
"no-eval": "off",
|
||||
"no-lone-blocks": "off",
|
||||
"no-octal": "off",
|
||||
"no-redeclare": "off",
|
||||
"no-shadow": "off",
|
||||
"no-throw-literal": "off",
|
||||
"no-undef": "off",
|
||||
"no-unsanitized/method": "off",
|
||||
"no-unused-vars": "off",
|
||||
"no-useless-return": "off",
|
||||
"object-shorthand": "off",
|
||||
}
|
||||
}, {
|
||||
"files": [
|
||||
"toolkit/components/aboutmemory/tests/test_aboutmemory.xhtml",
|
||||
"toolkit/components/aboutmemory/tests/test_aboutmemory2.xhtml",
|
||||
"toolkit/components/aboutmemory/tests/test_aboutmemory3.xhtml",
|
||||
"toolkit/components/aboutmemory/tests/test_aboutmemory4.xhtml",
|
||||
"toolkit/components/aboutmemory/tests/test_aboutmemory5.xhtml",
|
||||
"toolkit/components/aboutmemory/tests/test_aboutmemory7.xhtml",
|
||||
"toolkit/components/aboutmemory/tests/test_dumpGCAndCCLogsToFile.xhtml",
|
||||
"toolkit/components/aboutmemory/tests/test_memoryReporters.xhtml",
|
||||
"toolkit/components/aboutmemory/tests/test_memoryReporters2.xhtml",
|
||||
"toolkit/components/aboutmemory/tests/test_sqliteMultiReporter.xhtml",
|
||||
"toolkit/components/ctypes/tests/chrome/test_ctypes.xhtml",
|
||||
"toolkit/components/osfile/tests/mochi/test_osfile_back.xhtml",
|
||||
"toolkit/components/osfile/tests/mochi/test_osfile_comms.xhtml",
|
||||
"toolkit/components/osfile/tests/mochi/test_osfile_front.xhtml",
|
||||
"toolkit/components/places/tests/chrome/browser_disableglobalhistory.xhtml",
|
||||
"toolkit/components/places/tests/chrome/test_browser_disableglobalhistory.xhtml",
|
||||
"toolkit/components/places/tests/chrome/test_favicon_annotations.xhtml",
|
||||
"toolkit/components/workerloader/tests/test_loading.xhtml",
|
||||
"toolkit/content/tests/chrome/bug263683_window.xhtml",
|
||||
"toolkit/content/tests/chrome/bug304188_window.xhtml",
|
||||
"toolkit/content/tests/chrome/bug331215_window.xhtml",
|
||||
"toolkit/content/tests/chrome/bug360437_window.xhtml",
|
||||
"toolkit/content/tests/chrome/bug366992_window.xhtml",
|
||||
"toolkit/content/tests/chrome/bug409624_window.xhtml",
|
||||
"toolkit/content/tests/chrome/bug429723_window.xhtml",
|
||||
"toolkit/content/tests/chrome/bug451540_window.xhtml",
|
||||
"toolkit/content/tests/chrome/dialog_dialogfocus.xhtml",
|
||||
"toolkit/content/tests/chrome/findbar_entireword_window.xhtml",
|
||||
"toolkit/content/tests/chrome/findbar_events_window.xhtml",
|
||||
"toolkit/content/tests/chrome/findbar_window.xhtml",
|
||||
"toolkit/content/tests/chrome/frame_popup_anchor.xhtml",
|
||||
"toolkit/content/tests/chrome/frame_subframe_origin_subframe1.xhtml",
|
||||
"toolkit/content/tests/chrome/frame_subframe_origin_subframe2.xhtml",
|
||||
"toolkit/content/tests/chrome/test_arrowpanel.xhtml",
|
||||
"toolkit/content/tests/chrome/test_autocomplete2.xhtml",
|
||||
"toolkit/content/tests/chrome/test_autocomplete3.xhtml",
|
||||
"toolkit/content/tests/chrome/test_autocomplete4.xhtml",
|
||||
"toolkit/content/tests/chrome/test_autocomplete5.xhtml",
|
||||
"toolkit/content/tests/chrome/test_autocomplete_emphasis.xhtml",
|
||||
"toolkit/content/tests/chrome/test_autocomplete_mac_caret.xhtml",
|
||||
"toolkit/content/tests/chrome/test_autocomplete_placehold_last_complete.xhtml",
|
||||
"toolkit/content/tests/chrome/test_browser_drop.xhtml",
|
||||
"toolkit/content/tests/chrome/test_bug1048178.xhtml",
|
||||
"toolkit/content/tests/chrome/test_bug382990.xhtml",
|
||||
"toolkit/content/tests/chrome/test_bug437844.xhtml",
|
||||
"toolkit/content/tests/chrome/test_bug624329.xhtml",
|
||||
"toolkit/content/tests/chrome/test_bug792324.xhtml",
|
||||
"toolkit/content/tests/chrome/test_contextmenu_list.xhtml",
|
||||
"toolkit/content/tests/chrome/test_cursorsnap.xhtml",
|
||||
"toolkit/content/tests/chrome/test_dialogfocus.xhtml",
|
||||
"toolkit/content/tests/chrome/test_hiddenitems.xhtml",
|
||||
"toolkit/content/tests/chrome/test_hiddenpaging.xhtml",
|
||||
"toolkit/content/tests/chrome/test_maximized_persist.xhtml",
|
||||
"toolkit/content/tests/chrome/test_menu.xhtml",
|
||||
"toolkit/content/tests/chrome/test_menuitem_blink.xhtml",
|
||||
"toolkit/content/tests/chrome/test_menulist.xhtml",
|
||||
"toolkit/content/tests/chrome/test_menulist_keynav.xhtml",
|
||||
"toolkit/content/tests/chrome/test_mousescroll.xhtml",
|
||||
"toolkit/content/tests/chrome/test_mozinputbox_dictionary.xhtml",
|
||||
"toolkit/content/tests/chrome/test_notificationbox.xhtml",
|
||||
"toolkit/content/tests/chrome/test_panel_focus.xhtml",
|
||||
"toolkit/content/tests/chrome/test_popup_keys.xhtml",
|
||||
"toolkit/content/tests/chrome/test_popup_scaled.xhtml",
|
||||
"toolkit/content/tests/chrome/test_popupincontent.xhtml",
|
||||
"toolkit/content/tests/chrome/test_popupremoving.xhtml",
|
||||
"toolkit/content/tests/chrome/test_popupremoving_frame.xhtml",
|
||||
"toolkit/content/tests/chrome/test_position.xhtml",
|
||||
"toolkit/content/tests/chrome/test_preferences.xhtml",
|
||||
"toolkit/content/tests/chrome/test_richlistbox.xhtml",
|
||||
"toolkit/content/tests/chrome/test_righttoleft.xhtml",
|
||||
"toolkit/content/tests/chrome/test_screenPersistence.xhtml",
|
||||
"toolkit/content/tests/chrome/test_scrollbar.xhtml",
|
||||
"toolkit/content/tests/chrome/test_showcaret.xhtml",
|
||||
"toolkit/content/tests/chrome/test_tabbox.xhtml",
|
||||
"toolkit/content/tests/chrome/test_textbox_search.xhtml",
|
||||
"toolkit/content/tests/chrome/test_tree_view.xhtml",
|
||||
"toolkit/content/tests/chrome/window_browser_drop.xhtml",
|
||||
"toolkit/content/tests/chrome/window_cursorsnap_dialog.xhtml",
|
||||
"toolkit/content/tests/chrome/window_cursorsnap_wizard.xhtml",
|
||||
"toolkit/content/tests/chrome/window_keys.xhtml",
|
||||
"toolkit/content/tests/chrome/window_largemenu.xhtml",
|
||||
"toolkit/content/tests/chrome/window_panel.xhtml",
|
||||
"toolkit/content/tests/chrome/window_panel_anchoradjust.xhtml",
|
||||
"toolkit/content/tests/chrome/window_popup_preventdefault_chrome.xhtml",
|
||||
"toolkit/content/tests/chrome/window_preferences.xhtml",
|
||||
"toolkit/content/tests/chrome/window_preferences3.xhtml",
|
||||
"toolkit/content/tests/chrome/window_preferences_beforeaccept.xhtml",
|
||||
"toolkit/content/tests/chrome/window_preferences_commandretarget.xhtml",
|
||||
"toolkit/content/tests/chrome/window_preferences_onsyncfrompreference.xhtml",
|
||||
"toolkit/content/tests/chrome/window_subframe_origin.xhtml",
|
||||
"toolkit/content/tests/chrome/window_titlebar.xhtml",
|
||||
"toolkit/content/tests/chrome/window_tooltip.xhtml",
|
||||
"toolkit/content/tests/widgets/test_contextmenu_menugroup.xhtml",
|
||||
"toolkit/content/tests/widgets/test_contextmenu_nested.xhtml",
|
||||
"toolkit/content/tests/widgets/test_editor_currentURI.xhtml",
|
||||
"toolkit/content/tests/widgets/test_popupanchor.xhtml",
|
||||
"toolkit/content/tests/widgets/test_popupreflows.xhtml",
|
||||
"toolkit/content/tests/widgets/window_menubar.xhtml",
|
||||
"toolkit/modules/tests/chrome/test_bug544442_checkCert.xhtml",
|
||||
"toolkit/profile/test/test_create_profile.xhtml",
|
||||
],
|
||||
"rules": {
|
||||
"object-shorthand": "off",
|
||||
"consistent-return": "off",
|
||||
"mozilla/consistent-if-bracing": "off",
|
||||
"mozilla/no-compare-against-boolean-literals": "off",
|
||||
"mozilla/no-useless-parameters": "off",
|
||||
"mozilla/no-useless-removeEventListener": "off",
|
||||
"mozilla/prefer-boolean-length-check": "off",
|
||||
"mozilla/use-cc-etc": "off",
|
||||
"mozilla/use-chromeutils-generateqi": "off",
|
||||
"mozilla/use-chromeutils-import": "off",
|
||||
"mozilla/use-default-preference-values": "off",
|
||||
"mozilla/use-services": "off",
|
||||
"no-caller": "off",
|
||||
"no-else-return": "off",
|
||||
"no-eval": "off",
|
||||
"no-fallthrough": "off",
|
||||
"no-irregular-whitespace": "off",
|
||||
"no-lonely-if": "off",
|
||||
"no-nested-ternary": "off",
|
||||
"no-redeclare": "off",
|
||||
"no-sequences": "off",
|
||||
"no-shadow": "off",
|
||||
"no-throw-literal": "off",
|
||||
"no-undef": "off",
|
||||
"no-unneeded-ternary": "off",
|
||||
"no-unused-vars": "off",
|
||||
"no-useless-concat": "off",
|
||||
"no-useless-return": "off",
|
||||
}
|
||||
}, {
|
||||
"files": [
|
||||
"accessible/**",
|
||||
"devtools/**",
|
||||
"dom/**",
|
||||
"docshell/**",
|
||||
"editor/libeditor/tests/**",
|
||||
"editor/spellchecker/tests/test_bug338427.html",
|
||||
"gfx/**",
|
||||
"image/test/browser/browser_image.js",
|
||||
"js/src/builtin/**",
|
||||
"layout/**",
|
||||
"mobile/android/**",
|
||||
"modules/**",
|
||||
"netwerk/**",
|
||||
"remote/**",
|
||||
"security/manager/**",
|
||||
"services/**",
|
||||
"storage/test/unit/test_vacuum.js",
|
||||
"taskcluster/docker/periodic-updates/scripts/**",
|
||||
"testing/**",
|
||||
"tools/**",
|
||||
"widget/tests/test_assign_event_data.html",
|
||||
],
|
||||
"rules": {
|
||||
"mozilla/prefer-boolean-length-check": "off",
|
||||
}
|
||||
}]
|
||||
};
|
||||
|
4
Cargo.lock
generated
4
Cargo.lock
generated
@ -796,9 +796,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "dogear"
|
||||
version = "0.2.5"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "26b7583e1427e296c852f3217eaab3890e698f742b8d7349beb1f40c4e946fc9"
|
||||
checksum = "c01a457f8d6689260111be60774bfb68e558b41bc89b866ebc3bbed60ba255cb"
|
||||
dependencies = [
|
||||
"log",
|
||||
"smallbitvec",
|
||||
|
11
README.md
11
README.md
@ -7,7 +7,7 @@ A browser for Windows XP based on Firefox 68.
|
||||
|
||||
## KNOWN PROBLEMS
|
||||
|
||||
- 1.5gb memory limit on winxp, if the browser reaches the limit it crashes inevitably, singleporess mode crashes all,
|
||||
- 1.5gb memory limit on winxp, if the browser reaches the limit it crashes inevitably, singleprocess mode crashes all,
|
||||
multiprocess only this which reaches 1.5gb, so it better here.
|
||||
I think this is OS limitation, nothing to do with this.
|
||||
|
||||
@ -17,8 +17,9 @@ A browser for Windows XP based on Firefox 68.
|
||||
|
||||
- This browser does not run well on winxp SP2 and lower. If you do not want to install SP3, be ready for crashes and blue screens.
|
||||
If you are on SP2 and lower, there is no need to post a screenshot from blue_screen_view. And i suggest to apply postready updates of 2019.
|
||||
Some say that it runs fine on sp2 but it is no accurate data what to do.
|
||||
Some say that it runs fine on sp2 but it is no accurate data what to do, [there about win2000](https://mrqash.blogspot.com/2022/04/mypal-68-firefox-68121-on-windows-2000.html).
|
||||
|
||||
## [UPDATING AND POSSIBLE PROBLEMS](https://github.com/Feodor2/Mypal68/wiki/Updating-to-a-new-version)
|
||||
|
||||
## IF YOU GOT A BLUE SCREEN
|
||||
|
||||
@ -33,15 +34,15 @@ Do not post pictures of the crash, this is useless and a waste.
|
||||
Also put your pc specs: cpu, ram and graphics card
|
||||
If I don't reproduce the crash myself then you may to submit drwatson.log.
|
||||
Drwatson log is usually inside All Users\Application Data\Microsoft\Dr Watson.
|
||||
Minidump also may be usefull. Do not post any irrelevent logs.
|
||||
An issue without details cosider as invalid.
|
||||
Minidump also may be usefull. Do not post any irrelevant logs.
|
||||
An issue without details considered as invalid.
|
||||
|
||||
## IF YOU WANT REPORT A SITE
|
||||
|
||||
Report [there](https://github.com/Feodor2/Mypal68/issues/228).
|
||||
Put the actual link to the site
|
||||
Notice that I never would look to the site which requires the login, including any goolag sites.
|
||||
Please try to find what feature is missig by yourself by checking on newer firefoxes and find first version where it works.
|
||||
Please try to find what feature is missing by yourself by checking on newer firefoxes and find first version where it works (mozregression day).
|
||||
Actually I do not look every site, no time for this.
|
||||
|
||||
## YOU MAY DONATE
|
||||
|
@ -5,17 +5,22 @@
|
||||
#include "AccessibleWrap.h"
|
||||
|
||||
#include "Accessible-inl.h"
|
||||
#include "AccEvent.h"
|
||||
#include "AndroidInputType.h"
|
||||
#include "DocAccessibleWrap.h"
|
||||
#include "IDSet.h"
|
||||
#include "JavaBuiltins.h"
|
||||
#include "SessionAccessibility.h"
|
||||
#include "TraversalRule.h"
|
||||
#include "Pivot.h"
|
||||
#include "nsAccessibilityService.h"
|
||||
#include "nsEventShell.h"
|
||||
#include "nsPersistentProperties.h"
|
||||
#include "nsIAccessibleAnnouncementEvent.h"
|
||||
#include "nsIStringBundle.h"
|
||||
#include "nsAccUtils.h"
|
||||
#include "nsTextEquivUtils.h"
|
||||
#include "RootAccessible.h"
|
||||
|
||||
#include "mozilla/a11y/PDocAccessibleChild.h"
|
||||
#include "mozilla/jni/GeckoBundleUtils.h"
|
||||
@ -78,6 +83,27 @@ nsresult AccessibleWrap::HandleAccEvent(AccEvent* aEvent) {
|
||||
}
|
||||
break;
|
||||
}
|
||||
case nsIAccessibleEvent::EVENT_TEXT_CARET_MOVED: {
|
||||
if (accessible != aEvent->Document() && !aEvent->IsFromUserInput()) {
|
||||
AccCaretMoveEvent* caretEvent = downcast_accEvent(aEvent);
|
||||
if (IsHyperText()) {
|
||||
DOMPoint point =
|
||||
AsHyperText()->OffsetToDOMPoint(caretEvent->GetCaretOffset());
|
||||
if (Accessible* newPos =
|
||||
doc->GetAccessibleOrContainer(point.node)) {
|
||||
static_cast<AccessibleWrap*>(newPos)->Pivot(
|
||||
java::SessionAccessibility::HTML_GRANULARITY_DEFAULT, true,
|
||||
true);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case nsIAccessibleEvent::EVENT_SCROLLING_START: {
|
||||
accessible->Pivot(java::SessionAccessibility::HTML_GRANULARITY_DEFAULT,
|
||||
true, true);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@ -122,15 +148,11 @@ nsresult AccessibleWrap::HandleAccEvent(AccEvent* aEvent) {
|
||||
|
||||
RefPtr<AccessibleWrap> newPosition =
|
||||
static_cast<AccessibleWrap*>(vcEvent->NewAccessible());
|
||||
auto oldPosition = static_cast<AccessibleWrap*>(vcEvent->OldAccessible());
|
||||
|
||||
if (sessionAcc && newPosition) {
|
||||
if (oldPosition != newPosition) {
|
||||
if (vcEvent->Reason() == nsIAccessiblePivot::REASON_POINT) {
|
||||
sessionAcc->SendHoverEnterEvent(newPosition);
|
||||
} else {
|
||||
sessionAcc->SendAccessibilityFocusedEvent(newPosition);
|
||||
}
|
||||
if (vcEvent->Reason() == nsIAccessiblePivot::REASON_POINT) {
|
||||
sessionAcc->SendHoverEnterEvent(newPosition);
|
||||
} else {
|
||||
sessionAcc->SendAccessibilityFocusedEvent(newPosition);
|
||||
}
|
||||
|
||||
if (vcEvent->BoundaryType() != nsIAccessiblePivot::NO_BOUNDARY) {
|
||||
@ -247,6 +269,155 @@ bool AccessibleWrap::GetSelectionBounds(int32_t* aStartOffset,
|
||||
return false;
|
||||
}
|
||||
|
||||
void AccessibleWrap::Pivot(int32_t aGranularity, bool aForward,
|
||||
bool aInclusive) {
|
||||
a11y::Pivot pivot(RootAccessible());
|
||||
TraversalRule rule(aGranularity);
|
||||
Accessible* result = aForward ? pivot.Next(this, rule, aInclusive)
|
||||
: pivot.Prev(this, rule, aInclusive);
|
||||
if (result && (result != this || aInclusive)) {
|
||||
PivotMoveReason reason = aForward ? nsIAccessiblePivot::REASON_NEXT
|
||||
: nsIAccessiblePivot::REASON_PREV;
|
||||
RefPtr<AccEvent> event = new AccVCChangeEvent(
|
||||
result->Document(), this, -1, -1, result, -1, -1, reason,
|
||||
nsIAccessiblePivot::NO_BOUNDARY, eFromUserInput);
|
||||
nsEventShell::FireEvent(event);
|
||||
}
|
||||
}
|
||||
|
||||
void AccessibleWrap::ExploreByTouch(float aX, float aY) {
|
||||
a11y::Pivot pivot(RootAccessible());
|
||||
TraversalRule rule;
|
||||
|
||||
Accessible* result = pivot.AtPoint(aX, aY, rule);
|
||||
|
||||
if (result && result != this) {
|
||||
RefPtr<AccEvent> event =
|
||||
new AccVCChangeEvent(result->Document(), this, -1, -1, result, -1, -1,
|
||||
nsIAccessiblePivot::REASON_POINT,
|
||||
nsIAccessiblePivot::NO_BOUNDARY, eFromUserInput);
|
||||
nsEventShell::FireEvent(event);
|
||||
}
|
||||
}
|
||||
|
||||
void AccessibleWrap::NavigateText(int32_t aGranularity, int32_t aStartOffset,
|
||||
int32_t aEndOffset, bool aForward,
|
||||
bool aSelect) {
|
||||
a11y::Pivot pivot(RootAccessible());
|
||||
|
||||
HyperTextAccessible* editable =
|
||||
(State() & states::EDITABLE) != 0 ? AsHyperText() : nullptr;
|
||||
|
||||
int32_t start = aStartOffset, end = aEndOffset;
|
||||
// If the accessible is an editable, set the virtual cursor position
|
||||
// to its caret offset. Otherwise use the document's virtual cursor
|
||||
// position as a starting offset.
|
||||
if (editable) {
|
||||
start = end = editable->CaretOffset();
|
||||
}
|
||||
|
||||
uint16_t pivotGranularity = nsIAccessiblePivot::LINE_BOUNDARY;
|
||||
switch (aGranularity) {
|
||||
case 1: // MOVEMENT_GRANULARITY_CHARACTER
|
||||
pivotGranularity = nsIAccessiblePivot::CHAR_BOUNDARY;
|
||||
break;
|
||||
case 2: // MOVEMENT_GRANULARITY_WORD
|
||||
pivotGranularity = nsIAccessiblePivot::WORD_BOUNDARY;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
int32_t newOffset;
|
||||
Accessible* newAnchor = nullptr;
|
||||
if (aForward) {
|
||||
newAnchor = pivot.NextText(this, &start, &end, pivotGranularity);
|
||||
newOffset = end;
|
||||
} else {
|
||||
newAnchor = pivot.PrevText(this, &start, &end, pivotGranularity);
|
||||
newOffset = start;
|
||||
}
|
||||
|
||||
if (newAnchor && (start != aStartOffset || end != aEndOffset)) {
|
||||
RefPtr<AccEvent> event = new AccVCChangeEvent(
|
||||
newAnchor->Document(), this, aStartOffset, aEndOffset, newAnchor, start,
|
||||
end, nsIAccessiblePivot::REASON_NONE, pivotGranularity, eFromUserInput);
|
||||
nsEventShell::FireEvent(event);
|
||||
}
|
||||
|
||||
// If we are in an editable, move the caret to the new virtual cursor
|
||||
// offset.
|
||||
if (editable) {
|
||||
if (aSelect) {
|
||||
int32_t anchor = editable->CaretOffset();
|
||||
if (editable->SelectionCount()) {
|
||||
int32_t startSel, endSel;
|
||||
GetSelectionOrCaret(&startSel, &endSel);
|
||||
anchor = startSel == anchor ? endSel : startSel;
|
||||
}
|
||||
editable->SetSelectionBoundsAt(0, anchor, newOffset);
|
||||
} else {
|
||||
editable->SetCaretOffset(newOffset);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void AccessibleWrap::SetSelection(int32_t aStart, int32_t aEnd) {
|
||||
if (HyperTextAccessible* textAcc = AsHyperText()) {
|
||||
if (aStart == aEnd) {
|
||||
textAcc->SetCaretOffset(aStart);
|
||||
} else {
|
||||
textAcc->SetSelectionBoundsAt(0, aStart, aEnd);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void AccessibleWrap::Cut() {
|
||||
if ((State() & states::EDITABLE) == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (HyperTextAccessible* textAcc = AsHyperText()) {
|
||||
int32_t startSel, endSel;
|
||||
GetSelectionOrCaret(&startSel, &endSel);
|
||||
textAcc->CutText(startSel, endSel);
|
||||
}
|
||||
}
|
||||
|
||||
void AccessibleWrap::Copy() {
|
||||
if (HyperTextAccessible* textAcc = AsHyperText()) {
|
||||
int32_t startSel, endSel;
|
||||
GetSelectionOrCaret(&startSel, &endSel);
|
||||
textAcc->CopyText(startSel, endSel);
|
||||
}
|
||||
}
|
||||
|
||||
void AccessibleWrap::Paste() {
|
||||
if ((State() & states::EDITABLE) == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (IsHyperText()) {
|
||||
RefPtr<HyperTextAccessible> textAcc = AsHyperText();
|
||||
int32_t startSel, endSel;
|
||||
GetSelectionOrCaret(&startSel, &endSel);
|
||||
if (startSel != endSel) {
|
||||
textAcc->DeleteText(startSel, endSel);
|
||||
}
|
||||
textAcc->PasteText(startSel);
|
||||
}
|
||||
}
|
||||
|
||||
void AccessibleWrap::GetSelectionOrCaret(int32_t* aStartOffset,
|
||||
int32_t* aEndOffset) {
|
||||
*aStartOffset = *aEndOffset = -1;
|
||||
if (HyperTextAccessible* textAcc = AsHyperText()) {
|
||||
if (!textAcc->SelectionBoundsAt(0, aStartOffset, aEndOffset)) {
|
||||
*aStartOffset = *aEndOffset = textAcc->CaretOffset();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t AccessibleWrap::GetFlags(role aRole, uint64_t aState,
|
||||
uint8_t aActionCount) {
|
||||
uint32_t flags = 0;
|
||||
|
@ -34,6 +34,22 @@ class AccessibleWrap : public Accessible {
|
||||
|
||||
virtual bool GetSelectionBounds(int32_t* aStartOffset, int32_t* aEndOffset);
|
||||
|
||||
virtual void Pivot(int32_t aGranularity, bool aForward, bool aInclusive);
|
||||
|
||||
virtual void ExploreByTouch(float aX, float aY);
|
||||
|
||||
virtual void NavigateText(int32_t aGranularity, int32_t aStartOffset,
|
||||
int32_t aEndOffset, bool aForward, bool aSelect);
|
||||
|
||||
virtual void SetSelection(int32_t aStart, int32_t aEnd);
|
||||
|
||||
virtual void Cut();
|
||||
|
||||
virtual void Copy();
|
||||
|
||||
MOZ_CAN_RUN_SCRIPT_BOUNDARY
|
||||
virtual void Paste();
|
||||
|
||||
mozilla::java::GeckoBundle::LocalRef ToBundle(bool aSmall = false);
|
||||
|
||||
mozilla::java::GeckoBundle::LocalRef ToBundle(
|
||||
@ -84,6 +100,8 @@ class AccessibleWrap : public Accessible {
|
||||
|
||||
bool HandleLiveRegionEvent(AccEvent* aEvent);
|
||||
|
||||
void GetSelectionOrCaret(int32_t* aStartOffset, int32_t* aEndOffset);
|
||||
|
||||
static void GetRoleDescription(role aRole,
|
||||
nsIPersistentProperties* aAttributes,
|
||||
nsAString& aGeckoRole,
|
||||
|
@ -128,13 +128,11 @@ void a11y::ProxyVirtualCursorChangeEvent(
|
||||
return;
|
||||
}
|
||||
|
||||
if (aOldPosition != aNewPosition) {
|
||||
if (aReason == nsIAccessiblePivot::REASON_POINT) {
|
||||
sessionAcc->SendHoverEnterEvent(WrapperFor(aNewPosition));
|
||||
} else {
|
||||
RefPtr<AccessibleWrap> wrapperForNewPosition = WrapperFor(aNewPosition);
|
||||
sessionAcc->SendAccessibilityFocusedEvent(wrapperForNewPosition);
|
||||
}
|
||||
if (aReason == nsIAccessiblePivot::REASON_POINT) {
|
||||
sessionAcc->SendHoverEnterEvent(WrapperFor(aNewPosition));
|
||||
} else {
|
||||
RefPtr<AccessibleWrap> wrapperForNewPosition = WrapperFor(aNewPosition);
|
||||
sessionAcc->SendAccessibilityFocusedEvent(wrapperForNewPosition);
|
||||
}
|
||||
|
||||
if (aBoundaryType != nsIAccessiblePivot::NO_BOUNDARY) {
|
||||
|
@ -3,8 +3,11 @@
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "ProxyAccessibleWrap.h"
|
||||
|
||||
#include "nsPersistentProperties.h"
|
||||
|
||||
#include "mozilla/a11y/DocAccessiblePlatformExtParent.h"
|
||||
|
||||
using namespace mozilla::a11y;
|
||||
|
||||
ProxyAccessibleWrap::ProxyAccessibleWrap(ProxyAccessible* aProxy)
|
||||
@ -105,6 +108,43 @@ bool ProxyAccessibleWrap::GetSelectionBounds(int32_t* aStartOffset,
|
||||
return Proxy()->SelectionBoundsAt(0, unused, aStartOffset, aEndOffset);
|
||||
}
|
||||
|
||||
void ProxyAccessibleWrap::Pivot(int32_t aGranularity, bool aForward,
|
||||
bool aInclusive) {
|
||||
Unused << Proxy()->Document()->GetPlatformExtension()->SendPivot(
|
||||
Proxy()->ID(), aGranularity, aForward, aInclusive);
|
||||
}
|
||||
|
||||
void ProxyAccessibleWrap::ExploreByTouch(float aX, float aY) {
|
||||
Unused << Proxy()->Document()->GetPlatformExtension()->SendExploreByTouch(
|
||||
Proxy()->ID(), aX, aY);
|
||||
}
|
||||
|
||||
void ProxyAccessibleWrap::NavigateText(int32_t aGranularity,
|
||||
int32_t aStartOffset, int32_t aEndOffset,
|
||||
bool aForward, bool aSelect) {
|
||||
Unused << Proxy()->Document()->GetPlatformExtension()->SendNavigateText(
|
||||
Proxy()->ID(), aGranularity, aStartOffset, aEndOffset, aForward, aSelect);
|
||||
}
|
||||
|
||||
void ProxyAccessibleWrap::SetSelection(int32_t aStart, int32_t aEnd) {
|
||||
Unused << Proxy()->Document()->GetPlatformExtension()->SendSetSelection(
|
||||
Proxy()->ID(), aStart, aEnd);
|
||||
}
|
||||
|
||||
void ProxyAccessibleWrap::Cut() {
|
||||
Unused << Proxy()->Document()->GetPlatformExtension()->SendCut(Proxy()->ID());
|
||||
}
|
||||
|
||||
void ProxyAccessibleWrap::Copy() {
|
||||
Unused << Proxy()->Document()->GetPlatformExtension()->SendCopy(
|
||||
Proxy()->ID());
|
||||
}
|
||||
|
||||
void ProxyAccessibleWrap::Paste() {
|
||||
Unused << Proxy()->Document()->GetPlatformExtension()->SendPaste(
|
||||
Proxy()->ID());
|
||||
}
|
||||
|
||||
role ProxyAccessibleWrap::WrapperRole() { return Proxy()->Role(); }
|
||||
|
||||
AccessibleWrap* ProxyAccessibleWrap::WrapperParent() {
|
||||
|
@ -57,6 +57,23 @@ class ProxyAccessibleWrap : public AccessibleWrap {
|
||||
virtual bool GetSelectionBounds(int32_t* aStartOffset,
|
||||
int32_t* aEndOffset) override;
|
||||
|
||||
virtual void Pivot(int32_t aGranularity, bool aForward,
|
||||
bool aInclusive) override;
|
||||
|
||||
virtual void NavigateText(int32_t aGranularity, int32_t aStartOffset,
|
||||
int32_t aEndOffset, bool aForward,
|
||||
bool aSelect) override;
|
||||
|
||||
virtual void SetSelection(int32_t aStart, int32_t aEnd) override;
|
||||
|
||||
virtual void Cut() override;
|
||||
|
||||
virtual void Copy() override;
|
||||
|
||||
virtual void Paste() override;
|
||||
|
||||
virtual void ExploreByTouch(float aX, float aY) override;
|
||||
|
||||
virtual void WrapperDOMNodeID(nsString& aDOMNodeID) override;
|
||||
|
||||
private:
|
||||
|
@ -30,6 +30,16 @@
|
||||
} while (0)
|
||||
#endif
|
||||
|
||||
#define FORWARD_ACTION_TO_ACCESSIBLE(funcname, ...) \
|
||||
if (RootAccessibleWrap* rootAcc = GetRoot()) { \
|
||||
AccessibleWrap* acc = rootAcc->FindAccessibleById(aID); \
|
||||
if (!acc) { \
|
||||
return; \
|
||||
} \
|
||||
\
|
||||
acc->funcname(__VA_ARGS__); \
|
||||
}
|
||||
|
||||
template <>
|
||||
const char nsWindow::NativePtr<mozilla::a11y::SessionAccessibility>::sName[] =
|
||||
"SessionAccessibility";
|
||||
@ -97,25 +107,45 @@ RootAccessibleWrap* SessionAccessibility::GetRoot() {
|
||||
}
|
||||
|
||||
void SessionAccessibility::SetText(int32_t aID, jni::String::Param aText) {
|
||||
if (RootAccessibleWrap* rootAcc = GetRoot()) {
|
||||
AccessibleWrap* acc = rootAcc->FindAccessibleById(aID);
|
||||
if (!acc) {
|
||||
return;
|
||||
}
|
||||
|
||||
acc->SetTextContents(aText->ToString());
|
||||
}
|
||||
FORWARD_ACTION_TO_ACCESSIBLE(SetTextContents, aText->ToString());
|
||||
}
|
||||
|
||||
void SessionAccessibility::Click(int32_t aID) {
|
||||
if (RootAccessibleWrap* rootAcc = GetRoot()) {
|
||||
AccessibleWrap* acc = rootAcc->FindAccessibleById(aID);
|
||||
if (!acc) {
|
||||
return;
|
||||
}
|
||||
FORWARD_ACTION_TO_ACCESSIBLE(DoAction, 0);
|
||||
}
|
||||
|
||||
acc->DoAction(0);
|
||||
}
|
||||
void SessionAccessibility::Pivot(int32_t aID, int32_t aGranularity,
|
||||
bool aForward, bool aInclusive) {
|
||||
FORWARD_ACTION_TO_ACCESSIBLE(Pivot, aGranularity, aForward, aInclusive);
|
||||
}
|
||||
|
||||
void SessionAccessibility::ExploreByTouch(int32_t aID, float aX, float aY) {
|
||||
FORWARD_ACTION_TO_ACCESSIBLE(ExploreByTouch, aX, aY);
|
||||
}
|
||||
|
||||
void SessionAccessibility::NavigateText(int32_t aID, int32_t aGranularity,
|
||||
int32_t aStartOffset,
|
||||
int32_t aEndOffset, bool aForward,
|
||||
bool aSelect) {
|
||||
FORWARD_ACTION_TO_ACCESSIBLE(NavigateText, aGranularity, aStartOffset,
|
||||
aEndOffset, aForward, aSelect);
|
||||
}
|
||||
|
||||
void SessionAccessibility::SetSelection(int32_t aID, int32_t aStart,
|
||||
int32_t aEnd) {
|
||||
FORWARD_ACTION_TO_ACCESSIBLE(SetSelection, aStart, aEnd);
|
||||
}
|
||||
|
||||
void SessionAccessibility::Cut(int32_t aID) {
|
||||
FORWARD_ACTION_TO_ACCESSIBLE(Cut);
|
||||
}
|
||||
|
||||
void SessionAccessibility::Copy(int32_t aID) {
|
||||
FORWARD_ACTION_TO_ACCESSIBLE(Copy);
|
||||
}
|
||||
|
||||
void SessionAccessibility::Paste(int32_t aID) {
|
||||
FORWARD_ACTION_TO_ACCESSIBLE(Paste);
|
||||
}
|
||||
|
||||
SessionAccessibility* SessionAccessibility::GetInstanceFor(
|
||||
@ -417,3 +447,5 @@ void SessionAccessibility::UpdateCachedBounds(
|
||||
mSessionAccessibility->UpdateCachedBounds(infos);
|
||||
SendWindowContentChangedEvent();
|
||||
}
|
||||
|
||||
#undef FORWARD_ACTION_TO_ACCESSIBLE
|
@ -53,6 +53,14 @@ class SessionAccessibility final
|
||||
jni::Object::LocalRef GetNodeInfo(int32_t aID);
|
||||
void SetText(int32_t aID, jni::String::Param aText);
|
||||
void Click(int32_t aID);
|
||||
void Pivot(int32_t aID, int32_t aGranularity, bool aForward, bool aInclusive);
|
||||
void ExploreByTouch(int32_t aID, float aX, float aY);
|
||||
void NavigateText(int32_t aID, int32_t aGranularity, int32_t aStartOffset,
|
||||
int32_t aEndOffset, bool aForward, bool aSelect);
|
||||
void SetSelection(int32_t aID, int32_t aStart, int32_t aEnd);
|
||||
void Cut(int32_t aID);
|
||||
void Copy(int32_t aID);
|
||||
void Paste(int32_t aID);
|
||||
void StartNativeAccessibility();
|
||||
|
||||
// Event methods
|
||||
|
251
accessible/android/TraversalRule.cpp
Normal file
251
accessible/android/TraversalRule.cpp
Normal file
@ -0,0 +1,251 @@
|
||||
/* 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 "TraversalRule.h"
|
||||
|
||||
#include "mozilla/ArrayUtils.h"
|
||||
|
||||
#include "Role.h"
|
||||
#include "Accessible.h"
|
||||
#include "HTMLListAccessible.h"
|
||||
#include "SessionAccessibility.h"
|
||||
#include "nsAccUtils.h"
|
||||
#include "nsIAccessiblePivot.h"
|
||||
|
||||
using namespace mozilla;
|
||||
using namespace mozilla::a11y;
|
||||
|
||||
TraversalRule::TraversalRule()
|
||||
: TraversalRule(java::SessionAccessibility::HTML_GRANULARITY_DEFAULT) {}
|
||||
|
||||
TraversalRule::TraversalRule(int32_t aGranularity)
|
||||
: mGranularity(aGranularity) {}
|
||||
|
||||
uint16_t TraversalRule::Match(Accessible* aAccessible) {
|
||||
uint16_t result = nsIAccessibleTraversalRule::FILTER_IGNORE;
|
||||
|
||||
if (nsAccUtils::MustPrune(aAccessible)) {
|
||||
result |= nsIAccessibleTraversalRule::FILTER_IGNORE_SUBTREE;
|
||||
}
|
||||
|
||||
uint64_t state = aAccessible->State();
|
||||
|
||||
if ((state & states::INVISIBLE) != 0) {
|
||||
return result;
|
||||
}
|
||||
|
||||
if ((state & states::OPAQUE1) == 0) {
|
||||
nsIFrame* frame = aAccessible->GetFrame();
|
||||
if (frame->StyleEffects()->mOpacity == 0.0f) {
|
||||
return result | nsIAccessibleTraversalRule::FILTER_IGNORE_SUBTREE;
|
||||
}
|
||||
}
|
||||
|
||||
switch (mGranularity) {
|
||||
case java::SessionAccessibility::HTML_GRANULARITY_LINK:
|
||||
result |= LinkMatch(aAccessible);
|
||||
break;
|
||||
case java::SessionAccessibility::HTML_GRANULARITY_CONTROL:
|
||||
result |= ControlMatch(aAccessible);
|
||||
break;
|
||||
case java::SessionAccessibility::HTML_GRANULARITY_SECTION:
|
||||
result |= SectionMatch(aAccessible);
|
||||
break;
|
||||
case java::SessionAccessibility::HTML_GRANULARITY_HEADING:
|
||||
result |= HeadingMatch(aAccessible);
|
||||
break;
|
||||
default:
|
||||
result |= DefaultMatch(aAccessible);
|
||||
break;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
bool TraversalRule::IsSingleLineage(Accessible* aAccessible) {
|
||||
Accessible* child = aAccessible;
|
||||
while (child) {
|
||||
switch (child->ChildCount()) {
|
||||
case 0:
|
||||
return true;
|
||||
case 1:
|
||||
child = child->FirstChild();
|
||||
break;
|
||||
case 2:
|
||||
if (Accessible* bullet =
|
||||
child->Parent()->IsHTMLListItem()
|
||||
? child->Parent()->AsHTMLListItem()->Bullet()
|
||||
: nullptr) {
|
||||
child = bullet->NextSibling();
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool TraversalRule::IsListItemBullet(const Accessible* aAccessible) {
|
||||
Accessible* parent = aAccessible->Parent();
|
||||
return parent && parent->IsHTMLListItem() &&
|
||||
parent->AsHTMLListItem()->Bullet() == aAccessible;
|
||||
}
|
||||
|
||||
bool TraversalRule::IsFlatSubtree(const Accessible* aAccessible) {
|
||||
for (auto child = aAccessible->FirstChild(); child;
|
||||
child = child->NextSibling()) {
|
||||
roles::Role role = child->Role();
|
||||
if (role == roles::TEXT_LEAF || role == roles::STATICTEXT) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (child->ChildCount() > 0 || child->ActionCount() > 0) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool TraversalRule::HasName(const Accessible* aAccessible) {
|
||||
nsAutoString name;
|
||||
aAccessible->Name(name);
|
||||
name.CompressWhitespace();
|
||||
return !name.IsEmpty();
|
||||
}
|
||||
|
||||
uint16_t TraversalRule::LinkMatch(Accessible* aAccessible) {
|
||||
if (aAccessible->Role() == roles::LINK &&
|
||||
(aAccessible->State() & states::LINKED) != 0) {
|
||||
return nsIAccessibleTraversalRule::FILTER_MATCH |
|
||||
nsIAccessibleTraversalRule::FILTER_IGNORE_SUBTREE;
|
||||
}
|
||||
|
||||
return nsIAccessibleTraversalRule::FILTER_IGNORE;
|
||||
}
|
||||
|
||||
uint16_t TraversalRule::HeadingMatch(Accessible* aAccessible) {
|
||||
if (aAccessible->Role() == roles::HEADING && aAccessible->ChildCount()) {
|
||||
return nsIAccessibleTraversalRule::FILTER_MATCH;
|
||||
}
|
||||
|
||||
return nsIAccessibleTraversalRule::FILTER_IGNORE;
|
||||
}
|
||||
|
||||
uint16_t TraversalRule::SectionMatch(Accessible* aAccessible) {
|
||||
roles::Role role = aAccessible->Role();
|
||||
if (role == roles::HEADING || role == roles::LANDMARK ||
|
||||
aAccessible->LandmarkRole()) {
|
||||
return nsIAccessibleTraversalRule::FILTER_MATCH;
|
||||
}
|
||||
|
||||
return nsIAccessibleTraversalRule::FILTER_IGNORE;
|
||||
}
|
||||
|
||||
uint16_t TraversalRule::ControlMatch(Accessible* aAccessible) {
|
||||
switch (aAccessible->Role()) {
|
||||
case roles::PUSHBUTTON:
|
||||
case roles::SPINBUTTON:
|
||||
case roles::TOGGLE_BUTTON:
|
||||
case roles::BUTTONDROPDOWN:
|
||||
case roles::BUTTONDROPDOWNGRID:
|
||||
case roles::COMBOBOX:
|
||||
case roles::LISTBOX:
|
||||
case roles::ENTRY:
|
||||
case roles::PASSWORD_TEXT:
|
||||
case roles::PAGETAB:
|
||||
case roles::RADIOBUTTON:
|
||||
case roles::RADIO_MENU_ITEM:
|
||||
case roles::SLIDER:
|
||||
case roles::CHECKBUTTON:
|
||||
case roles::CHECK_MENU_ITEM:
|
||||
case roles::SWITCH:
|
||||
case roles::MENUITEM:
|
||||
return nsIAccessibleTraversalRule::FILTER_MATCH |
|
||||
nsIAccessibleTraversalRule::FILTER_IGNORE_SUBTREE;
|
||||
case roles::LINK:
|
||||
return LinkMatch(aAccessible);
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return nsIAccessibleTraversalRule::FILTER_IGNORE;
|
||||
}
|
||||
|
||||
uint16_t TraversalRule::DefaultMatch(Accessible* aAccessible) {
|
||||
switch (aAccessible->Role()) {
|
||||
case roles::COMBOBOX:
|
||||
// We don't want to ignore the subtree because this is often
|
||||
// where the list box hangs out.
|
||||
return nsIAccessibleTraversalRule::FILTER_MATCH;
|
||||
case roles::TEXT_LEAF:
|
||||
case roles::GRAPHIC:
|
||||
// Nameless text leaves are boring, skip them.
|
||||
if (HasName(aAccessible)) {
|
||||
return nsIAccessibleTraversalRule::FILTER_MATCH;
|
||||
}
|
||||
break;
|
||||
case roles::STATICTEXT:
|
||||
// Ignore list bullets
|
||||
if (!IsListItemBullet(aAccessible)) {
|
||||
return nsIAccessibleTraversalRule::FILTER_MATCH;
|
||||
}
|
||||
break;
|
||||
case roles::HEADER:
|
||||
case roles::HEADING:
|
||||
case roles::COLUMNHEADER:
|
||||
case roles::ROWHEADER:
|
||||
case roles::STATUSBAR:
|
||||
if ((aAccessible->ChildCount() > 0 || HasName(aAccessible)) &&
|
||||
(IsSingleLineage(aAccessible) || IsFlatSubtree(aAccessible))) {
|
||||
return nsIAccessibleTraversalRule::FILTER_MATCH |
|
||||
nsIAccessibleTraversalRule::FILTER_IGNORE_SUBTREE;
|
||||
}
|
||||
break;
|
||||
case roles::GRID_CELL:
|
||||
if (IsSingleLineage(aAccessible) || IsFlatSubtree(aAccessible)) {
|
||||
return nsIAccessibleTraversalRule::FILTER_MATCH |
|
||||
nsIAccessibleTraversalRule::FILTER_IGNORE_SUBTREE;
|
||||
}
|
||||
break;
|
||||
case roles::LISTITEM:
|
||||
if (IsFlatSubtree(aAccessible) || IsSingleLineage(aAccessible)) {
|
||||
return nsIAccessibleTraversalRule::FILTER_MATCH |
|
||||
nsIAccessibleTraversalRule::FILTER_IGNORE_SUBTREE;
|
||||
}
|
||||
break;
|
||||
case roles::MENUITEM:
|
||||
case roles::LINK:
|
||||
case roles::PAGETAB:
|
||||
case roles::PUSHBUTTON:
|
||||
case roles::CHECKBUTTON:
|
||||
case roles::RADIOBUTTON:
|
||||
case roles::PROGRESSBAR:
|
||||
case roles::BUTTONDROPDOWN:
|
||||
case roles::BUTTONMENU:
|
||||
case roles::CHECK_MENU_ITEM:
|
||||
case roles::PASSWORD_TEXT:
|
||||
case roles::RADIO_MENU_ITEM:
|
||||
case roles::TOGGLE_BUTTON:
|
||||
case roles::ENTRY:
|
||||
case roles::KEY:
|
||||
case roles::SLIDER:
|
||||
case roles::SPINBUTTON:
|
||||
case roles::OPTION:
|
||||
case roles::SWITCH:
|
||||
case roles::MATHML_MATH:
|
||||
// Ignore the subtree, if there is one. So that we don't land on
|
||||
// the same content that was already presented by its parent.
|
||||
return nsIAccessibleTraversalRule::FILTER_MATCH |
|
||||
nsIAccessibleTraversalRule::FILTER_IGNORE_SUBTREE;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return nsIAccessibleTraversalRule::FILTER_IGNORE;
|
||||
}
|
52
accessible/android/TraversalRule.h
Normal file
52
accessible/android/TraversalRule.h
Normal file
@ -0,0 +1,52 @@
|
||||
/* 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 _TraversalRule_H_
|
||||
#define _TraversalRule_H_
|
||||
|
||||
#include "Pivot.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace a11y {
|
||||
|
||||
class Accessible;
|
||||
|
||||
/**
|
||||
* Class represents a simple traversal rule.
|
||||
*/
|
||||
class TraversalRule final : public PivotRule {
|
||||
public:
|
||||
TraversalRule();
|
||||
explicit TraversalRule(int32_t aGranularity);
|
||||
|
||||
~TraversalRule() = default;
|
||||
|
||||
virtual uint16_t Match(Accessible* aAccessible) override;
|
||||
|
||||
private:
|
||||
bool IsSingleLineage(Accessible* aAccessible);
|
||||
|
||||
bool IsFlatSubtree(const Accessible* aAccessible);
|
||||
|
||||
bool IsListItemBullet(const Accessible* aAccessible);
|
||||
|
||||
bool HasName(const Accessible* aAccessible);
|
||||
|
||||
uint16_t DefaultMatch(Accessible* aAccessible);
|
||||
|
||||
uint16_t LinkMatch(Accessible* aAccessible);
|
||||
|
||||
uint16_t HeadingMatch(Accessible* aAccessible);
|
||||
|
||||
uint16_t ControlMatch(Accessible* aAccessible);
|
||||
|
||||
uint16_t SectionMatch(Accessible* aAccessible);
|
||||
|
||||
int32_t mGranularity;
|
||||
};
|
||||
|
||||
} // namespace a11y
|
||||
} // namespace mozilla
|
||||
|
||||
#endif
|
@ -5,6 +5,7 @@
|
||||
EXPORTS.mozilla.a11y += ['AccessibleWrap.h',
|
||||
'HyperTextAccessibleWrap.h',
|
||||
'SessionAccessibility.h',
|
||||
'TraversalRule.h',
|
||||
]
|
||||
|
||||
SOURCES += [
|
||||
@ -14,6 +15,7 @@ SOURCES += [
|
||||
'ProxyAccessibleWrap.cpp',
|
||||
'RootAccessibleWrap.cpp',
|
||||
'SessionAccessibility.cpp',
|
||||
'TraversalRule.cpp',
|
||||
]
|
||||
|
||||
LOCAL_INCLUDES += [
|
||||
@ -22,6 +24,7 @@ LOCAL_INCLUDES += [
|
||||
'/accessible/html',
|
||||
'/accessible/ipc',
|
||||
'/accessible/ipc/other',
|
||||
'/accessible/xpcom',
|
||||
'/accessible/xul',
|
||||
'/dom/base',
|
||||
'/widget',
|
||||
|
@ -62,7 +62,7 @@ class AccessibleWrap : public Accessible {
|
||||
|
||||
static const char* ReturnString(nsAString& aString) {
|
||||
static nsCString returnedString;
|
||||
returnedString = NS_ConvertUTF16toUTF8(aString);
|
||||
CopyUTF16toUTF8(aString, returnedString);
|
||||
return returnedString.get();
|
||||
}
|
||||
|
||||
|
@ -72,16 +72,10 @@ RelatedAccIterator::RelatedAccIterator(DocAccessible* aDocument,
|
||||
: mDocument(aDocument),
|
||||
mRelAttr(aRelAttr),
|
||||
mProviders(nullptr),
|
||||
mBindingParent(nullptr),
|
||||
mIndex(0) {
|
||||
mBindingParent = aDependentContent->IsInAnonymousSubtree()
|
||||
? aDependentContent->GetBindingParent()
|
||||
: nullptr;
|
||||
nsAtom* IDAttr = mBindingParent ? nsGkAtoms::anonid : nsGkAtoms::id;
|
||||
|
||||
nsAutoString id;
|
||||
if (aDependentContent->IsElement() &&
|
||||
aDependentContent->AsElement()->GetAttr(kNameSpaceID_None, IDAttr, id)) {
|
||||
aDependentContent->AsElement()->GetAttr(kNameSpaceID_None, nsGkAtoms::id, id)) {
|
||||
mProviders = mDocument->GetRelProviders(aDependentContent->AsElement(), id);
|
||||
}
|
||||
}
|
||||
@ -92,22 +86,17 @@ Accessible* RelatedAccIterator::Next() {
|
||||
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.
|
||||
// Return related accessible for the given attribute.
|
||||
if (provider->mRelAttr == mRelAttr) {
|
||||
nsIContent* bindingParent = provider->mContent->IsInAnonymousSubtree()
|
||||
? provider->mContent->GetBindingParent()
|
||||
: nullptr;
|
||||
bool inScope = mBindingParent == bindingParent ||
|
||||
mBindingParent == provider->mContent;
|
||||
Accessible* related = mDocument->GetAccessible(provider->mContent);
|
||||
if (related) {
|
||||
return related;
|
||||
}
|
||||
|
||||
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;
|
||||
// If the document content is pointed by relation then return the
|
||||
// document itself.
|
||||
if (provider->mContent == mDocument->GetContent()) {
|
||||
return mDocument;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -255,40 +244,27 @@ nsIContent* IDRefsIterator::NextElem() {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
nsIContent* IDRefsIterator::GetElem(const nsDependentSubstring& aID) {
|
||||
dom::Element* IDRefsIterator::GetElem(nsIContent* aContent,
|
||||
const nsAString& aID) {
|
||||
// Get elements in DOM tree by ID attribute if this is an explicit content.
|
||||
// In case of bound element check its anonymous subtree.
|
||||
if (!mContent->IsInAnonymousSubtree()) {
|
||||
if (!aContent->IsInAnonymousSubtree()) {
|
||||
dom::DocumentOrShadowRoot* docOrShadowRoot =
|
||||
mContent->GetUncomposedDocOrConnectedShadowRoot();
|
||||
aContent->GetUncomposedDocOrConnectedShadowRoot();
|
||||
if (docOrShadowRoot) {
|
||||
dom::Element* refElm = docOrShadowRoot->GetElementById(aID);
|
||||
if (refElm || !mContent->GetXBLBinding()) return refElm;
|
||||
if (refElm) {
|
||||
return refElm;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If content is in anonymous subtree or an element having anonymous subtree
|
||||
// then use "anonid" attribute to get elements in anonymous subtree.
|
||||
|
||||
// Check inside the binding the element is contained in.
|
||||
nsIContent* bindingParent = mContent->GetBindingParent();
|
||||
if (bindingParent) {
|
||||
nsIContent* refElm =
|
||||
bindingParent->OwnerDoc()->GetAnonymousElementByAttribute(
|
||||
bindingParent, nsGkAtoms::anonid, aID);
|
||||
|
||||
if (refElm) return refElm;
|
||||
}
|
||||
|
||||
// Check inside the binding of the element.
|
||||
if (mContent->GetXBLBinding()) {
|
||||
return mContent->OwnerDoc()->GetAnonymousElementByAttribute(
|
||||
mContent, nsGkAtoms::anonid, aID);
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
dom::Element* IDRefsIterator::GetElem(const nsDependentSubstring& aID) {
|
||||
return GetElem(mContent, aID);
|
||||
}
|
||||
|
||||
Accessible* IDRefsIterator::Next() {
|
||||
nsIContent* nextEl = nullptr;
|
||||
while ((nextEl = NextElem())) {
|
||||
|
@ -95,7 +95,6 @@ class RelatedAccIterator : public AccIterable {
|
||||
DocAccessible* mDocument;
|
||||
nsAtom* mRelAttr;
|
||||
DocAccessible::AttrRelProviders* mProviders;
|
||||
nsIContent* mBindingParent;
|
||||
uint32_t mIndex;
|
||||
};
|
||||
|
||||
@ -217,7 +216,8 @@ class IDRefsIterator : public AccIterable {
|
||||
/**
|
||||
* Return the element with the given ID.
|
||||
*/
|
||||
nsIContent* GetElem(const nsDependentSubstring& aID);
|
||||
static dom::Element* GetElem(nsIContent* aContent, const nsAString& aID);
|
||||
dom::Element* GetElem(const nsDependentSubstring& aID);
|
||||
|
||||
// AccIterable
|
||||
virtual Accessible* Next() override;
|
||||
|
@ -412,35 +412,9 @@ void NotificationController::ScheduleChildDocBinding(DocAccessible* aDocument) {
|
||||
}
|
||||
|
||||
void NotificationController::ScheduleContentInsertion(
|
||||
nsIContent* aStartChildNode, nsIContent* aEndChildNode) {
|
||||
// The frame constructor guarantees that only ranges with the same parent
|
||||
// arrive here in presence of dynamic changes to the page, see
|
||||
// nsCSSFrameConstructor::IssueSingleInsertNotifications' callers.
|
||||
nsINode* parent = aStartChildNode->GetFlattenedTreeParentNode();
|
||||
if (!parent) {
|
||||
return;
|
||||
}
|
||||
|
||||
Accessible* container = mDocument->AccessibleOrTrueContainer(parent);
|
||||
if (!container) {
|
||||
return;
|
||||
}
|
||||
|
||||
AutoTArray<nsCOMPtr<nsIContent>, 10> list;
|
||||
for (nsIContent* node = aStartChildNode; node != aEndChildNode;
|
||||
node = node->GetNextSibling()) {
|
||||
MOZ_ASSERT(parent == node->GetFlattenedTreeParentNode());
|
||||
// Notification triggers for content insertion even if no content was
|
||||
// actually inserted (like if the content is display: none). Try to catch
|
||||
// this case early.
|
||||
if (node->GetPrimaryFrame() ||
|
||||
(node->IsElement() && node->AsElement()->IsDisplayContents())) {
|
||||
list.AppendElement(node);
|
||||
}
|
||||
}
|
||||
|
||||
if (!list.IsEmpty()) {
|
||||
mContentInsertions.LookupOrAdd(container)->AppendElements(list);
|
||||
Accessible* aContainer, nsTArray<nsCOMPtr<nsIContent>>& aInsertions) {
|
||||
if (!aInsertions.IsEmpty()) {
|
||||
mContentInsertions.LookupOrAdd(aContainer)->AppendElements(aInsertions);
|
||||
ScheduleProcessing();
|
||||
}
|
||||
}
|
||||
@ -827,18 +801,8 @@ void NotificationController::WillRefresh(mozilla::TimeStamp aTime) {
|
||||
}
|
||||
}
|
||||
|
||||
// Process only currently queued generic notifications.
|
||||
nsTArray<RefPtr<Notification>> notifications;
|
||||
notifications.SwapElements(mNotifications);
|
||||
|
||||
uint32_t notificationCount = notifications.Length();
|
||||
for (uint32_t idx = 0; idx < notificationCount; idx++) {
|
||||
notifications[idx]->Process();
|
||||
if (!mDocument) return;
|
||||
}
|
||||
|
||||
// Process invalidation list of the document after all accessible tree
|
||||
// modification are done.
|
||||
// mutation is done.
|
||||
mDocument->ProcessInvalidationList();
|
||||
|
||||
// Process relocation list.
|
||||
@ -852,6 +816,20 @@ void NotificationController::WillRefresh(mozilla::TimeStamp aTime) {
|
||||
}
|
||||
mRelocations.Clear();
|
||||
|
||||
// Process only currently queued generic notifications.
|
||||
// These are used for processing aria-activedescendant, DOMMenuItemActive,
|
||||
// etc. Therefore, they must be processed after relocations, since relocated
|
||||
// subtrees might not have been created before relocation processing and the
|
||||
// target might be inside a relocated subtree.
|
||||
nsTArray<RefPtr<Notification>> notifications;
|
||||
notifications.SwapElements(mNotifications);
|
||||
|
||||
uint32_t notificationCount = notifications.Length();
|
||||
for (uint32_t idx = 0; idx < notificationCount; idx++) {
|
||||
notifications[idx]->Process();
|
||||
if (!mDocument) return;
|
||||
}
|
||||
|
||||
// If a generic notification occurs after this point then we may be allowed to
|
||||
// process it synchronously. However we do not want to reenter if fireing
|
||||
// events causes script to run.
|
||||
@ -924,6 +902,7 @@ void NotificationController::WillRefresh(mozilla::TimeStamp aTime) {
|
||||
if (browserChild) {
|
||||
static_cast<BrowserChild*>(browserChild.get())
|
||||
->SendPDocAccessibleConstructor(ipcDoc, parentIPCDoc, id, 0, 0);
|
||||
ipcDoc->SendPDocAccessiblePlatformExtConstructor();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
@ -190,8 +190,8 @@ class NotificationController final : public EventQueue,
|
||||
/**
|
||||
* Pend accessible tree update for content insertion.
|
||||
*/
|
||||
void ScheduleContentInsertion(nsIContent* aStartChildNode,
|
||||
nsIContent* aEndChildNode);
|
||||
void ScheduleContentInsertion(Accessible* aContainer,
|
||||
nsTArray<nsCOMPtr<nsIContent>>& aInsertions);
|
||||
|
||||
/**
|
||||
* Pend an accessible subtree relocation.
|
||||
|
@ -27,8 +27,7 @@ TreeWalker::TreeWalker(Accessible* aContext)
|
||||
mChildFilter(nsIContent::eSkipPlaceholderContent),
|
||||
mFlags(0),
|
||||
mPhase(eAtStart) {
|
||||
mChildFilter |=
|
||||
mContext->NoXBLKids() ? nsIContent::eAllButXBL : nsIContent::eAllChildren;
|
||||
mChildFilter |= nsIContent::eAllChildren;
|
||||
|
||||
mAnchorNode = mContext->IsDoc() ? mDoc->DocumentNode()->GetRootElement()
|
||||
: mContext->GetContent();
|
||||
@ -49,8 +48,7 @@ TreeWalker::TreeWalker(Accessible* aContext, nsIContent* aAnchorNode,
|
||||
"This constructor cannot be used for tree creation");
|
||||
MOZ_ASSERT(aAnchorNode, "No anchor node for the accessible tree walker");
|
||||
|
||||
mChildFilter |=
|
||||
mContext->NoXBLKids() ? nsIContent::eAllButXBL : nsIContent::eAllChildren;
|
||||
mChildFilter |= nsIContent::eAllChildren;
|
||||
|
||||
MOZ_COUNT_CTOR(TreeWalker);
|
||||
}
|
||||
@ -100,10 +98,16 @@ bool TreeWalker::Seek(nsIContent* aChildNode) {
|
||||
nsINode* parentNode = aChildNode;
|
||||
do {
|
||||
childNode = parentNode->AsContent();
|
||||
parentNode = childNode->HasFlag(NODE_MAY_BE_IN_BINDING_MNGR) &&
|
||||
(mChildFilter & nsIContent::eAllButXBL)
|
||||
? childNode->GetParentNode()
|
||||
: childNode->GetFlattenedTreeParent();
|
||||
parentNode = childNode->GetFlattenedTreeParent();
|
||||
|
||||
// Handle the special case of XBL binding child under a shadow root.
|
||||
if (parentNode && parentNode->IsShadowRoot()) {
|
||||
parentNode = childNode->GetFlattenedTreeParent();
|
||||
if (parentNode == mAnchorNode) {
|
||||
return true;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!parentNode || !parentNode->IsElement()) {
|
||||
return false;
|
||||
|
@ -82,15 +82,6 @@ XULMAP(popup, [](Element* aElement, Accessible* aContext) {
|
||||
return CreateMenupopupAccessible(aElement, aContext);
|
||||
})
|
||||
|
||||
XULMAP(textbox, [](Element* aElement, Accessible* aContext) -> Accessible* {
|
||||
if (aElement->AttrValueIs(kNameSpaceID_None, nsGkAtoms::type,
|
||||
nsGkAtoms::autocomplete, eIgnoreCase)) {
|
||||
return new XULComboboxAccessible(aElement, aContext->Document());
|
||||
}
|
||||
|
||||
return new EnumRoleAccessible<roles::SECTION>(aElement, aContext->Document());
|
||||
})
|
||||
|
||||
XULMAP(tree, [](Element* aElement, Accessible* aContext) -> Accessible* {
|
||||
nsIContent* child =
|
||||
nsTreeUtils::GetDescendantChild(aElement, nsGkAtoms::treechildren);
|
||||
|
@ -79,7 +79,6 @@ LOCAL_INCLUDES += [
|
||||
'/accessible/xpcom',
|
||||
'/accessible/xul',
|
||||
'/dom/base',
|
||||
'/dom/xbl',
|
||||
'/ipc/chromium/src',
|
||||
'/layout/generic',
|
||||
'/layout/style',
|
||||
|
@ -61,8 +61,6 @@
|
||||
#include "nsTreeBodyFrame.h"
|
||||
#include "nsTreeColumns.h"
|
||||
#include "nsTreeUtils.h"
|
||||
#include "nsXBLPrototypeBinding.h"
|
||||
#include "nsXBLBinding.h"
|
||||
#include "mozilla/ArrayUtils.h"
|
||||
#include "mozilla/dom/DOMStringList.h"
|
||||
#include "mozilla/dom/EventTarget.h"
|
||||
@ -935,7 +933,7 @@ Accessible* nsAccessibilityService::CreateAccessible(nsINode* aNode,
|
||||
if (!frame || !frame->StyleVisibility()->IsVisible()) {
|
||||
// display:contents element doesn't have a frame, but retains the semantics.
|
||||
// All its children are unaffected.
|
||||
if (content->IsElement() && content->AsElement()->IsDisplayContents()) {
|
||||
if (nsCoreUtils::IsDisplayContents(content)) {
|
||||
const HTMLMarkupMapInfo* markupMap =
|
||||
mHTMLMarkupMap.Get(content->NodeInfo()->NameAtom());
|
||||
if (markupMap && markupMap->new_func) {
|
||||
@ -1092,7 +1090,7 @@ Accessible* nsAccessibilityService::CreateAccessible(nsINode* aNode,
|
||||
}
|
||||
}
|
||||
|
||||
// Accessible XBL types and deck stuff are used in XUL only currently.
|
||||
// XUL accessibles.
|
||||
if (!newAcc && content->IsXULElement()) {
|
||||
// No accessible for not selected deck panel and its children.
|
||||
if (!aContext->IsXULTabpanels()) {
|
||||
@ -1133,6 +1131,8 @@ Accessible* nsAccessibilityService::CreateAccessible(nsINode* aNode,
|
||||
// polyline and image. A 'use' and 'text' graphic elements require
|
||||
// special support.
|
||||
newAcc = new EnumRoleAccessible<roles::GRAPHIC>(content, document);
|
||||
} else if (content->IsSVGElement(nsGkAtoms::text)) {
|
||||
newAcc = new HyperTextAccessibleWrap(content->AsElement(), document);
|
||||
} else if (content->IsSVGElement(nsGkAtoms::svg)) {
|
||||
newAcc = new EnumRoleAccessible<roles::DIAGRAM>(content, document);
|
||||
}
|
||||
@ -1528,10 +1528,13 @@ void nsAccessibilityService::RemoveNativeRootAccessible(
|
||||
bool nsAccessibilityService::HasAccessible(nsINode* aDOMNode) {
|
||||
if (!aDOMNode) return false;
|
||||
|
||||
DocAccessible* document = GetDocAccessible(aDOMNode->OwnerDoc());
|
||||
Document* document = aDOMNode->OwnerDoc();
|
||||
if (!document) return false;
|
||||
|
||||
return document->HasAccessible(aDOMNode);
|
||||
DocAccessible* docAcc = GetExistingDocAccessible(aDOMNode->OwnerDoc());
|
||||
if (!docAcc) return false;
|
||||
|
||||
return docAcc->HasAccessible(aDOMNode);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -544,3 +544,8 @@ void nsCoreUtils::DispatchAccEvent(RefPtr<nsIAccessibleEvent> event) {
|
||||
|
||||
obsService->NotifyObservers(event, NS_ACCESSIBLE_EVENT_TOPIC, nullptr);
|
||||
}
|
||||
|
||||
bool nsCoreUtils::IsDisplayContents(nsIContent* aContent) {
|
||||
return aContent && aContent->IsElement() &&
|
||||
aContent->AsElement()->IsDisplayContents();
|
||||
}
|
||||
|
@ -322,6 +322,8 @@ class nsCoreUtils {
|
||||
* Notify accessible event observers of an event.
|
||||
*/
|
||||
static void DispatchAccEvent(RefPtr<nsIAccessibleEvent> aEvent);
|
||||
|
||||
static bool IsDisplayContents(nsIContent* aContent);
|
||||
};
|
||||
|
||||
#endif
|
||||
|
@ -4,8 +4,6 @@
|
||||
|
||||
#include "Accessible-inl.h"
|
||||
|
||||
#include "nsIXBLAccessible.h"
|
||||
|
||||
#include "EmbeddedObjCollector.h"
|
||||
#include "AccGroupInfo.h"
|
||||
#include "AccIterator.h"
|
||||
@ -28,7 +26,6 @@
|
||||
#include "TableAccessible.h"
|
||||
#include "TableCellAccessible.h"
|
||||
#include "TreeWalker.h"
|
||||
#include "XULDocument.h"
|
||||
|
||||
#include "nsIDOMXULButtonElement.h"
|
||||
#include "nsIDOMXULSelectCntrlEl.h"
|
||||
@ -131,12 +128,6 @@ ENameValueFlag Accessible::Name(nsString& aName) const {
|
||||
ARIAName(aName);
|
||||
if (!aName.IsEmpty()) return eNameOK;
|
||||
|
||||
nsCOMPtr<nsIXBLAccessible> xblAccessible(do_QueryInterface(mContent));
|
||||
if (xblAccessible) {
|
||||
xblAccessible->GetAccessibleName(aName);
|
||||
if (!aName.IsEmpty()) return eNameOK;
|
||||
}
|
||||
|
||||
ENameValueFlag nameFlag = NativeName(aName);
|
||||
if (!aName.IsEmpty()) return nameFlag;
|
||||
|
||||
@ -229,8 +220,8 @@ KeyBinding Accessible::AccessKey() const {
|
||||
HTMLLabelIterator iter(Document(), this,
|
||||
HTMLLabelIterator::eSkipAncestorLabel);
|
||||
label = iter.Next();
|
||||
|
||||
} else if (mContent->IsXULElement()) {
|
||||
}
|
||||
if (!label) {
|
||||
XULLabelIterator iter(Document(), mContent);
|
||||
label = iter.Next();
|
||||
}
|
||||
@ -303,7 +294,7 @@ uint64_t Accessible::VisibilityState() const {
|
||||
if (!frame) {
|
||||
// Element having display:contents is considered visible semantically,
|
||||
// despite it doesn't have a visually visible box.
|
||||
if (mContent->IsElement() && mContent->AsElement()->IsDisplayContents()) {
|
||||
if (nsCoreUtils::IsDisplayContents(mContent)) {
|
||||
return states::OFFSCREEN;
|
||||
}
|
||||
return states::INVISIBLE;
|
||||
@ -726,6 +717,22 @@ void Accessible::TakeFocus() const {
|
||||
}
|
||||
}
|
||||
|
||||
void Accessible::NameFromAssociatedXULLabel(DocAccessible* aDocument,
|
||||
nsIContent* aElm, nsString& aName) {
|
||||
Accessible* label = nullptr;
|
||||
XULLabelIterator iter(aDocument, aElm);
|
||||
while ((label = iter.Next())) {
|
||||
// Check if label's value attribute is used
|
||||
label->Elm()->GetAttr(kNameSpaceID_None, nsGkAtoms::value, aName);
|
||||
if (aName.IsEmpty()) {
|
||||
// If no value attribute, a non-empty label must contain
|
||||
// children that define its text -- possibly using HTML
|
||||
nsTextEquivUtils::AppendTextEquivFromContent(label, label->Elm(), &aName);
|
||||
}
|
||||
}
|
||||
aName.CompressWhitespace();
|
||||
}
|
||||
|
||||
void Accessible::XULElmName(DocAccessible* aDocument, nsIContent* aElm,
|
||||
nsString& aName) {
|
||||
/**
|
||||
@ -759,47 +766,10 @@ void Accessible::XULElmName(DocAccessible* aDocument, nsIContent* aElm,
|
||||
// CASES #2 and #3 ------ label as a child or <label control="id" ... >
|
||||
// </label>
|
||||
if (aName.IsEmpty()) {
|
||||
Accessible* label = nullptr;
|
||||
XULLabelIterator iter(aDocument, aElm);
|
||||
while ((label = iter.Next())) {
|
||||
// Check if label's value attribute is used
|
||||
label->Elm()->GetAttr(kNameSpaceID_None, nsGkAtoms::value, aName);
|
||||
if (aName.IsEmpty()) {
|
||||
// If no value attribute, a non-empty label must contain
|
||||
// children that define its text -- possibly using HTML
|
||||
nsTextEquivUtils::AppendTextEquivFromContent(label, label->Elm(),
|
||||
&aName);
|
||||
}
|
||||
}
|
||||
NameFromAssociatedXULLabel(aDocument, aElm, aName);
|
||||
}
|
||||
|
||||
aName.CompressWhitespace();
|
||||
if (!aName.IsEmpty()) return;
|
||||
|
||||
// Can get text from title of <toolbaritem> if we're a child of a
|
||||
// <toolbaritem>
|
||||
nsIContent* bindingParent = aElm->GetBindingParent();
|
||||
nsIContent* parent =
|
||||
bindingParent ? bindingParent->GetParent() : aElm->GetParent();
|
||||
nsAutoString ancestorTitle;
|
||||
while (parent) {
|
||||
if (parent->IsXULElement(nsGkAtoms::toolbaritem) &&
|
||||
parent->AsElement()->GetAttr(kNameSpaceID_None, nsGkAtoms::title,
|
||||
ancestorTitle)) {
|
||||
// Before returning this, check if the element itself has a tooltip:
|
||||
if (aElm->IsElement() &&
|
||||
aElm->AsElement()->GetAttr(kNameSpaceID_None, nsGkAtoms::tooltiptext,
|
||||
aName)) {
|
||||
aName.CompressWhitespace();
|
||||
return;
|
||||
}
|
||||
|
||||
aName.Assign(ancestorTitle);
|
||||
aName.CompressWhitespace();
|
||||
return;
|
||||
}
|
||||
parent = parent->GetParent();
|
||||
}
|
||||
}
|
||||
|
||||
nsresult Accessible::HandleAccEvent(AccEvent* aEvent) {
|
||||
@ -1591,9 +1561,8 @@ Relation Accessible::RelationByType(RelationType aType) const {
|
||||
new IDRefsIterator(mDoc, mContent, nsGkAtoms::aria_labelledby));
|
||||
if (mContent->IsHTMLElement()) {
|
||||
rel.AppendIter(new HTMLLabelIterator(Document(), this));
|
||||
} else if (mContent->IsXULElement()) {
|
||||
rel.AppendIter(new XULLabelIterator(Document(), mContent));
|
||||
}
|
||||
rel.AppendIter(new XULLabelIterator(Document(), mContent));
|
||||
|
||||
return rel;
|
||||
}
|
||||
@ -1718,11 +1687,10 @@ Relation Accessible::RelationByType(RelationType aType) const {
|
||||
// In XUL, use first <button default="true" .../> in the document
|
||||
dom::Document* doc = mContent->OwnerDoc();
|
||||
nsIContent* buttonEl = nullptr;
|
||||
if (doc->IsXULDocument()) {
|
||||
dom::XULDocument* xulDoc = doc->AsXULDocument();
|
||||
if (doc->AllowXULXBL()) {
|
||||
nsCOMPtr<nsIHTMLCollection> possibleDefaultButtons =
|
||||
xulDoc->GetElementsByAttribute(NS_LITERAL_STRING("default"),
|
||||
NS_LITERAL_STRING("true"));
|
||||
doc->GetElementsByAttribute(NS_LITERAL_STRING("default"),
|
||||
NS_LITERAL_STRING("true"));
|
||||
if (possibleDefaultButtons) {
|
||||
uint32_t length = possibleDefaultButtons->Length();
|
||||
// Check for button in list of default="true" elements
|
||||
@ -1736,21 +1704,6 @@ Relation Accessible::RelationByType(RelationType aType) const {
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!buttonEl) { // Check for anonymous accept button in <dialog>
|
||||
dom::Element* rootElm = mContent->OwnerDoc()->GetRootElement();
|
||||
if (rootElm) {
|
||||
nsIContent* possibleButtonEl =
|
||||
rootElm->OwnerDoc()->GetAnonymousElementByAttribute(
|
||||
rootElm, nsGkAtoms::_default, NS_LITERAL_STRING("true"));
|
||||
if (possibleButtonEl && possibleButtonEl->IsElement()) {
|
||||
RefPtr<nsIDOMXULButtonElement> button =
|
||||
possibleButtonEl->AsElement()->AsXULButton();
|
||||
if (button) {
|
||||
buttonEl = possibleButtonEl;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return Relation(mDoc, buttonEl);
|
||||
}
|
||||
}
|
||||
@ -1895,7 +1848,7 @@ void Accessible::AppendTextTo(nsAString& aText, uint32_t aStartOffset,
|
||||
|
||||
nsIFrame* frame = GetFrame();
|
||||
if (!frame) {
|
||||
if (mContent->IsElement() && mContent->AsElement()->IsDisplayContents()) {
|
||||
if (nsCoreUtils::IsDisplayContents(mContent)) {
|
||||
aText += kEmbeddedObjectChar;
|
||||
}
|
||||
return;
|
||||
@ -1966,6 +1919,11 @@ ENameValueFlag Accessible::NativeName(nsString& aName) const {
|
||||
|
||||
if (!aName.IsEmpty()) return eNameOK;
|
||||
|
||||
NameFromAssociatedXULLabel(mDoc, mContent, aName);
|
||||
if (!aName.IsEmpty()) {
|
||||
return eNameOK;
|
||||
}
|
||||
|
||||
nsTextEquivUtils::GetNameFromSubtree(this, aName);
|
||||
return aName.IsEmpty() ? eNameOK : eNameFromSubtree;
|
||||
}
|
||||
@ -2430,8 +2388,7 @@ Accessible* Accessible::CurrentItem() const {
|
||||
if (HasOwnContent() && mContent->IsElement() &&
|
||||
mContent->AsElement()->GetAttr(kNameSpaceID_None,
|
||||
nsGkAtoms::aria_activedescendant, id)) {
|
||||
dom::Document* DOMDoc = mContent->OwnerDoc();
|
||||
dom::Element* activeDescendantElm = DOMDoc->GetElementById(id);
|
||||
dom::Element* activeDescendantElm = IDRefsIterator::GetElem(mContent, id);
|
||||
if (activeDescendantElm) {
|
||||
if (mContent->IsInclusiveDescendantOf(activeDescendantElm)) {
|
||||
// Don't want a cyclical descendant relationship. That would be bad.
|
||||
|
@ -917,12 +917,6 @@ class Accessible : public nsISupports {
|
||||
mStateFlags &= ~eRelocated;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the accessible doesn't allow accessible children from XBL
|
||||
* anonymous subtree.
|
||||
*/
|
||||
bool NoXBLKids() const { return mStateFlags & eNoXBLKids; }
|
||||
|
||||
/**
|
||||
* Return true if the accessible allows accessible children from subtree of
|
||||
* a DOM element of this accessible.
|
||||
@ -1028,11 +1022,10 @@ class Accessible : public nsISupports {
|
||||
eKidsMutating = 1 << 6, // subtree is being mutated
|
||||
eIgnoreDOMUIEvent = 1 << 7, // don't process DOM UI events for a11y events
|
||||
eRelocated = 1 << 8, // accessible was moved in tree
|
||||
eNoXBLKids = 1 << 9, // accessible don't allows XBL children
|
||||
eNoKidsFromDOM = 1 << 10, // accessible doesn't allow children from DOM
|
||||
eHasTextKids = 1 << 11, // accessible have a text leaf in children
|
||||
eNoKidsFromDOM = 1 << 9, // accessible doesn't allow children from DOM
|
||||
eHasTextKids = 1 << 10, // accessible have a text leaf in children
|
||||
|
||||
eLastStateFlag = eNoKidsFromDOM
|
||||
eLastStateFlag = eHasTextKids
|
||||
};
|
||||
|
||||
/**
|
||||
@ -1063,6 +1056,13 @@ class Accessible : public nsISupports {
|
||||
*/
|
||||
void ARIAName(nsString& aName) const;
|
||||
|
||||
/**
|
||||
* Returns the accessible name specified for this control using XUL
|
||||
* <label control="id" ...>.
|
||||
*/
|
||||
static void NameFromAssociatedXULLabel(DocAccessible* aDocument,
|
||||
nsIContent* aElm, nsString& aName);
|
||||
|
||||
/**
|
||||
* Return the name for XUL element.
|
||||
*/
|
||||
@ -1136,7 +1136,7 @@ class Accessible : public nsISupports {
|
||||
nsTArray<Accessible*> mChildren;
|
||||
int32_t mIndexInParent;
|
||||
|
||||
static const uint8_t kStateFlagsBits = 12;
|
||||
static const uint8_t kStateFlagsBits = 11;
|
||||
static const uint8_t kContextFlagsBits = 2;
|
||||
static const uint8_t kTypeBits = 6;
|
||||
static const uint8_t kGenericTypesBits = 16;
|
||||
|
@ -93,10 +93,6 @@ DocAccessible::DocAccessible(dom::Document* aDocument,
|
||||
|
||||
MOZ_ASSERT(mPresShell, "should have been given a pres shell");
|
||||
mPresShell->SetDocAccessible(this);
|
||||
|
||||
// If this is a XUL Document, it should not implement nsHyperText
|
||||
if (mDocumentNode && mDocumentNode->IsXULDocument())
|
||||
mGenericTypes &= ~eHyperText;
|
||||
}
|
||||
|
||||
DocAccessible::~DocAccessible() {
|
||||
@ -198,10 +194,6 @@ role DocAccessible::NativeRole() const {
|
||||
return roles::CHROME_WINDOW;
|
||||
|
||||
if (itemType == nsIDocShellTreeItem::typeContent) {
|
||||
#ifdef MOZ_XUL
|
||||
if (mDocumentNode && mDocumentNode->IsXULDocument())
|
||||
return roles::APPLICATION;
|
||||
#endif
|
||||
return roles::DOCUMENT;
|
||||
}
|
||||
} else if (itemType == nsIDocShellTreeItem::typeContent) {
|
||||
@ -343,13 +335,6 @@ void DocAccessible::URL(nsAString& aURL) const {
|
||||
}
|
||||
|
||||
void DocAccessible::DocType(nsAString& aType) const {
|
||||
#ifdef MOZ_XUL
|
||||
if (mDocumentNode->IsXULDocument()) {
|
||||
aType.AssignLiteral("window"); // doctype not implemented for XUL at time
|
||||
// of writing - causes assertion
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
dom::DocumentType* docType = mDocumentNode->GetDoctype();
|
||||
if (docType) docType->GetPublicId(aType);
|
||||
}
|
||||
@ -686,7 +671,19 @@ void DocAccessible::AttributeWillChange(dom::Element* aElement,
|
||||
}
|
||||
|
||||
void DocAccessible::NativeAnonymousChildListChange(nsIContent* aContent,
|
||||
bool aIsRemove) {}
|
||||
bool aIsRemove) {
|
||||
if (aIsRemove) {
|
||||
#ifdef A11Y_LOG
|
||||
if (logging::IsEnabled(logging::eTree)) {
|
||||
logging::MsgBegin("TREE", "Anonymous content removed; doc: %p", this);
|
||||
logging::Node("node", aContent);
|
||||
logging::MsgEnd();
|
||||
}
|
||||
#endif
|
||||
|
||||
ContentRemoved(aContent);
|
||||
}
|
||||
}
|
||||
|
||||
void DocAccessible::AttributeChanged(dom::Element* aElement,
|
||||
int32_t aNameSpaceID, nsAtom* aAttribute,
|
||||
@ -994,7 +991,7 @@ void DocAccessible::ARIAActiveDescendantChanged(Accessible* aAccessible) {
|
||||
nsAutoString id;
|
||||
if (elm->AsElement()->GetAttr(kNameSpaceID_None,
|
||||
nsGkAtoms::aria_activedescendant, id)) {
|
||||
dom::Element* activeDescendantElm = elm->OwnerDoc()->GetElementById(id);
|
||||
dom::Element* activeDescendantElm = IDRefsIterator::GetElem(elm, id);
|
||||
if (activeDescendantElm) {
|
||||
Accessible* activeDescendant = GetAccessible(activeDescendantElm);
|
||||
if (activeDescendant) {
|
||||
@ -1267,12 +1264,148 @@ void DocAccessible::ContentInserted(nsIContent* aStartChildNode,
|
||||
nsIContent* aEndChildNode) {
|
||||
// Ignore content insertions until we constructed accessible tree. Otherwise
|
||||
// schedule tree update on content insertion after layout.
|
||||
if (mNotificationController && HasLoadState(eTreeConstructed)) {
|
||||
// Update the whole tree of this document accessible when the container is
|
||||
// null (document element is inserted or removed).
|
||||
mNotificationController->ScheduleContentInsertion(aStartChildNode,
|
||||
aEndChildNode);
|
||||
if (!mNotificationController || !HasLoadState(eTreeConstructed)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// The frame constructor guarantees that only ranges with the same parent
|
||||
// arrive here in presence of dynamic changes to the page, see
|
||||
// nsCSSFrameConstructor::IssueSingleInsertNotifications' callers.
|
||||
nsINode* parent = aStartChildNode->GetFlattenedTreeParentNode();
|
||||
if (!parent) {
|
||||
return;
|
||||
}
|
||||
|
||||
Accessible* container = AccessibleOrTrueContainer(parent);
|
||||
if (!container) {
|
||||
return;
|
||||
}
|
||||
|
||||
AutoTArray<nsCOMPtr<nsIContent>, 10> list;
|
||||
for (nsIContent* node = aStartChildNode; node != aEndChildNode;
|
||||
node = node->GetNextSibling()) {
|
||||
MOZ_ASSERT(parent == node->GetFlattenedTreeParentNode());
|
||||
if (PruneOrInsertSubtree(node)) {
|
||||
list.AppendElement(node);
|
||||
}
|
||||
}
|
||||
|
||||
mNotificationController->ScheduleContentInsertion(container, list);
|
||||
}
|
||||
|
||||
bool DocAccessible::PruneOrInsertSubtree(nsIContent* aRoot) {
|
||||
bool insert = false;
|
||||
|
||||
// In the case that we are, or are in, a shadow host, we need to assure
|
||||
// some accessibles are removed if they are not rendered anymore.
|
||||
nsIContent* shadowHost =
|
||||
aRoot->GetShadowRoot() ? aRoot : aRoot->GetContainingShadowHost();
|
||||
if (shadowHost) {
|
||||
dom::ExplicitChildIterator iter(shadowHost);
|
||||
|
||||
// Check all explicit children in the host, if they are not slotted
|
||||
// then remove their accessibles and subtrees.
|
||||
while (nsIContent* childNode = iter.GetNextChild()) {
|
||||
if (!childNode->GetPrimaryFrame() &&
|
||||
!nsCoreUtils::IsDisplayContents(childNode)) {
|
||||
ContentRemoved(childNode);
|
||||
}
|
||||
}
|
||||
|
||||
// If this is a slot, check to see if its fallback content is rendered,
|
||||
// if not - remove it.
|
||||
if (aRoot->IsHTMLElement(nsGkAtoms::slot)) {
|
||||
for (nsIContent* childNode = aRoot->GetFirstChild(); childNode;
|
||||
childNode = childNode->GetNextSibling()) {
|
||||
if (!childNode->GetPrimaryFrame() &&
|
||||
!nsCoreUtils::IsDisplayContents(childNode)) {
|
||||
ContentRemoved(childNode);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If we already have an accessible, check if we need to remove it, recreate
|
||||
// it, or keep it in place.
|
||||
Accessible* acc = GetAccessible(aRoot);
|
||||
if (acc) {
|
||||
MOZ_ASSERT(aRoot == acc->GetContent(), "Accessible has differing content!");
|
||||
#ifdef A11Y_LOG
|
||||
if (logging::IsEnabled(logging::eTree)) {
|
||||
logging::MsgBegin(
|
||||
"TREE", "inserted content already has accessible; doc: %p", this);
|
||||
logging::Node("content node", aRoot);
|
||||
logging::AccessibleInfo("accessible node", acc);
|
||||
logging::MsgEnd();
|
||||
}
|
||||
#endif
|
||||
|
||||
nsIFrame* frame = acc->GetFrame();
|
||||
|
||||
// Accessible has no frame and it's not display:contents. Remove it.
|
||||
// As well as removing the a11y subtree, we must also remove Accessibles
|
||||
// for DOM descendants, since some of these might be relocated Accessibles
|
||||
// and their DOM nodes are now hidden as well.
|
||||
if (!frame && !nsCoreUtils::IsDisplayContents(aRoot)) {
|
||||
ContentRemoved(aRoot);
|
||||
return false;
|
||||
}
|
||||
|
||||
// If it's a XULLabel it was probably reframed because a `value` attribute
|
||||
// was added. The accessible creates its text leaf upon construction, so we
|
||||
// need to recreate. Remove it, and schedule for reconstruction.
|
||||
if (acc->IsXULLabel()) {
|
||||
ContentRemoved(acc);
|
||||
return true;
|
||||
}
|
||||
|
||||
// It is a broken image that is being reframed because it either got
|
||||
// or lost an `alt` tag that would rerender this node as text.
|
||||
if (frame && (acc->IsImage() != (frame->AccessibleType() == eImageType))) {
|
||||
ContentRemoved(aRoot);
|
||||
return true;
|
||||
}
|
||||
|
||||
// The accessible can be reparented or reordered in its parent.
|
||||
// We schedule it for reinsertion. For example, a slotted element
|
||||
// can change its slot attribute to a different slot.
|
||||
insert = true;
|
||||
} else {
|
||||
// If there is no current accessible, and the node has a frame, or is
|
||||
// display:contents, schedule it for insertion.
|
||||
if (aRoot->GetPrimaryFrame() || nsCoreUtils::IsDisplayContents(aRoot)) {
|
||||
// This may be a new subtree, the insertion process will recurse through
|
||||
// its descendants.
|
||||
if (!GetAccessibleOrDescendant(aRoot)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Content is not an accessible, but has accessible descendants.
|
||||
// We schedule this container for insertion strictly for the case where it
|
||||
// itself now needs an accessible. We will still need to recurse into the
|
||||
// descendant content to prune accessibles, and in all likelyness to
|
||||
// insert accessibles since accessible insertions will likeley get missed
|
||||
// in an existing subtree.
|
||||
insert = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (Accessible* container = AccessibleOrTrueContainer(aRoot)) {
|
||||
AutoTArray<nsCOMPtr<nsIContent>, 10> list;
|
||||
dom::AllChildrenIterator iter =
|
||||
dom::AllChildrenIterator(aRoot, nsIContent::eAllChildren, true);
|
||||
while (nsIContent* childNode = iter.GetNextChild()) {
|
||||
if (PruneOrInsertSubtree(childNode)) {
|
||||
list.AppendElement(childNode);
|
||||
}
|
||||
}
|
||||
|
||||
if (!list.IsEmpty()) {
|
||||
mNotificationController->ScheduleContentInsertion(container, list);
|
||||
}
|
||||
}
|
||||
|
||||
return insert;
|
||||
}
|
||||
|
||||
void DocAccessible::RecreateAccessible(nsIContent* aContent) {
|
||||
@ -1394,6 +1527,9 @@ void DocAccessible::DoInitialUpdate() {
|
||||
#endif
|
||||
browserChild->SendPDocAccessibleConstructor(ipcDoc, nullptr, 0,
|
||||
childID, holder);
|
||||
#if !defined(XP_WIN)
|
||||
ipcDoc->SendPDocAccessiblePlatformExtConstructor();
|
||||
#endif
|
||||
}
|
||||
|
||||
if (IsRoot()) {
|
||||
@ -1603,6 +1739,12 @@ bool DocAccessible::UpdateAccessibleOnAttrChange(dom::Element* aElement,
|
||||
return true;
|
||||
}
|
||||
|
||||
if (aAttribute == nsGkAtoms::type) {
|
||||
// If the input[type] changes, we should recreate the accessible.
|
||||
RecreateAccessible(aElement);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -1659,6 +1801,7 @@ class InsertIterator final {
|
||||
TreeWalker mWalker;
|
||||
|
||||
const nsTArray<nsCOMPtr<nsIContent> >* mNodes;
|
||||
nsTHashtable<nsPtrHashKey<const nsIContent>> mProcessedNodes;
|
||||
uint32_t mNodesIdx;
|
||||
};
|
||||
|
||||
@ -1684,7 +1827,15 @@ bool InsertIterator::Next() {
|
||||
// what means there's no container. Ignore the insertion too.
|
||||
nsIContent* prevNode = mNodes->SafeElementAt(mNodesIdx - 1);
|
||||
nsIContent* node = mNodes->ElementAt(mNodesIdx++);
|
||||
Accessible* container = Document()->AccessibleOrTrueContainer(node, true);
|
||||
// Check to see if we already processed this node with this iterator.
|
||||
// this can happen if we get two redundant insertions in the case of a
|
||||
// text and frame insertion.
|
||||
if (!mProcessedNodes.EnsureInserted(node)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
Accessible* container =
|
||||
Document()->AccessibleOrTrueContainer(node->GetParentNode(), true);
|
||||
if (container != Context()) {
|
||||
continue;
|
||||
}
|
||||
@ -1753,20 +1904,17 @@ void DocAccessible::ProcessContentInserted(
|
||||
do {
|
||||
Accessible* parent = iter.Child()->Parent();
|
||||
if (parent) {
|
||||
if (parent != aContainer) {
|
||||
Accessible* previousSibling = iter.ChildBefore();
|
||||
if (parent != aContainer ||
|
||||
iter.Child()->PrevSibling() != previousSibling) {
|
||||
#ifdef A11Y_LOG
|
||||
logging::TreeInfo("stealing accessible", 0, "old parent", parent,
|
||||
logging::TreeInfo("relocating accessible", 0, "old parent", parent,
|
||||
"new parent", aContainer, "child", iter.Child(),
|
||||
nullptr);
|
||||
#endif
|
||||
MOZ_ASSERT_UNREACHABLE("stealing accessible");
|
||||
continue;
|
||||
MoveChild(iter.Child(), aContainer,
|
||||
previousSibling ? previousSibling->IndexInParent() + 1 : 0);
|
||||
}
|
||||
|
||||
#ifdef A11Y_LOG
|
||||
logging::TreeInfo("binding to same parent", logging::eVerbose, "parent",
|
||||
aContainer, "child", iter.Child(), nullptr);
|
||||
#endif
|
||||
continue;
|
||||
}
|
||||
|
||||
@ -2101,7 +2249,7 @@ void DocAccessible::PutChildrenBack(nsTArray<RefPtr<Accessible> >* aChildren,
|
||||
}
|
||||
}
|
||||
|
||||
aChildren->RemoveElementsAt(aStartIdx, aChildren->Length() - aStartIdx);
|
||||
aChildren->RemoveLastElements(aChildren->Length() - aStartIdx);
|
||||
}
|
||||
|
||||
bool DocAccessible::MoveChild(Accessible* aChild, Accessible* aNewParent,
|
||||
|
@ -325,10 +325,6 @@ class DocAccessible : public HyperTextAccessibleWrap,
|
||||
|
||||
/**
|
||||
* Return true if the given ID is referred by relation attribute.
|
||||
*
|
||||
* @note Different elements may share the same ID if they are hosted inside
|
||||
* XBL bindings. Be careful the result of this method may be senseless
|
||||
* while it's called for XUL elements (where XBL is used widely).
|
||||
*/
|
||||
bool IsDependentID(dom::Element* aElement, const nsAString& aID) const {
|
||||
return GetRelProviders(aElement, aID);
|
||||
@ -595,6 +591,19 @@ class DocAccessible : public HyperTextAccessibleWrap,
|
||||
*/
|
||||
void ARIAActiveDescendantIDMaybeMoved(dom::Element* aElm);
|
||||
|
||||
/**
|
||||
* Traverse content subtree and for each node do one of 3 things:
|
||||
* 1. Check if content node has an accessible that should be removed and
|
||||
* remove it.
|
||||
* 2. Check if content node has an accessible that needs to be recreated.
|
||||
* Remove it and schedule it for reinsertion.
|
||||
* 3. Check if content node has no accessible but needs one. Schedule one for
|
||||
* insertion.
|
||||
*
|
||||
* Returns true if the root node should be reinserted.
|
||||
*/
|
||||
bool PruneOrInsertSubtree(nsIContent* aRoot);
|
||||
|
||||
protected:
|
||||
/**
|
||||
* State and property flags, kept by mDocFlags.
|
||||
|
@ -1792,18 +1792,20 @@ void HyperTextAccessible::Shutdown() {
|
||||
}
|
||||
|
||||
bool HyperTextAccessible::RemoveChild(Accessible* aAccessible) {
|
||||
int32_t childIndex = aAccessible->IndexInParent();
|
||||
int32_t count = mOffsets.Length() - childIndex;
|
||||
if (count > 0) mOffsets.RemoveElementsAt(childIndex, count);
|
||||
const int32_t childIndex = aAccessible->IndexInParent();
|
||||
if (childIndex < static_cast<int64_t>(mOffsets.Length())) {
|
||||
mOffsets.RemoveLastElements(mOffsets.Length() -
|
||||
aAccessible->IndexInParent());
|
||||
}
|
||||
|
||||
return AccessibleWrap::RemoveChild(aAccessible);
|
||||
}
|
||||
|
||||
bool HyperTextAccessible::InsertChildAt(uint32_t aIndex, Accessible* aChild) {
|
||||
int32_t count = mOffsets.Length() - aIndex;
|
||||
if (count > 0) {
|
||||
mOffsets.RemoveElementsAt(aIndex, count);
|
||||
if (aIndex < mOffsets.Length()) {
|
||||
mOffsets.RemoveLastElements(mOffsets.Length() - aIndex);
|
||||
}
|
||||
|
||||
return AccessibleWrap::InsertChildAt(aIndex, aChild);
|
||||
}
|
||||
|
||||
|
@ -41,7 +41,7 @@
|
||||
#include "nsGlobalWindow.h"
|
||||
|
||||
#ifdef MOZ_XUL
|
||||
# include "nsIXULWindow.h"
|
||||
# include "nsIAppWindow.h"
|
||||
#endif
|
||||
|
||||
using namespace mozilla;
|
||||
@ -78,33 +78,23 @@ ENameValueFlag RootAccessible::Name(nsString& aName) const {
|
||||
return eNameOK;
|
||||
}
|
||||
|
||||
role RootAccessible::NativeRole() const {
|
||||
// If it's a <dialog> or <wizard>, use roles::DIALOG instead
|
||||
dom::Element* rootElm = mDocumentNode->GetRootElement();
|
||||
if (rootElm &&
|
||||
rootElm->IsAnyOfXULElements(nsGkAtoms::dialog, nsGkAtoms::wizard))
|
||||
return roles::DIALOG;
|
||||
|
||||
return DocAccessibleWrap::NativeRole();
|
||||
}
|
||||
|
||||
// RootAccessible protected member
|
||||
#ifdef MOZ_XUL
|
||||
uint32_t RootAccessible::GetChromeFlags() const {
|
||||
// Return the flag set for the top level window as defined
|
||||
// by nsIWebBrowserChrome::CHROME_WINDOW_[FLAGNAME]
|
||||
// Not simple: nsIXULWindow is not just a QI from nsIDOMWindow
|
||||
// Not simple: nsIAppWindow is not just a QI from nsIDOMWindow
|
||||
nsCOMPtr<nsIDocShell> docShell = nsCoreUtils::GetDocShellFor(mDocumentNode);
|
||||
NS_ENSURE_TRUE(docShell, 0);
|
||||
nsCOMPtr<nsIDocShellTreeOwner> treeOwner;
|
||||
docShell->GetTreeOwner(getter_AddRefs(treeOwner));
|
||||
NS_ENSURE_TRUE(treeOwner, 0);
|
||||
nsCOMPtr<nsIXULWindow> xulWin(do_GetInterface(treeOwner));
|
||||
if (!xulWin) {
|
||||
nsCOMPtr<nsIAppWindow> appWin(do_GetInterface(treeOwner));
|
||||
if (!appWin) {
|
||||
return 0;
|
||||
}
|
||||
uint32_t chromeFlags;
|
||||
xulWin->GetChromeFlags(&chromeFlags);
|
||||
appWin->GetChromeFlags(&chromeFlags);
|
||||
return chromeFlags;
|
||||
}
|
||||
#endif
|
||||
|
@ -29,7 +29,6 @@ class RootAccessible : public DocAccessibleWrap, public nsIDOMEventListener {
|
||||
virtual void Shutdown() override;
|
||||
virtual mozilla::a11y::ENameValueFlag Name(nsString& aName) const override;
|
||||
virtual Relation RelationByType(RelationType aType) const override;
|
||||
virtual mozilla::a11y::role NativeRole() const override;
|
||||
virtual uint64_t NativeState() const override;
|
||||
|
||||
// RootAccessible
|
||||
|
@ -163,11 +163,11 @@ role HTMLHeaderOrFooterAccessible::NativeRole() const {
|
||||
// If other sectioning or sectioning root elements, they become sections.
|
||||
nsIContent* parent = mContent->GetParent();
|
||||
while (parent) {
|
||||
if (parent->IsAnyOfHTMLElements(nsGkAtoms::article, nsGkAtoms::aside,
|
||||
nsGkAtoms::nav, nsGkAtoms::section,
|
||||
nsGkAtoms::blockquote, nsGkAtoms::details,
|
||||
nsGkAtoms::dialog, nsGkAtoms::fieldset,
|
||||
nsGkAtoms::figure, nsGkAtoms::td)) {
|
||||
if (parent->IsAnyOfHTMLElements(
|
||||
nsGkAtoms::article, nsGkAtoms::aside, nsGkAtoms::nav,
|
||||
nsGkAtoms::section, nsGkAtoms::main, nsGkAtoms::blockquote,
|
||||
nsGkAtoms::details, nsGkAtoms::dialog, nsGkAtoms::fieldset,
|
||||
nsGkAtoms::figure, nsGkAtoms::td)) {
|
||||
break;
|
||||
}
|
||||
parent = parent->GetParent();
|
||||
|
@ -98,17 +98,16 @@ class HTMLTextFieldAccessible : public HyperTextAccessibleWrap {
|
||||
virtual ENameValueFlag NativeName(nsString& aName) const override;
|
||||
|
||||
/**
|
||||
* Return a widget element this input is part of, for example, XUL:textbox or
|
||||
* HTML:input@type="number".
|
||||
* Return a widget element this input is part of, for example, search-textbox.
|
||||
*
|
||||
* FIXME: This should probably be renamed.
|
||||
*/
|
||||
nsIContent* BindingOrWidgetParent() const {
|
||||
nsIContent* el = mContent->GetBindingParent();
|
||||
if (el) {
|
||||
if (auto* el = mContent->GetClosestNativeAnonymousSubtreeRootParent()) {
|
||||
return el;
|
||||
}
|
||||
// XUL textboxes custom elements implementation.
|
||||
ErrorResult rv;
|
||||
return Elm()->Closest(NS_LITERAL_STRING("textbox"), rv);
|
||||
// XUL search-textbox custom element
|
||||
return Elm()->Closest(NS_LITERAL_STRING("search-textbox"), IgnoreErrors());
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -34,7 +34,6 @@ XPIDL_SOURCES += [
|
||||
'nsIAccessibleTypes.idl',
|
||||
'nsIAccessibleValue.idl',
|
||||
'nsIAccessibleVirtualCursorChangeEvent.idl',
|
||||
'nsIXBLAccessible.idl',
|
||||
]
|
||||
|
||||
XPIDL_MODULE = 'accessibility'
|
||||
|
@ -1,18 +0,0 @@
|
||||
/* 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 "nsISupports.idl"
|
||||
|
||||
/**
|
||||
* XBL controls can implement this interface to provide own implementation of
|
||||
* accessible properties.
|
||||
*/
|
||||
[scriptable, builtinclass, uuid(3716eb86-166b-445b-a94a-9b522fee96e6)]
|
||||
interface nsIXBLAccessible : nsISupports
|
||||
{
|
||||
/**
|
||||
* Return accessible name.
|
||||
*/
|
||||
readonly attribute AString accessibleName;
|
||||
};
|
@ -17,6 +17,8 @@
|
||||
# include "mozilla/mscom/Ptr.h"
|
||||
# include "nsWinUtils.h"
|
||||
# include "RootAccessible.h"
|
||||
#else
|
||||
# include "mozilla/a11y/DocAccessiblePlatformExtParent.h"
|
||||
#endif
|
||||
|
||||
namespace mozilla {
|
||||
@ -818,6 +820,23 @@ mozilla::ipc::IPCResult DocAccessibleParent::RecvBatch(
|
||||
# endif // defined(XP_WIN)
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
bool DocAccessibleParent::DeallocPDocAccessiblePlatformExtParent(
|
||||
PDocAccessiblePlatformExtParent* aActor) {
|
||||
delete aActor;
|
||||
return true;
|
||||
}
|
||||
|
||||
PDocAccessiblePlatformExtParent*
|
||||
DocAccessibleParent::AllocPDocAccessiblePlatformExtParent() {
|
||||
return new DocAccessiblePlatformExtParent();
|
||||
}
|
||||
|
||||
DocAccessiblePlatformExtParent* DocAccessibleParent::GetPlatformExtension() {
|
||||
return static_cast<DocAccessiblePlatformExtParent*>(
|
||||
SingleManagedOrNull(ManagedPDocAccessiblePlatformExtParent()));
|
||||
}
|
||||
|
||||
#endif // !defined(XP_WIN)
|
||||
|
||||
} // namespace a11y
|
||||
|
@ -17,6 +17,10 @@ namespace a11y {
|
||||
|
||||
class xpcAccessibleGeneric;
|
||||
|
||||
#if !defined(XP_WIN)
|
||||
class DocAccessiblePlatformExtParent;
|
||||
#endif
|
||||
|
||||
/*
|
||||
* These objects live in the main process and comunicate with and represent
|
||||
* an accessible document in a content process.
|
||||
@ -225,6 +229,14 @@ class DocAccessibleParent : public ProxyAccessible,
|
||||
#if !defined(XP_WIN)
|
||||
virtual mozilla::ipc::IPCResult RecvBatch(
|
||||
const uint64_t& aBatchType, nsTArray<BatchData>&& aData) override;
|
||||
|
||||
virtual bool DeallocPDocAccessiblePlatformExtParent(
|
||||
PDocAccessiblePlatformExtParent* aActor) override;
|
||||
|
||||
virtual PDocAccessiblePlatformExtParent*
|
||||
AllocPDocAccessiblePlatformExtParent() override;
|
||||
|
||||
DocAccessiblePlatformExtParent* GetPlatformExtension();
|
||||
#endif
|
||||
|
||||
private:
|
||||
|
@ -0,0 +1,82 @@
|
||||
/* 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 "DocAccessiblePlatformExtChild.h"
|
||||
|
||||
#include "DocAccessibleChild.h"
|
||||
#include "AccessibleWrap.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace a11y {
|
||||
|
||||
mozilla::ipc::IPCResult DocAccessiblePlatformExtChild::RecvPivot(
|
||||
uint64_t aID, int32_t aGranularity, bool aForward, bool aInclusive) {
|
||||
if (auto acc = IdToAccessibleWrap(aID)) {
|
||||
acc->Pivot(aGranularity, aForward, aInclusive);
|
||||
}
|
||||
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
mozilla::ipc::IPCResult DocAccessiblePlatformExtChild::RecvNavigateText(
|
||||
uint64_t aID, int32_t aGranularity, int32_t aStartOffset, int32_t aEndOffset,
|
||||
bool aForward, bool aSelect) {
|
||||
if (auto acc = IdToAccessibleWrap(aID)) {
|
||||
acc->NavigateText(aGranularity, aStartOffset, aEndOffset, aForward,
|
||||
aSelect);
|
||||
}
|
||||
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
mozilla::ipc::IPCResult DocAccessiblePlatformExtChild::RecvSetSelection(
|
||||
uint64_t aID, int32_t aStart, int32_t aEnd) {
|
||||
if (auto acc = IdToAccessibleWrap(aID)) {
|
||||
acc->SetSelection(aStart, aEnd);
|
||||
}
|
||||
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
mozilla::ipc::IPCResult DocAccessiblePlatformExtChild::RecvCut(uint64_t aID) {
|
||||
if (auto acc = IdToAccessibleWrap(aID)) {
|
||||
acc->Cut();
|
||||
}
|
||||
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
mozilla::ipc::IPCResult DocAccessiblePlatformExtChild::RecvCopy(uint64_t aID) {
|
||||
if (auto acc = IdToAccessibleWrap(aID)) {
|
||||
acc->Copy();
|
||||
}
|
||||
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
mozilla::ipc::IPCResult DocAccessiblePlatformExtChild::RecvPaste(uint64_t aID) {
|
||||
if (auto acc = IdToAccessibleWrap(aID)) {
|
||||
acc->Paste();
|
||||
}
|
||||
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
mozilla::ipc::IPCResult DocAccessiblePlatformExtChild::RecvExploreByTouch(
|
||||
uint64_t aID, float aX, float aY) {
|
||||
if (auto acc = IdToAccessibleWrap(aID)) {
|
||||
acc->ExploreByTouch(aX, aY);
|
||||
}
|
||||
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
AccessibleWrap* DocAccessiblePlatformExtChild::IdToAccessibleWrap(
|
||||
const uint64_t& aID) const {
|
||||
return static_cast<AccessibleWrap*>(
|
||||
static_cast<DocAccessibleChild*>(Manager())->IdToAccessible(aID));
|
||||
}
|
||||
|
||||
} // namespace a11y
|
||||
} // namespace mozilla
|
@ -0,0 +1,43 @@
|
||||
/* 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_DocAccessiblePlatformExtChild_h
|
||||
#define mozilla_a11y_DocAccessiblePlatformExtChild_h
|
||||
|
||||
#include "mozilla/a11y/PDocAccessiblePlatformExtChild.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace a11y {
|
||||
|
||||
class AccessibleWrap;
|
||||
class DocAccessibleChild;
|
||||
|
||||
class DocAccessiblePlatformExtChild : public PDocAccessiblePlatformExtChild {
|
||||
public:
|
||||
mozilla::ipc::IPCResult RecvPivot(uint64_t aID, int32_t aGranularity,
|
||||
bool aForward, bool aInclusive);
|
||||
|
||||
mozilla::ipc::IPCResult RecvNavigateText(uint64_t aID, int32_t aGranularity,
|
||||
int32_t aStartOffset,
|
||||
int32_t aEndOffset, bool aForward,
|
||||
bool aSelect);
|
||||
|
||||
mozilla::ipc::IPCResult RecvSetSelection(uint64_t aID, int32_t aStart,
|
||||
int32_t aEnd);
|
||||
|
||||
mozilla::ipc::IPCResult RecvCut(uint64_t aID);
|
||||
|
||||
mozilla::ipc::IPCResult RecvCopy(uint64_t aID);
|
||||
|
||||
mozilla::ipc::IPCResult RecvPaste(uint64_t aID);
|
||||
|
||||
mozilla::ipc::IPCResult RecvExploreByTouch(uint64_t aID, float aX, float aY);
|
||||
|
||||
private:
|
||||
AccessibleWrap* IdToAccessibleWrap(const uint64_t& aID) const;
|
||||
};
|
||||
} // namespace a11y
|
||||
} // namespace mozilla
|
||||
|
||||
#endif
|
@ -0,0 +1,17 @@
|
||||
/* 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_DocAccessiblePlatformExtParent_h
|
||||
#define mozilla_a11y_DocAccessiblePlatformExtParent_h
|
||||
|
||||
#include "mozilla/a11y/PDocAccessiblePlatformExtParent.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace a11y {
|
||||
class DocAccessiblePlatformExtParent : public PDocAccessiblePlatformExtParent {
|
||||
};
|
||||
} // namespace a11y
|
||||
} // namespace mozilla
|
||||
|
||||
#endif
|
@ -0,0 +1,31 @@
|
||||
/* 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 protocol PDocAccessible;
|
||||
|
||||
namespace mozilla {
|
||||
namespace a11y {
|
||||
|
||||
protocol PDocAccessiblePlatformExt {
|
||||
manager PDocAccessible;
|
||||
|
||||
child:
|
||||
async __delete__();
|
||||
|
||||
async Pivot(uint64_t aID, int32_t aGranularity, bool aForward, bool aInclusive);
|
||||
|
||||
async NavigateText(uint64_t aID, int32_t aGranularity, int32_t aStartOffset, int32_t aEndOffset, bool aForward, bool aSelect);
|
||||
|
||||
async SetSelection(uint64_t aID, int32_t aStart, int32_t aEnd);
|
||||
|
||||
async Cut(uint64_t aID);
|
||||
|
||||
async Copy(uint64_t aID);
|
||||
|
||||
async Paste(uint64_t aID);
|
||||
|
||||
async ExploreByTouch(uint64_t aID, float aX, float aY);
|
||||
};
|
||||
}
|
||||
}
|
27
accessible/ipc/extension/android/moz.build
Normal file
27
accessible/ipc/extension/android/moz.build
Normal file
@ -0,0 +1,27 @@
|
||||
# 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/.
|
||||
|
||||
# With --disable-accessibility, we need to compile PDocAccessiblePlatformExt.ipdl, but
|
||||
# not the C++.
|
||||
|
||||
IPDL_SOURCES += ['PDocAccessiblePlatformExt.ipdl']
|
||||
|
||||
if CONFIG['ACCESSIBILITY']:
|
||||
EXPORTS.mozilla.a11y += [
|
||||
'DocAccessiblePlatformExtChild.h',
|
||||
'DocAccessiblePlatformExtParent.h',
|
||||
]
|
||||
|
||||
SOURCES += [
|
||||
'DocAccessiblePlatformExtChild.cpp',
|
||||
]
|
||||
|
||||
LOCAL_INCLUDES += [
|
||||
'/accessible/android',
|
||||
'/accessible/ipc/other',
|
||||
]
|
||||
|
||||
include('/ipc/chromium/chromium-config.mozbuild')
|
||||
|
||||
FINAL_LIBRARY = 'xul'
|
@ -2,5 +2,7 @@
|
||||
# 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/.
|
||||
|
||||
toolkit.jar:
|
||||
content/global/accessibility/content-script.js (content-script.js)
|
||||
if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'android':
|
||||
DIRS += ['android']
|
||||
else:
|
||||
DIRS += ['other']
|
@ -0,0 +1,19 @@
|
||||
/* 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_DocAccessiblePlatformExtChild_h
|
||||
#define mozilla_a11y_DocAccessiblePlatformExtChild_h
|
||||
|
||||
#include "mozilla/a11y/PDocAccessiblePlatformExtChild.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace a11y {
|
||||
|
||||
class DocAccessibleChild;
|
||||
|
||||
class DocAccessiblePlatformExtChild : public PDocAccessiblePlatformExtChild {};
|
||||
} // namespace a11y
|
||||
} // namespace mozilla
|
||||
|
||||
#endif
|
@ -0,0 +1,17 @@
|
||||
/* 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_DocAccessiblePlatformExtParent_h
|
||||
#define mozilla_a11y_DocAccessiblePlatformExtParent_h
|
||||
|
||||
#include "mozilla/a11y/PDocAccessiblePlatformExtParent.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace a11y {
|
||||
class DocAccessiblePlatformExtParent : public PDocAccessiblePlatformExtParent {
|
||||
};
|
||||
} // namespace a11y
|
||||
} // namespace mozilla
|
||||
|
||||
#endif
|
@ -0,0 +1,17 @@
|
||||
/* 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 protocol PDocAccessible;
|
||||
|
||||
namespace mozilla {
|
||||
namespace a11y {
|
||||
|
||||
protocol PDocAccessiblePlatformExt {
|
||||
manager PDocAccessible;
|
||||
|
||||
child:
|
||||
async __delete__();
|
||||
};
|
||||
|
||||
}}
|
18
accessible/ipc/extension/other/moz.build
Normal file
18
accessible/ipc/extension/other/moz.build
Normal file
@ -0,0 +1,18 @@
|
||||
# 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/.
|
||||
|
||||
# With --disable-accessibility, we need to compile PDocAccessiblePlatformExt.ipdl, but
|
||||
# not the C++.
|
||||
|
||||
IPDL_SOURCES += ['PDocAccessiblePlatformExt.ipdl']
|
||||
|
||||
if CONFIG['ACCESSIBILITY']:
|
||||
EXPORTS.mozilla.a11y += [
|
||||
'DocAccessiblePlatformExtChild.h',
|
||||
'DocAccessiblePlatformExtParent.h',
|
||||
]
|
||||
|
||||
include('/ipc/chromium/chromium-config.mozbuild')
|
||||
|
||||
FINAL_LIBRARY = 'xul'
|
@ -10,7 +10,7 @@ if CONFIG['OS_ARCH'] == 'WINNT':
|
||||
'/accessible/windows/msaa',
|
||||
]
|
||||
else:
|
||||
DIRS += ['other']
|
||||
DIRS += ['other', 'extension']
|
||||
LOCAL_INCLUDES += [
|
||||
'/accessible/ipc/other',
|
||||
]
|
||||
|
@ -19,6 +19,7 @@
|
||||
# include "AccessibleWrap.h"
|
||||
#endif
|
||||
#include "mozilla/PresShell.h"
|
||||
#include "mozilla/a11y/DocAccessiblePlatformExtChild.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace a11y {
|
||||
@ -1677,5 +1678,16 @@ mozilla::ipc::IPCResult DocAccessibleChild::RecvRestoreFocus() {
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
bool DocAccessibleChild::DeallocPDocAccessiblePlatformExtChild(
|
||||
PDocAccessiblePlatformExtChild* aActor) {
|
||||
delete aActor;
|
||||
return true;
|
||||
}
|
||||
|
||||
PDocAccessiblePlatformExtChild*
|
||||
DocAccessibleChild::AllocPDocAccessiblePlatformExtChild() {
|
||||
return new DocAccessiblePlatformExtChild();
|
||||
}
|
||||
|
||||
} // namespace a11y
|
||||
} // namespace mozilla
|
||||
|
@ -11,6 +11,7 @@ namespace mozilla {
|
||||
namespace a11y {
|
||||
|
||||
class Accessible;
|
||||
class DocAccessiblePlatformExtChild;
|
||||
class HyperTextAccessible;
|
||||
class TextLeafAccessible;
|
||||
class ImageAccessible;
|
||||
@ -22,6 +23,8 @@ class TableCellAccessible;
|
||||
* and their lifetime is the same as the document they represent.
|
||||
*/
|
||||
class DocAccessibleChild : public DocAccessibleChildBase {
|
||||
friend DocAccessiblePlatformExtChild;
|
||||
|
||||
public:
|
||||
DocAccessibleChild(DocAccessible* aDoc, IProtocol* aManager)
|
||||
: DocAccessibleChildBase(aDoc) {
|
||||
@ -469,6 +472,12 @@ class DocAccessibleChild : public DocAccessibleChildBase {
|
||||
virtual mozilla::ipc::IPCResult RecvDOMNodeID(const uint64_t& aID,
|
||||
nsString* aDOMNodeID) override;
|
||||
|
||||
virtual bool DeallocPDocAccessiblePlatformExtChild(
|
||||
PDocAccessiblePlatformExtChild* aActor) override;
|
||||
|
||||
virtual PDocAccessiblePlatformExtChild* AllocPDocAccessiblePlatformExtChild()
|
||||
override;
|
||||
|
||||
private:
|
||||
Accessible* IdToAccessible(const uint64_t& aID) const;
|
||||
Accessible* IdToAccessibleLink(const uint64_t& aID) const;
|
||||
|
@ -4,6 +4,7 @@
|
||||
|
||||
include protocol PFileDescriptorSet;
|
||||
include protocol PBrowser;
|
||||
include protocol PDocAccessiblePlatformExt;
|
||||
|
||||
include "mozilla/GfxMessageUtils.h";
|
||||
|
||||
@ -69,8 +70,10 @@ struct RelationTargets
|
||||
nested(upto inside_sync) sync protocol PDocAccessible
|
||||
{
|
||||
manager PBrowser;
|
||||
manages PDocAccessiblePlatformExt;
|
||||
|
||||
parent:
|
||||
async PDocAccessiblePlatformExt();
|
||||
async Shutdown();
|
||||
|
||||
/*
|
||||
|
@ -1,355 +0,0 @@
|
||||
/* 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/. */
|
||||
|
||||
"use strict";
|
||||
|
||||
var EXPORTED_SYMBOLS = ["AccessFu"];
|
||||
|
||||
const { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
|
||||
const { Logger, Utils } = ChromeUtils.import(
|
||||
"resource://gre/modules/accessibility/Utils.jsm"
|
||||
);
|
||||
ChromeUtils.defineModuleGetter(
|
||||
this,
|
||||
"Rect",
|
||||
"resource://gre/modules/Geometry.jsm"
|
||||
);
|
||||
|
||||
const GECKOVIEW_MESSAGE = {
|
||||
ACTIVATE: "GeckoView:AccessibilityActivate",
|
||||
BY_GRANULARITY: "GeckoView:AccessibilityByGranularity",
|
||||
CLIPBOARD: "GeckoView:AccessibilityClipboard",
|
||||
CURSOR_TO_FOCUSED: "GeckoView:AccessibilityCursorToFocused",
|
||||
EXPLORE_BY_TOUCH: "GeckoView:AccessibilityExploreByTouch",
|
||||
LONG_PRESS: "GeckoView:AccessibilityLongPress",
|
||||
NEXT: "GeckoView:AccessibilityNext",
|
||||
PREVIOUS: "GeckoView:AccessibilityPrevious",
|
||||
SCROLL_BACKWARD: "GeckoView:AccessibilityScrollBackward",
|
||||
SCROLL_FORWARD: "GeckoView:AccessibilityScrollForward",
|
||||
SET_SELECTION: "GeckoView:AccessibilitySetSelection",
|
||||
VIEW_FOCUSED: "GeckoView:AccessibilityViewFocused",
|
||||
CLEAR_CURSOR: "GeckoView:AccessibilityClearCursor",
|
||||
};
|
||||
|
||||
const ACCESSFU_MESSAGE = {
|
||||
DOSCROLL: "AccessFu:DoScroll",
|
||||
};
|
||||
|
||||
const FRAME_SCRIPT = "chrome://global/content/accessibility/content-script.js";
|
||||
|
||||
var AccessFu = {
|
||||
/**
|
||||
* A lazy getter for event handler that binds the scope to AccessFu object.
|
||||
*/
|
||||
get handleEvent() {
|
||||
delete this.handleEvent;
|
||||
this.handleEvent = this._handleEvent.bind(this);
|
||||
return this.handleEvent;
|
||||
},
|
||||
|
||||
/**
|
||||
* Start AccessFu mode.
|
||||
*/
|
||||
enable: function enable() {
|
||||
if (this._enabled) {
|
||||
return;
|
||||
}
|
||||
this._enabled = true;
|
||||
|
||||
Services.obs.addObserver(this, "remote-browser-shown");
|
||||
Services.obs.addObserver(this, "inprocess-browser-shown");
|
||||
Services.ww.registerNotification(this);
|
||||
|
||||
for (let win of Services.wm.getEnumerator(null)) {
|
||||
this._attachWindow(win);
|
||||
}
|
||||
|
||||
Logger.info("AccessFu:Enabled");
|
||||
},
|
||||
|
||||
/**
|
||||
* Disable AccessFu and return to default interaction mode.
|
||||
*/
|
||||
disable: function disable() {
|
||||
if (!this._enabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
this._enabled = false;
|
||||
|
||||
Services.obs.removeObserver(this, "remote-browser-shown");
|
||||
Services.obs.removeObserver(this, "inprocess-browser-shown");
|
||||
Services.ww.unregisterNotification(this);
|
||||
|
||||
for (let win of Services.wm.getEnumerator(null)) {
|
||||
this._detachWindow(win);
|
||||
}
|
||||
|
||||
if (this.doneCallback) {
|
||||
this.doneCallback();
|
||||
delete this.doneCallback;
|
||||
}
|
||||
|
||||
Logger.info("AccessFu:Disabled");
|
||||
},
|
||||
|
||||
receiveMessage: function receiveMessage(aMessage) {
|
||||
Logger.debug(() => {
|
||||
return ["Recieved", aMessage.name, JSON.stringify(aMessage.json)];
|
||||
});
|
||||
|
||||
switch (aMessage.name) {
|
||||
case ACCESSFU_MESSAGE.DOSCROLL:
|
||||
this.Input.doScroll(aMessage.json, aMessage.target);
|
||||
break;
|
||||
}
|
||||
},
|
||||
|
||||
_attachWindow: function _attachWindow(win) {
|
||||
let wtype = win.document.documentElement.getAttribute("windowtype");
|
||||
if (wtype != "navigator:browser" && wtype != "navigator:geckoview") {
|
||||
// Don't attach to non-browser or geckoview windows.
|
||||
return;
|
||||
}
|
||||
|
||||
// Set up frame script
|
||||
let mm = win.messageManager;
|
||||
for (let messageName of Object.values(ACCESSFU_MESSAGE)) {
|
||||
mm.addMessageListener(messageName, this);
|
||||
}
|
||||
mm.loadFrameScript(FRAME_SCRIPT, true);
|
||||
|
||||
win.addEventListener("TabSelect", this);
|
||||
if (win.WindowEventDispatcher && !this._eventDispatcherListeners.has(win)) {
|
||||
const listener = (event, data, callback) => {
|
||||
this.onEvent(event, data, callback, win);
|
||||
};
|
||||
this._eventDispatcherListeners.set(win, listener);
|
||||
// desktop mochitests don't have this.
|
||||
win.WindowEventDispatcher.registerListener(
|
||||
listener,
|
||||
Object.values(GECKOVIEW_MESSAGE)
|
||||
);
|
||||
}
|
||||
},
|
||||
|
||||
_detachWindow: function _detachWindow(win) {
|
||||
let mm = win.messageManager;
|
||||
mm.broadcastAsyncMessage("AccessFu:Stop");
|
||||
mm.removeDelayedFrameScript(FRAME_SCRIPT);
|
||||
for (let messageName of Object.values(ACCESSFU_MESSAGE)) {
|
||||
mm.removeMessageListener(messageName, this);
|
||||
}
|
||||
|
||||
win.removeEventListener("TabSelect", this);
|
||||
if (win.WindowEventDispatcher && this._eventDispatcherListeners.has(win)) {
|
||||
// desktop mochitests don't have this.
|
||||
win.WindowEventDispatcher.unregisterListener(
|
||||
this._eventDispatcherListeners.get(win),
|
||||
Object.values(GECKOVIEW_MESSAGE)
|
||||
);
|
||||
this._eventDispatcherListeners.delete(win);
|
||||
}
|
||||
},
|
||||
|
||||
onEvent(event, data, callback, win) {
|
||||
switch (event) {
|
||||
case GECKOVIEW_MESSAGE.SETTINGS:
|
||||
if (data.enabled) {
|
||||
this._enable();
|
||||
} else {
|
||||
this._disable();
|
||||
}
|
||||
break;
|
||||
case GECKOVIEW_MESSAGE.NEXT:
|
||||
case GECKOVIEW_MESSAGE.PREVIOUS: {
|
||||
let rule = "Simple";
|
||||
if (data && data.rule && data.rule.length) {
|
||||
rule =
|
||||
data.rule.substr(0, 1).toUpperCase() +
|
||||
data.rule.substr(1).toLowerCase();
|
||||
}
|
||||
let method = event.replace(/GeckoView:Accessibility(\w+)/, "move$1");
|
||||
this.Input.moveCursor(method, rule, "gesture", win);
|
||||
break;
|
||||
}
|
||||
case GECKOVIEW_MESSAGE.ACTIVATE:
|
||||
this.Input.activateCurrent(data, win);
|
||||
break;
|
||||
case GECKOVIEW_MESSAGE.LONG_PRESS:
|
||||
// XXX: Advertize long press on supported objects and implement action
|
||||
break;
|
||||
case GECKOVIEW_MESSAGE.SCROLL_FORWARD:
|
||||
this.Input.androidScroll("forward", win);
|
||||
break;
|
||||
case GECKOVIEW_MESSAGE.SCROLL_BACKWARD:
|
||||
this.Input.androidScroll("backward", win);
|
||||
break;
|
||||
case GECKOVIEW_MESSAGE.CURSOR_TO_FOCUSED:
|
||||
this.autoMove({ moveToFocused: true }, win);
|
||||
break;
|
||||
case GECKOVIEW_MESSAGE.BY_GRANULARITY:
|
||||
this.Input.moveByGranularity(data, win);
|
||||
break;
|
||||
case GECKOVIEW_MESSAGE.EXPLORE_BY_TOUCH:
|
||||
this.Input.moveToPoint("Simple", ...data.coordinates, win);
|
||||
break;
|
||||
case GECKOVIEW_MESSAGE.SET_SELECTION:
|
||||
this.Input.setSelection(data, win);
|
||||
break;
|
||||
case GECKOVIEW_MESSAGE.CLIPBOARD:
|
||||
this.Input.clipboard(data, win);
|
||||
break;
|
||||
case GECKOVIEW_MESSAGE.CLEAR_CURSOR:
|
||||
this.Input.clearCursor(win);
|
||||
}
|
||||
},
|
||||
|
||||
observe: function observe(aSubject, aTopic, aData) {
|
||||
switch (aTopic) {
|
||||
case "domwindowopened": {
|
||||
let win = aSubject.QueryInterface(Ci.nsIDOMWindow);
|
||||
win.addEventListener(
|
||||
"load",
|
||||
() => {
|
||||
this._attachWindow(win);
|
||||
},
|
||||
{ once: true }
|
||||
);
|
||||
break;
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
_handleEvent: function _handleEvent(aEvent) {
|
||||
switch (aEvent.type) {
|
||||
case "TabSelect": {
|
||||
if (this._focused) {
|
||||
// We delay this for half a second so the awesomebar could close,
|
||||
// and we could use the current coordinates for the content item.
|
||||
// XXX TODO figure out how to avoid magic wait here.
|
||||
this.autoMove({
|
||||
delay: 500,
|
||||
forcePresent: true,
|
||||
noOpIfOnScreen: true,
|
||||
moveMethod: "moveFirst",
|
||||
});
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
},
|
||||
|
||||
autoMove: function autoMove(aOptions, aWindow) {
|
||||
const mm = Utils.getCurrentMessageManager(aWindow);
|
||||
mm.sendAsyncMessage("AccessFu:AutoMove", aOptions);
|
||||
},
|
||||
|
||||
// So we don't enable/disable twice
|
||||
_enabled: false,
|
||||
|
||||
// Layerview is focused
|
||||
_focused: false,
|
||||
|
||||
_eventDispatcherListeners: new WeakMap(),
|
||||
|
||||
/**
|
||||
* Adjusts the given bounds that are defined in device display pixels
|
||||
* to client-relative CSS pixels of the chrome window.
|
||||
* @param {Rect} aJsonBounds the bounds to adjust
|
||||
* @param {Window} aWindow the window containing the item
|
||||
*/
|
||||
screenToClientBounds(aJsonBounds, aWindow) {
|
||||
let bounds = new Rect(
|
||||
aJsonBounds.left,
|
||||
aJsonBounds.top,
|
||||
aJsonBounds.right - aJsonBounds.left,
|
||||
aJsonBounds.bottom - aJsonBounds.top
|
||||
);
|
||||
let { devicePixelRatio, mozInnerScreenX, mozInnerScreenY } = aWindow;
|
||||
|
||||
bounds = bounds.scale(1 / devicePixelRatio, 1 / devicePixelRatio);
|
||||
bounds = bounds.translate(-mozInnerScreenX, -mozInnerScreenY);
|
||||
return bounds.expandToIntegers();
|
||||
},
|
||||
};
|
||||
|
||||
var Input = {
|
||||
moveToPoint: function moveToPoint(aRule, aX, aY, aWindow) {
|
||||
Logger.debug("moveToPoint", aX, aY);
|
||||
const mm = Utils.getCurrentMessageManager(aWindow);
|
||||
mm.sendAsyncMessage("AccessFu:MoveToPoint", {
|
||||
rule: aRule,
|
||||
x: aX,
|
||||
y: aY,
|
||||
origin: "top",
|
||||
});
|
||||
},
|
||||
|
||||
moveCursor: function moveCursor(aAction, aRule, aInputType, aWindow) {
|
||||
const mm = Utils.getCurrentMessageManager(aWindow);
|
||||
mm.sendAsyncMessage("AccessFu:MoveCursor", {
|
||||
action: aAction,
|
||||
rule: aRule,
|
||||
origin: "top",
|
||||
inputType: aInputType,
|
||||
});
|
||||
},
|
||||
|
||||
androidScroll: function androidScroll(aDirection, aWindow) {
|
||||
const mm = Utils.getCurrentMessageManager(aWindow);
|
||||
mm.sendAsyncMessage("AccessFu:AndroidScroll", {
|
||||
direction: aDirection,
|
||||
origin: "top",
|
||||
});
|
||||
},
|
||||
|
||||
moveByGranularity: function moveByGranularity(aDetails, aWindow) {
|
||||
const mm = Utils.getCurrentMessageManager(aWindow);
|
||||
mm.sendAsyncMessage("AccessFu:MoveByGranularity", aDetails);
|
||||
},
|
||||
|
||||
setSelection: function setSelection(aDetails, aWindow) {
|
||||
const mm = Utils.getCurrentMessageManager(aWindow);
|
||||
mm.sendAsyncMessage("AccessFu:SetSelection", aDetails);
|
||||
},
|
||||
|
||||
clipboard: function clipboard(aDetails, aWindow) {
|
||||
const mm = Utils.getCurrentMessageManager(aWindow);
|
||||
mm.sendAsyncMessage("AccessFu:Clipboard", aDetails);
|
||||
},
|
||||
|
||||
activateCurrent: function activateCurrent(aData, aWindow) {
|
||||
let mm = Utils.getCurrentMessageManager(aWindow);
|
||||
mm.sendAsyncMessage("AccessFu:Activate", { offset: 0 });
|
||||
},
|
||||
|
||||
doScroll: function doScroll(aDetails, aBrowser) {
|
||||
let horizontal = aDetails.horizontal;
|
||||
let page = aDetails.page;
|
||||
let win = aBrowser.ownerGlobal;
|
||||
let winUtils = win.windowUtils;
|
||||
let p = AccessFu.screenToClientBounds(aDetails.bounds, win).center();
|
||||
winUtils.sendWheelEvent(
|
||||
p.x,
|
||||
p.y,
|
||||
horizontal ? page : 0,
|
||||
horizontal ? 0 : page,
|
||||
0,
|
||||
win.WheelEvent.DOM_DELTA_PAGE,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0
|
||||
);
|
||||
},
|
||||
|
||||
clearCursor: function clearCursor(aWindow) {
|
||||
const mm = Utils.getCurrentMessageManager(aWindow);
|
||||
mm.sendAsyncMessage("AccessFu:ClearCursor");
|
||||
},
|
||||
};
|
||||
AccessFu.Input = Input;
|
@ -1,73 +0,0 @@
|
||||
const { XPCOMUtils } = ChromeUtils.import(
|
||||
"resource://gre/modules/XPCOMUtils.jsm"
|
||||
);
|
||||
|
||||
const AndroidEvents = {
|
||||
VIEW_CLICKED: 0x01,
|
||||
VIEW_LONG_CLICKED: 0x02,
|
||||
VIEW_SELECTED: 0x04,
|
||||
VIEW_FOCUSED: 0x08,
|
||||
VIEW_TEXT_CHANGED: 0x10,
|
||||
WINDOW_STATE_CHANGED: 0x20,
|
||||
VIEW_HOVER_ENTER: 0x80,
|
||||
VIEW_HOVER_EXIT: 0x100,
|
||||
WINDOW_CONTENT_CHANGED: 0x800,
|
||||
VIEW_SCROLLED: 0x1000,
|
||||
VIEW_TEXT_SELECTION_CHANGED: 0x2000,
|
||||
ANNOUNCEMENT: 0x4000,
|
||||
VIEW_ACCESSIBILITY_FOCUSED: 0x8000,
|
||||
VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY: 0x20000,
|
||||
};
|
||||
|
||||
function ConstantsMap(aObject, aPrefix, aMap = {}, aModifier = null) {
|
||||
let offset = aPrefix.length;
|
||||
for (var name in aObject) {
|
||||
if (name.indexOf(aPrefix) === 0) {
|
||||
aMap[name.slice(offset)] = aModifier
|
||||
? aModifier(aObject[name])
|
||||
: aObject[name];
|
||||
}
|
||||
}
|
||||
|
||||
return aMap;
|
||||
}
|
||||
|
||||
XPCOMUtils.defineLazyGetter(this, "Roles", function() {
|
||||
return ConstantsMap(Ci.nsIAccessibleRole, "ROLE_");
|
||||
});
|
||||
|
||||
XPCOMUtils.defineLazyGetter(this, "Events", function() {
|
||||
return ConstantsMap(Ci.nsIAccessibleEvent, "EVENT_");
|
||||
});
|
||||
|
||||
XPCOMUtils.defineLazyGetter(this, "Relations", function() {
|
||||
return ConstantsMap(Ci.nsIAccessibleRelation, "RELATION_");
|
||||
});
|
||||
|
||||
XPCOMUtils.defineLazyGetter(this, "Prefilters", function() {
|
||||
return ConstantsMap(Ci.nsIAccessibleTraversalRule, "PREFILTER_");
|
||||
});
|
||||
|
||||
XPCOMUtils.defineLazyGetter(this, "Filters", function() {
|
||||
return ConstantsMap(Ci.nsIAccessibleTraversalRule, "FILTER_");
|
||||
});
|
||||
|
||||
XPCOMUtils.defineLazyGetter(this, "States", function() {
|
||||
let statesMap = ConstantsMap(Ci.nsIAccessibleStates, "STATE_", {}, val => {
|
||||
return { base: val, extended: 0 };
|
||||
});
|
||||
ConstantsMap(Ci.nsIAccessibleStates, "EXT_STATE_", statesMap, val => {
|
||||
return { base: 0, extended: val };
|
||||
});
|
||||
return statesMap;
|
||||
});
|
||||
|
||||
var EXPORTED_SYMBOLS = [
|
||||
"Roles",
|
||||
"Events",
|
||||
"Relations",
|
||||
"Filters",
|
||||
"States",
|
||||
"Prefilters",
|
||||
"AndroidEvents",
|
||||
];
|
@ -1,574 +0,0 @@
|
||||
/* 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/. */
|
||||
|
||||
ChromeUtils.defineModuleGetter(
|
||||
this,
|
||||
"Utils",
|
||||
"resource://gre/modules/accessibility/Utils.jsm"
|
||||
);
|
||||
ChromeUtils.defineModuleGetter(
|
||||
this,
|
||||
"Logger",
|
||||
"resource://gre/modules/accessibility/Utils.jsm"
|
||||
);
|
||||
ChromeUtils.defineModuleGetter(
|
||||
this,
|
||||
"Roles",
|
||||
"resource://gre/modules/accessibility/Constants.jsm"
|
||||
);
|
||||
ChromeUtils.defineModuleGetter(
|
||||
this,
|
||||
"States",
|
||||
"resource://gre/modules/accessibility/Constants.jsm"
|
||||
);
|
||||
ChromeUtils.defineModuleGetter(
|
||||
this,
|
||||
"TraversalRules",
|
||||
"resource://gre/modules/accessibility/Traversal.jsm"
|
||||
);
|
||||
ChromeUtils.defineModuleGetter(
|
||||
this,
|
||||
"TraversalHelper",
|
||||
"resource://gre/modules/accessibility/Traversal.jsm"
|
||||
);
|
||||
|
||||
var EXPORTED_SYMBOLS = ["ContentControl"];
|
||||
|
||||
const MOVEMENT_GRANULARITY_CHARACTER = 1;
|
||||
const MOVEMENT_GRANULARITY_WORD = 2;
|
||||
const MOVEMENT_GRANULARITY_LINE = 4;
|
||||
|
||||
const CLIPBOARD_COPY = 0x4000;
|
||||
const CLIPBOARD_PASTE = 0x8000;
|
||||
const CLIPBOARD_CUT = 0x10000;
|
||||
|
||||
function ContentControl(aContentScope) {
|
||||
this._contentScope = Cu.getWeakReference(aContentScope);
|
||||
this._childMessageSenders = new WeakMap();
|
||||
}
|
||||
|
||||
this.ContentControl.prototype = {
|
||||
messagesOfInterest: [
|
||||
"AccessFu:Activate",
|
||||
"AccessFu:AndroidScroll",
|
||||
"AccessFu:AutoMove",
|
||||
"AccessFu:ClearCursor",
|
||||
"AccessFu:Clipboard",
|
||||
"AccessFu:MoveByGranularity",
|
||||
"AccessFu:MoveCursor",
|
||||
"AccessFu:MoveToPoint",
|
||||
"AccessFu:SetSelection",
|
||||
],
|
||||
|
||||
start: function cc_start() {
|
||||
let cs = this._contentScope.get();
|
||||
for (let message of this.messagesOfInterest) {
|
||||
cs.addMessageListener(message, this);
|
||||
}
|
||||
},
|
||||
|
||||
stop: function cc_stop() {
|
||||
let cs = this._contentScope.get();
|
||||
for (let message of this.messagesOfInterest) {
|
||||
cs.removeMessageListener(message, this);
|
||||
}
|
||||
},
|
||||
|
||||
get document() {
|
||||
return this._contentScope.get().content.document;
|
||||
},
|
||||
|
||||
get window() {
|
||||
return this._contentScope.get().content;
|
||||
},
|
||||
|
||||
get vc() {
|
||||
return Utils.getVirtualCursor(this.document);
|
||||
},
|
||||
|
||||
receiveMessage: function cc_receiveMessage(aMessage) {
|
||||
Logger.debug(() => {
|
||||
return [
|
||||
"ContentControl.receiveMessage",
|
||||
aMessage.name,
|
||||
JSON.stringify(aMessage.json),
|
||||
];
|
||||
});
|
||||
|
||||
// If we get an explicit message, we should immediately cancel any autoMove
|
||||
this.cancelAutoMove();
|
||||
|
||||
try {
|
||||
let func = this["handle" + aMessage.name.slice(9)]; // 'AccessFu:'.length
|
||||
if (func) {
|
||||
func.bind(this)(aMessage);
|
||||
} else {
|
||||
Logger.warning("ContentControl: Unhandled message:", aMessage.name);
|
||||
}
|
||||
} catch (x) {
|
||||
Logger.logException(
|
||||
x,
|
||||
"Error handling message: " + JSON.stringify(aMessage.json)
|
||||
);
|
||||
}
|
||||
},
|
||||
|
||||
handleAndroidScroll: function cc_handleAndroidScroll(aMessage) {
|
||||
let vc = this.vc;
|
||||
let position = vc.position;
|
||||
|
||||
if (aMessage.json.origin != "child" && this.sendToChild(vc, aMessage)) {
|
||||
// Forwarded succesfully to child cursor.
|
||||
return;
|
||||
}
|
||||
|
||||
// Counter-intuitive, but scrolling backward (ie. up), actually should
|
||||
// increase range values.
|
||||
if (this.adjustRange(position, aMessage.json.direction === "backward")) {
|
||||
return;
|
||||
}
|
||||
|
||||
this._contentScope.get().sendAsyncMessage("AccessFu:DoScroll", {
|
||||
bounds: Utils.getBounds(position),
|
||||
page: aMessage.json.direction === "forward" ? 1 : -1,
|
||||
horizontal: false,
|
||||
});
|
||||
},
|
||||
|
||||
handleMoveCursor: function cc_handleMoveCursor(aMessage) {
|
||||
let origin = aMessage.json.origin;
|
||||
let action = aMessage.json.action;
|
||||
let adjustRange = aMessage.json.adjustRange;
|
||||
let vc = this.vc;
|
||||
|
||||
if (origin != "child" && this.sendToChild(vc, aMessage)) {
|
||||
// Forwarded succesfully to child cursor.
|
||||
return;
|
||||
}
|
||||
|
||||
if (adjustRange && this.adjustRange(vc.position, action === "moveNext")) {
|
||||
return;
|
||||
}
|
||||
|
||||
let moved = TraversalHelper.move(vc, action, aMessage.json.rule);
|
||||
|
||||
if (moved) {
|
||||
if (origin === "child") {
|
||||
// We just stepped out of a child, clear child cursor.
|
||||
Utils.getMessageManagerForFrame(aMessage.target).sendAsyncMessage(
|
||||
"AccessFu:ClearCursor",
|
||||
{}
|
||||
);
|
||||
} else {
|
||||
// We potentially landed on a new child cursor. If so, we want to
|
||||
// either be on the first or last item in the child doc.
|
||||
let childAction = action;
|
||||
if (action === "moveNext") {
|
||||
childAction = "moveFirst";
|
||||
} else if (action === "movePrevious") {
|
||||
childAction = "moveLast";
|
||||
}
|
||||
|
||||
// Attempt to forward move to a potential child cursor in our
|
||||
// new position.
|
||||
this.sendToChild(vc, aMessage, { action: childAction }, true);
|
||||
}
|
||||
} else if (
|
||||
!this._childMessageSenders.has(aMessage.target) &&
|
||||
origin !== "top"
|
||||
) {
|
||||
// We failed to move, and the message is not from a parent, so forward
|
||||
// to it.
|
||||
this.sendToParent(aMessage);
|
||||
}
|
||||
},
|
||||
|
||||
handleMoveToPoint: function cc_handleMoveToPoint(aMessage) {
|
||||
let [x, y] = [aMessage.json.x, aMessage.json.y];
|
||||
let rule = TraversalRules[aMessage.json.rule];
|
||||
|
||||
this.vc.moveToPoint(rule, x, y, true);
|
||||
},
|
||||
|
||||
handleClearCursor: function cc_handleClearCursor(aMessage) {
|
||||
let forwarded = this.sendToChild(this.vc, aMessage);
|
||||
this.vc.position = null;
|
||||
if (!forwarded) {
|
||||
this._contentScope.get().sendAsyncMessage("AccessFu:CursorCleared");
|
||||
}
|
||||
},
|
||||
|
||||
handleAutoMove: function cc_handleAutoMove(aMessage) {
|
||||
this.autoMove(null, aMessage.json);
|
||||
},
|
||||
|
||||
handleActivate: function cc_handleActivate(aMessage) {
|
||||
let activateAccessible = aAccessible => {
|
||||
Logger.debug(() => {
|
||||
return ["activateAccessible", Logger.accessibleToString(aAccessible)];
|
||||
});
|
||||
|
||||
if (aAccessible.actionCount > 0) {
|
||||
aAccessible.doAction(0);
|
||||
} else {
|
||||
let control = Utils.getEmbeddedControl(aAccessible);
|
||||
if (control && control.actionCount > 0) {
|
||||
control.doAction(0);
|
||||
}
|
||||
|
||||
// XXX Some mobile widget sets do not expose actions properly
|
||||
// (via ARIA roles, etc.), so we need to generate a click.
|
||||
// Could possibly be made simpler in the future. Maybe core
|
||||
// engine could expose nsCoreUtiles::DispatchMouseEvent()?
|
||||
let docAcc = Utils.AccService.getAccessibleFor(this.document);
|
||||
let docX = {},
|
||||
docY = {},
|
||||
docW = {},
|
||||
docH = {};
|
||||
docAcc.getBounds(docX, docY, docW, docH);
|
||||
|
||||
let objX = {},
|
||||
objY = {},
|
||||
objW = {},
|
||||
objH = {};
|
||||
aAccessible.getBounds(objX, objY, objW, objH);
|
||||
|
||||
let x = Math.round(objX.value - docX.value + objW.value / 2);
|
||||
let y = Math.round(objY.value - docY.value + objH.value / 2);
|
||||
|
||||
let node = aAccessible.DOMNode || aAccessible.parent.DOMNode;
|
||||
|
||||
for (let eventType of ["mousedown", "mouseup"]) {
|
||||
let evt = this.document.createEvent("MouseEvents");
|
||||
evt.initMouseEvent(
|
||||
eventType,
|
||||
true,
|
||||
true,
|
||||
this.window,
|
||||
x,
|
||||
y,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
0,
|
||||
null
|
||||
);
|
||||
node.dispatchEvent(evt);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
let focusedAcc = Utils.AccService.getAccessibleFor(
|
||||
this.document.activeElement
|
||||
);
|
||||
if (
|
||||
focusedAcc &&
|
||||
this.vc.position === focusedAcc &&
|
||||
focusedAcc.role === Roles.ENTRY
|
||||
) {
|
||||
let accText = focusedAcc.QueryInterface(Ci.nsIAccessibleText);
|
||||
let newOffset = aMessage.json.offset;
|
||||
if (newOffset >= 0 && newOffset <= accText.characterCount) {
|
||||
accText.caretOffset = newOffset;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// recursively find a descendant that is activatable.
|
||||
let getActivatableDescendant = aAccessible => {
|
||||
if (aAccessible.actionCount > 0) {
|
||||
return aAccessible;
|
||||
}
|
||||
|
||||
for (let acc = aAccessible.firstChild; acc; acc = acc.nextSibling) {
|
||||
let activatable = getActivatableDescendant(acc);
|
||||
if (activatable) {
|
||||
return activatable;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
};
|
||||
|
||||
let vc = this.vc;
|
||||
if (!this.sendToChild(vc, aMessage, null, true)) {
|
||||
let position = vc.position;
|
||||
activateAccessible(getActivatableDescendant(position) || position);
|
||||
}
|
||||
},
|
||||
|
||||
adjustRange: function cc_adjustRange(aAccessible, aStepUp) {
|
||||
let acc = Utils.getEmbeddedControl(aAccessible) || aAccessible;
|
||||
try {
|
||||
acc.QueryInterface(Ci.nsIAccessibleValue);
|
||||
} catch (x) {
|
||||
// This is not an adjustable, return false.
|
||||
return false;
|
||||
}
|
||||
|
||||
let elem = acc.DOMNode;
|
||||
if (!elem) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (elem.tagName === "INPUT" && elem.type === "range") {
|
||||
elem[aStepUp ? "stepDown" : "stepUp"]();
|
||||
let evt = this.document.createEvent("UIEvent");
|
||||
evt.initEvent("change", true, true);
|
||||
elem.dispatchEvent(evt);
|
||||
} else {
|
||||
let evt = this.document.createEvent("KeyboardEvent");
|
||||
let keycode = aStepUp ? evt.DOM_VK_DOWN : evt.DOM_VK_UP;
|
||||
evt.initKeyEvent(
|
||||
"keypress",
|
||||
false,
|
||||
true,
|
||||
null,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
keycode,
|
||||
0
|
||||
);
|
||||
elem.dispatchEvent(evt);
|
||||
}
|
||||
|
||||
return true;
|
||||
},
|
||||
|
||||
handleMoveByGranularity: function cc_handleMoveByGranularity(aMessage) {
|
||||
const { direction, granularity, select } = aMessage.json;
|
||||
const focusedAcc = Utils.AccService.getAccessibleFor(
|
||||
this.document.activeElement
|
||||
);
|
||||
const editable =
|
||||
focusedAcc && Utils.getState(focusedAcc).contains(States.EDITABLE)
|
||||
? focusedAcc.QueryInterface(Ci.nsIAccessibleText)
|
||||
: null;
|
||||
|
||||
if (editable) {
|
||||
const caretOffset = editable.caretOffset;
|
||||
this.vc.setTextRange(editable, caretOffset, caretOffset, false);
|
||||
}
|
||||
|
||||
let pivotGranularity;
|
||||
switch (granularity) {
|
||||
case MOVEMENT_GRANULARITY_CHARACTER:
|
||||
pivotGranularity = Ci.nsIAccessiblePivot.CHAR_BOUNDARY;
|
||||
break;
|
||||
case MOVEMENT_GRANULARITY_WORD:
|
||||
pivotGranularity = Ci.nsIAccessiblePivot.WORD_BOUNDARY;
|
||||
break;
|
||||
case MOVEMENT_GRANULARITY_LINE:
|
||||
pivotGranularity = Ci.nsIAccessiblePivot.LINE_BOUNDARY;
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
|
||||
if (direction === "Previous") {
|
||||
this.vc.movePreviousByText(pivotGranularity);
|
||||
} else if (direction === "Next") {
|
||||
this.vc.moveNextByText(pivotGranularity);
|
||||
}
|
||||
|
||||
if (editable) {
|
||||
const newOffset =
|
||||
direction === "Next" ? this.vc.endOffset : this.vc.startOffset;
|
||||
if (select) {
|
||||
let anchor = editable.caretOffset;
|
||||
if (editable.selectionCount) {
|
||||
const [startSel, endSel] = Utils.getTextSelection(editable);
|
||||
anchor = startSel == anchor ? endSel : startSel;
|
||||
}
|
||||
editable.setSelectionBounds(0, anchor, newOffset);
|
||||
} else {
|
||||
editable.caretOffset = newOffset;
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
handleSetSelection: function cc_handleSetSelection(aMessage) {
|
||||
const { start, end } = aMessage.json;
|
||||
const focusedAcc = Utils.AccService.getAccessibleFor(
|
||||
this.document.activeElement
|
||||
);
|
||||
if (focusedAcc) {
|
||||
const accText = focusedAcc.QueryInterface(Ci.nsIAccessibleText);
|
||||
if (start == end) {
|
||||
accText.caretOffset = start;
|
||||
} else {
|
||||
accText.setSelectionBounds(0, start, end);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
handleClipboard: function cc_handleClipboard(aMessage) {
|
||||
const { action } = aMessage.json;
|
||||
const focusedAcc = Utils.AccService.getAccessibleFor(
|
||||
this.document.activeElement
|
||||
);
|
||||
if (focusedAcc) {
|
||||
const [startSel, endSel] = Utils.getTextSelection(focusedAcc);
|
||||
const editText = focusedAcc.QueryInterface(Ci.nsIAccessibleEditableText);
|
||||
switch (action) {
|
||||
case CLIPBOARD_COPY:
|
||||
if (startSel != endSel) {
|
||||
editText.copyText(startSel, endSel);
|
||||
}
|
||||
break;
|
||||
case CLIPBOARD_PASTE:
|
||||
if (startSel != endSel) {
|
||||
editText.deleteText(startSel, endSel);
|
||||
}
|
||||
editText.pasteText(startSel);
|
||||
break;
|
||||
case CLIPBOARD_CUT:
|
||||
if (startSel != endSel) {
|
||||
editText.cutText(startSel, endSel);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
getChildCursor: function cc_getChildCursor(aAccessible) {
|
||||
let acc = aAccessible || this.vc.position;
|
||||
if (Utils.isAliveAndVisible(acc) && acc.role === Roles.INTERNAL_FRAME) {
|
||||
let domNode = acc.DOMNode;
|
||||
let mm = this._childMessageSenders.get(domNode, null);
|
||||
if (!mm) {
|
||||
mm = Utils.getMessageManagerForFrame(domNode);
|
||||
mm.addWeakMessageListener("AccessFu:MoveCursor", this);
|
||||
this._childMessageSenders.set(domNode, mm);
|
||||
}
|
||||
|
||||
return mm;
|
||||
}
|
||||
|
||||
return null;
|
||||
},
|
||||
|
||||
sendToChild: function cc_sendToChild(
|
||||
aVirtualCursor,
|
||||
aMessage,
|
||||
aReplacer,
|
||||
aFocus
|
||||
) {
|
||||
let position = aVirtualCursor.position;
|
||||
let mm = this.getChildCursor(position);
|
||||
if (!mm) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (aFocus) {
|
||||
position.takeFocus();
|
||||
}
|
||||
|
||||
// XXX: This is a silly way to make a deep copy
|
||||
let newJSON = JSON.parse(JSON.stringify(aMessage.json));
|
||||
newJSON.origin = "parent";
|
||||
for (let attr in aReplacer) {
|
||||
newJSON[attr] = aReplacer[attr];
|
||||
}
|
||||
|
||||
mm.sendAsyncMessage(aMessage.name, newJSON);
|
||||
return true;
|
||||
},
|
||||
|
||||
sendToParent: function cc_sendToParent(aMessage) {
|
||||
// XXX: This is a silly way to make a deep copy
|
||||
let newJSON = JSON.parse(JSON.stringify(aMessage.json));
|
||||
newJSON.origin = "child";
|
||||
aMessage.target.sendAsyncMessage(aMessage.name, newJSON);
|
||||
},
|
||||
|
||||
/**
|
||||
* Move cursor.
|
||||
* aOptions could have any of these fields:
|
||||
* - delay: in ms, before actual move is performed. Another autoMove call
|
||||
* would cancel it. Useful if we want to wait for a possible trailing
|
||||
* focus move. Default 0.
|
||||
* - noOpIfOnScreen: if accessible is alive and visible, don't do anything.
|
||||
* - moveToFocused: if there is a focused accessible move to that. This takes
|
||||
* precedence over given anchor.
|
||||
* - moveMethod: pivot move method to use, default is 'moveNext',
|
||||
*/
|
||||
autoMove: function cc_autoMove(aAnchor, aOptions = {}) {
|
||||
this.cancelAutoMove();
|
||||
|
||||
let moveFunc = () => {
|
||||
let vc = this.vc;
|
||||
let acc = aAnchor;
|
||||
let rule = aOptions.onScreenOnly
|
||||
? TraversalRules.SimpleOnScreen
|
||||
: TraversalRules.Simple;
|
||||
|
||||
if (
|
||||
aOptions.noOpIfOnScreen &&
|
||||
Utils.isAliveAndVisible(vc.position, true)
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (aOptions.moveToFocused) {
|
||||
acc =
|
||||
Utils.AccService.getAccessibleFor(this.document.activeElement) || acc;
|
||||
}
|
||||
|
||||
let moved = false;
|
||||
let moveMethod = aOptions.moveMethod || "moveNext"; // default is moveNext
|
||||
let moveFirstOrLast = moveMethod in ["moveFirst", "moveLast"];
|
||||
if (!moveFirstOrLast || acc) {
|
||||
// We either need next/previous or there is an anchor we need to use.
|
||||
moved = vc[moveFirstOrLast ? "moveNext" : moveMethod](
|
||||
rule,
|
||||
acc,
|
||||
true,
|
||||
true
|
||||
);
|
||||
}
|
||||
if (moveFirstOrLast && !moved) {
|
||||
// We move to first/last after no anchor move happened or succeeded.
|
||||
moved = vc[moveMethod](rule, true);
|
||||
}
|
||||
|
||||
this.sendToChild(
|
||||
vc,
|
||||
{
|
||||
name: "AccessFu:AutoMove",
|
||||
json: {
|
||||
moveMethod: aOptions.moveMethod,
|
||||
moveToFocused: aOptions.moveToFocused,
|
||||
noOpIfOnScreen: true,
|
||||
},
|
||||
},
|
||||
null,
|
||||
true
|
||||
);
|
||||
};
|
||||
|
||||
if (aOptions.delay) {
|
||||
this._autoMove = this.window.setTimeout(moveFunc, aOptions.delay);
|
||||
} else {
|
||||
moveFunc();
|
||||
}
|
||||
},
|
||||
|
||||
cancelAutoMove: function cc_cancelAutoMove() {
|
||||
this.window.clearTimeout(this._autoMove);
|
||||
this._autoMove = 0;
|
||||
},
|
||||
|
||||
QueryInterface: ChromeUtils.generateQI([
|
||||
Ci.nsISupportsWeakReference,
|
||||
Ci.nsIMessageListener,
|
||||
]),
|
||||
};
|
@ -1,301 +0,0 @@
|
||||
/* 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/. */
|
||||
|
||||
"use strict";
|
||||
|
||||
ChromeUtils.defineModuleGetter(
|
||||
this,
|
||||
"Services",
|
||||
"resource://gre/modules/Services.jsm"
|
||||
);
|
||||
ChromeUtils.defineModuleGetter(
|
||||
this,
|
||||
"Utils",
|
||||
"resource://gre/modules/accessibility/Utils.jsm"
|
||||
);
|
||||
ChromeUtils.defineModuleGetter(
|
||||
this,
|
||||
"Logger",
|
||||
"resource://gre/modules/accessibility/Utils.jsm"
|
||||
);
|
||||
ChromeUtils.defineModuleGetter(
|
||||
this,
|
||||
"Events",
|
||||
"resource://gre/modules/accessibility/Constants.jsm"
|
||||
);
|
||||
|
||||
var EXPORTED_SYMBOLS = ["EventManager"];
|
||||
|
||||
function EventManager(aContentScope) {
|
||||
this.contentScope = aContentScope;
|
||||
this.addEventListener = this.contentScope.addEventListener.bind(
|
||||
this.contentScope
|
||||
);
|
||||
this.removeEventListener = this.contentScope.removeEventListener.bind(
|
||||
this.contentScope
|
||||
);
|
||||
this.sendMsgFunc = this.contentScope.sendAsyncMessage.bind(this.contentScope);
|
||||
}
|
||||
|
||||
this.EventManager.prototype = {
|
||||
start: function start() {
|
||||
try {
|
||||
if (!this._started) {
|
||||
Logger.debug("EventManager.start");
|
||||
|
||||
this._started = true;
|
||||
|
||||
AccessibilityEventObserver.addListener(this);
|
||||
|
||||
this._preDialogPosition = new WeakMap();
|
||||
}
|
||||
} catch (x) {
|
||||
Logger.logException(x, "Failed to start EventManager");
|
||||
}
|
||||
},
|
||||
|
||||
// XXX: Stop is not called when the tab is closed (|TabClose| event is too
|
||||
// late). It is only called when the AccessFu is disabled explicitly.
|
||||
stop: function stop() {
|
||||
if (!this._started) {
|
||||
return;
|
||||
}
|
||||
Logger.debug("EventManager.stop");
|
||||
AccessibilityEventObserver.removeListener(this);
|
||||
try {
|
||||
this._preDialogPosition = new WeakMap();
|
||||
} catch (x) {
|
||||
// contentScope is dead.
|
||||
} finally {
|
||||
this._started = false;
|
||||
}
|
||||
},
|
||||
|
||||
get contentControl() {
|
||||
return this.contentScope._jsat_contentControl;
|
||||
},
|
||||
|
||||
handleAccEvent: function handleAccEvent(aEvent) {
|
||||
Logger.debug(() => {
|
||||
return [
|
||||
"A11yEvent",
|
||||
Logger.eventToString(aEvent),
|
||||
Logger.accessibleToString(aEvent.accessible),
|
||||
];
|
||||
});
|
||||
|
||||
// Don't bother with non-content events in firefox.
|
||||
if (
|
||||
Utils.MozBuildApp == "browser" &&
|
||||
aEvent.eventType != Events.VIRTUALCURSOR_CHANGED &&
|
||||
// XXX Bug 442005 results in DocAccessible::getDocType returning
|
||||
// NS_ERROR_FAILURE. Checking for aEvent.accessibleDocument.docType ==
|
||||
// 'window' does not currently work.
|
||||
(aEvent.accessibleDocument.DOMDocument.doctype &&
|
||||
aEvent.accessibleDocument.DOMDocument.doctype.name === "window")
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
switch (aEvent.eventType) {
|
||||
case Events.TEXT_CARET_MOVED: {
|
||||
if (
|
||||
aEvent.accessible != aEvent.accessibleDocument &&
|
||||
!aEvent.isFromUserInput
|
||||
) {
|
||||
// If caret moves in document without direct user
|
||||
// we are probably stepping through results in find-in-page.
|
||||
let acc = Utils.getTextLeafForOffset(
|
||||
aEvent.accessible,
|
||||
aEvent.QueryInterface(Ci.nsIAccessibleCaretMoveEvent).caretOffset
|
||||
);
|
||||
this.contentControl.autoMove(acc);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case Events.NAME_CHANGE: {
|
||||
// XXX: Port to Android
|
||||
break;
|
||||
}
|
||||
case Events.SCROLLING_START: {
|
||||
this.contentControl.autoMove(aEvent.accessible);
|
||||
break;
|
||||
}
|
||||
case Events.SHOW: {
|
||||
// XXX: Port to Android
|
||||
break;
|
||||
}
|
||||
case Events.HIDE: {
|
||||
// XXX: Port to Android
|
||||
break;
|
||||
}
|
||||
case Events.VALUE_CHANGE: {
|
||||
// XXX: Port to Android
|
||||
break;
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
QueryInterface: ChromeUtils.generateQI([
|
||||
Ci.nsISupportsWeakReference,
|
||||
Ci.nsIObserver,
|
||||
]),
|
||||
};
|
||||
|
||||
const AccessibilityEventObserver = {
|
||||
/**
|
||||
* A WeakMap containing [content, EventManager] pairs.
|
||||
*/
|
||||
eventManagers: new WeakMap(),
|
||||
|
||||
/**
|
||||
* A total number of registered eventManagers.
|
||||
*/
|
||||
listenerCount: 0,
|
||||
|
||||
/**
|
||||
* An indicator of an active 'accessible-event' observer.
|
||||
*/
|
||||
started: false,
|
||||
|
||||
/**
|
||||
* Start an AccessibilityEventObserver.
|
||||
*/
|
||||
start: function start() {
|
||||
if (this.started || this.listenerCount === 0) {
|
||||
return;
|
||||
}
|
||||
Services.obs.addObserver(this, "accessible-event");
|
||||
this.started = true;
|
||||
},
|
||||
|
||||
/**
|
||||
* Stop an AccessibilityEventObserver.
|
||||
*/
|
||||
stop: function stop() {
|
||||
if (!this.started) {
|
||||
return;
|
||||
}
|
||||
Services.obs.removeObserver(this, "accessible-event");
|
||||
// Clean up all registered event managers.
|
||||
this.eventManagers = new WeakMap();
|
||||
this.listenerCount = 0;
|
||||
this.started = false;
|
||||
},
|
||||
|
||||
/**
|
||||
* Register an EventManager and start listening to the
|
||||
* 'accessible-event' messages.
|
||||
*
|
||||
* @param aEventManager EventManager
|
||||
* An EventManager object that was loaded into the specific content.
|
||||
*/
|
||||
addListener: function addListener(aEventManager) {
|
||||
let content = aEventManager.contentScope.content;
|
||||
if (!this.eventManagers.has(content)) {
|
||||
this.listenerCount++;
|
||||
}
|
||||
this.eventManagers.set(content, aEventManager);
|
||||
// Since at least one EventManager was registered, start listening.
|
||||
Logger.debug(
|
||||
"AccessibilityEventObserver.addListener. Total:",
|
||||
this.listenerCount
|
||||
);
|
||||
this.start();
|
||||
},
|
||||
|
||||
/**
|
||||
* Unregister an EventManager and, optionally, stop listening to the
|
||||
* 'accessible-event' messages.
|
||||
*
|
||||
* @param aEventManager EventManager
|
||||
* An EventManager object that was stopped in the specific content.
|
||||
*/
|
||||
removeListener: function removeListener(aEventManager) {
|
||||
let content = aEventManager.contentScope.content;
|
||||
if (!this.eventManagers.delete(content)) {
|
||||
return;
|
||||
}
|
||||
this.listenerCount--;
|
||||
Logger.debug(
|
||||
"AccessibilityEventObserver.removeListener. Total:",
|
||||
this.listenerCount
|
||||
);
|
||||
if (this.listenerCount === 0) {
|
||||
// If there are no EventManagers registered at the moment, stop listening
|
||||
// to the 'accessible-event' messages.
|
||||
this.stop();
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Lookup an EventManager for a specific content. If the EventManager is not
|
||||
* found, walk up the hierarchy of parent windows.
|
||||
* @param content Window
|
||||
* A content Window used to lookup the corresponding EventManager.
|
||||
*/
|
||||
getListener: function getListener(content) {
|
||||
let eventManager = this.eventManagers.get(content);
|
||||
if (eventManager) {
|
||||
return eventManager;
|
||||
}
|
||||
let parent = content.parent;
|
||||
if (parent === content) {
|
||||
// There is no parent or the parent is of a different type.
|
||||
return null;
|
||||
}
|
||||
return this.getListener(parent);
|
||||
},
|
||||
|
||||
/**
|
||||
* Handle the 'accessible-event' message.
|
||||
*/
|
||||
observe: function observe(aSubject, aTopic, aData) {
|
||||
if (aTopic !== "accessible-event") {
|
||||
return;
|
||||
}
|
||||
let event = aSubject.QueryInterface(Ci.nsIAccessibleEvent);
|
||||
if (!event.accessibleDocument) {
|
||||
Logger.warning(
|
||||
"AccessibilityEventObserver.observe: no accessible document:",
|
||||
Logger.eventToString(event),
|
||||
"accessible:",
|
||||
Logger.accessibleToString(event.accessible)
|
||||
);
|
||||
return;
|
||||
}
|
||||
let content;
|
||||
try {
|
||||
content = event.accessibleDocument.window;
|
||||
} catch (e) {
|
||||
Logger.warning(
|
||||
"AccessibilityEventObserver.observe: no window for accessible document:",
|
||||
Logger.eventToString(event),
|
||||
"accessible:",
|
||||
Logger.accessibleToString(event.accessible)
|
||||
);
|
||||
return;
|
||||
}
|
||||
// Match the content window to its EventManager.
|
||||
let eventManager = this.getListener(content);
|
||||
if (!eventManager || !eventManager._started) {
|
||||
if (Utils.MozBuildApp === "browser" && !content.isChromeWindow) {
|
||||
Logger.warning(
|
||||
"AccessibilityEventObserver.observe: ignored event:",
|
||||
Logger.eventToString(event),
|
||||
"accessible:",
|
||||
Logger.accessibleToString(event.accessible),
|
||||
"document:",
|
||||
Logger.accessibleToString(event.accessibleDocument)
|
||||
);
|
||||
}
|
||||
return;
|
||||
}
|
||||
try {
|
||||
eventManager.handleAccEvent(event);
|
||||
} catch (x) {
|
||||
Logger.logException(x, "Error handing accessible event");
|
||||
}
|
||||
},
|
||||
};
|
@ -1,433 +0,0 @@
|
||||
/* 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/. */
|
||||
|
||||
"use strict";
|
||||
|
||||
var EXPORTED_SYMBOLS = ["TraversalRules", "TraversalHelper"]; // jshint ignore:line
|
||||
|
||||
const { PrefCache, Utils } = ChromeUtils.import(
|
||||
"resource://gre/modules/accessibility/Utils.jsm"
|
||||
);
|
||||
ChromeUtils.defineModuleGetter(
|
||||
this,
|
||||
"Roles", // jshint ignore:line
|
||||
"resource://gre/modules/accessibility/Constants.jsm"
|
||||
);
|
||||
ChromeUtils.defineModuleGetter(
|
||||
this,
|
||||
"Filters", // jshint ignore:line
|
||||
"resource://gre/modules/accessibility/Constants.jsm"
|
||||
);
|
||||
ChromeUtils.defineModuleGetter(
|
||||
this,
|
||||
"States", // jshint ignore:line
|
||||
"resource://gre/modules/accessibility/Constants.jsm"
|
||||
);
|
||||
ChromeUtils.defineModuleGetter(
|
||||
this,
|
||||
"Prefilters", // jshint ignore:line
|
||||
"resource://gre/modules/accessibility/Constants.jsm"
|
||||
);
|
||||
|
||||
var gSkipEmptyImages = new PrefCache(
|
||||
"accessibility.accessfu.skip_empty_images"
|
||||
);
|
||||
|
||||
function BaseTraversalRule(aRoles, aMatchFunc, aPreFilter, aContainerRule) {
|
||||
this._explicitMatchRoles = new Set(aRoles);
|
||||
this._matchRoles = aRoles;
|
||||
if (aRoles.length) {
|
||||
if (!aRoles.includes(Roles.LABEL)) {
|
||||
this._matchRoles.push(Roles.LABEL);
|
||||
}
|
||||
if (!aRoles.includes(Roles.INTERNAL_FRAME)) {
|
||||
// Used for traversing in to child OOP frames.
|
||||
this._matchRoles.push(Roles.INTERNAL_FRAME);
|
||||
}
|
||||
}
|
||||
this._matchFunc =
|
||||
aMatchFunc ||
|
||||
function() {
|
||||
return Filters.MATCH;
|
||||
};
|
||||
this.preFilter = aPreFilter || gSimplePreFilter;
|
||||
this.containerRule = aContainerRule;
|
||||
}
|
||||
|
||||
BaseTraversalRule.prototype = {
|
||||
getMatchRoles: function BaseTraversalRule_getmatchRoles() {
|
||||
return this._matchRoles;
|
||||
},
|
||||
|
||||
match: function BaseTraversalRule_match(aAccessible) {
|
||||
let role = aAccessible.role;
|
||||
if (role == Roles.INTERNAL_FRAME) {
|
||||
return Utils.getMessageManagerForFrame(aAccessible.DOMNode)
|
||||
? Filters.MATCH | Filters.IGNORE_SUBTREE
|
||||
: Filters.IGNORE;
|
||||
}
|
||||
|
||||
if (this._explicitMatchRoles.has(role) || !this._explicitMatchRoles.size) {
|
||||
return this._matchFunc(aAccessible);
|
||||
}
|
||||
|
||||
return Filters.IGNORE;
|
||||
},
|
||||
|
||||
QueryInterface: ChromeUtils.generateQI([Ci.nsIAccessibleTraversalRule]),
|
||||
};
|
||||
|
||||
var gSimpleTraversalRoles = [
|
||||
Roles.MENUITEM,
|
||||
Roles.LINK,
|
||||
Roles.PAGETAB,
|
||||
Roles.GRAPHIC,
|
||||
Roles.STATICTEXT,
|
||||
Roles.TEXT_LEAF,
|
||||
Roles.PUSHBUTTON,
|
||||
Roles.CHECKBUTTON,
|
||||
Roles.RADIOBUTTON,
|
||||
Roles.COMBOBOX,
|
||||
Roles.PROGRESSBAR,
|
||||
Roles.BUTTONDROPDOWN,
|
||||
Roles.BUTTONMENU,
|
||||
Roles.CHECK_MENU_ITEM,
|
||||
Roles.PASSWORD_TEXT,
|
||||
Roles.RADIO_MENU_ITEM,
|
||||
Roles.TOGGLE_BUTTON,
|
||||
Roles.ENTRY,
|
||||
Roles.KEY,
|
||||
Roles.HEADER,
|
||||
Roles.HEADING,
|
||||
Roles.SLIDER,
|
||||
Roles.SPINBUTTON,
|
||||
Roles.OPTION,
|
||||
Roles.LISTITEM,
|
||||
Roles.GRID_CELL,
|
||||
Roles.COLUMNHEADER,
|
||||
Roles.ROWHEADER,
|
||||
Roles.STATUSBAR,
|
||||
Roles.SWITCH,
|
||||
Roles.MATHML_MATH,
|
||||
];
|
||||
|
||||
var gSimpleMatchFunc = function gSimpleMatchFunc(aAccessible) {
|
||||
// An object is simple, if it either has a single child lineage,
|
||||
// or has a flat subtree.
|
||||
function isSingleLineage(acc) {
|
||||
for (let child = acc; child; child = child.firstChild) {
|
||||
if (Utils.visibleChildCount(child) > 1) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
function isFlatSubtree(acc) {
|
||||
for (let child = acc.firstChild; child; child = child.nextSibling) {
|
||||
// text leafs inherit the actionCount of any ancestor that has a click
|
||||
// listener.
|
||||
if ([Roles.TEXT_LEAF, Roles.STATICTEXT].includes(child.role)) {
|
||||
continue;
|
||||
}
|
||||
if (Utils.visibleChildCount(child) > 0 || child.actionCount > 0) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
switch (aAccessible.role) {
|
||||
case Roles.COMBOBOX:
|
||||
// We don't want to ignore the subtree because this is often
|
||||
// where the list box hangs out.
|
||||
return Filters.MATCH;
|
||||
case Roles.TEXT_LEAF: {
|
||||
// Nameless text leaves are boring, skip them.
|
||||
let name = aAccessible.name;
|
||||
return name && name.trim() ? Filters.MATCH : Filters.IGNORE;
|
||||
}
|
||||
case Roles.STATICTEXT:
|
||||
// Ignore prefix static text in list items. They are typically bullets or numbers.
|
||||
return Utils.isListItemDecorator(aAccessible)
|
||||
? Filters.IGNORE
|
||||
: Filters.MATCH;
|
||||
case Roles.GRAPHIC:
|
||||
return TraversalRules._shouldSkipImage(aAccessible);
|
||||
case Roles.HEADER:
|
||||
case Roles.HEADING:
|
||||
case Roles.COLUMNHEADER:
|
||||
case Roles.ROWHEADER:
|
||||
case Roles.STATUSBAR:
|
||||
if (
|
||||
(aAccessible.childCount > 0 || aAccessible.name) &&
|
||||
(isSingleLineage(aAccessible) || isFlatSubtree(aAccessible))
|
||||
) {
|
||||
return Filters.MATCH | Filters.IGNORE_SUBTREE;
|
||||
}
|
||||
return Filters.IGNORE;
|
||||
case Roles.GRID_CELL:
|
||||
return isSingleLineage(aAccessible) || isFlatSubtree(aAccessible)
|
||||
? Filters.MATCH | Filters.IGNORE_SUBTREE
|
||||
: Filters.IGNORE;
|
||||
case Roles.LISTITEM: {
|
||||
let item =
|
||||
aAccessible.childCount === 2 &&
|
||||
aAccessible.firstChild.role === Roles.STATICTEXT
|
||||
? aAccessible.lastChild
|
||||
: aAccessible;
|
||||
return isSingleLineage(item) || isFlatSubtree(item)
|
||||
? Filters.MATCH | Filters.IGNORE_SUBTREE
|
||||
: Filters.IGNORE;
|
||||
}
|
||||
default:
|
||||
// Ignore the subtree, if there is one. So that we don't land on
|
||||
// the same content that was already presented by its parent.
|
||||
return Filters.MATCH | Filters.IGNORE_SUBTREE;
|
||||
}
|
||||
};
|
||||
|
||||
var gSimplePreFilter =
|
||||
Prefilters.DEFUNCT |
|
||||
Prefilters.INVISIBLE |
|
||||
Prefilters.TRANSPARENT |
|
||||
Prefilters.PLATFORM_PRUNED;
|
||||
|
||||
var TraversalRules = {
|
||||
// jshint ignore:line
|
||||
Simple: new BaseTraversalRule(gSimpleTraversalRoles, gSimpleMatchFunc),
|
||||
|
||||
SimpleOnScreen: new BaseTraversalRule(
|
||||
gSimpleTraversalRoles,
|
||||
gSimpleMatchFunc,
|
||||
gSimplePreFilter | Prefilters.OFFSCREEN
|
||||
),
|
||||
|
||||
Anchor: new BaseTraversalRule([Roles.LINK], function Anchor_match(
|
||||
aAccessible
|
||||
) {
|
||||
// We want to ignore links, only focus named anchors.
|
||||
if (Utils.getState(aAccessible).contains(States.LINKED)) {
|
||||
return Filters.IGNORE;
|
||||
}
|
||||
return Filters.MATCH;
|
||||
}),
|
||||
|
||||
Button: new BaseTraversalRule([
|
||||
Roles.PUSHBUTTON,
|
||||
Roles.SPINBUTTON,
|
||||
Roles.TOGGLE_BUTTON,
|
||||
Roles.BUTTONDROPDOWN,
|
||||
Roles.BUTTONDROPDOWNGRID,
|
||||
]),
|
||||
|
||||
Combobox: new BaseTraversalRule([Roles.COMBOBOX, Roles.LISTBOX]),
|
||||
|
||||
Landmark: new BaseTraversalRule(
|
||||
[],
|
||||
function Landmark_match(aAccessible) {
|
||||
return Utils.getLandmarkName(aAccessible)
|
||||
? Filters.MATCH
|
||||
: Filters.IGNORE;
|
||||
},
|
||||
null,
|
||||
true
|
||||
),
|
||||
|
||||
/* A rule for Android's section navigation, lands on landmarks, regions, and
|
||||
on headings to aid navigation of traditionally structured documents */
|
||||
Section: new BaseTraversalRule(
|
||||
[],
|
||||
function Section_match(aAccessible) {
|
||||
if (aAccessible.role === Roles.HEADING) {
|
||||
return Filters.MATCH;
|
||||
}
|
||||
|
||||
let matchedRole = Utils.matchRoles(aAccessible, [
|
||||
"banner",
|
||||
"complementary",
|
||||
"contentinfo",
|
||||
"main",
|
||||
"navigation",
|
||||
"search",
|
||||
"region",
|
||||
]);
|
||||
|
||||
return matchedRole ? Filters.MATCH : Filters.IGNORE;
|
||||
},
|
||||
null,
|
||||
true
|
||||
),
|
||||
|
||||
Entry: new BaseTraversalRule([Roles.ENTRY, Roles.PASSWORD_TEXT]),
|
||||
|
||||
FormElement: new BaseTraversalRule([
|
||||
Roles.PUSHBUTTON,
|
||||
Roles.SPINBUTTON,
|
||||
Roles.TOGGLE_BUTTON,
|
||||
Roles.BUTTONDROPDOWN,
|
||||
Roles.BUTTONDROPDOWNGRID,
|
||||
Roles.COMBOBOX,
|
||||
Roles.LISTBOX,
|
||||
Roles.ENTRY,
|
||||
Roles.PASSWORD_TEXT,
|
||||
Roles.PAGETAB,
|
||||
Roles.RADIOBUTTON,
|
||||
Roles.RADIO_MENU_ITEM,
|
||||
Roles.SLIDER,
|
||||
Roles.CHECKBUTTON,
|
||||
Roles.CHECK_MENU_ITEM,
|
||||
Roles.SWITCH,
|
||||
]),
|
||||
|
||||
Graphic: new BaseTraversalRule([Roles.GRAPHIC], function Graphic_match(
|
||||
aAccessible
|
||||
) {
|
||||
return TraversalRules._shouldSkipImage(aAccessible);
|
||||
}),
|
||||
|
||||
Heading: new BaseTraversalRule([Roles.HEADING], function Heading_match(
|
||||
aAccessible
|
||||
) {
|
||||
return aAccessible.childCount > 0 ? Filters.MATCH : Filters.IGNORE;
|
||||
}),
|
||||
|
||||
ListItem: new BaseTraversalRule([Roles.LISTITEM, Roles.TERM]),
|
||||
|
||||
Link: new BaseTraversalRule([Roles.LINK], function Link_match(aAccessible) {
|
||||
// We want to ignore anchors, only focus real links.
|
||||
if (Utils.getState(aAccessible).contains(States.LINKED)) {
|
||||
return Filters.MATCH;
|
||||
}
|
||||
return Filters.IGNORE;
|
||||
}),
|
||||
|
||||
/* For TalkBack's "Control" granularity. Form conrols and links */
|
||||
Control: new BaseTraversalRule(
|
||||
[
|
||||
Roles.PUSHBUTTON,
|
||||
Roles.SPINBUTTON,
|
||||
Roles.TOGGLE_BUTTON,
|
||||
Roles.BUTTONDROPDOWN,
|
||||
Roles.BUTTONDROPDOWNGRID,
|
||||
Roles.COMBOBOX,
|
||||
Roles.LISTBOX,
|
||||
Roles.ENTRY,
|
||||
Roles.PASSWORD_TEXT,
|
||||
Roles.PAGETAB,
|
||||
Roles.RADIOBUTTON,
|
||||
Roles.RADIO_MENU_ITEM,
|
||||
Roles.SLIDER,
|
||||
Roles.CHECKBUTTON,
|
||||
Roles.CHECK_MENU_ITEM,
|
||||
Roles.SWITCH,
|
||||
Roles.LINK,
|
||||
Roles.MENUITEM,
|
||||
],
|
||||
function Control_match(aAccessible) {
|
||||
// We want to ignore anchors, only focus real links.
|
||||
if (
|
||||
aAccessible.role == Roles.LINK &&
|
||||
!Utils.getState(aAccessible).contains(States.LINKED)
|
||||
) {
|
||||
return Filters.IGNORE;
|
||||
}
|
||||
return Filters.MATCH;
|
||||
}
|
||||
),
|
||||
|
||||
List: new BaseTraversalRule(
|
||||
[Roles.LIST, Roles.DEFINITION_LIST],
|
||||
null,
|
||||
null,
|
||||
true
|
||||
),
|
||||
|
||||
PageTab: new BaseTraversalRule([Roles.PAGETAB]),
|
||||
|
||||
Paragraph: new BaseTraversalRule(
|
||||
[Roles.PARAGRAPH, Roles.SECTION],
|
||||
function Paragraph_match(aAccessible) {
|
||||
for (
|
||||
let child = aAccessible.firstChild;
|
||||
child;
|
||||
child = child.nextSibling
|
||||
) {
|
||||
if (child.role === Roles.TEXT_LEAF) {
|
||||
return Filters.MATCH | Filters.IGNORE_SUBTREE;
|
||||
}
|
||||
}
|
||||
|
||||
return Filters.IGNORE;
|
||||
}
|
||||
),
|
||||
|
||||
RadioButton: new BaseTraversalRule([
|
||||
Roles.RADIOBUTTON,
|
||||
Roles.RADIO_MENU_ITEM,
|
||||
]),
|
||||
|
||||
Separator: new BaseTraversalRule([Roles.SEPARATOR]),
|
||||
|
||||
Table: new BaseTraversalRule([Roles.TABLE]),
|
||||
|
||||
Checkbox: new BaseTraversalRule([
|
||||
Roles.CHECKBUTTON,
|
||||
Roles.CHECK_MENU_ITEM,
|
||||
Roles.SWITCH /* A type of checkbox that represents on/off values */,
|
||||
]),
|
||||
|
||||
_shouldSkipImage: function _shouldSkipImage(aAccessible) {
|
||||
if (gSkipEmptyImages.value && aAccessible.name === "") {
|
||||
return Filters.IGNORE;
|
||||
}
|
||||
return Filters.MATCH;
|
||||
},
|
||||
};
|
||||
|
||||
var TraversalHelper = {
|
||||
_helperPivotCache: null,
|
||||
|
||||
get helperPivotCache() {
|
||||
delete this.helperPivotCache;
|
||||
this.helperPivotCache = new WeakMap();
|
||||
return this.helperPivotCache;
|
||||
},
|
||||
|
||||
getHelperPivot: function TraversalHelper_getHelperPivot(aRoot) {
|
||||
let pivot = this.helperPivotCache.get(aRoot.DOMNode);
|
||||
if (!pivot) {
|
||||
pivot = Utils.AccService.createAccessiblePivot(aRoot);
|
||||
this.helperPivotCache.set(aRoot.DOMNode, pivot);
|
||||
}
|
||||
|
||||
return pivot;
|
||||
},
|
||||
|
||||
move: function TraversalHelper_move(aVirtualCursor, aMethod, aRule) {
|
||||
let rule = TraversalRules[aRule];
|
||||
|
||||
if (rule.containerRule) {
|
||||
let moved = false;
|
||||
let helperPivot = this.getHelperPivot(aVirtualCursor.root);
|
||||
helperPivot.position = aVirtualCursor.position;
|
||||
|
||||
// We continue to step through containers until there is one with an
|
||||
// atomic child (via 'Simple') on which we could land.
|
||||
while (!moved) {
|
||||
if (helperPivot[aMethod](rule)) {
|
||||
aVirtualCursor.modalRoot = helperPivot.position;
|
||||
moved = aVirtualCursor.moveFirst(TraversalRules.Simple);
|
||||
aVirtualCursor.modalRoot = null;
|
||||
} else {
|
||||
// If we failed to step to another container, break and return false.
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return moved;
|
||||
}
|
||||
return aVirtualCursor[aMethod](rule);
|
||||
},
|
||||
};
|
File diff suppressed because it is too large
Load Diff
@ -1,69 +0,0 @@
|
||||
/* 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/. */
|
||||
|
||||
/* eslint-env mozilla/frame-script */
|
||||
|
||||
ChromeUtils.defineModuleGetter(
|
||||
this,
|
||||
"Logger",
|
||||
"resource://gre/modules/accessibility/Utils.jsm"
|
||||
);
|
||||
ChromeUtils.defineModuleGetter(
|
||||
this,
|
||||
"Utils",
|
||||
"resource://gre/modules/accessibility/Utils.jsm"
|
||||
);
|
||||
ChromeUtils.defineModuleGetter(
|
||||
this,
|
||||
"EventManager",
|
||||
"resource://gre/modules/accessibility/EventManager.jsm"
|
||||
);
|
||||
ChromeUtils.defineModuleGetter(
|
||||
this,
|
||||
"ContentControl",
|
||||
"resource://gre/modules/accessibility/ContentControl.jsm"
|
||||
);
|
||||
ChromeUtils.defineModuleGetter(
|
||||
this,
|
||||
"States",
|
||||
"resource://gre/modules/accessibility/Constants.jsm"
|
||||
);
|
||||
|
||||
Logger.info("content-script.js", content.document.location);
|
||||
|
||||
function onStop(m) {
|
||||
Logger.debug("AccessFu:Stop");
|
||||
|
||||
removeMessageListener("AccessFu:Stop", onStop);
|
||||
|
||||
this._jsat_eventManager.stop();
|
||||
this._jsat_contentControl.stop();
|
||||
}
|
||||
|
||||
addMessageListener("AccessFu:Stop", onStop);
|
||||
|
||||
if (!this._jsat_contentControl) {
|
||||
this._jsat_contentControl = new ContentControl(this);
|
||||
}
|
||||
this._jsat_contentControl.start();
|
||||
|
||||
if (!this._jsat_eventManager) {
|
||||
this._jsat_eventManager = new EventManager(this);
|
||||
}
|
||||
this._jsat_eventManager.start();
|
||||
|
||||
function contentStarted() {
|
||||
let accDoc = Utils.AccService.getAccessibleFor(content.document);
|
||||
if (accDoc && !Utils.getState(accDoc).contains(States.BUSY)) {
|
||||
sendAsyncMessage("AccessFu:ContentStarted");
|
||||
} else {
|
||||
content.setTimeout(contentStarted, 0);
|
||||
}
|
||||
}
|
||||
|
||||
if (Utils.inTest) {
|
||||
// During a test we want to wait for the document to finish loading for
|
||||
// consistency.
|
||||
contentStarted();
|
||||
}
|
@ -1,14 +0,0 @@
|
||||
# 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/.
|
||||
|
||||
EXTRA_JS_MODULES.accessibility += [
|
||||
'AccessFu.jsm',
|
||||
'Constants.jsm',
|
||||
'ContentControl.jsm',
|
||||
'EventManager.jsm',
|
||||
'Traversal.jsm',
|
||||
'Utils.jsm'
|
||||
]
|
||||
|
||||
JAR_MANIFESTS += ['jar.mn']
|
@ -21,7 +21,6 @@ DIRS += [ 'aom',
|
||||
'html',
|
||||
'interfaces',
|
||||
'ipc',
|
||||
'jsat',
|
||||
'xpcom'
|
||||
]
|
||||
|
||||
|
@ -1,7 +1,6 @@
|
||||
[DEFAULT]
|
||||
support-files =
|
||||
head.js
|
||||
!/accessible/tests/browser/events.js
|
||||
!/accessible/tests/browser/shared-head.js
|
||||
!/accessible/tests/mochitest/*.js
|
||||
!/accessible/tests/mochitest/letters.gif
|
||||
|
@ -19,7 +19,7 @@ Services.scriptloader.loadSubScript(
|
||||
loadScripts(
|
||||
{ name: "common.js", dir: MOCHITESTS_DIR },
|
||||
{ name: "layout.js", dir: MOCHITESTS_DIR },
|
||||
"events.js"
|
||||
{ name: "promisified-events.js", dir: MOCHITESTS_DIR }
|
||||
);
|
||||
|
||||
/**
|
||||
|
@ -1,7 +1,7 @@
|
||||
[DEFAULT]
|
||||
skip-if = (os == 'win' && processor == 'aarch64') # 1534855
|
||||
support-files =
|
||||
events.js
|
||||
!/accessible/tests/mochitest/*.js
|
||||
head.js
|
||||
shared-head.js
|
||||
|
||||
|
@ -7,7 +7,6 @@ support-files =
|
||||
doc_treeupdate_removal.xhtml
|
||||
doc_treeupdate_visibility.html
|
||||
doc_treeupdate_whitespace.html
|
||||
!/accessible/tests/browser/events.js
|
||||
!/accessible/tests/browser/shared-head.js
|
||||
!/accessible/tests/mochitest/*.js
|
||||
!/accessible/tests/mochitest/letters.gif
|
||||
|
@ -46,14 +46,14 @@ const rules = {
|
||||
],
|
||||
HTMLInputImage: [
|
||||
...HTMLControlHeadRule,
|
||||
{ attr: "alt", recreated: true },
|
||||
{ attr: "value", recreated: true },
|
||||
{ attr: "alt" },
|
||||
{ attr: "value" },
|
||||
{ attr: "title" },
|
||||
],
|
||||
HTMLInputImageNoValidSrc: [
|
||||
...HTMLControlHeadRule,
|
||||
{ attr: "alt", recreated: true },
|
||||
{ attr: "value", recreated: true },
|
||||
{ attr: "alt" },
|
||||
{ attr: "value" },
|
||||
],
|
||||
HTMLInputReset: [
|
||||
...HTMLControlHeadRule,
|
||||
|
@ -9,15 +9,10 @@ loadScripts({ name: "role.js", dir: MOCHITESTS_DIR });
|
||||
|
||||
addAccessibleTask(
|
||||
`
|
||||
<div id="container"><div id="scrollarea" style="overflow:auto;"><input>
|
||||
</div></div>
|
||||
<div id="container2"><div id="scrollarea2" style="overflow:hidden;">
|
||||
</div></div>`,
|
||||
<div id="container"><div id="scrollarea" style="overflow:auto;"><input>`,
|
||||
async function(browser, accDoc) {
|
||||
const id1 = "container";
|
||||
const id2 = "container2";
|
||||
const container = findAccessibleChildByID(accDoc, id1);
|
||||
const container2 = findAccessibleChildByID(accDoc, id2);
|
||||
|
||||
/* ================= Change scroll range ================================== */
|
||||
let tree = {
|
||||
@ -60,26 +55,5 @@ addAccessibleTask(
|
||||
],
|
||||
};
|
||||
testAccessibleTree(container, tree);
|
||||
|
||||
/* ================= Change scrollbar styles ============================== */
|
||||
tree = {
|
||||
SECTION: [
|
||||
// container2
|
||||
{ SECTION: [] }, // scroll area because of its ID
|
||||
],
|
||||
};
|
||||
testAccessibleTree(container2, tree);
|
||||
|
||||
onReorder = waitForEvent(EVENT_REORDER, id2);
|
||||
await invokeSetStyle(browser, "scrollarea2", "overflow", "auto");
|
||||
await onReorder;
|
||||
|
||||
tree = {
|
||||
SECTION: [
|
||||
// container
|
||||
{ SECTION: [] }, // scroll area
|
||||
],
|
||||
};
|
||||
testAccessibleTree(container2, tree);
|
||||
}
|
||||
);
|
||||
|
@ -70,7 +70,7 @@ addAccessibleTask(
|
||||
};
|
||||
testAccessibleTree(container1, tree);
|
||||
|
||||
onReorder = waitForEvent(EVENT_REORDER, id2);
|
||||
onReorder = waitForEvent(EVENT_REORDER, "container2_child");
|
||||
// Add CSS generated content to an element in container2's subtree
|
||||
await invokeSetAttribute(browser, "container2_child", "class", "gentext");
|
||||
await onReorder;
|
||||
|
@ -12,5 +12,8 @@ Services.scriptloader.loadSubScript(
|
||||
);
|
||||
|
||||
// Loading and common.js from accessible/tests/mochitest/ for all tests, as
|
||||
// well as events.js.
|
||||
loadScripts({ name: "common.js", dir: MOCHITESTS_DIR }, "events.js");
|
||||
// well as promisified-events.js.
|
||||
loadScripts(
|
||||
{ name: "common.js", dir: MOCHITESTS_DIR },
|
||||
{ name: "promisified-events.js", dir: MOCHITESTS_DIR }
|
||||
);
|
||||
|
@ -1,7 +1,6 @@
|
||||
[DEFAULT]
|
||||
support-files =
|
||||
head.js
|
||||
!/accessible/tests/browser/events.js
|
||||
!/accessible/tests/browser/shared-head.js
|
||||
!/accessible/tests/mochitest/*.js
|
||||
|
||||
|
@ -32,8 +32,10 @@ async function runTests(browser, accDoc) {
|
||||
evt = await onFocus;
|
||||
testStates(evt.accessible, STATE_FOCUSED);
|
||||
|
||||
let inputField = browser.ownerDocument.getElementById("urlbar").inputField;
|
||||
onFocus = waitForEvent(EVENT_FOCUS, getAccessible(inputField));
|
||||
onFocus = waitForEvent(
|
||||
EVENT_FOCUS,
|
||||
event => event.accessible.DOMNode == gURLBar.inputField
|
||||
);
|
||||
EventUtils.synthesizeKey("t", { accelKey: true }, browser.ownerGlobal);
|
||||
evt = await onFocus;
|
||||
testStates(evt.accessible, STATE_FOCUSED);
|
||||
|
@ -24,6 +24,28 @@ function isEventForAutocompleteItem(event) {
|
||||
return event.accessible.role == ROLE_COMBOBOX_OPTION;
|
||||
}
|
||||
|
||||
function isEventForButton(event) {
|
||||
return event.accessible.role == ROLE_PUSHBUTTON;
|
||||
}
|
||||
|
||||
function isEventForOneOffEngine(event) {
|
||||
let parent = event.accessible.parent;
|
||||
return (
|
||||
event.accessible.role == ROLE_PUSHBUTTON &&
|
||||
parent &&
|
||||
parent.role == ROLE_GROUPING &&
|
||||
parent.name
|
||||
);
|
||||
}
|
||||
|
||||
function isEventForMenuPopup(event) {
|
||||
return event.accessible.role == ROLE_MENUPOPUP;
|
||||
}
|
||||
|
||||
function isEventForMenuItem(event) {
|
||||
return event.accessible.role == ROLE_MENUITEM;
|
||||
}
|
||||
|
||||
/**
|
||||
* Wait for an autocomplete search to finish.
|
||||
* This is necessary to ensure predictable results, as these searches are
|
||||
@ -134,6 +156,12 @@ async function runTests() {
|
||||
event = await focused;
|
||||
testStates(event.accessible, STATE_FOCUSED);
|
||||
|
||||
info("Ensuring autocomplete focus on arrow up for search settings button");
|
||||
focused = waitForEvent(EVENT_FOCUS, isEventForButton);
|
||||
EventUtils.synthesizeKey("KEY_ArrowUp");
|
||||
event = await focused;
|
||||
testStates(event.accessible, STATE_FOCUSED);
|
||||
|
||||
info("Ensuring text box focus when text is typed");
|
||||
focused = waitForEvent(EVENT_FOCUS, textBox);
|
||||
EventUtils.sendString("z");
|
||||
@ -154,12 +182,20 @@ async function runTests() {
|
||||
await focused;
|
||||
testStates(textBox, STATE_FOCUSED);
|
||||
|
||||
info("Ensuring autocomplete focus on arrow down & up");
|
||||
info("Ensuring autocomplete focus on arrow down (4)");
|
||||
focused = waitForEvent(EVENT_FOCUS, isEventForAutocompleteItem);
|
||||
EventUtils.synthesizeKey("KEY_ArrowDown");
|
||||
// With the quantumbar enabled, we only get one result here, and arrow down
|
||||
// selects a one-off search button. We arrow back up to re-select the
|
||||
// autocomplete result.
|
||||
event = await focused;
|
||||
testStates(event.accessible, STATE_FOCUSED);
|
||||
|
||||
info("Ensuring one-off search button focus on arrow down");
|
||||
focused = waitForEvent(EVENT_FOCUS, isEventForOneOffEngine);
|
||||
EventUtils.synthesizeKey("KEY_ArrowDown");
|
||||
event = await focused;
|
||||
testStates(event.accessible, STATE_FOCUSED);
|
||||
|
||||
info("Ensuring autocomplete focus on arrow up");
|
||||
focused = waitForEvent(EVENT_FOCUS, isEventForAutocompleteItem);
|
||||
EventUtils.synthesizeKey("KEY_ArrowUp");
|
||||
event = await focused;
|
||||
testStates(event.accessible, STATE_FOCUSED);
|
||||
@ -181,6 +217,34 @@ async function runTests() {
|
||||
event = await focused;
|
||||
testStates(event.accessible, STATE_FOCUSED);
|
||||
}
|
||||
|
||||
info(
|
||||
"Ensuring context menu gets menu event on launch, item focus on down, and address bar focus on escape."
|
||||
);
|
||||
let menuEvent = waitForEvent(
|
||||
nsIAccessibleEvent.EVENT_MENUPOPUP_START,
|
||||
isEventForMenuPopup
|
||||
);
|
||||
EventUtils.sendMouseEvent(
|
||||
{ type: "contextmenu" },
|
||||
gURLBar.querySelector("moz-input-box")
|
||||
);
|
||||
await menuEvent;
|
||||
|
||||
focused = waitForEvent(EVENT_FOCUS, isEventForMenuItem);
|
||||
EventUtils.synthesizeKey("KEY_ArrowDown");
|
||||
event = await focused;
|
||||
testStates(event.accessible, STATE_FOCUSED);
|
||||
|
||||
focused = waitForEvent(EVENT_FOCUS, textBox);
|
||||
let closed = waitForEvent(
|
||||
nsIAccessibleEvent.EVENT_MENUPOPUP_END,
|
||||
isEventForMenuPopup
|
||||
);
|
||||
EventUtils.synthesizeKey("KEY_Escape");
|
||||
await closed;
|
||||
await focused;
|
||||
testStates(textBox, STATE_FOCUSED);
|
||||
}
|
||||
|
||||
addAccessibleTask(``, runTests);
|
||||
|
@ -30,7 +30,7 @@ async function checkURLBarCaretEvents() {
|
||||
});
|
||||
info("Loaded " + kURL);
|
||||
|
||||
let urlbarInputEl = newWin.document.getElementById("urlbar").inputField;
|
||||
let urlbarInputEl = newWin.gURLBar.inputField;
|
||||
let urlbarInput = getAccessible(urlbarInputEl, [nsIAccessibleText]);
|
||||
|
||||
let onCaretMove = waitForEvents([
|
||||
|
@ -12,5 +12,8 @@ Services.scriptloader.loadSubScript(
|
||||
);
|
||||
|
||||
// Loading and common.js from accessible/tests/mochitest/ for all tests, as
|
||||
// well as events.js.
|
||||
loadScripts({ name: "common.js", dir: MOCHITESTS_DIR }, "events.js");
|
||||
// well as promisified-events.js.
|
||||
loadScripts(
|
||||
{ name: "common.js", dir: MOCHITESTS_DIR },
|
||||
{ name: "promisified-events.js", dir: MOCHITESTS_DIR }
|
||||
);
|
||||
|
@ -21,9 +21,9 @@ add_task(async function testAutocompleteRichResult() {
|
||||
value: "a",
|
||||
});
|
||||
|
||||
info("Waiting for accessibility to be created for the richlistbox");
|
||||
info("Waiting for accessibility to be created for the results list");
|
||||
let resultsView;
|
||||
resultsView = gURLBar.view.panel.querySelector("#urlbarView-results");
|
||||
resultsView = gURLBar.view.panel.querySelector(".urlbarView-results");
|
||||
await BrowserTestUtils.waitForCondition(() =>
|
||||
accService.getAccessibleFor(resultsView)
|
||||
);
|
||||
|
@ -1,7 +1,6 @@
|
||||
[DEFAULT]
|
||||
support-files =
|
||||
head.js
|
||||
!/accessible/tests/browser/events.js
|
||||
!/accessible/tests/browser/shared-head.js
|
||||
!/accessible/tests/mochitest/*.js
|
||||
|
||||
|
@ -12,5 +12,8 @@ Services.scriptloader.loadSubScript(
|
||||
);
|
||||
|
||||
// Loading and common.js from accessible/tests/mochitest/ for all tests, as
|
||||
// well as events.js.
|
||||
loadScripts({ name: "common.js", dir: MOCHITESTS_DIR }, "events.js");
|
||||
// well as promisified-events.js.
|
||||
loadScripts(
|
||||
{ name: "common.js", dir: MOCHITESTS_DIR },
|
||||
{ name: "promisified-events.js", dir: MOCHITESTS_DIR }
|
||||
);
|
||||
|
@ -5,13 +5,13 @@
|
||||
"use strict";
|
||||
|
||||
/* import-globals-from ../mochitest/common.js */
|
||||
/* import-globals-from events.js */
|
||||
/* import-globals-from ../mochitest/promisified-events.js */
|
||||
|
||||
/* exported Logger, MOCHITESTS_DIR, invokeSetAttribute, invokeFocus,
|
||||
invokeSetStyle, getAccessibleDOMNodeID, getAccessibleTagName,
|
||||
addAccessibleTask, findAccessibleChildByID, isDefunct,
|
||||
CURRENT_CONTENT_DIR, loadScripts, loadFrameScripts, snippetToURL,
|
||||
Cc, Cu, arrayFromChildren, forceGC */
|
||||
Cc, Cu, arrayFromChildren, forceGC, contentSpawnMutation */
|
||||
|
||||
/**
|
||||
* Current browser test directory path used to load subscripts.
|
||||
@ -153,7 +153,7 @@ function invokeFocus(browser, id) {
|
||||
Logger.log(`Setting focus on a node with id: ${id}`);
|
||||
return ContentTask.spawn(browser, id, contentId => {
|
||||
let elm = content.document.getElementById(contentId);
|
||||
if (elm.editor || elm.localName == "textbox") {
|
||||
if (elm.editor) {
|
||||
elm.selectionStart = elm.selectionEnd = elm.value.length;
|
||||
}
|
||||
elm.focus();
|
||||
@ -389,3 +389,42 @@ function forceGC() {
|
||||
SpecialPowers.forceShrinkingGC();
|
||||
SpecialPowers.forceCC();
|
||||
}
|
||||
|
||||
/*
|
||||
* This function spawns a content task and awaits expected mutation events from
|
||||
* various content changes. It's good at catching events we did *not* expect. We
|
||||
* do this advancing the layout refresh to flush the relocations/insertions
|
||||
* queue.
|
||||
*/
|
||||
async function contentSpawnMutation(browser, waitFor, func, args = null) {
|
||||
let onReorders = waitForEvents({ expected: waitFor.expected || [] });
|
||||
let unexpectedListener = new UnexpectedEvents(waitFor.unexpected || []);
|
||||
|
||||
function tick() {
|
||||
// 100ms is an arbitrary positive number to advance the clock.
|
||||
// We don't need to advance the clock for a11y mutations, but other
|
||||
// tick listeners may depend on an advancing clock with each refresh.
|
||||
content.windowUtils.advanceTimeAndRefresh(100);
|
||||
}
|
||||
|
||||
// This stops the refreh driver from doing its regular ticks, and leaves
|
||||
// us in control.
|
||||
await ContentTask.spawn(browser, null, tick);
|
||||
|
||||
// Perform the tree mutation.
|
||||
await ContentTask.spawn(browser, args, func);
|
||||
|
||||
// Do one tick to flush our queue (insertions, relocations, etc.)
|
||||
await ContentTask.spawn(browser, null, tick);
|
||||
|
||||
let events = await onReorders;
|
||||
|
||||
unexpectedListener.stop();
|
||||
|
||||
// Go back to normal refresh driver ticks.
|
||||
await ContentTask.spawn(browser, null, function() {
|
||||
content.windowUtils.restoreNormalRefresh();
|
||||
});
|
||||
|
||||
return events;
|
||||
}
|
||||
|
@ -1,7 +1,6 @@
|
||||
[DEFAULT]
|
||||
support-files =
|
||||
head.js
|
||||
!/accessible/tests/browser/events.js
|
||||
!/accessible/tests/browser/shared-head.js
|
||||
!/accessible/tests/mochitest/*.js
|
||||
|
||||
|
@ -12,5 +12,8 @@ Services.scriptloader.loadSubScript(
|
||||
);
|
||||
|
||||
// Loading and common.js from accessible/tests/mochitest/ for all tests, as
|
||||
// well as events.js.
|
||||
loadScripts({ name: "common.js", dir: MOCHITESTS_DIR }, "events.js");
|
||||
// well as promisified-events.js.
|
||||
loadScripts(
|
||||
{ name: "common.js", dir: MOCHITESTS_DIR },
|
||||
{ name: "promisified-events.js", dir: MOCHITESTS_DIR }
|
||||
);
|
||||
|
@ -1,9 +1,10 @@
|
||||
[DEFAULT]
|
||||
support-files =
|
||||
head.js
|
||||
!/accessible/tests/browser/events.js
|
||||
!/accessible/tests/browser/shared-head.js
|
||||
!/accessible/tests/mochitest/*.js
|
||||
|
||||
[browser_aria_owns.js]
|
||||
skip-if = true || (verify && !debug && (os == 'linux')) #Bug 1445513
|
||||
[browser_searchbar.js]
|
||||
[browser_shadowdom.js]
|
||||
|
52
accessible/tests/browser/tree/browser_searchbar.js
Normal file
52
accessible/tests/browser/tree/browser_searchbar.js
Normal file
@ -0,0 +1,52 @@
|
||||
"use strict";
|
||||
|
||||
/* import-globals-from ../../mochitest/role.js */
|
||||
loadScripts({ name: "role.js", dir: MOCHITESTS_DIR });
|
||||
|
||||
// eslint-disable-next-line camelcase
|
||||
add_task(async function test_searchbar_a11y_tree() {
|
||||
await SpecialPowers.pushPrefEnv({
|
||||
set: [["browser.search.widget.inNavBar", true]],
|
||||
});
|
||||
|
||||
let searchbar = await TestUtils.waitForCondition(
|
||||
() => document.getElementById("searchbar"),
|
||||
"wait for search bar to appear"
|
||||
);
|
||||
|
||||
// Make sure the popup has been rendered so it shows up in the a11y tree.
|
||||
let popup = document.getElementById("PopupSearchAutoComplete");
|
||||
let promise = BrowserTestUtils.waitForEvent(popup, "popupshown", false);
|
||||
searchbar.textbox.openPopup();
|
||||
await promise;
|
||||
|
||||
promise = BrowserTestUtils.waitForEvent(popup, "popuphidden", false);
|
||||
searchbar.textbox.closePopup();
|
||||
await promise;
|
||||
|
||||
const TREE = {
|
||||
role: ROLE_EDITCOMBOBOX,
|
||||
|
||||
children: [
|
||||
// input element
|
||||
{
|
||||
role: ROLE_ENTRY,
|
||||
children: [],
|
||||
},
|
||||
|
||||
// context menu
|
||||
{
|
||||
role: ROLE_COMBOBOX_LIST,
|
||||
children: [],
|
||||
},
|
||||
|
||||
// result list
|
||||
{
|
||||
role: ROLE_GROUPING,
|
||||
// not testing the structure inside the result list
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
testAccessibleTree(searchbar, TREE);
|
||||
});
|
38
accessible/tests/browser/tree/browser_shadowdom.js
Normal file
38
accessible/tests/browser/tree/browser_shadowdom.js
Normal file
@ -0,0 +1,38 @@
|
||||
/* 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/. */
|
||||
|
||||
"use strict";
|
||||
|
||||
const REORDER = { expected: [[EVENT_REORDER, "container"]] };
|
||||
|
||||
// Dynamically inserted slotted accessible elements should be in
|
||||
// the accessible tree.
|
||||
const snippet = `
|
||||
<script>
|
||||
customElements.define("x-el", class extends HTMLElement {
|
||||
constructor() {
|
||||
super();
|
||||
this.attachShadow({ mode: "open" });
|
||||
this.shadowRoot.innerHTML =
|
||||
"<div role='presentation'><slot></slot></div>";
|
||||
}
|
||||
});
|
||||
</script>
|
||||
<x-el id="container" role="group"><label id="l1">label1</label></x-el>
|
||||
`;
|
||||
addAccessibleTask(snippet, async function(browser, accDoc) {
|
||||
let container = findAccessibleChildByID(accDoc, "container");
|
||||
|
||||
testChildrenIds(container, ["l1"]);
|
||||
|
||||
await contentSpawnMutation(browser, REORDER, function() {
|
||||
let labelEl = content.document.createElement("label");
|
||||
labelEl.id = "l2";
|
||||
|
||||
let containerEl = content.document.getElementById("container");
|
||||
containerEl.appendChild(labelEl);
|
||||
});
|
||||
|
||||
testChildrenIds(container, ["l1", "l2"]);
|
||||
});
|
@ -14,8 +14,11 @@ Services.scriptloader.loadSubScript(
|
||||
);
|
||||
|
||||
// Loading and common.js from accessible/tests/mochitest/ for all tests, as
|
||||
// well as events.js.
|
||||
loadScripts({ name: "common.js", dir: MOCHITESTS_DIR }, "events.js");
|
||||
// well as promisified-events.js.
|
||||
loadScripts(
|
||||
{ name: "common.js", dir: MOCHITESTS_DIR },
|
||||
{ name: "promisified-events.js", dir: MOCHITESTS_DIR }
|
||||
);
|
||||
|
||||
/*
|
||||
* A test function for comparing the IDs of an accessible's children
|
||||
|
@ -1,5 +1,5 @@
|
||||
load 448064.xhtml # This test instantiates a11y, so be careful about adding tests before it
|
||||
load 471493.xul
|
||||
load chrome://reftest/content/crashtests/accessible/tests/crashtests/471493.xhtml
|
||||
asserts-if(!browserIsRemote,2) load 884202.html
|
||||
load 890760.html
|
||||
load 893515.html
|
||||
@ -12,6 +12,6 @@ load 1494707.html
|
||||
load 1503964.html
|
||||
load 1655983.html
|
||||
|
||||
# last_test_to_unload_testsuite.xul MUST be the last test in the list because it
|
||||
# last_test_to_unload_testsuite.xhtml MUST be the last test in the list because it
|
||||
# is responsible for shutting down accessibility service affecting later tests.
|
||||
skip-if(/^Windows\x20NT\x2010\.0/.test(http.oscpu)&&/^aarch64-msvc/.test(xulRuntime.XPCOMABI)) load last_test_to_unload_testsuite.xul
|
||||
skip-if(/^Windows\x20NT\x2010\.0/.test(http.oscpu)&&/^aarch64-msvc/.test(xulRuntime.XPCOMABI)) load chrome://reftest/content/crashtests/accessible/tests/crashtests/last_test_to_unload_testsuite.xhtml
|
||||
|
@ -35,6 +35,10 @@ const XUL_EVENTS = CLICK_EVENTS | COMMAND_EVENT;
|
||||
* // used with 'events', if missing then 'ID' is used instead.
|
||||
* get targetID() {},
|
||||
*
|
||||
* // [optional] true to match DOM events bubbled up to the target,
|
||||
* // false (default) to only match events fired directly on the target.
|
||||
* get allowBubbling() {},
|
||||
*
|
||||
* // [optional] perform checks when 'click' event is handled if 'events'
|
||||
* // is used.
|
||||
* checkOnClickEvent: function() {},
|
||||
@ -182,6 +186,17 @@ function checkerOfActionInvoker(aType, aTarget, aActionObj) {
|
||||
this.eventTarget = aActionObj.eventTarget;
|
||||
}
|
||||
|
||||
if (aActionObj && aActionObj.allowBubbling) {
|
||||
// Normally, we add event listeners on the document. To catch bubbled
|
||||
// events, we need to add the listener on the target itself.
|
||||
this.eventTarget = "element";
|
||||
// Normally, we only match an event fired directly on the target. Override
|
||||
// this to match a bubbled event.
|
||||
this.match = function(aEvent) {
|
||||
return aEvent.currentTarget == aTarget;
|
||||
};
|
||||
}
|
||||
|
||||
this.phase = false;
|
||||
|
||||
this.getID = function getID() {
|
||||
|
@ -7,11 +7,11 @@ support-files =
|
||||
[test_aria.html]
|
||||
[test_controls.html]
|
||||
[test_general.html]
|
||||
[test_general.xul]
|
||||
[test_general.xhtml]
|
||||
[test_keys.html]
|
||||
[test_keys_menu.xul]
|
||||
[test_keys.xhtml]
|
||||
[test_link.html]
|
||||
[test_media.html]
|
||||
[test_select.html]
|
||||
[test_tree.xul]
|
||||
[test_treegrid.xul]
|
||||
[test_tree.xhtml]
|
||||
[test_treegrid.xhtml]
|
||||
|
@ -7,6 +7,7 @@
|
||||
|
||||
|
||||
<window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
|
||||
xmlns:html="http://www.w3.org/1999/xhtml"
|
||||
title="nsIAccessible actions testing">
|
||||
|
||||
<script src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js" />
|
||||
@ -17,6 +18,10 @@
|
||||
src="../events.js" />
|
||||
<script type="application/javascript"
|
||||
src="../actions.js" />
|
||||
<script type="application/javascript"
|
||||
src="../role.js" />
|
||||
<script type="application/javascript"
|
||||
src="../states.js" />
|
||||
|
||||
<script type="application/javascript">
|
||||
<![CDATA[
|
||||
@ -71,6 +76,22 @@
|
||||
ID: "labelWithPopup",
|
||||
actionName: "click",
|
||||
events: CLICK_EVENTS
|
||||
},
|
||||
{
|
||||
ID: "toolbarbutton_label",
|
||||
actionName: "click",
|
||||
targetID: "toolbarbutton",
|
||||
events: XUL_EVENTS,
|
||||
allowBubbling: true
|
||||
},
|
||||
{
|
||||
ID: "menulist_label",
|
||||
actionName: "click",
|
||||
// focusChecker expects a unique focus event. However, there might
|
||||
// still be pending focus events not caught by previous tests.
|
||||
eventSeq: [
|
||||
new invokerChecker(EVENT_FOCUS, getNode("menulist"))
|
||||
]
|
||||
}/*, // XXX: bug 490288
|
||||
{
|
||||
ID: "buttonmenu_item",
|
||||
@ -136,7 +157,14 @@
|
||||
tabindex="0"/>
|
||||
<hbox>
|
||||
<label id="name_entry_label" value="Name" control="name_entry"/>
|
||||
<textbox id="name_entry"/>
|
||||
<html:input id="name_entry"/>
|
||||
</hbox>
|
||||
<toolbarbutton id="toolbarbutton">
|
||||
<label id="toolbarbutton_label">toolbarbutton</label>
|
||||
</toolbarbutton>
|
||||
<hbox>
|
||||
<label id="menulist_label" control="menulist">menulist</label>
|
||||
<menulist id="menulist"/>
|
||||
</hbox>
|
||||
</vbox>
|
||||
</hbox>
|
@ -4,6 +4,7 @@
|
||||
type="text/css"?>
|
||||
|
||||
<window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
|
||||
xmlns:html="http://www.w3.org/1999/xhtml"
|
||||
title="Accessible XUL access keys and shortcut keys tests">
|
||||
|
||||
<script src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js" />
|
||||
@ -17,8 +18,8 @@
|
||||
<![CDATA[
|
||||
function openMenu(aMenuID, aMenuitemID)
|
||||
{
|
||||
this.menuNode = getNode(aMenuID),
|
||||
this.menuitemNode = getNode(aMenuitemID),
|
||||
this.menuNode = getNode(aMenuID);
|
||||
this.menuitemNode = getNode(aMenuitemID);
|
||||
|
||||
this.eventSeq = [
|
||||
new invokerChecker(EVENT_FOCUS, this.menuNode)
|
||||
@ -53,6 +54,11 @@
|
||||
var gQueue = null;
|
||||
function doTest()
|
||||
{
|
||||
// HTML element should get accessKey from associated XUL label.
|
||||
let input = getAccessible("input");
|
||||
is(input.accessKey, (MAC ? "⌃⌥i" : "Alt+Shift+i"),
|
||||
"Wrong accessKey on input");
|
||||
|
||||
gQueue = new eventQueue();
|
||||
gQueue.push(new openMenu("menu", "menuitem"));
|
||||
gQueue.invoke(); // Will call SimpleTest.finish();
|
||||
@ -78,6 +84,9 @@
|
||||
</body>
|
||||
|
||||
<vbox flex="1">
|
||||
<label control="input" accesskey="i">input</label>
|
||||
<html:input id="input"/>
|
||||
|
||||
<keyset>
|
||||
<key key="l" modifiers="control" id="key1"/>
|
||||
</keyset>
|
@ -7,9 +7,9 @@ support-files =
|
||||
[test_listbox.html]
|
||||
[test_obj.html]
|
||||
[test_obj_css.html]
|
||||
[test_obj_css.xul]
|
||||
[test_obj_css.xhtml]
|
||||
[test_obj_group.html]
|
||||
[test_obj_group.xul]
|
||||
[test_obj_group_tree.xul]
|
||||
[test_obj_group.xhtml]
|
||||
[test_obj_group_tree.xhtml]
|
||||
[test_tag.html]
|
||||
[test_xml-roles.html]
|
||||
|
@ -12,7 +12,7 @@
|
||||
<script type="application/javascript"
|
||||
src="../attributes.js"></script>
|
||||
<script type="application/javascript"
|
||||
src="../events.js"></script>
|
||||
src="../promisified-events.js"></script>
|
||||
|
||||
<script type="application/javascript">
|
||||
async function doTest() {
|
||||
@ -25,7 +25,7 @@
|
||||
testGroupAttrs("f", 6, 6);
|
||||
// Remove c, reducing the set to 5.
|
||||
let listbox = getAccessible("listbox");
|
||||
let updated = waitForEventPromise(EVENT_REORDER, listbox);
|
||||
let updated = waitForEvent(EVENT_REORDER, listbox);
|
||||
c.remove();
|
||||
await updated;
|
||||
testGroupAttrs("a", 1, 5);
|
||||
@ -34,7 +34,7 @@
|
||||
testGroupAttrs("e", 4, 5);
|
||||
testGroupAttrs("f", 5, 5);
|
||||
// Now, remove the first element.
|
||||
updated = waitForEventPromise(EVENT_REORDER, listbox);
|
||||
updated = waitForEvent(EVENT_REORDER, listbox);
|
||||
a.remove();
|
||||
await updated;
|
||||
testGroupAttrs("b", 1, 4);
|
||||
@ -42,14 +42,14 @@
|
||||
testGroupAttrs("e", 3, 4);
|
||||
testGroupAttrs("f", 4, 4);
|
||||
// Remove the last item.
|
||||
updated = waitForEventPromise(EVENT_REORDER, listbox);
|
||||
updated = waitForEvent(EVENT_REORDER, listbox);
|
||||
f.remove();
|
||||
await updated;
|
||||
testGroupAttrs("b", 1, 3);
|
||||
testGroupAttrs("d", 2, 3);
|
||||
testGroupAttrs("e", 3, 3);
|
||||
// Finally, remove the middle item.
|
||||
updated = waitForEventPromise(EVENT_REORDER, listbox);
|
||||
updated = waitForEvent(EVENT_REORDER, listbox);
|
||||
d.remove();
|
||||
await updated;
|
||||
testGroupAttrs("b", 1, 2);
|
||||
@ -76,7 +76,7 @@
|
||||
<div id="d" role="option">Option d</div>
|
||||
<div id="e" role="option">Option e</div>
|
||||
<div id="f" role="option">Option f</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
@ -25,7 +25,6 @@
|
||||
testCSSAttrs("display_mozgrid");
|
||||
testCSSAttrs("display_mozgridgroup");
|
||||
testCSSAttrs("display_mozgridline");
|
||||
testCSSAttrs("display_mozstack");
|
||||
testCSSAttrs("display_mozdeck");
|
||||
testCSSAttrs("display_mozpopup");
|
||||
|
||||
@ -57,10 +56,8 @@
|
||||
<vbox id="display_mozgrid" style="display: -moz-grid;" role="img"/>
|
||||
<vbox id="display_mozgridgroup" style="display: -moz-grid-group;" role="img"/>
|
||||
<vbox id="display_mozgridline" style="display: -moz-grid-line;" role="img"/>
|
||||
<vbox id="display_mozstack" style="display: -moz-stack;" role="img"/>
|
||||
<vbox id="display_mozdeck" style="display: -moz-deck;" role="img"/>
|
||||
<vbox id="display_mozpopup" style="display: -moz-popup;" role="img"/>
|
||||
|
||||
</hbox>
|
||||
</window>
|
||||
|
@ -21,9 +21,11 @@
|
||||
testAttrs("nav", {"xml-roles": "navigation"}, true);
|
||||
testAttrs("header", {"xml-roles": "banner"}, true);
|
||||
testAbsentAttrs("article_header", {"xml-roles": "banner"});
|
||||
testAbsentAttrs("main_header", {"xml-roles": "banner"});
|
||||
testAbsentAttrs("section_header", {"xml-roles": "banner"});
|
||||
testAttrs("footer", {"xml-roles": "contentinfo"}, true);
|
||||
testAbsentAttrs("article_footer", {"xml-roles": "contentinfo"});
|
||||
testAbsentAttrs("main_footer", {"xml-roles": "contentinfo"});
|
||||
testAbsentAttrs("section_footer", {"xml-roles": "contentinfo"});
|
||||
testAttrs("aside", {"xml-roles": "complementary"}, true);
|
||||
testAbsentAttrs("section", {"xml-roles": "region"}, true);
|
||||
@ -157,6 +159,10 @@
|
||||
<header id="article_header">a header within an article</header>
|
||||
<footer id="article_footer">a footer within an article</footer>
|
||||
</article>
|
||||
<main id="main_with_header_and_footer">
|
||||
<header id="main_header">a header within a main</header>
|
||||
<footer id="main_footer">a footer within a main</footer>
|
||||
</main>
|
||||
<section id="section_with_header_and_footer">
|
||||
<header id="section_header">a header within an section</header>
|
||||
<footer id="section_footer">a footer within an section</footer>
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user