mirror of
https://github.com/Feodor2/Mypal68.git
synced 2025-06-18 14:55: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/components/translation/cld2/.*
|
||||||
browser/extensions/mortar/ppapi/.*
|
browser/extensions/mortar/ppapi/.*
|
||||||
devtools/client/shared/sourceeditor/codemirror/.*
|
devtools/client/shared/sourceeditor/codemirror/.*
|
||||||
devtools/client/shared/sourceeditor/tern/.*
|
|
||||||
dom/canvas/test/webgl-conf/checkout/closure-library/.*
|
dom/canvas/test/webgl-conf/checkout/closure-library/.*
|
||||||
dom/media/gmp/rlz/.*
|
dom/media/gmp/rlz/.*
|
||||||
dom/media/platforms/ffmpeg/ffmpeg57/.*
|
dom/media/platforms/ffmpeg/ffmpeg57/.*
|
||||||
|
@ -125,7 +125,6 @@ devtools/client/shared/source-map/
|
|||||||
devtools/client/shared/vendor/
|
devtools/client/shared/vendor/
|
||||||
devtools/client/shared/sourceeditor/codemirror/*.js
|
devtools/client/shared/sourceeditor/codemirror/*.js
|
||||||
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/cm_mode_ruby.js
|
||||||
devtools/client/shared/sourceeditor/test/codemirror/
|
devtools/client/shared/sourceeditor/test/codemirror/
|
||||||
devtools/server/actors/utils/automation-timeline.js
|
devtools/server/actors/utils/automation-timeline.js
|
||||||
@ -326,9 +325,6 @@ toolkit/components/reader/JSDOMParser.js
|
|||||||
# Uses preprocessing
|
# Uses preprocessing
|
||||||
toolkit/components/reader/Readerable.jsm
|
toolkit/components/reader/Readerable.jsm
|
||||||
|
|
||||||
# Should be going away soon
|
|
||||||
toolkit/content/widgets/wizard.xml
|
|
||||||
|
|
||||||
# Uses preprocessing
|
# Uses preprocessing
|
||||||
toolkit/mozapps/update/tests/data/xpcshellConstantsPP.js
|
toolkit/mozapps/update/tests/data/xpcshellConstantsPP.js
|
||||||
toolkit/modules/AppConstants.jsm
|
toolkit/modules/AppConstants.jsm
|
||||||
|
452
.eslintrc.js
452
.eslintrc.js
@ -135,6 +135,7 @@ module.exports = {
|
|||||||
"no-array-constructor": "off",
|
"no-array-constructor": "off",
|
||||||
"no-undef": "off",
|
"no-undef": "off",
|
||||||
"no-unused-vars": "off",
|
"no-unused-vars": "off",
|
||||||
|
"no-useless-concat": "off",
|
||||||
"no-redeclare": "off",
|
"no-redeclare": "off",
|
||||||
"no-global-assign": "off",
|
"no-global-assign": "off",
|
||||||
}
|
}
|
||||||
@ -187,6 +188,8 @@ module.exports = {
|
|||||||
"mozilla/reject-importGlobalProperties": "off",
|
"mozilla/reject-importGlobalProperties": "off",
|
||||||
"mozilla/no-arbitrary-setTimeout": "off",
|
"mozilla/no-arbitrary-setTimeout": "off",
|
||||||
"mozilla/no-define-cc-etc": "off",
|
"mozilla/no-define-cc-etc": "off",
|
||||||
|
"mozilla/no-useless-parameters": "off",
|
||||||
|
"mozilla/no-useless-removeEventListener": "off",
|
||||||
"mozilla/use-chromeutils-generateqi": "off",
|
"mozilla/use-chromeutils-generateqi": "off",
|
||||||
"mozilla/use-default-preference-values": "off",
|
"mozilla/use-default-preference-values": "off",
|
||||||
"mozilla/use-includes-instead-of-indexOf": "off",
|
"mozilla/use-includes-instead-of-indexOf": "off",
|
||||||
@ -209,6 +212,7 @@ module.exports = {
|
|||||||
"no-restricted-globals": "off",
|
"no-restricted-globals": "off",
|
||||||
"no-return-await": "off",
|
"no-return-await": "off",
|
||||||
"no-sequences": "off",
|
"no-sequences": "off",
|
||||||
|
"no-shadow": "off",
|
||||||
"no-throw-literal": "off",
|
"no-throw-literal": "off",
|
||||||
"no-useless-concat": "off",
|
"no-useless-concat": "off",
|
||||||
"no-undef": "off",
|
"no-undef": "off",
|
||||||
@ -259,10 +263,10 @@ module.exports = {
|
|||||||
"dom/websocket/**",
|
"dom/websocket/**",
|
||||||
"dom/workers/**",
|
"dom/workers/**",
|
||||||
"dom/worklet/**",
|
"dom/worklet/**",
|
||||||
"dom/xbl/**",
|
|
||||||
"dom/xml/**",
|
"dom/xml/**",
|
||||||
"dom/xslt/**",
|
"dom/xslt/**",
|
||||||
"dom/xul/**",
|
"dom/xul/**",
|
||||||
|
"dom/ipc/test.xhtml",
|
||||||
],
|
],
|
||||||
"rules": {
|
"rules": {
|
||||||
"consistent-return": "off",
|
"consistent-return": "off",
|
||||||
@ -359,5 +363,451 @@ module.exports = {
|
|||||||
"rules": {
|
"rules": {
|
||||||
"no-async-promise-executor": "off",
|
"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]]
|
[[package]]
|
||||||
name = "dogear"
|
name = "dogear"
|
||||||
version = "0.2.5"
|
version = "0.4.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "26b7583e1427e296c852f3217eaab3890e698f742b8d7349beb1f40c4e946fc9"
|
checksum = "c01a457f8d6689260111be60774bfb68e558b41bc89b866ebc3bbed60ba255cb"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"log",
|
"log",
|
||||||
"smallbitvec",
|
"smallbitvec",
|
||||||
|
11
README.md
11
README.md
@ -7,7 +7,7 @@ A browser for Windows XP based on Firefox 68.
|
|||||||
|
|
||||||
## KNOWN PROBLEMS
|
## 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.
|
multiprocess only this which reaches 1.5gb, so it better here.
|
||||||
I think this is OS limitation, nothing to do with this.
|
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.
|
- 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.
|
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
|
## 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
|
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.
|
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.
|
Drwatson log is usually inside All Users\Application Data\Microsoft\Dr Watson.
|
||||||
Minidump also may be usefull. Do not post any irrelevent logs.
|
Minidump also may be usefull. Do not post any irrelevant logs.
|
||||||
An issue without details cosider as invalid.
|
An issue without details considered as invalid.
|
||||||
|
|
||||||
## IF YOU WANT REPORT A SITE
|
## IF YOU WANT REPORT A SITE
|
||||||
|
|
||||||
Report [there](https://github.com/Feodor2/Mypal68/issues/228).
|
Report [there](https://github.com/Feodor2/Mypal68/issues/228).
|
||||||
Put the actual link to the site
|
Put the actual link to the site
|
||||||
Notice that I never would look to the site which requires the login, including any goolag sites.
|
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.
|
Actually I do not look every site, no time for this.
|
||||||
|
|
||||||
## YOU MAY DONATE
|
## YOU MAY DONATE
|
||||||
|
@ -5,17 +5,22 @@
|
|||||||
#include "AccessibleWrap.h"
|
#include "AccessibleWrap.h"
|
||||||
|
|
||||||
#include "Accessible-inl.h"
|
#include "Accessible-inl.h"
|
||||||
|
#include "AccEvent.h"
|
||||||
#include "AndroidInputType.h"
|
#include "AndroidInputType.h"
|
||||||
#include "DocAccessibleWrap.h"
|
#include "DocAccessibleWrap.h"
|
||||||
#include "IDSet.h"
|
#include "IDSet.h"
|
||||||
#include "JavaBuiltins.h"
|
#include "JavaBuiltins.h"
|
||||||
#include "SessionAccessibility.h"
|
#include "SessionAccessibility.h"
|
||||||
|
#include "TraversalRule.h"
|
||||||
|
#include "Pivot.h"
|
||||||
#include "nsAccessibilityService.h"
|
#include "nsAccessibilityService.h"
|
||||||
|
#include "nsEventShell.h"
|
||||||
#include "nsPersistentProperties.h"
|
#include "nsPersistentProperties.h"
|
||||||
#include "nsIAccessibleAnnouncementEvent.h"
|
#include "nsIAccessibleAnnouncementEvent.h"
|
||||||
#include "nsIStringBundle.h"
|
#include "nsIStringBundle.h"
|
||||||
#include "nsAccUtils.h"
|
#include "nsAccUtils.h"
|
||||||
#include "nsTextEquivUtils.h"
|
#include "nsTextEquivUtils.h"
|
||||||
|
#include "RootAccessible.h"
|
||||||
|
|
||||||
#include "mozilla/a11y/PDocAccessibleChild.h"
|
#include "mozilla/a11y/PDocAccessibleChild.h"
|
||||||
#include "mozilla/jni/GeckoBundleUtils.h"
|
#include "mozilla/jni/GeckoBundleUtils.h"
|
||||||
@ -78,6 +83,27 @@ nsresult AccessibleWrap::HandleAccEvent(AccEvent* aEvent) {
|
|||||||
}
|
}
|
||||||
break;
|
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:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -122,15 +148,11 @@ nsresult AccessibleWrap::HandleAccEvent(AccEvent* aEvent) {
|
|||||||
|
|
||||||
RefPtr<AccessibleWrap> newPosition =
|
RefPtr<AccessibleWrap> newPosition =
|
||||||
static_cast<AccessibleWrap*>(vcEvent->NewAccessible());
|
static_cast<AccessibleWrap*>(vcEvent->NewAccessible());
|
||||||
auto oldPosition = static_cast<AccessibleWrap*>(vcEvent->OldAccessible());
|
|
||||||
|
|
||||||
if (sessionAcc && newPosition) {
|
if (sessionAcc && newPosition) {
|
||||||
if (oldPosition != newPosition) {
|
if (vcEvent->Reason() == nsIAccessiblePivot::REASON_POINT) {
|
||||||
if (vcEvent->Reason() == nsIAccessiblePivot::REASON_POINT) {
|
sessionAcc->SendHoverEnterEvent(newPosition);
|
||||||
sessionAcc->SendHoverEnterEvent(newPosition);
|
} else {
|
||||||
} else {
|
sessionAcc->SendAccessibilityFocusedEvent(newPosition);
|
||||||
sessionAcc->SendAccessibilityFocusedEvent(newPosition);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (vcEvent->BoundaryType() != nsIAccessiblePivot::NO_BOUNDARY) {
|
if (vcEvent->BoundaryType() != nsIAccessiblePivot::NO_BOUNDARY) {
|
||||||
@ -247,6 +269,155 @@ bool AccessibleWrap::GetSelectionBounds(int32_t* aStartOffset,
|
|||||||
return false;
|
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,
|
uint32_t AccessibleWrap::GetFlags(role aRole, uint64_t aState,
|
||||||
uint8_t aActionCount) {
|
uint8_t aActionCount) {
|
||||||
uint32_t flags = 0;
|
uint32_t flags = 0;
|
||||||
|
@ -34,6 +34,22 @@ class AccessibleWrap : public Accessible {
|
|||||||
|
|
||||||
virtual bool GetSelectionBounds(int32_t* aStartOffset, int32_t* aEndOffset);
|
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(bool aSmall = false);
|
||||||
|
|
||||||
mozilla::java::GeckoBundle::LocalRef ToBundle(
|
mozilla::java::GeckoBundle::LocalRef ToBundle(
|
||||||
@ -84,6 +100,8 @@ class AccessibleWrap : public Accessible {
|
|||||||
|
|
||||||
bool HandleLiveRegionEvent(AccEvent* aEvent);
|
bool HandleLiveRegionEvent(AccEvent* aEvent);
|
||||||
|
|
||||||
|
void GetSelectionOrCaret(int32_t* aStartOffset, int32_t* aEndOffset);
|
||||||
|
|
||||||
static void GetRoleDescription(role aRole,
|
static void GetRoleDescription(role aRole,
|
||||||
nsIPersistentProperties* aAttributes,
|
nsIPersistentProperties* aAttributes,
|
||||||
nsAString& aGeckoRole,
|
nsAString& aGeckoRole,
|
||||||
|
@ -128,13 +128,11 @@ void a11y::ProxyVirtualCursorChangeEvent(
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (aOldPosition != aNewPosition) {
|
if (aReason == nsIAccessiblePivot::REASON_POINT) {
|
||||||
if (aReason == nsIAccessiblePivot::REASON_POINT) {
|
sessionAcc->SendHoverEnterEvent(WrapperFor(aNewPosition));
|
||||||
sessionAcc->SendHoverEnterEvent(WrapperFor(aNewPosition));
|
} else {
|
||||||
} else {
|
RefPtr<AccessibleWrap> wrapperForNewPosition = WrapperFor(aNewPosition);
|
||||||
RefPtr<AccessibleWrap> wrapperForNewPosition = WrapperFor(aNewPosition);
|
sessionAcc->SendAccessibilityFocusedEvent(wrapperForNewPosition);
|
||||||
sessionAcc->SendAccessibilityFocusedEvent(wrapperForNewPosition);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (aBoundaryType != nsIAccessiblePivot::NO_BOUNDARY) {
|
if (aBoundaryType != nsIAccessiblePivot::NO_BOUNDARY) {
|
||||||
|
@ -3,8 +3,11 @@
|
|||||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
#include "ProxyAccessibleWrap.h"
|
#include "ProxyAccessibleWrap.h"
|
||||||
|
|
||||||
#include "nsPersistentProperties.h"
|
#include "nsPersistentProperties.h"
|
||||||
|
|
||||||
|
#include "mozilla/a11y/DocAccessiblePlatformExtParent.h"
|
||||||
|
|
||||||
using namespace mozilla::a11y;
|
using namespace mozilla::a11y;
|
||||||
|
|
||||||
ProxyAccessibleWrap::ProxyAccessibleWrap(ProxyAccessible* aProxy)
|
ProxyAccessibleWrap::ProxyAccessibleWrap(ProxyAccessible* aProxy)
|
||||||
@ -105,6 +108,43 @@ bool ProxyAccessibleWrap::GetSelectionBounds(int32_t* aStartOffset,
|
|||||||
return Proxy()->SelectionBoundsAt(0, unused, aStartOffset, aEndOffset);
|
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(); }
|
role ProxyAccessibleWrap::WrapperRole() { return Proxy()->Role(); }
|
||||||
|
|
||||||
AccessibleWrap* ProxyAccessibleWrap::WrapperParent() {
|
AccessibleWrap* ProxyAccessibleWrap::WrapperParent() {
|
||||||
|
@ -57,6 +57,23 @@ class ProxyAccessibleWrap : public AccessibleWrap {
|
|||||||
virtual bool GetSelectionBounds(int32_t* aStartOffset,
|
virtual bool GetSelectionBounds(int32_t* aStartOffset,
|
||||||
int32_t* aEndOffset) override;
|
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;
|
virtual void WrapperDOMNodeID(nsString& aDOMNodeID) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@ -30,6 +30,16 @@
|
|||||||
} while (0)
|
} while (0)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#define FORWARD_ACTION_TO_ACCESSIBLE(funcname, ...) \
|
||||||
|
if (RootAccessibleWrap* rootAcc = GetRoot()) { \
|
||||||
|
AccessibleWrap* acc = rootAcc->FindAccessibleById(aID); \
|
||||||
|
if (!acc) { \
|
||||||
|
return; \
|
||||||
|
} \
|
||||||
|
\
|
||||||
|
acc->funcname(__VA_ARGS__); \
|
||||||
|
}
|
||||||
|
|
||||||
template <>
|
template <>
|
||||||
const char nsWindow::NativePtr<mozilla::a11y::SessionAccessibility>::sName[] =
|
const char nsWindow::NativePtr<mozilla::a11y::SessionAccessibility>::sName[] =
|
||||||
"SessionAccessibility";
|
"SessionAccessibility";
|
||||||
@ -97,25 +107,45 @@ RootAccessibleWrap* SessionAccessibility::GetRoot() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void SessionAccessibility::SetText(int32_t aID, jni::String::Param aText) {
|
void SessionAccessibility::SetText(int32_t aID, jni::String::Param aText) {
|
||||||
if (RootAccessibleWrap* rootAcc = GetRoot()) {
|
FORWARD_ACTION_TO_ACCESSIBLE(SetTextContents, aText->ToString());
|
||||||
AccessibleWrap* acc = rootAcc->FindAccessibleById(aID);
|
|
||||||
if (!acc) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
acc->SetTextContents(aText->ToString());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void SessionAccessibility::Click(int32_t aID) {
|
void SessionAccessibility::Click(int32_t aID) {
|
||||||
if (RootAccessibleWrap* rootAcc = GetRoot()) {
|
FORWARD_ACTION_TO_ACCESSIBLE(DoAction, 0);
|
||||||
AccessibleWrap* acc = rootAcc->FindAccessibleById(aID);
|
}
|
||||||
if (!acc) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
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(
|
SessionAccessibility* SessionAccessibility::GetInstanceFor(
|
||||||
@ -417,3 +447,5 @@ void SessionAccessibility::UpdateCachedBounds(
|
|||||||
mSessionAccessibility->UpdateCachedBounds(infos);
|
mSessionAccessibility->UpdateCachedBounds(infos);
|
||||||
SendWindowContentChangedEvent();
|
SendWindowContentChangedEvent();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#undef FORWARD_ACTION_TO_ACCESSIBLE
|
@ -53,6 +53,14 @@ class SessionAccessibility final
|
|||||||
jni::Object::LocalRef GetNodeInfo(int32_t aID);
|
jni::Object::LocalRef GetNodeInfo(int32_t aID);
|
||||||
void SetText(int32_t aID, jni::String::Param aText);
|
void SetText(int32_t aID, jni::String::Param aText);
|
||||||
void Click(int32_t aID);
|
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();
|
void StartNativeAccessibility();
|
||||||
|
|
||||||
// Event methods
|
// 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',
|
EXPORTS.mozilla.a11y += ['AccessibleWrap.h',
|
||||||
'HyperTextAccessibleWrap.h',
|
'HyperTextAccessibleWrap.h',
|
||||||
'SessionAccessibility.h',
|
'SessionAccessibility.h',
|
||||||
|
'TraversalRule.h',
|
||||||
]
|
]
|
||||||
|
|
||||||
SOURCES += [
|
SOURCES += [
|
||||||
@ -14,6 +15,7 @@ SOURCES += [
|
|||||||
'ProxyAccessibleWrap.cpp',
|
'ProxyAccessibleWrap.cpp',
|
||||||
'RootAccessibleWrap.cpp',
|
'RootAccessibleWrap.cpp',
|
||||||
'SessionAccessibility.cpp',
|
'SessionAccessibility.cpp',
|
||||||
|
'TraversalRule.cpp',
|
||||||
]
|
]
|
||||||
|
|
||||||
LOCAL_INCLUDES += [
|
LOCAL_INCLUDES += [
|
||||||
@ -22,6 +24,7 @@ LOCAL_INCLUDES += [
|
|||||||
'/accessible/html',
|
'/accessible/html',
|
||||||
'/accessible/ipc',
|
'/accessible/ipc',
|
||||||
'/accessible/ipc/other',
|
'/accessible/ipc/other',
|
||||||
|
'/accessible/xpcom',
|
||||||
'/accessible/xul',
|
'/accessible/xul',
|
||||||
'/dom/base',
|
'/dom/base',
|
||||||
'/widget',
|
'/widget',
|
||||||
|
@ -62,7 +62,7 @@ class AccessibleWrap : public Accessible {
|
|||||||
|
|
||||||
static const char* ReturnString(nsAString& aString) {
|
static const char* ReturnString(nsAString& aString) {
|
||||||
static nsCString returnedString;
|
static nsCString returnedString;
|
||||||
returnedString = NS_ConvertUTF16toUTF8(aString);
|
CopyUTF16toUTF8(aString, returnedString);
|
||||||
return returnedString.get();
|
return returnedString.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -72,16 +72,10 @@ RelatedAccIterator::RelatedAccIterator(DocAccessible* aDocument,
|
|||||||
: mDocument(aDocument),
|
: mDocument(aDocument),
|
||||||
mRelAttr(aRelAttr),
|
mRelAttr(aRelAttr),
|
||||||
mProviders(nullptr),
|
mProviders(nullptr),
|
||||||
mBindingParent(nullptr),
|
|
||||||
mIndex(0) {
|
mIndex(0) {
|
||||||
mBindingParent = aDependentContent->IsInAnonymousSubtree()
|
|
||||||
? aDependentContent->GetBindingParent()
|
|
||||||
: nullptr;
|
|
||||||
nsAtom* IDAttr = mBindingParent ? nsGkAtoms::anonid : nsGkAtoms::id;
|
|
||||||
|
|
||||||
nsAutoString id;
|
nsAutoString id;
|
||||||
if (aDependentContent->IsElement() &&
|
if (aDependentContent->IsElement() &&
|
||||||
aDependentContent->AsElement()->GetAttr(kNameSpaceID_None, IDAttr, id)) {
|
aDependentContent->AsElement()->GetAttr(kNameSpaceID_None, nsGkAtoms::id, id)) {
|
||||||
mProviders = mDocument->GetRelProviders(aDependentContent->AsElement(), id);
|
mProviders = mDocument->GetRelProviders(aDependentContent->AsElement(), id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -92,22 +86,17 @@ Accessible* RelatedAccIterator::Next() {
|
|||||||
while (mIndex < mProviders->Length()) {
|
while (mIndex < mProviders->Length()) {
|
||||||
DocAccessible::AttrRelProvider* provider = (*mProviders)[mIndex++];
|
DocAccessible::AttrRelProvider* provider = (*mProviders)[mIndex++];
|
||||||
|
|
||||||
// Return related accessible for the given attribute and if the provider
|
// Return related accessible for the given attribute.
|
||||||
// content is in the same binding in the case of XBL usage.
|
|
||||||
if (provider->mRelAttr == mRelAttr) {
|
if (provider->mRelAttr == mRelAttr) {
|
||||||
nsIContent* bindingParent = provider->mContent->IsInAnonymousSubtree()
|
Accessible* related = mDocument->GetAccessible(provider->mContent);
|
||||||
? provider->mContent->GetBindingParent()
|
if (related) {
|
||||||
: nullptr;
|
return related;
|
||||||
bool inScope = mBindingParent == bindingParent ||
|
}
|
||||||
mBindingParent == provider->mContent;
|
|
||||||
|
|
||||||
if (inScope) {
|
// If the document content is pointed by relation then return the
|
||||||
Accessible* related = mDocument->GetAccessible(provider->mContent);
|
// document itself.
|
||||||
if (related) return related;
|
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;
|
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.
|
// Get elements in DOM tree by ID attribute if this is an explicit content.
|
||||||
// In case of bound element check its anonymous subtree.
|
// In case of bound element check its anonymous subtree.
|
||||||
if (!mContent->IsInAnonymousSubtree()) {
|
if (!aContent->IsInAnonymousSubtree()) {
|
||||||
dom::DocumentOrShadowRoot* docOrShadowRoot =
|
dom::DocumentOrShadowRoot* docOrShadowRoot =
|
||||||
mContent->GetUncomposedDocOrConnectedShadowRoot();
|
aContent->GetUncomposedDocOrConnectedShadowRoot();
|
||||||
if (docOrShadowRoot) {
|
if (docOrShadowRoot) {
|
||||||
dom::Element* refElm = docOrShadowRoot->GetElementById(aID);
|
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;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
dom::Element* IDRefsIterator::GetElem(const nsDependentSubstring& aID) {
|
||||||
|
return GetElem(mContent, aID);
|
||||||
|
}
|
||||||
|
|
||||||
Accessible* IDRefsIterator::Next() {
|
Accessible* IDRefsIterator::Next() {
|
||||||
nsIContent* nextEl = nullptr;
|
nsIContent* nextEl = nullptr;
|
||||||
while ((nextEl = NextElem())) {
|
while ((nextEl = NextElem())) {
|
||||||
|
@ -95,7 +95,6 @@ class RelatedAccIterator : public AccIterable {
|
|||||||
DocAccessible* mDocument;
|
DocAccessible* mDocument;
|
||||||
nsAtom* mRelAttr;
|
nsAtom* mRelAttr;
|
||||||
DocAccessible::AttrRelProviders* mProviders;
|
DocAccessible::AttrRelProviders* mProviders;
|
||||||
nsIContent* mBindingParent;
|
|
||||||
uint32_t mIndex;
|
uint32_t mIndex;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -217,7 +216,8 @@ class IDRefsIterator : public AccIterable {
|
|||||||
/**
|
/**
|
||||||
* Return the element with the given ID.
|
* 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
|
// AccIterable
|
||||||
virtual Accessible* Next() override;
|
virtual Accessible* Next() override;
|
||||||
|
@ -412,35 +412,9 @@ void NotificationController::ScheduleChildDocBinding(DocAccessible* aDocument) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void NotificationController::ScheduleContentInsertion(
|
void NotificationController::ScheduleContentInsertion(
|
||||||
nsIContent* aStartChildNode, nsIContent* aEndChildNode) {
|
Accessible* aContainer, nsTArray<nsCOMPtr<nsIContent>>& aInsertions) {
|
||||||
// The frame constructor guarantees that only ranges with the same parent
|
if (!aInsertions.IsEmpty()) {
|
||||||
// arrive here in presence of dynamic changes to the page, see
|
mContentInsertions.LookupOrAdd(aContainer)->AppendElements(aInsertions);
|
||||||
// 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);
|
|
||||||
ScheduleProcessing();
|
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
|
// Process invalidation list of the document after all accessible tree
|
||||||
// modification are done.
|
// mutation is done.
|
||||||
mDocument->ProcessInvalidationList();
|
mDocument->ProcessInvalidationList();
|
||||||
|
|
||||||
// Process relocation list.
|
// Process relocation list.
|
||||||
@ -852,6 +816,20 @@ void NotificationController::WillRefresh(mozilla::TimeStamp aTime) {
|
|||||||
}
|
}
|
||||||
mRelocations.Clear();
|
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
|
// 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
|
// process it synchronously. However we do not want to reenter if fireing
|
||||||
// events causes script to run.
|
// events causes script to run.
|
||||||
@ -924,6 +902,7 @@ void NotificationController::WillRefresh(mozilla::TimeStamp aTime) {
|
|||||||
if (browserChild) {
|
if (browserChild) {
|
||||||
static_cast<BrowserChild*>(browserChild.get())
|
static_cast<BrowserChild*>(browserChild.get())
|
||||||
->SendPDocAccessibleConstructor(ipcDoc, parentIPCDoc, id, 0, 0);
|
->SendPDocAccessibleConstructor(ipcDoc, parentIPCDoc, id, 0, 0);
|
||||||
|
ipcDoc->SendPDocAccessiblePlatformExtConstructor();
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
@ -190,8 +190,8 @@ class NotificationController final : public EventQueue,
|
|||||||
/**
|
/**
|
||||||
* Pend accessible tree update for content insertion.
|
* Pend accessible tree update for content insertion.
|
||||||
*/
|
*/
|
||||||
void ScheduleContentInsertion(nsIContent* aStartChildNode,
|
void ScheduleContentInsertion(Accessible* aContainer,
|
||||||
nsIContent* aEndChildNode);
|
nsTArray<nsCOMPtr<nsIContent>>& aInsertions);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Pend an accessible subtree relocation.
|
* Pend an accessible subtree relocation.
|
||||||
|
@ -27,8 +27,7 @@ TreeWalker::TreeWalker(Accessible* aContext)
|
|||||||
mChildFilter(nsIContent::eSkipPlaceholderContent),
|
mChildFilter(nsIContent::eSkipPlaceholderContent),
|
||||||
mFlags(0),
|
mFlags(0),
|
||||||
mPhase(eAtStart) {
|
mPhase(eAtStart) {
|
||||||
mChildFilter |=
|
mChildFilter |= nsIContent::eAllChildren;
|
||||||
mContext->NoXBLKids() ? nsIContent::eAllButXBL : nsIContent::eAllChildren;
|
|
||||||
|
|
||||||
mAnchorNode = mContext->IsDoc() ? mDoc->DocumentNode()->GetRootElement()
|
mAnchorNode = mContext->IsDoc() ? mDoc->DocumentNode()->GetRootElement()
|
||||||
: mContext->GetContent();
|
: mContext->GetContent();
|
||||||
@ -49,8 +48,7 @@ TreeWalker::TreeWalker(Accessible* aContext, nsIContent* aAnchorNode,
|
|||||||
"This constructor cannot be used for tree creation");
|
"This constructor cannot be used for tree creation");
|
||||||
MOZ_ASSERT(aAnchorNode, "No anchor node for the accessible tree walker");
|
MOZ_ASSERT(aAnchorNode, "No anchor node for the accessible tree walker");
|
||||||
|
|
||||||
mChildFilter |=
|
mChildFilter |= nsIContent::eAllChildren;
|
||||||
mContext->NoXBLKids() ? nsIContent::eAllButXBL : nsIContent::eAllChildren;
|
|
||||||
|
|
||||||
MOZ_COUNT_CTOR(TreeWalker);
|
MOZ_COUNT_CTOR(TreeWalker);
|
||||||
}
|
}
|
||||||
@ -100,10 +98,16 @@ bool TreeWalker::Seek(nsIContent* aChildNode) {
|
|||||||
nsINode* parentNode = aChildNode;
|
nsINode* parentNode = aChildNode;
|
||||||
do {
|
do {
|
||||||
childNode = parentNode->AsContent();
|
childNode = parentNode->AsContent();
|
||||||
parentNode = childNode->HasFlag(NODE_MAY_BE_IN_BINDING_MNGR) &&
|
parentNode = childNode->GetFlattenedTreeParent();
|
||||||
(mChildFilter & nsIContent::eAllButXBL)
|
|
||||||
? childNode->GetParentNode()
|
// Handle the special case of XBL binding child under a shadow root.
|
||||||
: childNode->GetFlattenedTreeParent();
|
if (parentNode && parentNode->IsShadowRoot()) {
|
||||||
|
parentNode = childNode->GetFlattenedTreeParent();
|
||||||
|
if (parentNode == mAnchorNode) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
if (!parentNode || !parentNode->IsElement()) {
|
if (!parentNode || !parentNode->IsElement()) {
|
||||||
return false;
|
return false;
|
||||||
|
@ -82,15 +82,6 @@ XULMAP(popup, [](Element* aElement, Accessible* aContext) {
|
|||||||
return CreateMenupopupAccessible(aElement, 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* {
|
XULMAP(tree, [](Element* aElement, Accessible* aContext) -> Accessible* {
|
||||||
nsIContent* child =
|
nsIContent* child =
|
||||||
nsTreeUtils::GetDescendantChild(aElement, nsGkAtoms::treechildren);
|
nsTreeUtils::GetDescendantChild(aElement, nsGkAtoms::treechildren);
|
||||||
|
@ -79,7 +79,6 @@ LOCAL_INCLUDES += [
|
|||||||
'/accessible/xpcom',
|
'/accessible/xpcom',
|
||||||
'/accessible/xul',
|
'/accessible/xul',
|
||||||
'/dom/base',
|
'/dom/base',
|
||||||
'/dom/xbl',
|
|
||||||
'/ipc/chromium/src',
|
'/ipc/chromium/src',
|
||||||
'/layout/generic',
|
'/layout/generic',
|
||||||
'/layout/style',
|
'/layout/style',
|
||||||
|
@ -61,8 +61,6 @@
|
|||||||
#include "nsTreeBodyFrame.h"
|
#include "nsTreeBodyFrame.h"
|
||||||
#include "nsTreeColumns.h"
|
#include "nsTreeColumns.h"
|
||||||
#include "nsTreeUtils.h"
|
#include "nsTreeUtils.h"
|
||||||
#include "nsXBLPrototypeBinding.h"
|
|
||||||
#include "nsXBLBinding.h"
|
|
||||||
#include "mozilla/ArrayUtils.h"
|
#include "mozilla/ArrayUtils.h"
|
||||||
#include "mozilla/dom/DOMStringList.h"
|
#include "mozilla/dom/DOMStringList.h"
|
||||||
#include "mozilla/dom/EventTarget.h"
|
#include "mozilla/dom/EventTarget.h"
|
||||||
@ -935,7 +933,7 @@ Accessible* nsAccessibilityService::CreateAccessible(nsINode* aNode,
|
|||||||
if (!frame || !frame->StyleVisibility()->IsVisible()) {
|
if (!frame || !frame->StyleVisibility()->IsVisible()) {
|
||||||
// display:contents element doesn't have a frame, but retains the semantics.
|
// display:contents element doesn't have a frame, but retains the semantics.
|
||||||
// All its children are unaffected.
|
// All its children are unaffected.
|
||||||
if (content->IsElement() && content->AsElement()->IsDisplayContents()) {
|
if (nsCoreUtils::IsDisplayContents(content)) {
|
||||||
const HTMLMarkupMapInfo* markupMap =
|
const HTMLMarkupMapInfo* markupMap =
|
||||||
mHTMLMarkupMap.Get(content->NodeInfo()->NameAtom());
|
mHTMLMarkupMap.Get(content->NodeInfo()->NameAtom());
|
||||||
if (markupMap && markupMap->new_func) {
|
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()) {
|
if (!newAcc && content->IsXULElement()) {
|
||||||
// No accessible for not selected deck panel and its children.
|
// No accessible for not selected deck panel and its children.
|
||||||
if (!aContext->IsXULTabpanels()) {
|
if (!aContext->IsXULTabpanels()) {
|
||||||
@ -1133,6 +1131,8 @@ Accessible* nsAccessibilityService::CreateAccessible(nsINode* aNode,
|
|||||||
// polyline and image. A 'use' and 'text' graphic elements require
|
// polyline and image. A 'use' and 'text' graphic elements require
|
||||||
// special support.
|
// special support.
|
||||||
newAcc = new EnumRoleAccessible<roles::GRAPHIC>(content, document);
|
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)) {
|
} else if (content->IsSVGElement(nsGkAtoms::svg)) {
|
||||||
newAcc = new EnumRoleAccessible<roles::DIAGRAM>(content, document);
|
newAcc = new EnumRoleAccessible<roles::DIAGRAM>(content, document);
|
||||||
}
|
}
|
||||||
@ -1528,10 +1528,13 @@ void nsAccessibilityService::RemoveNativeRootAccessible(
|
|||||||
bool nsAccessibilityService::HasAccessible(nsINode* aDOMNode) {
|
bool nsAccessibilityService::HasAccessible(nsINode* aDOMNode) {
|
||||||
if (!aDOMNode) return false;
|
if (!aDOMNode) return false;
|
||||||
|
|
||||||
DocAccessible* document = GetDocAccessible(aDOMNode->OwnerDoc());
|
Document* document = aDOMNode->OwnerDoc();
|
||||||
if (!document) return false;
|
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);
|
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.
|
* Notify accessible event observers of an event.
|
||||||
*/
|
*/
|
||||||
static void DispatchAccEvent(RefPtr<nsIAccessibleEvent> aEvent);
|
static void DispatchAccEvent(RefPtr<nsIAccessibleEvent> aEvent);
|
||||||
|
|
||||||
|
static bool IsDisplayContents(nsIContent* aContent);
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -4,8 +4,6 @@
|
|||||||
|
|
||||||
#include "Accessible-inl.h"
|
#include "Accessible-inl.h"
|
||||||
|
|
||||||
#include "nsIXBLAccessible.h"
|
|
||||||
|
|
||||||
#include "EmbeddedObjCollector.h"
|
#include "EmbeddedObjCollector.h"
|
||||||
#include "AccGroupInfo.h"
|
#include "AccGroupInfo.h"
|
||||||
#include "AccIterator.h"
|
#include "AccIterator.h"
|
||||||
@ -28,7 +26,6 @@
|
|||||||
#include "TableAccessible.h"
|
#include "TableAccessible.h"
|
||||||
#include "TableCellAccessible.h"
|
#include "TableCellAccessible.h"
|
||||||
#include "TreeWalker.h"
|
#include "TreeWalker.h"
|
||||||
#include "XULDocument.h"
|
|
||||||
|
|
||||||
#include "nsIDOMXULButtonElement.h"
|
#include "nsIDOMXULButtonElement.h"
|
||||||
#include "nsIDOMXULSelectCntrlEl.h"
|
#include "nsIDOMXULSelectCntrlEl.h"
|
||||||
@ -131,12 +128,6 @@ ENameValueFlag Accessible::Name(nsString& aName) const {
|
|||||||
ARIAName(aName);
|
ARIAName(aName);
|
||||||
if (!aName.IsEmpty()) return eNameOK;
|
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);
|
ENameValueFlag nameFlag = NativeName(aName);
|
||||||
if (!aName.IsEmpty()) return nameFlag;
|
if (!aName.IsEmpty()) return nameFlag;
|
||||||
|
|
||||||
@ -229,8 +220,8 @@ KeyBinding Accessible::AccessKey() const {
|
|||||||
HTMLLabelIterator iter(Document(), this,
|
HTMLLabelIterator iter(Document(), this,
|
||||||
HTMLLabelIterator::eSkipAncestorLabel);
|
HTMLLabelIterator::eSkipAncestorLabel);
|
||||||
label = iter.Next();
|
label = iter.Next();
|
||||||
|
}
|
||||||
} else if (mContent->IsXULElement()) {
|
if (!label) {
|
||||||
XULLabelIterator iter(Document(), mContent);
|
XULLabelIterator iter(Document(), mContent);
|
||||||
label = iter.Next();
|
label = iter.Next();
|
||||||
}
|
}
|
||||||
@ -303,7 +294,7 @@ uint64_t Accessible::VisibilityState() const {
|
|||||||
if (!frame) {
|
if (!frame) {
|
||||||
// Element having display:contents is considered visible semantically,
|
// Element having display:contents is considered visible semantically,
|
||||||
// despite it doesn't have a visually visible box.
|
// despite it doesn't have a visually visible box.
|
||||||
if (mContent->IsElement() && mContent->AsElement()->IsDisplayContents()) {
|
if (nsCoreUtils::IsDisplayContents(mContent)) {
|
||||||
return states::OFFSCREEN;
|
return states::OFFSCREEN;
|
||||||
}
|
}
|
||||||
return states::INVISIBLE;
|
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,
|
void Accessible::XULElmName(DocAccessible* aDocument, nsIContent* aElm,
|
||||||
nsString& aName) {
|
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" ... >
|
// CASES #2 and #3 ------ label as a child or <label control="id" ... >
|
||||||
// </label>
|
// </label>
|
||||||
if (aName.IsEmpty()) {
|
if (aName.IsEmpty()) {
|
||||||
Accessible* label = nullptr;
|
NameFromAssociatedXULLabel(aDocument, aElm, aName);
|
||||||
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();
|
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) {
|
nsresult Accessible::HandleAccEvent(AccEvent* aEvent) {
|
||||||
@ -1591,9 +1561,8 @@ Relation Accessible::RelationByType(RelationType aType) const {
|
|||||||
new IDRefsIterator(mDoc, mContent, nsGkAtoms::aria_labelledby));
|
new IDRefsIterator(mDoc, mContent, nsGkAtoms::aria_labelledby));
|
||||||
if (mContent->IsHTMLElement()) {
|
if (mContent->IsHTMLElement()) {
|
||||||
rel.AppendIter(new HTMLLabelIterator(Document(), this));
|
rel.AppendIter(new HTMLLabelIterator(Document(), this));
|
||||||
} else if (mContent->IsXULElement()) {
|
|
||||||
rel.AppendIter(new XULLabelIterator(Document(), mContent));
|
|
||||||
}
|
}
|
||||||
|
rel.AppendIter(new XULLabelIterator(Document(), mContent));
|
||||||
|
|
||||||
return rel;
|
return rel;
|
||||||
}
|
}
|
||||||
@ -1718,11 +1687,10 @@ Relation Accessible::RelationByType(RelationType aType) const {
|
|||||||
// In XUL, use first <button default="true" .../> in the document
|
// In XUL, use first <button default="true" .../> in the document
|
||||||
dom::Document* doc = mContent->OwnerDoc();
|
dom::Document* doc = mContent->OwnerDoc();
|
||||||
nsIContent* buttonEl = nullptr;
|
nsIContent* buttonEl = nullptr;
|
||||||
if (doc->IsXULDocument()) {
|
if (doc->AllowXULXBL()) {
|
||||||
dom::XULDocument* xulDoc = doc->AsXULDocument();
|
|
||||||
nsCOMPtr<nsIHTMLCollection> possibleDefaultButtons =
|
nsCOMPtr<nsIHTMLCollection> possibleDefaultButtons =
|
||||||
xulDoc->GetElementsByAttribute(NS_LITERAL_STRING("default"),
|
doc->GetElementsByAttribute(NS_LITERAL_STRING("default"),
|
||||||
NS_LITERAL_STRING("true"));
|
NS_LITERAL_STRING("true"));
|
||||||
if (possibleDefaultButtons) {
|
if (possibleDefaultButtons) {
|
||||||
uint32_t length = possibleDefaultButtons->Length();
|
uint32_t length = possibleDefaultButtons->Length();
|
||||||
// Check for button in list of default="true" elements
|
// 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);
|
return Relation(mDoc, buttonEl);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1895,7 +1848,7 @@ void Accessible::AppendTextTo(nsAString& aText, uint32_t aStartOffset,
|
|||||||
|
|
||||||
nsIFrame* frame = GetFrame();
|
nsIFrame* frame = GetFrame();
|
||||||
if (!frame) {
|
if (!frame) {
|
||||||
if (mContent->IsElement() && mContent->AsElement()->IsDisplayContents()) {
|
if (nsCoreUtils::IsDisplayContents(mContent)) {
|
||||||
aText += kEmbeddedObjectChar;
|
aText += kEmbeddedObjectChar;
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
@ -1966,6 +1919,11 @@ ENameValueFlag Accessible::NativeName(nsString& aName) const {
|
|||||||
|
|
||||||
if (!aName.IsEmpty()) return eNameOK;
|
if (!aName.IsEmpty()) return eNameOK;
|
||||||
|
|
||||||
|
NameFromAssociatedXULLabel(mDoc, mContent, aName);
|
||||||
|
if (!aName.IsEmpty()) {
|
||||||
|
return eNameOK;
|
||||||
|
}
|
||||||
|
|
||||||
nsTextEquivUtils::GetNameFromSubtree(this, aName);
|
nsTextEquivUtils::GetNameFromSubtree(this, aName);
|
||||||
return aName.IsEmpty() ? eNameOK : eNameFromSubtree;
|
return aName.IsEmpty() ? eNameOK : eNameFromSubtree;
|
||||||
}
|
}
|
||||||
@ -2430,8 +2388,7 @@ Accessible* Accessible::CurrentItem() const {
|
|||||||
if (HasOwnContent() && mContent->IsElement() &&
|
if (HasOwnContent() && mContent->IsElement() &&
|
||||||
mContent->AsElement()->GetAttr(kNameSpaceID_None,
|
mContent->AsElement()->GetAttr(kNameSpaceID_None,
|
||||||
nsGkAtoms::aria_activedescendant, id)) {
|
nsGkAtoms::aria_activedescendant, id)) {
|
||||||
dom::Document* DOMDoc = mContent->OwnerDoc();
|
dom::Element* activeDescendantElm = IDRefsIterator::GetElem(mContent, id);
|
||||||
dom::Element* activeDescendantElm = DOMDoc->GetElementById(id);
|
|
||||||
if (activeDescendantElm) {
|
if (activeDescendantElm) {
|
||||||
if (mContent->IsInclusiveDescendantOf(activeDescendantElm)) {
|
if (mContent->IsInclusiveDescendantOf(activeDescendantElm)) {
|
||||||
// Don't want a cyclical descendant relationship. That would be bad.
|
// Don't want a cyclical descendant relationship. That would be bad.
|
||||||
|
@ -917,12 +917,6 @@ class Accessible : public nsISupports {
|
|||||||
mStateFlags &= ~eRelocated;
|
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
|
* Return true if the accessible allows accessible children from subtree of
|
||||||
* a DOM element of this accessible.
|
* a DOM element of this accessible.
|
||||||
@ -1028,11 +1022,10 @@ class Accessible : public nsISupports {
|
|||||||
eKidsMutating = 1 << 6, // subtree is being mutated
|
eKidsMutating = 1 << 6, // subtree is being mutated
|
||||||
eIgnoreDOMUIEvent = 1 << 7, // don't process DOM UI events for a11y events
|
eIgnoreDOMUIEvent = 1 << 7, // don't process DOM UI events for a11y events
|
||||||
eRelocated = 1 << 8, // accessible was moved in tree
|
eRelocated = 1 << 8, // accessible was moved in tree
|
||||||
eNoXBLKids = 1 << 9, // accessible don't allows XBL children
|
eNoKidsFromDOM = 1 << 9, // accessible doesn't allow children from DOM
|
||||||
eNoKidsFromDOM = 1 << 10, // accessible doesn't allow children from DOM
|
eHasTextKids = 1 << 10, // accessible have a text leaf in children
|
||||||
eHasTextKids = 1 << 11, // accessible have a text leaf in children
|
|
||||||
|
|
||||||
eLastStateFlag = eNoKidsFromDOM
|
eLastStateFlag = eHasTextKids
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -1063,6 +1056,13 @@ class Accessible : public nsISupports {
|
|||||||
*/
|
*/
|
||||||
void ARIAName(nsString& aName) const;
|
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.
|
* Return the name for XUL element.
|
||||||
*/
|
*/
|
||||||
@ -1136,7 +1136,7 @@ class Accessible : public nsISupports {
|
|||||||
nsTArray<Accessible*> mChildren;
|
nsTArray<Accessible*> mChildren;
|
||||||
int32_t mIndexInParent;
|
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 kContextFlagsBits = 2;
|
||||||
static const uint8_t kTypeBits = 6;
|
static const uint8_t kTypeBits = 6;
|
||||||
static const uint8_t kGenericTypesBits = 16;
|
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");
|
MOZ_ASSERT(mPresShell, "should have been given a pres shell");
|
||||||
mPresShell->SetDocAccessible(this);
|
mPresShell->SetDocAccessible(this);
|
||||||
|
|
||||||
// If this is a XUL Document, it should not implement nsHyperText
|
|
||||||
if (mDocumentNode && mDocumentNode->IsXULDocument())
|
|
||||||
mGenericTypes &= ~eHyperText;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
DocAccessible::~DocAccessible() {
|
DocAccessible::~DocAccessible() {
|
||||||
@ -198,10 +194,6 @@ role DocAccessible::NativeRole() const {
|
|||||||
return roles::CHROME_WINDOW;
|
return roles::CHROME_WINDOW;
|
||||||
|
|
||||||
if (itemType == nsIDocShellTreeItem::typeContent) {
|
if (itemType == nsIDocShellTreeItem::typeContent) {
|
||||||
#ifdef MOZ_XUL
|
|
||||||
if (mDocumentNode && mDocumentNode->IsXULDocument())
|
|
||||||
return roles::APPLICATION;
|
|
||||||
#endif
|
|
||||||
return roles::DOCUMENT;
|
return roles::DOCUMENT;
|
||||||
}
|
}
|
||||||
} else if (itemType == nsIDocShellTreeItem::typeContent) {
|
} else if (itemType == nsIDocShellTreeItem::typeContent) {
|
||||||
@ -343,13 +335,6 @@ void DocAccessible::URL(nsAString& aURL) const {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void DocAccessible::DocType(nsAString& aType) 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();
|
dom::DocumentType* docType = mDocumentNode->GetDoctype();
|
||||||
if (docType) docType->GetPublicId(aType);
|
if (docType) docType->GetPublicId(aType);
|
||||||
}
|
}
|
||||||
@ -686,7 +671,19 @@ void DocAccessible::AttributeWillChange(dom::Element* aElement,
|
|||||||
}
|
}
|
||||||
|
|
||||||
void DocAccessible::NativeAnonymousChildListChange(nsIContent* aContent,
|
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,
|
void DocAccessible::AttributeChanged(dom::Element* aElement,
|
||||||
int32_t aNameSpaceID, nsAtom* aAttribute,
|
int32_t aNameSpaceID, nsAtom* aAttribute,
|
||||||
@ -994,7 +991,7 @@ void DocAccessible::ARIAActiveDescendantChanged(Accessible* aAccessible) {
|
|||||||
nsAutoString id;
|
nsAutoString id;
|
||||||
if (elm->AsElement()->GetAttr(kNameSpaceID_None,
|
if (elm->AsElement()->GetAttr(kNameSpaceID_None,
|
||||||
nsGkAtoms::aria_activedescendant, id)) {
|
nsGkAtoms::aria_activedescendant, id)) {
|
||||||
dom::Element* activeDescendantElm = elm->OwnerDoc()->GetElementById(id);
|
dom::Element* activeDescendantElm = IDRefsIterator::GetElem(elm, id);
|
||||||
if (activeDescendantElm) {
|
if (activeDescendantElm) {
|
||||||
Accessible* activeDescendant = GetAccessible(activeDescendantElm);
|
Accessible* activeDescendant = GetAccessible(activeDescendantElm);
|
||||||
if (activeDescendant) {
|
if (activeDescendant) {
|
||||||
@ -1267,12 +1264,148 @@ void DocAccessible::ContentInserted(nsIContent* aStartChildNode,
|
|||||||
nsIContent* aEndChildNode) {
|
nsIContent* aEndChildNode) {
|
||||||
// Ignore content insertions until we constructed accessible tree. Otherwise
|
// Ignore content insertions until we constructed accessible tree. Otherwise
|
||||||
// schedule tree update on content insertion after layout.
|
// schedule tree update on content insertion after layout.
|
||||||
if (mNotificationController && HasLoadState(eTreeConstructed)) {
|
if (!mNotificationController || !HasLoadState(eTreeConstructed)) {
|
||||||
// Update the whole tree of this document accessible when the container is
|
return;
|
||||||
// null (document element is inserted or removed).
|
|
||||||
mNotificationController->ScheduleContentInsertion(aStartChildNode,
|
|
||||||
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 = 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) {
|
void DocAccessible::RecreateAccessible(nsIContent* aContent) {
|
||||||
@ -1394,6 +1527,9 @@ void DocAccessible::DoInitialUpdate() {
|
|||||||
#endif
|
#endif
|
||||||
browserChild->SendPDocAccessibleConstructor(ipcDoc, nullptr, 0,
|
browserChild->SendPDocAccessibleConstructor(ipcDoc, nullptr, 0,
|
||||||
childID, holder);
|
childID, holder);
|
||||||
|
#if !defined(XP_WIN)
|
||||||
|
ipcDoc->SendPDocAccessiblePlatformExtConstructor();
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
if (IsRoot()) {
|
if (IsRoot()) {
|
||||||
@ -1603,6 +1739,12 @@ bool DocAccessible::UpdateAccessibleOnAttrChange(dom::Element* aElement,
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (aAttribute == nsGkAtoms::type) {
|
||||||
|
// If the input[type] changes, we should recreate the accessible.
|
||||||
|
RecreateAccessible(aElement);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1659,6 +1801,7 @@ class InsertIterator final {
|
|||||||
TreeWalker mWalker;
|
TreeWalker mWalker;
|
||||||
|
|
||||||
const nsTArray<nsCOMPtr<nsIContent> >* mNodes;
|
const nsTArray<nsCOMPtr<nsIContent> >* mNodes;
|
||||||
|
nsTHashtable<nsPtrHashKey<const nsIContent>> mProcessedNodes;
|
||||||
uint32_t mNodesIdx;
|
uint32_t mNodesIdx;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -1684,7 +1827,15 @@ bool InsertIterator::Next() {
|
|||||||
// what means there's no container. Ignore the insertion too.
|
// what means there's no container. Ignore the insertion too.
|
||||||
nsIContent* prevNode = mNodes->SafeElementAt(mNodesIdx - 1);
|
nsIContent* prevNode = mNodes->SafeElementAt(mNodesIdx - 1);
|
||||||
nsIContent* node = mNodes->ElementAt(mNodesIdx++);
|
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()) {
|
if (container != Context()) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@ -1753,20 +1904,17 @@ void DocAccessible::ProcessContentInserted(
|
|||||||
do {
|
do {
|
||||||
Accessible* parent = iter.Child()->Parent();
|
Accessible* parent = iter.Child()->Parent();
|
||||||
if (parent) {
|
if (parent) {
|
||||||
if (parent != aContainer) {
|
Accessible* previousSibling = iter.ChildBefore();
|
||||||
|
if (parent != aContainer ||
|
||||||
|
iter.Child()->PrevSibling() != previousSibling) {
|
||||||
#ifdef A11Y_LOG
|
#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(),
|
"new parent", aContainer, "child", iter.Child(),
|
||||||
nullptr);
|
nullptr);
|
||||||
#endif
|
#endif
|
||||||
MOZ_ASSERT_UNREACHABLE("stealing accessible");
|
MoveChild(iter.Child(), aContainer,
|
||||||
continue;
|
previousSibling ? previousSibling->IndexInParent() + 1 : 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef A11Y_LOG
|
|
||||||
logging::TreeInfo("binding to same parent", logging::eVerbose, "parent",
|
|
||||||
aContainer, "child", iter.Child(), nullptr);
|
|
||||||
#endif
|
|
||||||
continue;
|
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,
|
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.
|
* 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 {
|
bool IsDependentID(dom::Element* aElement, const nsAString& aID) const {
|
||||||
return GetRelProviders(aElement, aID);
|
return GetRelProviders(aElement, aID);
|
||||||
@ -595,6 +591,19 @@ class DocAccessible : public HyperTextAccessibleWrap,
|
|||||||
*/
|
*/
|
||||||
void ARIAActiveDescendantIDMaybeMoved(dom::Element* aElm);
|
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:
|
protected:
|
||||||
/**
|
/**
|
||||||
* State and property flags, kept by mDocFlags.
|
* State and property flags, kept by mDocFlags.
|
||||||
|
@ -1792,18 +1792,20 @@ void HyperTextAccessible::Shutdown() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool HyperTextAccessible::RemoveChild(Accessible* aAccessible) {
|
bool HyperTextAccessible::RemoveChild(Accessible* aAccessible) {
|
||||||
int32_t childIndex = aAccessible->IndexInParent();
|
const int32_t childIndex = aAccessible->IndexInParent();
|
||||||
int32_t count = mOffsets.Length() - childIndex;
|
if (childIndex < static_cast<int64_t>(mOffsets.Length())) {
|
||||||
if (count > 0) mOffsets.RemoveElementsAt(childIndex, count);
|
mOffsets.RemoveLastElements(mOffsets.Length() -
|
||||||
|
aAccessible->IndexInParent());
|
||||||
|
}
|
||||||
|
|
||||||
return AccessibleWrap::RemoveChild(aAccessible);
|
return AccessibleWrap::RemoveChild(aAccessible);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool HyperTextAccessible::InsertChildAt(uint32_t aIndex, Accessible* aChild) {
|
bool HyperTextAccessible::InsertChildAt(uint32_t aIndex, Accessible* aChild) {
|
||||||
int32_t count = mOffsets.Length() - aIndex;
|
if (aIndex < mOffsets.Length()) {
|
||||||
if (count > 0) {
|
mOffsets.RemoveLastElements(mOffsets.Length() - aIndex);
|
||||||
mOffsets.RemoveElementsAt(aIndex, count);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return AccessibleWrap::InsertChildAt(aIndex, aChild);
|
return AccessibleWrap::InsertChildAt(aIndex, aChild);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -41,7 +41,7 @@
|
|||||||
#include "nsGlobalWindow.h"
|
#include "nsGlobalWindow.h"
|
||||||
|
|
||||||
#ifdef MOZ_XUL
|
#ifdef MOZ_XUL
|
||||||
# include "nsIXULWindow.h"
|
# include "nsIAppWindow.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
using namespace mozilla;
|
using namespace mozilla;
|
||||||
@ -78,33 +78,23 @@ ENameValueFlag RootAccessible::Name(nsString& aName) const {
|
|||||||
return eNameOK;
|
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
|
// RootAccessible protected member
|
||||||
#ifdef MOZ_XUL
|
#ifdef MOZ_XUL
|
||||||
uint32_t RootAccessible::GetChromeFlags() const {
|
uint32_t RootAccessible::GetChromeFlags() const {
|
||||||
// Return the flag set for the top level window as defined
|
// Return the flag set for the top level window as defined
|
||||||
// by nsIWebBrowserChrome::CHROME_WINDOW_[FLAGNAME]
|
// 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);
|
nsCOMPtr<nsIDocShell> docShell = nsCoreUtils::GetDocShellFor(mDocumentNode);
|
||||||
NS_ENSURE_TRUE(docShell, 0);
|
NS_ENSURE_TRUE(docShell, 0);
|
||||||
nsCOMPtr<nsIDocShellTreeOwner> treeOwner;
|
nsCOMPtr<nsIDocShellTreeOwner> treeOwner;
|
||||||
docShell->GetTreeOwner(getter_AddRefs(treeOwner));
|
docShell->GetTreeOwner(getter_AddRefs(treeOwner));
|
||||||
NS_ENSURE_TRUE(treeOwner, 0);
|
NS_ENSURE_TRUE(treeOwner, 0);
|
||||||
nsCOMPtr<nsIXULWindow> xulWin(do_GetInterface(treeOwner));
|
nsCOMPtr<nsIAppWindow> appWin(do_GetInterface(treeOwner));
|
||||||
if (!xulWin) {
|
if (!appWin) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
uint32_t chromeFlags;
|
uint32_t chromeFlags;
|
||||||
xulWin->GetChromeFlags(&chromeFlags);
|
appWin->GetChromeFlags(&chromeFlags);
|
||||||
return chromeFlags;
|
return chromeFlags;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
@ -29,7 +29,6 @@ class RootAccessible : public DocAccessibleWrap, public nsIDOMEventListener {
|
|||||||
virtual void Shutdown() override;
|
virtual void Shutdown() override;
|
||||||
virtual mozilla::a11y::ENameValueFlag Name(nsString& aName) const override;
|
virtual mozilla::a11y::ENameValueFlag Name(nsString& aName) const override;
|
||||||
virtual Relation RelationByType(RelationType aType) const override;
|
virtual Relation RelationByType(RelationType aType) const override;
|
||||||
virtual mozilla::a11y::role NativeRole() const override;
|
|
||||||
virtual uint64_t NativeState() const override;
|
virtual uint64_t NativeState() const override;
|
||||||
|
|
||||||
// RootAccessible
|
// RootAccessible
|
||||||
|
@ -163,11 +163,11 @@ role HTMLHeaderOrFooterAccessible::NativeRole() const {
|
|||||||
// If other sectioning or sectioning root elements, they become sections.
|
// If other sectioning or sectioning root elements, they become sections.
|
||||||
nsIContent* parent = mContent->GetParent();
|
nsIContent* parent = mContent->GetParent();
|
||||||
while (parent) {
|
while (parent) {
|
||||||
if (parent->IsAnyOfHTMLElements(nsGkAtoms::article, nsGkAtoms::aside,
|
if (parent->IsAnyOfHTMLElements(
|
||||||
nsGkAtoms::nav, nsGkAtoms::section,
|
nsGkAtoms::article, nsGkAtoms::aside, nsGkAtoms::nav,
|
||||||
nsGkAtoms::blockquote, nsGkAtoms::details,
|
nsGkAtoms::section, nsGkAtoms::main, nsGkAtoms::blockquote,
|
||||||
nsGkAtoms::dialog, nsGkAtoms::fieldset,
|
nsGkAtoms::details, nsGkAtoms::dialog, nsGkAtoms::fieldset,
|
||||||
nsGkAtoms::figure, nsGkAtoms::td)) {
|
nsGkAtoms::figure, nsGkAtoms::td)) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
parent = parent->GetParent();
|
parent = parent->GetParent();
|
||||||
|
@ -98,17 +98,16 @@ class HTMLTextFieldAccessible : public HyperTextAccessibleWrap {
|
|||||||
virtual ENameValueFlag NativeName(nsString& aName) const override;
|
virtual ENameValueFlag NativeName(nsString& aName) const override;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return a widget element this input is part of, for example, XUL:textbox or
|
* Return a widget element this input is part of, for example, search-textbox.
|
||||||
* HTML:input@type="number".
|
*
|
||||||
|
* FIXME: This should probably be renamed.
|
||||||
*/
|
*/
|
||||||
nsIContent* BindingOrWidgetParent() const {
|
nsIContent* BindingOrWidgetParent() const {
|
||||||
nsIContent* el = mContent->GetBindingParent();
|
if (auto* el = mContent->GetClosestNativeAnonymousSubtreeRootParent()) {
|
||||||
if (el) {
|
|
||||||
return el;
|
return el;
|
||||||
}
|
}
|
||||||
// XUL textboxes custom elements implementation.
|
// XUL search-textbox custom element
|
||||||
ErrorResult rv;
|
return Elm()->Closest(NS_LITERAL_STRING("search-textbox"), IgnoreErrors());
|
||||||
return Elm()->Closest(NS_LITERAL_STRING("textbox"), rv);
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -34,7 +34,6 @@ XPIDL_SOURCES += [
|
|||||||
'nsIAccessibleTypes.idl',
|
'nsIAccessibleTypes.idl',
|
||||||
'nsIAccessibleValue.idl',
|
'nsIAccessibleValue.idl',
|
||||||
'nsIAccessibleVirtualCursorChangeEvent.idl',
|
'nsIAccessibleVirtualCursorChangeEvent.idl',
|
||||||
'nsIXBLAccessible.idl',
|
|
||||||
]
|
]
|
||||||
|
|
||||||
XPIDL_MODULE = 'accessibility'
|
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 "mozilla/mscom/Ptr.h"
|
||||||
# include "nsWinUtils.h"
|
# include "nsWinUtils.h"
|
||||||
# include "RootAccessible.h"
|
# include "RootAccessible.h"
|
||||||
|
#else
|
||||||
|
# include "mozilla/a11y/DocAccessiblePlatformExtParent.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
namespace mozilla {
|
namespace mozilla {
|
||||||
@ -818,6 +820,23 @@ mozilla::ipc::IPCResult DocAccessibleParent::RecvBatch(
|
|||||||
# endif // defined(XP_WIN)
|
# endif // defined(XP_WIN)
|
||||||
return IPC_OK();
|
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)
|
#endif // !defined(XP_WIN)
|
||||||
|
|
||||||
} // namespace a11y
|
} // namespace a11y
|
||||||
|
@ -17,6 +17,10 @@ namespace a11y {
|
|||||||
|
|
||||||
class xpcAccessibleGeneric;
|
class xpcAccessibleGeneric;
|
||||||
|
|
||||||
|
#if !defined(XP_WIN)
|
||||||
|
class DocAccessiblePlatformExtParent;
|
||||||
|
#endif
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* These objects live in the main process and comunicate with and represent
|
* These objects live in the main process and comunicate with and represent
|
||||||
* an accessible document in a content process.
|
* an accessible document in a content process.
|
||||||
@ -225,6 +229,14 @@ class DocAccessibleParent : public ProxyAccessible,
|
|||||||
#if !defined(XP_WIN)
|
#if !defined(XP_WIN)
|
||||||
virtual mozilla::ipc::IPCResult RecvBatch(
|
virtual mozilla::ipc::IPCResult RecvBatch(
|
||||||
const uint64_t& aBatchType, nsTArray<BatchData>&& aData) override;
|
const uint64_t& aBatchType, nsTArray<BatchData>&& aData) override;
|
||||||
|
|
||||||
|
virtual bool DeallocPDocAccessiblePlatformExtParent(
|
||||||
|
PDocAccessiblePlatformExtParent* aActor) override;
|
||||||
|
|
||||||
|
virtual PDocAccessiblePlatformExtParent*
|
||||||
|
AllocPDocAccessiblePlatformExtParent() override;
|
||||||
|
|
||||||
|
DocAccessiblePlatformExtParent* GetPlatformExtension();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
private:
|
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
|
# 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/.
|
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||||
|
|
||||||
toolkit.jar:
|
if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'android':
|
||||||
content/global/accessibility/content-script.js (content-script.js)
|
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',
|
'/accessible/windows/msaa',
|
||||||
]
|
]
|
||||||
else:
|
else:
|
||||||
DIRS += ['other']
|
DIRS += ['other', 'extension']
|
||||||
LOCAL_INCLUDES += [
|
LOCAL_INCLUDES += [
|
||||||
'/accessible/ipc/other',
|
'/accessible/ipc/other',
|
||||||
]
|
]
|
||||||
|
@ -19,6 +19,7 @@
|
|||||||
# include "AccessibleWrap.h"
|
# include "AccessibleWrap.h"
|
||||||
#endif
|
#endif
|
||||||
#include "mozilla/PresShell.h"
|
#include "mozilla/PresShell.h"
|
||||||
|
#include "mozilla/a11y/DocAccessiblePlatformExtChild.h"
|
||||||
|
|
||||||
namespace mozilla {
|
namespace mozilla {
|
||||||
namespace a11y {
|
namespace a11y {
|
||||||
@ -1677,5 +1678,16 @@ mozilla::ipc::IPCResult DocAccessibleChild::RecvRestoreFocus() {
|
|||||||
return IPC_OK();
|
return IPC_OK();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool DocAccessibleChild::DeallocPDocAccessiblePlatformExtChild(
|
||||||
|
PDocAccessiblePlatformExtChild* aActor) {
|
||||||
|
delete aActor;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
PDocAccessiblePlatformExtChild*
|
||||||
|
DocAccessibleChild::AllocPDocAccessiblePlatformExtChild() {
|
||||||
|
return new DocAccessiblePlatformExtChild();
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace a11y
|
} // namespace a11y
|
||||||
} // namespace mozilla
|
} // namespace mozilla
|
||||||
|
@ -11,6 +11,7 @@ namespace mozilla {
|
|||||||
namespace a11y {
|
namespace a11y {
|
||||||
|
|
||||||
class Accessible;
|
class Accessible;
|
||||||
|
class DocAccessiblePlatformExtChild;
|
||||||
class HyperTextAccessible;
|
class HyperTextAccessible;
|
||||||
class TextLeafAccessible;
|
class TextLeafAccessible;
|
||||||
class ImageAccessible;
|
class ImageAccessible;
|
||||||
@ -22,6 +23,8 @@ class TableCellAccessible;
|
|||||||
* and their lifetime is the same as the document they represent.
|
* and their lifetime is the same as the document they represent.
|
||||||
*/
|
*/
|
||||||
class DocAccessibleChild : public DocAccessibleChildBase {
|
class DocAccessibleChild : public DocAccessibleChildBase {
|
||||||
|
friend DocAccessiblePlatformExtChild;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
DocAccessibleChild(DocAccessible* aDoc, IProtocol* aManager)
|
DocAccessibleChild(DocAccessible* aDoc, IProtocol* aManager)
|
||||||
: DocAccessibleChildBase(aDoc) {
|
: DocAccessibleChildBase(aDoc) {
|
||||||
@ -469,6 +472,12 @@ class DocAccessibleChild : public DocAccessibleChildBase {
|
|||||||
virtual mozilla::ipc::IPCResult RecvDOMNodeID(const uint64_t& aID,
|
virtual mozilla::ipc::IPCResult RecvDOMNodeID(const uint64_t& aID,
|
||||||
nsString* aDOMNodeID) override;
|
nsString* aDOMNodeID) override;
|
||||||
|
|
||||||
|
virtual bool DeallocPDocAccessiblePlatformExtChild(
|
||||||
|
PDocAccessiblePlatformExtChild* aActor) override;
|
||||||
|
|
||||||
|
virtual PDocAccessiblePlatformExtChild* AllocPDocAccessiblePlatformExtChild()
|
||||||
|
override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Accessible* IdToAccessible(const uint64_t& aID) const;
|
Accessible* IdToAccessible(const uint64_t& aID) const;
|
||||||
Accessible* IdToAccessibleLink(const uint64_t& aID) const;
|
Accessible* IdToAccessibleLink(const uint64_t& aID) const;
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
|
|
||||||
include protocol PFileDescriptorSet;
|
include protocol PFileDescriptorSet;
|
||||||
include protocol PBrowser;
|
include protocol PBrowser;
|
||||||
|
include protocol PDocAccessiblePlatformExt;
|
||||||
|
|
||||||
include "mozilla/GfxMessageUtils.h";
|
include "mozilla/GfxMessageUtils.h";
|
||||||
|
|
||||||
@ -69,8 +70,10 @@ struct RelationTargets
|
|||||||
nested(upto inside_sync) sync protocol PDocAccessible
|
nested(upto inside_sync) sync protocol PDocAccessible
|
||||||
{
|
{
|
||||||
manager PBrowser;
|
manager PBrowser;
|
||||||
|
manages PDocAccessiblePlatformExt;
|
||||||
|
|
||||||
parent:
|
parent:
|
||||||
|
async PDocAccessiblePlatformExt();
|
||||||
async Shutdown();
|
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',
|
'html',
|
||||||
'interfaces',
|
'interfaces',
|
||||||
'ipc',
|
'ipc',
|
||||||
'jsat',
|
|
||||||
'xpcom'
|
'xpcom'
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
[DEFAULT]
|
[DEFAULT]
|
||||||
support-files =
|
support-files =
|
||||||
head.js
|
head.js
|
||||||
!/accessible/tests/browser/events.js
|
|
||||||
!/accessible/tests/browser/shared-head.js
|
!/accessible/tests/browser/shared-head.js
|
||||||
!/accessible/tests/mochitest/*.js
|
!/accessible/tests/mochitest/*.js
|
||||||
!/accessible/tests/mochitest/letters.gif
|
!/accessible/tests/mochitest/letters.gif
|
||||||
|
@ -19,7 +19,7 @@ Services.scriptloader.loadSubScript(
|
|||||||
loadScripts(
|
loadScripts(
|
||||||
{ name: "common.js", dir: MOCHITESTS_DIR },
|
{ name: "common.js", dir: MOCHITESTS_DIR },
|
||||||
{ name: "layout.js", dir: MOCHITESTS_DIR },
|
{ name: "layout.js", dir: MOCHITESTS_DIR },
|
||||||
"events.js"
|
{ name: "promisified-events.js", dir: MOCHITESTS_DIR }
|
||||||
);
|
);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
[DEFAULT]
|
[DEFAULT]
|
||||||
skip-if = (os == 'win' && processor == 'aarch64') # 1534855
|
skip-if = (os == 'win' && processor == 'aarch64') # 1534855
|
||||||
support-files =
|
support-files =
|
||||||
events.js
|
!/accessible/tests/mochitest/*.js
|
||||||
head.js
|
head.js
|
||||||
shared-head.js
|
shared-head.js
|
||||||
|
|
||||||
|
@ -7,7 +7,6 @@ support-files =
|
|||||||
doc_treeupdate_removal.xhtml
|
doc_treeupdate_removal.xhtml
|
||||||
doc_treeupdate_visibility.html
|
doc_treeupdate_visibility.html
|
||||||
doc_treeupdate_whitespace.html
|
doc_treeupdate_whitespace.html
|
||||||
!/accessible/tests/browser/events.js
|
|
||||||
!/accessible/tests/browser/shared-head.js
|
!/accessible/tests/browser/shared-head.js
|
||||||
!/accessible/tests/mochitest/*.js
|
!/accessible/tests/mochitest/*.js
|
||||||
!/accessible/tests/mochitest/letters.gif
|
!/accessible/tests/mochitest/letters.gif
|
||||||
|
@ -46,14 +46,14 @@ const rules = {
|
|||||||
],
|
],
|
||||||
HTMLInputImage: [
|
HTMLInputImage: [
|
||||||
...HTMLControlHeadRule,
|
...HTMLControlHeadRule,
|
||||||
{ attr: "alt", recreated: true },
|
{ attr: "alt" },
|
||||||
{ attr: "value", recreated: true },
|
{ attr: "value" },
|
||||||
{ attr: "title" },
|
{ attr: "title" },
|
||||||
],
|
],
|
||||||
HTMLInputImageNoValidSrc: [
|
HTMLInputImageNoValidSrc: [
|
||||||
...HTMLControlHeadRule,
|
...HTMLControlHeadRule,
|
||||||
{ attr: "alt", recreated: true },
|
{ attr: "alt" },
|
||||||
{ attr: "value", recreated: true },
|
{ attr: "value" },
|
||||||
],
|
],
|
||||||
HTMLInputReset: [
|
HTMLInputReset: [
|
||||||
...HTMLControlHeadRule,
|
...HTMLControlHeadRule,
|
||||||
|
@ -9,15 +9,10 @@ loadScripts({ name: "role.js", dir: MOCHITESTS_DIR });
|
|||||||
|
|
||||||
addAccessibleTask(
|
addAccessibleTask(
|
||||||
`
|
`
|
||||||
<div id="container"><div id="scrollarea" style="overflow:auto;"><input>
|
<div id="container"><div id="scrollarea" style="overflow:auto;"><input>`,
|
||||||
</div></div>
|
|
||||||
<div id="container2"><div id="scrollarea2" style="overflow:hidden;">
|
|
||||||
</div></div>`,
|
|
||||||
async function(browser, accDoc) {
|
async function(browser, accDoc) {
|
||||||
const id1 = "container";
|
const id1 = "container";
|
||||||
const id2 = "container2";
|
|
||||||
const container = findAccessibleChildByID(accDoc, id1);
|
const container = findAccessibleChildByID(accDoc, id1);
|
||||||
const container2 = findAccessibleChildByID(accDoc, id2);
|
|
||||||
|
|
||||||
/* ================= Change scroll range ================================== */
|
/* ================= Change scroll range ================================== */
|
||||||
let tree = {
|
let tree = {
|
||||||
@ -60,26 +55,5 @@ addAccessibleTask(
|
|||||||
],
|
],
|
||||||
};
|
};
|
||||||
testAccessibleTree(container, tree);
|
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);
|
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
|
// Add CSS generated content to an element in container2's subtree
|
||||||
await invokeSetAttribute(browser, "container2_child", "class", "gentext");
|
await invokeSetAttribute(browser, "container2_child", "class", "gentext");
|
||||||
await onReorder;
|
await onReorder;
|
||||||
|
@ -12,5 +12,8 @@ Services.scriptloader.loadSubScript(
|
|||||||
);
|
);
|
||||||
|
|
||||||
// Loading and common.js from accessible/tests/mochitest/ for all tests, as
|
// Loading and common.js from accessible/tests/mochitest/ for all tests, as
|
||||||
// well as events.js.
|
// well as promisified-events.js.
|
||||||
loadScripts({ name: "common.js", dir: MOCHITESTS_DIR }, "events.js");
|
loadScripts(
|
||||||
|
{ name: "common.js", dir: MOCHITESTS_DIR },
|
||||||
|
{ name: "promisified-events.js", dir: MOCHITESTS_DIR }
|
||||||
|
);
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
[DEFAULT]
|
[DEFAULT]
|
||||||
support-files =
|
support-files =
|
||||||
head.js
|
head.js
|
||||||
!/accessible/tests/browser/events.js
|
|
||||||
!/accessible/tests/browser/shared-head.js
|
!/accessible/tests/browser/shared-head.js
|
||||||
!/accessible/tests/mochitest/*.js
|
!/accessible/tests/mochitest/*.js
|
||||||
|
|
||||||
|
@ -32,8 +32,10 @@ async function runTests(browser, accDoc) {
|
|||||||
evt = await onFocus;
|
evt = await onFocus;
|
||||||
testStates(evt.accessible, STATE_FOCUSED);
|
testStates(evt.accessible, STATE_FOCUSED);
|
||||||
|
|
||||||
let inputField = browser.ownerDocument.getElementById("urlbar").inputField;
|
onFocus = waitForEvent(
|
||||||
onFocus = waitForEvent(EVENT_FOCUS, getAccessible(inputField));
|
EVENT_FOCUS,
|
||||||
|
event => event.accessible.DOMNode == gURLBar.inputField
|
||||||
|
);
|
||||||
EventUtils.synthesizeKey("t", { accelKey: true }, browser.ownerGlobal);
|
EventUtils.synthesizeKey("t", { accelKey: true }, browser.ownerGlobal);
|
||||||
evt = await onFocus;
|
evt = await onFocus;
|
||||||
testStates(evt.accessible, STATE_FOCUSED);
|
testStates(evt.accessible, STATE_FOCUSED);
|
||||||
|
@ -24,6 +24,28 @@ function isEventForAutocompleteItem(event) {
|
|||||||
return event.accessible.role == ROLE_COMBOBOX_OPTION;
|
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.
|
* Wait for an autocomplete search to finish.
|
||||||
* This is necessary to ensure predictable results, as these searches are
|
* This is necessary to ensure predictable results, as these searches are
|
||||||
@ -134,6 +156,12 @@ async function runTests() {
|
|||||||
event = await focused;
|
event = await focused;
|
||||||
testStates(event.accessible, STATE_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");
|
info("Ensuring text box focus when text is typed");
|
||||||
focused = waitForEvent(EVENT_FOCUS, textBox);
|
focused = waitForEvent(EVENT_FOCUS, textBox);
|
||||||
EventUtils.sendString("z");
|
EventUtils.sendString("z");
|
||||||
@ -154,12 +182,20 @@ async function runTests() {
|
|||||||
await focused;
|
await focused;
|
||||||
testStates(textBox, STATE_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);
|
focused = waitForEvent(EVENT_FOCUS, isEventForAutocompleteItem);
|
||||||
EventUtils.synthesizeKey("KEY_ArrowDown");
|
EventUtils.synthesizeKey("KEY_ArrowDown");
|
||||||
// With the quantumbar enabled, we only get one result here, and arrow down
|
event = await focused;
|
||||||
// selects a one-off search button. We arrow back up to re-select the
|
testStates(event.accessible, STATE_FOCUSED);
|
||||||
// autocomplete result.
|
|
||||||
|
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");
|
EventUtils.synthesizeKey("KEY_ArrowUp");
|
||||||
event = await focused;
|
event = await focused;
|
||||||
testStates(event.accessible, STATE_FOCUSED);
|
testStates(event.accessible, STATE_FOCUSED);
|
||||||
@ -181,6 +217,34 @@ async function runTests() {
|
|||||||
event = await focused;
|
event = await focused;
|
||||||
testStates(event.accessible, STATE_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);
|
addAccessibleTask(``, runTests);
|
||||||
|
@ -30,7 +30,7 @@ async function checkURLBarCaretEvents() {
|
|||||||
});
|
});
|
||||||
info("Loaded " + kURL);
|
info("Loaded " + kURL);
|
||||||
|
|
||||||
let urlbarInputEl = newWin.document.getElementById("urlbar").inputField;
|
let urlbarInputEl = newWin.gURLBar.inputField;
|
||||||
let urlbarInput = getAccessible(urlbarInputEl, [nsIAccessibleText]);
|
let urlbarInput = getAccessible(urlbarInputEl, [nsIAccessibleText]);
|
||||||
|
|
||||||
let onCaretMove = waitForEvents([
|
let onCaretMove = waitForEvents([
|
||||||
|
@ -12,5 +12,8 @@ Services.scriptloader.loadSubScript(
|
|||||||
);
|
);
|
||||||
|
|
||||||
// Loading and common.js from accessible/tests/mochitest/ for all tests, as
|
// Loading and common.js from accessible/tests/mochitest/ for all tests, as
|
||||||
// well as events.js.
|
// well as promisified-events.js.
|
||||||
loadScripts({ name: "common.js", dir: MOCHITESTS_DIR }, "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",
|
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;
|
let resultsView;
|
||||||
resultsView = gURLBar.view.panel.querySelector("#urlbarView-results");
|
resultsView = gURLBar.view.panel.querySelector(".urlbarView-results");
|
||||||
await BrowserTestUtils.waitForCondition(() =>
|
await BrowserTestUtils.waitForCondition(() =>
|
||||||
accService.getAccessibleFor(resultsView)
|
accService.getAccessibleFor(resultsView)
|
||||||
);
|
);
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
[DEFAULT]
|
[DEFAULT]
|
||||||
support-files =
|
support-files =
|
||||||
head.js
|
head.js
|
||||||
!/accessible/tests/browser/events.js
|
|
||||||
!/accessible/tests/browser/shared-head.js
|
!/accessible/tests/browser/shared-head.js
|
||||||
!/accessible/tests/mochitest/*.js
|
!/accessible/tests/mochitest/*.js
|
||||||
|
|
||||||
|
@ -12,5 +12,8 @@ Services.scriptloader.loadSubScript(
|
|||||||
);
|
);
|
||||||
|
|
||||||
// Loading and common.js from accessible/tests/mochitest/ for all tests, as
|
// Loading and common.js from accessible/tests/mochitest/ for all tests, as
|
||||||
// well as events.js.
|
// well as promisified-events.js.
|
||||||
loadScripts({ name: "common.js", dir: MOCHITESTS_DIR }, "events.js");
|
loadScripts(
|
||||||
|
{ name: "common.js", dir: MOCHITESTS_DIR },
|
||||||
|
{ name: "promisified-events.js", dir: MOCHITESTS_DIR }
|
||||||
|
);
|
||||||
|
@ -5,13 +5,13 @@
|
|||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
/* import-globals-from ../mochitest/common.js */
|
/* import-globals-from ../mochitest/common.js */
|
||||||
/* import-globals-from events.js */
|
/* import-globals-from ../mochitest/promisified-events.js */
|
||||||
|
|
||||||
/* exported Logger, MOCHITESTS_DIR, invokeSetAttribute, invokeFocus,
|
/* exported Logger, MOCHITESTS_DIR, invokeSetAttribute, invokeFocus,
|
||||||
invokeSetStyle, getAccessibleDOMNodeID, getAccessibleTagName,
|
invokeSetStyle, getAccessibleDOMNodeID, getAccessibleTagName,
|
||||||
addAccessibleTask, findAccessibleChildByID, isDefunct,
|
addAccessibleTask, findAccessibleChildByID, isDefunct,
|
||||||
CURRENT_CONTENT_DIR, loadScripts, loadFrameScripts, snippetToURL,
|
CURRENT_CONTENT_DIR, loadScripts, loadFrameScripts, snippetToURL,
|
||||||
Cc, Cu, arrayFromChildren, forceGC */
|
Cc, Cu, arrayFromChildren, forceGC, contentSpawnMutation */
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Current browser test directory path used to load subscripts.
|
* 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}`);
|
Logger.log(`Setting focus on a node with id: ${id}`);
|
||||||
return ContentTask.spawn(browser, id, contentId => {
|
return ContentTask.spawn(browser, id, contentId => {
|
||||||
let elm = content.document.getElementById(contentId);
|
let elm = content.document.getElementById(contentId);
|
||||||
if (elm.editor || elm.localName == "textbox") {
|
if (elm.editor) {
|
||||||
elm.selectionStart = elm.selectionEnd = elm.value.length;
|
elm.selectionStart = elm.selectionEnd = elm.value.length;
|
||||||
}
|
}
|
||||||
elm.focus();
|
elm.focus();
|
||||||
@ -389,3 +389,42 @@ function forceGC() {
|
|||||||
SpecialPowers.forceShrinkingGC();
|
SpecialPowers.forceShrinkingGC();
|
||||||
SpecialPowers.forceCC();
|
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]
|
[DEFAULT]
|
||||||
support-files =
|
support-files =
|
||||||
head.js
|
head.js
|
||||||
!/accessible/tests/browser/events.js
|
|
||||||
!/accessible/tests/browser/shared-head.js
|
!/accessible/tests/browser/shared-head.js
|
||||||
!/accessible/tests/mochitest/*.js
|
!/accessible/tests/mochitest/*.js
|
||||||
|
|
||||||
|
@ -12,5 +12,8 @@ Services.scriptloader.loadSubScript(
|
|||||||
);
|
);
|
||||||
|
|
||||||
// Loading and common.js from accessible/tests/mochitest/ for all tests, as
|
// Loading and common.js from accessible/tests/mochitest/ for all tests, as
|
||||||
// well as events.js.
|
// well as promisified-events.js.
|
||||||
loadScripts({ name: "common.js", dir: MOCHITESTS_DIR }, "events.js");
|
loadScripts(
|
||||||
|
{ name: "common.js", dir: MOCHITESTS_DIR },
|
||||||
|
{ name: "promisified-events.js", dir: MOCHITESTS_DIR }
|
||||||
|
);
|
||||||
|
@ -1,9 +1,10 @@
|
|||||||
[DEFAULT]
|
[DEFAULT]
|
||||||
support-files =
|
support-files =
|
||||||
head.js
|
head.js
|
||||||
!/accessible/tests/browser/events.js
|
|
||||||
!/accessible/tests/browser/shared-head.js
|
!/accessible/tests/browser/shared-head.js
|
||||||
!/accessible/tests/mochitest/*.js
|
!/accessible/tests/mochitest/*.js
|
||||||
|
|
||||||
[browser_aria_owns.js]
|
[browser_aria_owns.js]
|
||||||
skip-if = true || (verify && !debug && (os == 'linux')) #Bug 1445513
|
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
|
// Loading and common.js from accessible/tests/mochitest/ for all tests, as
|
||||||
// well as events.js.
|
// well as promisified-events.js.
|
||||||
loadScripts({ name: "common.js", dir: MOCHITESTS_DIR }, "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
|
* 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 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
|
asserts-if(!browserIsRemote,2) load 884202.html
|
||||||
load 890760.html
|
load 890760.html
|
||||||
load 893515.html
|
load 893515.html
|
||||||
@ -12,6 +12,6 @@ load 1494707.html
|
|||||||
load 1503964.html
|
load 1503964.html
|
||||||
load 1655983.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.
|
# 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.
|
* // used with 'events', if missing then 'ID' is used instead.
|
||||||
* get targetID() {},
|
* 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'
|
* // [optional] perform checks when 'click' event is handled if 'events'
|
||||||
* // is used.
|
* // is used.
|
||||||
* checkOnClickEvent: function() {},
|
* checkOnClickEvent: function() {},
|
||||||
@ -182,6 +186,17 @@ function checkerOfActionInvoker(aType, aTarget, aActionObj) {
|
|||||||
this.eventTarget = aActionObj.eventTarget;
|
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.phase = false;
|
||||||
|
|
||||||
this.getID = function getID() {
|
this.getID = function getID() {
|
||||||
|
@ -7,11 +7,11 @@ support-files =
|
|||||||
[test_aria.html]
|
[test_aria.html]
|
||||||
[test_controls.html]
|
[test_controls.html]
|
||||||
[test_general.html]
|
[test_general.html]
|
||||||
[test_general.xul]
|
[test_general.xhtml]
|
||||||
[test_keys.html]
|
[test_keys.html]
|
||||||
[test_keys_menu.xul]
|
[test_keys.xhtml]
|
||||||
[test_link.html]
|
[test_link.html]
|
||||||
[test_media.html]
|
[test_media.html]
|
||||||
[test_select.html]
|
[test_select.html]
|
||||||
[test_tree.xul]
|
[test_tree.xhtml]
|
||||||
[test_treegrid.xul]
|
[test_treegrid.xhtml]
|
||||||
|
@ -7,6 +7,7 @@
|
|||||||
|
|
||||||
|
|
||||||
<window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
|
<window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
|
||||||
|
xmlns:html="http://www.w3.org/1999/xhtml"
|
||||||
title="nsIAccessible actions testing">
|
title="nsIAccessible actions testing">
|
||||||
|
|
||||||
<script src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js" />
|
<script src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js" />
|
||||||
@ -17,6 +18,10 @@
|
|||||||
src="../events.js" />
|
src="../events.js" />
|
||||||
<script type="application/javascript"
|
<script type="application/javascript"
|
||||||
src="../actions.js" />
|
src="../actions.js" />
|
||||||
|
<script type="application/javascript"
|
||||||
|
src="../role.js" />
|
||||||
|
<script type="application/javascript"
|
||||||
|
src="../states.js" />
|
||||||
|
|
||||||
<script type="application/javascript">
|
<script type="application/javascript">
|
||||||
<![CDATA[
|
<![CDATA[
|
||||||
@ -71,6 +76,22 @@
|
|||||||
ID: "labelWithPopup",
|
ID: "labelWithPopup",
|
||||||
actionName: "click",
|
actionName: "click",
|
||||||
events: CLICK_EVENTS
|
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
|
}/*, // XXX: bug 490288
|
||||||
{
|
{
|
||||||
ID: "buttonmenu_item",
|
ID: "buttonmenu_item",
|
||||||
@ -136,7 +157,14 @@
|
|||||||
tabindex="0"/>
|
tabindex="0"/>
|
||||||
<hbox>
|
<hbox>
|
||||||
<label id="name_entry_label" value="Name" control="name_entry"/>
|
<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>
|
</hbox>
|
||||||
</vbox>
|
</vbox>
|
||||||
</hbox>
|
</hbox>
|
@ -4,6 +4,7 @@
|
|||||||
type="text/css"?>
|
type="text/css"?>
|
||||||
|
|
||||||
<window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
|
<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">
|
title="Accessible XUL access keys and shortcut keys tests">
|
||||||
|
|
||||||
<script src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js" />
|
<script src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js" />
|
||||||
@ -17,8 +18,8 @@
|
|||||||
<![CDATA[
|
<![CDATA[
|
||||||
function openMenu(aMenuID, aMenuitemID)
|
function openMenu(aMenuID, aMenuitemID)
|
||||||
{
|
{
|
||||||
this.menuNode = getNode(aMenuID),
|
this.menuNode = getNode(aMenuID);
|
||||||
this.menuitemNode = getNode(aMenuitemID),
|
this.menuitemNode = getNode(aMenuitemID);
|
||||||
|
|
||||||
this.eventSeq = [
|
this.eventSeq = [
|
||||||
new invokerChecker(EVENT_FOCUS, this.menuNode)
|
new invokerChecker(EVENT_FOCUS, this.menuNode)
|
||||||
@ -53,6 +54,11 @@
|
|||||||
var gQueue = null;
|
var gQueue = null;
|
||||||
function doTest()
|
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 = new eventQueue();
|
||||||
gQueue.push(new openMenu("menu", "menuitem"));
|
gQueue.push(new openMenu("menu", "menuitem"));
|
||||||
gQueue.invoke(); // Will call SimpleTest.finish();
|
gQueue.invoke(); // Will call SimpleTest.finish();
|
||||||
@ -78,6 +84,9 @@
|
|||||||
</body>
|
</body>
|
||||||
|
|
||||||
<vbox flex="1">
|
<vbox flex="1">
|
||||||
|
<label control="input" accesskey="i">input</label>
|
||||||
|
<html:input id="input"/>
|
||||||
|
|
||||||
<keyset>
|
<keyset>
|
||||||
<key key="l" modifiers="control" id="key1"/>
|
<key key="l" modifiers="control" id="key1"/>
|
||||||
</keyset>
|
</keyset>
|
@ -7,9 +7,9 @@ support-files =
|
|||||||
[test_listbox.html]
|
[test_listbox.html]
|
||||||
[test_obj.html]
|
[test_obj.html]
|
||||||
[test_obj_css.html]
|
[test_obj_css.html]
|
||||||
[test_obj_css.xul]
|
[test_obj_css.xhtml]
|
||||||
[test_obj_group.html]
|
[test_obj_group.html]
|
||||||
[test_obj_group.xul]
|
[test_obj_group.xhtml]
|
||||||
[test_obj_group_tree.xul]
|
[test_obj_group_tree.xhtml]
|
||||||
[test_tag.html]
|
[test_tag.html]
|
||||||
[test_xml-roles.html]
|
[test_xml-roles.html]
|
||||||
|
@ -12,7 +12,7 @@
|
|||||||
<script type="application/javascript"
|
<script type="application/javascript"
|
||||||
src="../attributes.js"></script>
|
src="../attributes.js"></script>
|
||||||
<script type="application/javascript"
|
<script type="application/javascript"
|
||||||
src="../events.js"></script>
|
src="../promisified-events.js"></script>
|
||||||
|
|
||||||
<script type="application/javascript">
|
<script type="application/javascript">
|
||||||
async function doTest() {
|
async function doTest() {
|
||||||
@ -25,7 +25,7 @@
|
|||||||
testGroupAttrs("f", 6, 6);
|
testGroupAttrs("f", 6, 6);
|
||||||
// Remove c, reducing the set to 5.
|
// Remove c, reducing the set to 5.
|
||||||
let listbox = getAccessible("listbox");
|
let listbox = getAccessible("listbox");
|
||||||
let updated = waitForEventPromise(EVENT_REORDER, listbox);
|
let updated = waitForEvent(EVENT_REORDER, listbox);
|
||||||
c.remove();
|
c.remove();
|
||||||
await updated;
|
await updated;
|
||||||
testGroupAttrs("a", 1, 5);
|
testGroupAttrs("a", 1, 5);
|
||||||
@ -34,7 +34,7 @@
|
|||||||
testGroupAttrs("e", 4, 5);
|
testGroupAttrs("e", 4, 5);
|
||||||
testGroupAttrs("f", 5, 5);
|
testGroupAttrs("f", 5, 5);
|
||||||
// Now, remove the first element.
|
// Now, remove the first element.
|
||||||
updated = waitForEventPromise(EVENT_REORDER, listbox);
|
updated = waitForEvent(EVENT_REORDER, listbox);
|
||||||
a.remove();
|
a.remove();
|
||||||
await updated;
|
await updated;
|
||||||
testGroupAttrs("b", 1, 4);
|
testGroupAttrs("b", 1, 4);
|
||||||
@ -42,14 +42,14 @@
|
|||||||
testGroupAttrs("e", 3, 4);
|
testGroupAttrs("e", 3, 4);
|
||||||
testGroupAttrs("f", 4, 4);
|
testGroupAttrs("f", 4, 4);
|
||||||
// Remove the last item.
|
// Remove the last item.
|
||||||
updated = waitForEventPromise(EVENT_REORDER, listbox);
|
updated = waitForEvent(EVENT_REORDER, listbox);
|
||||||
f.remove();
|
f.remove();
|
||||||
await updated;
|
await updated;
|
||||||
testGroupAttrs("b", 1, 3);
|
testGroupAttrs("b", 1, 3);
|
||||||
testGroupAttrs("d", 2, 3);
|
testGroupAttrs("d", 2, 3);
|
||||||
testGroupAttrs("e", 3, 3);
|
testGroupAttrs("e", 3, 3);
|
||||||
// Finally, remove the middle item.
|
// Finally, remove the middle item.
|
||||||
updated = waitForEventPromise(EVENT_REORDER, listbox);
|
updated = waitForEvent(EVENT_REORDER, listbox);
|
||||||
d.remove();
|
d.remove();
|
||||||
await updated;
|
await updated;
|
||||||
testGroupAttrs("b", 1, 2);
|
testGroupAttrs("b", 1, 2);
|
||||||
@ -76,7 +76,7 @@
|
|||||||
<div id="d" role="option">Option d</div>
|
<div id="d" role="option">Option d</div>
|
||||||
<div id="e" role="option">Option e</div>
|
<div id="e" role="option">Option e</div>
|
||||||
<div id="f" role="option">Option f</div>
|
<div id="f" role="option">Option f</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
@ -25,7 +25,6 @@
|
|||||||
testCSSAttrs("display_mozgrid");
|
testCSSAttrs("display_mozgrid");
|
||||||
testCSSAttrs("display_mozgridgroup");
|
testCSSAttrs("display_mozgridgroup");
|
||||||
testCSSAttrs("display_mozgridline");
|
testCSSAttrs("display_mozgridline");
|
||||||
testCSSAttrs("display_mozstack");
|
|
||||||
testCSSAttrs("display_mozdeck");
|
testCSSAttrs("display_mozdeck");
|
||||||
testCSSAttrs("display_mozpopup");
|
testCSSAttrs("display_mozpopup");
|
||||||
|
|
||||||
@ -57,10 +56,8 @@
|
|||||||
<vbox id="display_mozgrid" style="display: -moz-grid;" role="img"/>
|
<vbox id="display_mozgrid" style="display: -moz-grid;" role="img"/>
|
||||||
<vbox id="display_mozgridgroup" style="display: -moz-grid-group;" 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_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_mozdeck" style="display: -moz-deck;" role="img"/>
|
||||||
<vbox id="display_mozpopup" style="display: -moz-popup;" role="img"/>
|
<vbox id="display_mozpopup" style="display: -moz-popup;" role="img"/>
|
||||||
|
|
||||||
</hbox>
|
</hbox>
|
||||||
</window>
|
</window>
|
||||||
|
|
@ -21,9 +21,11 @@
|
|||||||
testAttrs("nav", {"xml-roles": "navigation"}, true);
|
testAttrs("nav", {"xml-roles": "navigation"}, true);
|
||||||
testAttrs("header", {"xml-roles": "banner"}, true);
|
testAttrs("header", {"xml-roles": "banner"}, true);
|
||||||
testAbsentAttrs("article_header", {"xml-roles": "banner"});
|
testAbsentAttrs("article_header", {"xml-roles": "banner"});
|
||||||
|
testAbsentAttrs("main_header", {"xml-roles": "banner"});
|
||||||
testAbsentAttrs("section_header", {"xml-roles": "banner"});
|
testAbsentAttrs("section_header", {"xml-roles": "banner"});
|
||||||
testAttrs("footer", {"xml-roles": "contentinfo"}, true);
|
testAttrs("footer", {"xml-roles": "contentinfo"}, true);
|
||||||
testAbsentAttrs("article_footer", {"xml-roles": "contentinfo"});
|
testAbsentAttrs("article_footer", {"xml-roles": "contentinfo"});
|
||||||
|
testAbsentAttrs("main_footer", {"xml-roles": "contentinfo"});
|
||||||
testAbsentAttrs("section_footer", {"xml-roles": "contentinfo"});
|
testAbsentAttrs("section_footer", {"xml-roles": "contentinfo"});
|
||||||
testAttrs("aside", {"xml-roles": "complementary"}, true);
|
testAttrs("aside", {"xml-roles": "complementary"}, true);
|
||||||
testAbsentAttrs("section", {"xml-roles": "region"}, true);
|
testAbsentAttrs("section", {"xml-roles": "region"}, true);
|
||||||
@ -157,6 +159,10 @@
|
|||||||
<header id="article_header">a header within an article</header>
|
<header id="article_header">a header within an article</header>
|
||||||
<footer id="article_footer">a footer within an article</footer>
|
<footer id="article_footer">a footer within an article</footer>
|
||||||
</article>
|
</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">
|
<section id="section_with_header_and_footer">
|
||||||
<header id="section_header">a header within an section</header>
|
<header id="section_header">a header within an section</header>
|
||||||
<footer id="section_footer">a footer within an section</footer>
|
<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