mirror of
https://repo.dactyloidae.xyz/Dactyloidae/UXP.git
synced 2026-10-28 01:57:30 +09:00
import FIREFOX_52_6_0esr_RELEASE from mozilla-esr52 hg repo
This commit is contained in:
commit
dcd9973243
150858 changed files with 23884658 additions and 0 deletions
1
.cargo/.gitignore
vendored
Normal file
1
.cargo/.gitignore
vendored
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
config
|
||||||
6
.cargo/config.in
Normal file
6
.cargo/config.in
Normal file
|
|
@ -0,0 +1,6 @@
|
||||||
|
[source.crates-io]
|
||||||
|
registry = 'https://github.com/rust-lang/crates.io-index'
|
||||||
|
replace-with = 'vendored-sources'
|
||||||
|
|
||||||
|
[source.vendored-sources]
|
||||||
|
directory = '@top_srcdir@/third_party/rust'
|
||||||
4
.clang-format
Normal file
4
.clang-format
Normal file
|
|
@ -0,0 +1,4 @@
|
||||||
|
BasedOnStyle: Mozilla
|
||||||
|
|
||||||
|
# Ignore all comments because they aren't reflowed properly.
|
||||||
|
CommentPragmas: "^"
|
||||||
3
.clang-format-ignore
Normal file
3
.clang-format-ignore
Normal file
|
|
@ -0,0 +1,3 @@
|
||||||
|
^mfbt/.*
|
||||||
|
^js/.*
|
||||||
|
^media/.*
|
||||||
252
.eslintignore
Normal file
252
.eslintignore
Normal file
|
|
@ -0,0 +1,252 @@
|
||||||
|
# Always ignore node_modules.
|
||||||
|
**/node_modules/**/*.*
|
||||||
|
|
||||||
|
# Exclude expected objdirs.
|
||||||
|
obj*/**
|
||||||
|
|
||||||
|
# We ignore all these directories by default, until we get them enabled.
|
||||||
|
# If you are enabling a directory, please add directory specific exclusions
|
||||||
|
# below.
|
||||||
|
addon-sdk/**
|
||||||
|
build/**
|
||||||
|
caps/**
|
||||||
|
chrome/**
|
||||||
|
config/**
|
||||||
|
db/**
|
||||||
|
docshell/**
|
||||||
|
dom/**
|
||||||
|
editor/**
|
||||||
|
embedding/**
|
||||||
|
extensions/**
|
||||||
|
gfx/**
|
||||||
|
gradle/**
|
||||||
|
hal/**
|
||||||
|
image/**
|
||||||
|
intl/**
|
||||||
|
ipc/**
|
||||||
|
js/**
|
||||||
|
layout/**
|
||||||
|
media/**
|
||||||
|
memory/**
|
||||||
|
mfbt/**
|
||||||
|
modules/**
|
||||||
|
mozglue/**
|
||||||
|
netwerk/**
|
||||||
|
nsprpub/**
|
||||||
|
other-licenses/**
|
||||||
|
parser/**
|
||||||
|
probes/**
|
||||||
|
python/**
|
||||||
|
rdf/**
|
||||||
|
startupcache/**
|
||||||
|
testing/**
|
||||||
|
!tools/lint/eslint/eslint-plugin-mozilla/
|
||||||
|
tools/lint/eslint/eslint-plugin-mozilla/node_modules/**
|
||||||
|
tools/**
|
||||||
|
uriloader/**
|
||||||
|
view/**
|
||||||
|
widget/**
|
||||||
|
xpcom/**
|
||||||
|
xpfe/**
|
||||||
|
xulrunner/**
|
||||||
|
|
||||||
|
# b2g exclusions (pref files).
|
||||||
|
b2g/app/b2g.js
|
||||||
|
b2g/graphene/graphene.js
|
||||||
|
b2g/locales/en-US/b2g-l10n.js
|
||||||
|
|
||||||
|
# browser/ exclusions
|
||||||
|
browser/app/**
|
||||||
|
browser/branding/**/firefox-branding.js
|
||||||
|
browser/base/content/browser-social.js
|
||||||
|
browser/base/content/nsContextMenu.js
|
||||||
|
browser/base/content/sanitizeDialog.js
|
||||||
|
browser/base/content/test/general/file_csp_block_all_mixedcontent.html
|
||||||
|
browser/base/content/test/urlbar/file_blank_but_not_blank.html
|
||||||
|
browser/base/content/newtab/**
|
||||||
|
browser/components/downloads/**
|
||||||
|
browser/components/privatebrowsing/**
|
||||||
|
browser/components/sessionstore/**
|
||||||
|
browser/components/tabview/**
|
||||||
|
# generated files in cld2
|
||||||
|
browser/components/translation/cld2/cld-worker.js
|
||||||
|
browser/extensions/pdfjs/**
|
||||||
|
# generated or library files in pocket
|
||||||
|
browser/extensions/pocket/content/panels/js/tmpl.js
|
||||||
|
browser/extensions/pocket/content/panels/js/vendor/**
|
||||||
|
browser/locales/**
|
||||||
|
|
||||||
|
# devtools/ exclusions
|
||||||
|
devtools/client/canvasdebugger/**
|
||||||
|
devtools/client/commandline/**
|
||||||
|
devtools/client/debugger/**
|
||||||
|
devtools/client/framework/**
|
||||||
|
!devtools/client/framework/selection.js
|
||||||
|
!devtools/client/framework/toolbox.js
|
||||||
|
devtools/client/jsonview/lib/**
|
||||||
|
devtools/client/memory/**
|
||||||
|
devtools/client/netmonitor/test/**
|
||||||
|
devtools/client/netmonitor/har/test/**
|
||||||
|
devtools/client/projecteditor/**
|
||||||
|
devtools/client/promisedebugger/**
|
||||||
|
devtools/client/responsivedesign/**
|
||||||
|
devtools/client/scratchpad/**
|
||||||
|
devtools/client/shadereditor/**
|
||||||
|
devtools/client/shared/*.jsm
|
||||||
|
devtools/client/shared/webgl-utils.js
|
||||||
|
devtools/client/shared/widgets/*.jsm
|
||||||
|
devtools/client/sourceeditor/test/*.js
|
||||||
|
devtools/client/webaudioeditor/**
|
||||||
|
devtools/client/webconsole/**
|
||||||
|
!devtools/client/webconsole/panel.js
|
||||||
|
!devtools/client/webconsole/jsterm.js
|
||||||
|
!devtools/client/webconsole/console-commands.js
|
||||||
|
devtools/client/webide/**
|
||||||
|
!devtools/client/webide/components/webideCli.js
|
||||||
|
devtools/server/*.js
|
||||||
|
devtools/server/*.jsm
|
||||||
|
!devtools/server/child.js
|
||||||
|
!devtools/server/css-logic.js
|
||||||
|
!devtools/server/main.js
|
||||||
|
!devtools/server/websocket-server.js
|
||||||
|
devtools/server/actors/**
|
||||||
|
!devtools/server/actors/csscoverage.js
|
||||||
|
!devtools/server/actors/inspector.js
|
||||||
|
!devtools/server/actors/highlighters/css-grid.js
|
||||||
|
!devtools/server/actors/highlighters/eye-dropper.js
|
||||||
|
!devtools/server/actors/layout.js
|
||||||
|
!devtools/server/actors/string.js
|
||||||
|
!devtools/server/actors/styles.js
|
||||||
|
!devtools/server/actors/webbrowser.js
|
||||||
|
!devtools/server/actors/webextension.js
|
||||||
|
devtools/server/performance/**
|
||||||
|
devtools/server/tests/**
|
||||||
|
devtools/shared/*.js
|
||||||
|
!devtools/shared/async-storage.js
|
||||||
|
!devtools/shared/async-utils.js
|
||||||
|
!devtools/shared/defer.js
|
||||||
|
!devtools/shared/event-emitter.js
|
||||||
|
!devtools/shared/indentation.js
|
||||||
|
!devtools/shared/loader-plugin-raw.jsm
|
||||||
|
!devtools/shared/task.js
|
||||||
|
devtools/shared/apps/**
|
||||||
|
devtools/shared/client/**
|
||||||
|
devtools/shared/discovery/**
|
||||||
|
devtools/shared/gcli/**
|
||||||
|
!devtools/shared/gcli/templater.js
|
||||||
|
devtools/shared/heapsnapshot/**
|
||||||
|
devtools/shared/layout/**
|
||||||
|
devtools/shared/locales/**
|
||||||
|
devtools/shared/performance/**
|
||||||
|
!devtools/shared/platform/**
|
||||||
|
devtools/shared/qrcode/**
|
||||||
|
devtools/shared/security/**
|
||||||
|
devtools/shared/shims/**
|
||||||
|
devtools/shared/tests/**
|
||||||
|
!devtools/shared/tests/unit/test_csslexer.js
|
||||||
|
devtools/shared/touch/**
|
||||||
|
devtools/shared/transport/**
|
||||||
|
!devtools/shared/transport/transport.js
|
||||||
|
!devtools/shared/transport/websocket-transport.js
|
||||||
|
devtools/shared/webconsole/test/**
|
||||||
|
devtools/shared/worker/**
|
||||||
|
!devtools/shared/worker/worker.js
|
||||||
|
|
||||||
|
# Ignore devtools pre-processed files
|
||||||
|
devtools/client/framework/toolbox-process-window.js
|
||||||
|
devtools/client/performance/system.js
|
||||||
|
devtools/client/webide/webide-prefs.js
|
||||||
|
devtools/client/preferences/**
|
||||||
|
|
||||||
|
# Ignore devtools third-party libs
|
||||||
|
devtools/shared/jsbeautify/*
|
||||||
|
devtools/shared/acorn/*
|
||||||
|
devtools/client/sourceeditor/tern/*
|
||||||
|
devtools/shared/node-properties/*
|
||||||
|
devtools/shared/pretty-fast/*
|
||||||
|
devtools/shared/sourcemap/*
|
||||||
|
devtools/shared/sprintfjs/*
|
||||||
|
devtools/shared/qrcode/decoder/*
|
||||||
|
devtools/shared/qrcode/encoder/*
|
||||||
|
devtools/client/shared/demangle.js
|
||||||
|
devtools/client/shared/vendor/*
|
||||||
|
devtools/client/sourceeditor/codemirror/*.js
|
||||||
|
devtools/client/sourceeditor/codemirror/**/*.js
|
||||||
|
devtools/client/sourceeditor/test/codemirror/*
|
||||||
|
devtools/client/inspector/markup/test/lib_*
|
||||||
|
devtools/client/jsonview/lib/require.js
|
||||||
|
devtools/server/actors/utils/automation-timeline.js
|
||||||
|
|
||||||
|
# Ignore devtools files testing sourcemaps / code style
|
||||||
|
devtools/client/debugger/test/mochitest/code_binary_search.js
|
||||||
|
devtools/client/debugger/test/mochitest/code_math.min.js
|
||||||
|
devtools/client/debugger/test/mochitest/code_math_bogus_map.js
|
||||||
|
devtools/client/debugger/test/mochitest/code_ugly*
|
||||||
|
devtools/client/debugger/test/mochitest/code_worker-source-map.js
|
||||||
|
devtools/client/framework/test/code_ugly*
|
||||||
|
devtools/server/tests/unit/babel_and_browserify_script_with_source_map.js
|
||||||
|
devtools/server/tests/unit/setBreakpoint*
|
||||||
|
|
||||||
|
# mobile/android/ exclusions
|
||||||
|
mobile/android/tests/
|
||||||
|
|
||||||
|
# Uses `#filter substitution`
|
||||||
|
mobile/android/b2gdroid/app/b2gdroid.js
|
||||||
|
mobile/android/app/mobile.js
|
||||||
|
mobile/android/chrome/content/healthreport-prefs.js
|
||||||
|
|
||||||
|
# Uses `#expand`
|
||||||
|
mobile/android/chrome/content/about.js
|
||||||
|
|
||||||
|
# Not much JS to lint and non-standard at that
|
||||||
|
mobile/android/installer/
|
||||||
|
mobile/android/locales/
|
||||||
|
|
||||||
|
# Non-standard `(catch ex if ...)`
|
||||||
|
mobile/android/chrome/content/browser.js
|
||||||
|
mobile/android/components/Snippets.js
|
||||||
|
|
||||||
|
# Bug 1178739: Ignore this file as a quick fix for "Illegal yield expression"
|
||||||
|
mobile/android/modules/HomeProvider.jsm
|
||||||
|
|
||||||
|
# services/ exclusions
|
||||||
|
|
||||||
|
# Uses `#filter substitution`
|
||||||
|
services/sync/modules/constants.js
|
||||||
|
|
||||||
|
# toolkit/ exclusions
|
||||||
|
|
||||||
|
# Not part of the default build
|
||||||
|
toolkit/components/help/**
|
||||||
|
|
||||||
|
# Intentionally invalid JS
|
||||||
|
toolkit/components/workerloader/tests/moduleF-syntax-error.js
|
||||||
|
|
||||||
|
# Tests old non-star function generators
|
||||||
|
toolkit/modules/tests/xpcshell/test_task.js
|
||||||
|
|
||||||
|
# Not yet updated
|
||||||
|
toolkit/components/osfile/**
|
||||||
|
|
||||||
|
# External code:
|
||||||
|
toolkit/components/microformats/test/**
|
||||||
|
toolkit/components/reader/Readability.js
|
||||||
|
toolkit/components/reader/JSDOMParser.js
|
||||||
|
|
||||||
|
# Uses preprocessing
|
||||||
|
toolkit/content/widgets/wizard.xml
|
||||||
|
toolkit/components/jsdownloads/src/DownloadIntegration.jsm
|
||||||
|
toolkit/components/url-classifier/**
|
||||||
|
toolkit/components/urlformatter/nsURLFormatter.js
|
||||||
|
toolkit/identity/FirefoxAccounts.jsm
|
||||||
|
toolkit/modules/AppConstants.jsm
|
||||||
|
toolkit/mozapps/downloads/nsHelperAppDlg.js
|
||||||
|
toolkit/mozapps/extensions/internal/AddonConstants.jsm
|
||||||
|
toolkit/mozapps/update/tests/data/xpcshellConstantsPP.js
|
||||||
|
toolkit/webapps/**
|
||||||
|
|
||||||
|
# Third party
|
||||||
|
toolkit/modules/third_party/**
|
||||||
|
|
||||||
|
#NSS
|
||||||
|
security/nss/**
|
||||||
14
.eslintrc.js
Normal file
14
.eslintrc.js
Normal file
|
|
@ -0,0 +1,14 @@
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
// When adding items to this file please check for effects on sub-directories.
|
||||||
|
"plugins": [
|
||||||
|
"mozilla"
|
||||||
|
],
|
||||||
|
"rules": {
|
||||||
|
"mozilla/import-globals": "warn",
|
||||||
|
},
|
||||||
|
"env": {
|
||||||
|
"es6": true
|
||||||
|
},
|
||||||
|
};
|
||||||
5
.flake8
Normal file
5
.flake8
Normal file
|
|
@ -0,0 +1,5 @@
|
||||||
|
[flake8]
|
||||||
|
# See http://pep8.readthedocs.io/en/latest/intro.html#configuration
|
||||||
|
ignore = E121, E123, E126, E133, E226, E241, E242, E704, W503, E402
|
||||||
|
max-line-length = 99
|
||||||
|
filename = *.py, +.lint
|
||||||
189
.gdbinit
Normal file
189
.gdbinit
Normal file
|
|
@ -0,0 +1,189 @@
|
||||||
|
# .gdbinit file for debugging Mozilla
|
||||||
|
|
||||||
|
# You may need to put an 'add-auto-load-safe-path' command in your
|
||||||
|
# $HOME/.gdbinit file to get GDB to trust this file. If your builds are
|
||||||
|
# generally in $HOME/moz, then you can say:
|
||||||
|
#
|
||||||
|
# add-auto-load-safe-path ~/moz
|
||||||
|
|
||||||
|
# Don't stop for the SIG32/33/etc signals that Flash produces
|
||||||
|
handle SIG32 noprint nostop pass
|
||||||
|
handle SIG33 noprint nostop pass
|
||||||
|
handle SIGPIPE noprint nostop pass
|
||||||
|
|
||||||
|
# Don't stop for certain other signals where it's not useful,
|
||||||
|
# such as the SIG64 signals triggered by the Linux
|
||||||
|
# sandboxing code on older kernels.
|
||||||
|
handle SIG38 noprint nostop pass
|
||||||
|
handle SIG64 noprint nostop pass
|
||||||
|
|
||||||
|
# Show the concrete types behind nsIFoo
|
||||||
|
set print object on
|
||||||
|
|
||||||
|
# run when using the auto-solib-add trick
|
||||||
|
def prun
|
||||||
|
tbreak main
|
||||||
|
run
|
||||||
|
set auto-solib-add 0
|
||||||
|
cont
|
||||||
|
end
|
||||||
|
|
||||||
|
# run -mail, when using the auto-solib-add trick
|
||||||
|
def pmail
|
||||||
|
tbreak main
|
||||||
|
run -mail
|
||||||
|
set auto-solib-add 0
|
||||||
|
cont
|
||||||
|
end
|
||||||
|
|
||||||
|
# Define a "pu" command to display PRUnichar * strings (100 chars max)
|
||||||
|
# Also allows an optional argument for how many chars to print as long as
|
||||||
|
# it's less than 100.
|
||||||
|
def pu
|
||||||
|
set $uni = $arg0
|
||||||
|
if $argc == 2
|
||||||
|
set $limit = $arg1
|
||||||
|
if $limit > 100
|
||||||
|
set $limit = 100
|
||||||
|
end
|
||||||
|
else
|
||||||
|
set $limit = 100
|
||||||
|
end
|
||||||
|
# scratch array with space for 100 chars plus null terminator. Make
|
||||||
|
# sure to not use ' ' as the char so this copy/pastes well.
|
||||||
|
set $scratch = "____________________________________________________________________________________________________"
|
||||||
|
set $i = 0
|
||||||
|
set $scratch_idx = 0
|
||||||
|
while (*$uni && $i++ < $limit)
|
||||||
|
if (*$uni < 0x80)
|
||||||
|
set $scratch[$scratch_idx++] = *(char*)$uni++
|
||||||
|
else
|
||||||
|
if ($scratch_idx > 0)
|
||||||
|
set $scratch[$scratch_idx] = '\0'
|
||||||
|
print $scratch
|
||||||
|
set $scratch_idx = 0
|
||||||
|
end
|
||||||
|
print /x *(short*)$uni++
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if ($scratch_idx > 0)
|
||||||
|
set $scratch[$scratch_idx] = '\0'
|
||||||
|
print $scratch
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# Define a "ps" command to display subclasses of nsAC?String. Note that
|
||||||
|
# this assumes strings as of Gecko 1.9 (well, and probably a few
|
||||||
|
# releases before that as well); going back far enough will get you
|
||||||
|
# to string classes that this function doesn't work for.
|
||||||
|
def ps
|
||||||
|
set $str = $arg0
|
||||||
|
if (sizeof(*$str.mData) == 1 && ($str.mFlags & 1) != 0)
|
||||||
|
print $str.mData
|
||||||
|
else
|
||||||
|
pu $str.mData $str.mLength
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# Define a "pa" command to display the string value for an nsIAtom
|
||||||
|
def pa
|
||||||
|
set $atom = $arg0
|
||||||
|
if (sizeof(*((&*$atom)->mString)) == 2)
|
||||||
|
pu (&*$atom)->mString
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# define a "pxul" command to display the type of a XUL element from
|
||||||
|
# an nsXULElement* pointer.
|
||||||
|
def pxul
|
||||||
|
set $p = $arg0
|
||||||
|
print $p->mNodeInfo.mRawPtr->mInner.mName->mStaticAtom->mString
|
||||||
|
end
|
||||||
|
|
||||||
|
# define a "prefcnt" command to display the refcount of an XPCOM obj
|
||||||
|
def prefcnt
|
||||||
|
set $p = $arg0
|
||||||
|
print ((nsPurpleBufferEntry*)$p->mRefCnt.mTagged)->mRefCnt
|
||||||
|
end
|
||||||
|
|
||||||
|
# define a "ptag" command to display the tag name of a content node
|
||||||
|
def ptag
|
||||||
|
set $p = $arg0
|
||||||
|
pa $p->mNodeInfo.mRawPtr->mInner.mName
|
||||||
|
end
|
||||||
|
|
||||||
|
##
|
||||||
|
## nsTArray
|
||||||
|
##
|
||||||
|
define ptarray
|
||||||
|
if $argc == 0
|
||||||
|
help ptarray
|
||||||
|
else
|
||||||
|
set $size = $arg0.mHdr->mLength
|
||||||
|
set $capacity = $arg0.mHdr->mCapacity
|
||||||
|
set $size_max = $size - 1
|
||||||
|
set $elts = $arg0.Elements()
|
||||||
|
end
|
||||||
|
if $argc == 1
|
||||||
|
set $i = 0
|
||||||
|
while $i < $size
|
||||||
|
printf "elem[%u]: ", $i
|
||||||
|
p *($elts + $i)
|
||||||
|
set $i++
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if $argc == 2
|
||||||
|
set $idx = $arg1
|
||||||
|
if $idx < 0 || $idx > $size_max
|
||||||
|
printf "idx1, idx2 are not in acceptable range: [0..%u].\n", $size_max
|
||||||
|
else
|
||||||
|
printf "elem[%u]: ", $idx
|
||||||
|
p *($elts + $idx)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if $argc == 3
|
||||||
|
set $start_idx = $arg1
|
||||||
|
set $stop_idx = $arg2
|
||||||
|
if $start_idx > $stop_idx
|
||||||
|
set $tmp_idx = $start_idx
|
||||||
|
set $start_idx = $stop_idx
|
||||||
|
set $stop_idx = $tmp_idx
|
||||||
|
end
|
||||||
|
if $start_idx < 0 || $stop_idx < 0 || $start_idx > $size_max || $stop_idx > $size_max
|
||||||
|
printf "idx1, idx2 are not in acceptable range: [0..%u].\n", $size_max
|
||||||
|
else
|
||||||
|
set $i = $start_idx
|
||||||
|
while $i <= $stop_idx
|
||||||
|
printf "elem[%u]: ", $i
|
||||||
|
p *($elts + $i)
|
||||||
|
set $i++
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if $argc > 0
|
||||||
|
printf "nsTArray length = %u\n", $size
|
||||||
|
printf "nsTArray capacity = %u\n", $capacity
|
||||||
|
printf "Element "
|
||||||
|
whatis *$elts
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
document ptarray
|
||||||
|
Prints nsTArray information.
|
||||||
|
Syntax: ptarray
|
||||||
|
Note: idx, idx1 and idx2 must be in acceptable range [0...size()-1].
|
||||||
|
Examples:
|
||||||
|
ptarray a - Prints tarray content, size, capacity and T typedef
|
||||||
|
ptarray a 0 - Prints element[idx] from tarray
|
||||||
|
ptarray a 1 2 - Prints elements in range [idx1..idx2] from tarray
|
||||||
|
end
|
||||||
|
|
||||||
|
def js
|
||||||
|
call DumpJSStack()
|
||||||
|
end
|
||||||
|
|
||||||
|
def ft
|
||||||
|
call $arg0->DumpFrameTree()
|
||||||
|
end
|
||||||
|
|
||||||
|
source .gdbinit_python
|
||||||
5
.gdbinit_python
Normal file
5
.gdbinit_python
Normal file
|
|
@ -0,0 +1,5 @@
|
||||||
|
python
|
||||||
|
import sys
|
||||||
|
sys.path.append('python/gdbpp/')
|
||||||
|
import gdbpp
|
||||||
|
end
|
||||||
124
.gitignore
vendored
Normal file
124
.gitignore
vendored
Normal file
|
|
@ -0,0 +1,124 @@
|
||||||
|
# .gitignore - List of filenames git should ignore
|
||||||
|
|
||||||
|
# Filenames that should be ignored wherever they appear
|
||||||
|
*~
|
||||||
|
*.pyc
|
||||||
|
*.pyo
|
||||||
|
TAGS
|
||||||
|
tags
|
||||||
|
ID
|
||||||
|
.DS_Store*
|
||||||
|
*.pdb
|
||||||
|
*.egg-info
|
||||||
|
|
||||||
|
# Vim swap files.
|
||||||
|
.*.sw[a-z]
|
||||||
|
|
||||||
|
# Emacs directory variable files.
|
||||||
|
**/.dir-locals.el
|
||||||
|
|
||||||
|
# User files that may appear at the root
|
||||||
|
/.mozconfig*
|
||||||
|
/mozconfig
|
||||||
|
/configure
|
||||||
|
/old-configure
|
||||||
|
/config.cache
|
||||||
|
/config.log
|
||||||
|
/.clang_complete
|
||||||
|
/machrc
|
||||||
|
/.machrc
|
||||||
|
|
||||||
|
# Empty marker file that's generated when we check out NSS
|
||||||
|
security/manager/.nss.checkout
|
||||||
|
|
||||||
|
# Build directories
|
||||||
|
/obj*/
|
||||||
|
|
||||||
|
# Build directories for js shell
|
||||||
|
_DBG.OBJ/
|
||||||
|
_OPT.OBJ/
|
||||||
|
|
||||||
|
# SpiderMonkey configury
|
||||||
|
js/src/configure
|
||||||
|
js/src/old-configure
|
||||||
|
js/src/autom4te.cache
|
||||||
|
# SpiderMonkey test result logs
|
||||||
|
js/src/tests/results-*.html
|
||||||
|
js/src/tests/results-*.txt
|
||||||
|
|
||||||
|
# Java HTML5 parser classes
|
||||||
|
parser/html/java/htmlparser/
|
||||||
|
parser/html/java/javaparser/
|
||||||
|
|
||||||
|
# Ignore the files and directory that Eclipse IDE creates
|
||||||
|
.project
|
||||||
|
.cproject
|
||||||
|
.settings/
|
||||||
|
|
||||||
|
# Ignore the files and directory that JetBrains IDEs create.
|
||||||
|
/.idea/
|
||||||
|
*.iml
|
||||||
|
|
||||||
|
# Gradle cache.
|
||||||
|
/.gradle/
|
||||||
|
|
||||||
|
# Local Gradle configuration properties.
|
||||||
|
/local.properties
|
||||||
|
|
||||||
|
# Python virtualenv artifacts.
|
||||||
|
python/psutil/**/*.so
|
||||||
|
python/psutil/**/*.pyd
|
||||||
|
python/psutil/build/
|
||||||
|
|
||||||
|
# Ignore chrome.manifest files from the devtools loader
|
||||||
|
devtools/client/chrome.manifest
|
||||||
|
devtools/shared/chrome.manifest
|
||||||
|
|
||||||
|
# Ignore node_modules directories in devtools
|
||||||
|
devtools/**/node_modules
|
||||||
|
|
||||||
|
# Tag files generated by GNU Global
|
||||||
|
GTAGS
|
||||||
|
GRTAGS
|
||||||
|
GSYMS
|
||||||
|
GPATH
|
||||||
|
|
||||||
|
# Git clone directory for updating web-platform-tests
|
||||||
|
testing/web-platform/sync/
|
||||||
|
|
||||||
|
# Android Gradle artifacts.
|
||||||
|
mobile/android/gradle/.gradle
|
||||||
|
|
||||||
|
# XCode project cruft
|
||||||
|
embedding/ios/GeckoEmbed/GeckoEmbed.xcodeproj/project.xcworkspace/xcuserdata
|
||||||
|
embedding/ios/GeckoEmbed/GeckoEmbed.xcodeproj/xcuserdata
|
||||||
|
|
||||||
|
# Ignore mozharness execution files
|
||||||
|
testing/mozharness/.tox/
|
||||||
|
testing/mozharness/build/
|
||||||
|
testing/mozharness/logs/
|
||||||
|
testing/mozharness/.coverage
|
||||||
|
testing/mozharness/nosetests.xml
|
||||||
|
|
||||||
|
# Ignore node_modules
|
||||||
|
tools/lint/eslint/node_modules/
|
||||||
|
|
||||||
|
# Ignore talos virtualenv and tp5n files.
|
||||||
|
# The tp5n set is supposed to be decompressed at
|
||||||
|
# testing/talos/talos/page_load_test/tp5n in order to run tests like tps
|
||||||
|
# locally. Similarly, running talos requires a Python package virtual
|
||||||
|
# environment. Both the virtual environment and tp5n files end up littering
|
||||||
|
# the status command, so we ignore them.
|
||||||
|
testing/talos/.Python
|
||||||
|
testing/talos/bin/
|
||||||
|
testing/talos/include/
|
||||||
|
testing/talos/lib/
|
||||||
|
testing/talos/talos/tests/tp5n.zip
|
||||||
|
testing/talos/talos/tests/tp5n
|
||||||
|
testing/talos/talos/tests/devtools/damp.manifest.develop
|
||||||
|
|
||||||
|
# Ignore files created when running a reftest.
|
||||||
|
lextab.py
|
||||||
|
|
||||||
|
# tup database
|
||||||
|
/.tup
|
||||||
5
.hg_archival.txt
Normal file
5
.hg_archival.txt
Normal file
|
|
@ -0,0 +1,5 @@
|
||||||
|
repo: 8ba995b74e18334ab3707f27e9eb8f4e37ba3d29
|
||||||
|
node: a7c8e85285e290fdb1325edfb37e905a3779f3cd
|
||||||
|
branch: default
|
||||||
|
tag: FIREFOX_52_6_0esr_BUILD2
|
||||||
|
tag: FIREFOX_52_6_0esr_RELEASE
|
||||||
134
.hgignore
Normal file
134
.hgignore
Normal file
|
|
@ -0,0 +1,134 @@
|
||||||
|
# .hgignore - List of filenames hg should ignore
|
||||||
|
|
||||||
|
# Filenames that should be ignored wherever they appear
|
||||||
|
~$
|
||||||
|
\.py(c|o)$
|
||||||
|
(?i)(^|/)TAGS$
|
||||||
|
(^|/)ID$
|
||||||
|
(^|/)\.DS_Store$
|
||||||
|
\.pdb
|
||||||
|
\.egg-info
|
||||||
|
|
||||||
|
# Vim swap files.
|
||||||
|
^\.sw.$
|
||||||
|
.[^/]*\.sw.$
|
||||||
|
|
||||||
|
# Emacs directory variable files.
|
||||||
|
\.dir-locals\.el
|
||||||
|
|
||||||
|
# User files that may appear at the root
|
||||||
|
^\.mozconfig
|
||||||
|
^mozconfig*
|
||||||
|
^configure$
|
||||||
|
^old-configure$
|
||||||
|
^config\.cache$
|
||||||
|
^config\.log$
|
||||||
|
^\.clang_complete
|
||||||
|
^\.?machrc$
|
||||||
|
|
||||||
|
# Empty marker file that's generated when we check out NSS
|
||||||
|
^security/manager/\.nss\.checkout$
|
||||||
|
|
||||||
|
# Build directories
|
||||||
|
^obj
|
||||||
|
|
||||||
|
# Build directories for js shell
|
||||||
|
_DBG\.OBJ/
|
||||||
|
_OPT\.OBJ/
|
||||||
|
^js/src/.*-obj/
|
||||||
|
|
||||||
|
# SpiderMonkey configury
|
||||||
|
^js/src/configure$
|
||||||
|
^js/src/old-configure$
|
||||||
|
^js/src/autom4te.cache$
|
||||||
|
# SpiderMonkey test result logs
|
||||||
|
^js/src/tests/results-.*\.(html|txt)$
|
||||||
|
^js/src/devtools/rootAnalysis/t/out
|
||||||
|
|
||||||
|
# Java HTML5 parser classes
|
||||||
|
^parser/html/java/(html|java)parser/
|
||||||
|
|
||||||
|
# SVN directories
|
||||||
|
\.svn/
|
||||||
|
|
||||||
|
# Ignore the files and directory that Eclipse IDE creates
|
||||||
|
\.project$
|
||||||
|
\.cproject$
|
||||||
|
\.settings/
|
||||||
|
|
||||||
|
# Ignore the files and directory that JetBrains IDEs create.
|
||||||
|
\.idea/
|
||||||
|
\.iml$
|
||||||
|
|
||||||
|
# Gradle cache.
|
||||||
|
^.gradle/
|
||||||
|
|
||||||
|
# Local Gradle configuration properties.
|
||||||
|
^local.properties$
|
||||||
|
|
||||||
|
# Python stuff installed at build time.
|
||||||
|
^python/psutil/.*\.so
|
||||||
|
^python/psutil/.*\.pyd
|
||||||
|
^python/psutil/build/
|
||||||
|
|
||||||
|
# Git repositories
|
||||||
|
.git/
|
||||||
|
|
||||||
|
# Ignore chrome.manifest files from the devtools loader
|
||||||
|
^devtools/client/chrome.manifest$
|
||||||
|
^devtools/shared/chrome.manifest$
|
||||||
|
|
||||||
|
# Ignore node_modules directories in devtools
|
||||||
|
^devtools/.*/node_modules/
|
||||||
|
|
||||||
|
# git checkout of libstagefright
|
||||||
|
^media/libstagefright/android$
|
||||||
|
|
||||||
|
# Tag files generated by GNU Global
|
||||||
|
GTAGS
|
||||||
|
GRTAGS
|
||||||
|
GSYMS
|
||||||
|
GPATH
|
||||||
|
|
||||||
|
# Git clone directory for updating web-platform-tests
|
||||||
|
^testing/web-platform/sync/
|
||||||
|
|
||||||
|
# Android Gradle artifacts.
|
||||||
|
^mobile/android/gradle/.gradle
|
||||||
|
|
||||||
|
# XCode project cruft
|
||||||
|
^embedding/ios/GeckoEmbed/GeckoEmbed.xcodeproj/project.xcworkspace/xcuserdata
|
||||||
|
^embedding/ios/GeckoEmbed/GeckoEmbed.xcodeproj/xcuserdata
|
||||||
|
|
||||||
|
# Ignore mozharness execution files
|
||||||
|
^testing/mozharness/.tox/
|
||||||
|
^testing/mozharness/build/
|
||||||
|
^testing/mozharness/logs/
|
||||||
|
^testing/mozharness/.coverage
|
||||||
|
^testing/mozharness/nosetests.xml
|
||||||
|
|
||||||
|
# Ignore tox generated dir
|
||||||
|
.tox/
|
||||||
|
|
||||||
|
# Ignore node_modules
|
||||||
|
^tools/lint/eslint/node_modules/
|
||||||
|
|
||||||
|
# Ignore talos virtualenv and tp5n files.
|
||||||
|
# The tp5n set is supposed to be decompressed at
|
||||||
|
# testing/talos/talos/page_load_test/tp5n in order to run tests like tps
|
||||||
|
# locally. Similarly, running talos requires a Python package virtual
|
||||||
|
# environment. Both the virtual environment and tp5n files end up littering
|
||||||
|
# the status command, so we ignore them.
|
||||||
|
^testing/talos/.Python
|
||||||
|
^testing/talos/bin/
|
||||||
|
^testing/talos/include/
|
||||||
|
^testing/talos/lib/
|
||||||
|
^testing/talos/talos/tests/tp5n.zip
|
||||||
|
^testing/talos/talos/tests/tp5n
|
||||||
|
^testing/talos/talos/tests/devtools/damp.manifest.develop
|
||||||
|
|
||||||
|
# Ignore files created when running a reftest.
|
||||||
|
^lextab.py$
|
||||||
|
|
||||||
|
# tup database
|
||||||
|
^\.tup
|
||||||
489
.hgtags
Normal file
489
.hgtags
Normal file
|
|
@ -0,0 +1,489 @@
|
||||||
|
df7a3c8ffeeaba229067efee5a20e21dae0dd877 MOZILLA_1_9_a4_BASE
|
||||||
|
4209e16b58411750ac73f761023e46b76b793e2c MOZILLA_1_9_a6_BASE
|
||||||
|
66a5c7bce7ee86a820d3c0d54fa07cb719be751c MOZILLA_1_9_a7_BASE
|
||||||
|
caeba7562e495a9f604984df0b48b6f99bec3e2e FENNEC_M4
|
||||||
|
9d9941eacb14827fdab4716710042fdde84eb60d FIREFOX_3_1a1_RELEASE
|
||||||
|
9d9941eacb14827fdab4716710042fdde84eb60d FIREFOX_3_1a1_BUILD1
|
||||||
|
c1d7e318a27574c995631fec166ad42672475702 FIREFOX_3_1a1_BUILD2
|
||||||
|
c1d7e318a27574c995631fec166ad42672475702 FIREFOX_3_1a1_RELEASE
|
||||||
|
afc4ee509d9ca3bb4031015c3c22963dcb4b7e7f FIREFOX_3_1a1_RELEASE
|
||||||
|
afc4ee509d9ca3bb4031015c3c22963dcb4b7e7f FIREFOX_3_1a1_BUILD2
|
||||||
|
f197b51bbc29a30860e750ee87fd0a047a024f2e FIREFOX_3_1a2_BUILD1
|
||||||
|
f197b51bbc29a30860e750ee87fd0a047a024f2e FIREFOX_3_1a2_RELEASE
|
||||||
|
269af1ed75649989575d41f53a12048015c6d50e FENNEC_M8
|
||||||
|
920a4326d1087b174c2fa2b9a8358e12c697022c SEAMONKEY_2_0a1_BUILD1
|
||||||
|
920a4326d1087b174c2fa2b9a8358e12c697022c SEAMONKEY_2_0a1_RELEASE
|
||||||
|
f197b51bbc29a30860e750ee87fd0a047a024f2e UPDATE_PACKAGING_R5
|
||||||
|
f197b51bbc29a30860e750ee87fd0a047a024f2e -m
|
||||||
|
f197b51bbc29a30860e750ee87fd0a047a024f2e Adding UPDATE_PACKAGING_R5 tag in order to make patcher work.
|
||||||
|
15cb5d25db054d2d0b56869a2f6351388bfcddcd THUNDERBIRD_3_0a3_RELEASE
|
||||||
|
15cb5d25db054d2d0b56869a2f6351388bfcddcd THUNDERBIRD_3_0a3_BUILD1
|
||||||
|
0000000000000000000000000000000000000000 -m
|
||||||
|
0000000000000000000000000000000000000000 Adding UPDATE_PACKAGING_R5 tag in order to make patcher work.
|
||||||
|
f197b51bbc29a30860e750ee87fd0a047a024f2e UPDATE_PACKAGING_R6
|
||||||
|
d7d64f68423b68a671f623f123e90057ebc49dac UPDATE_PACKAGING_R6
|
||||||
|
0000000000000000000000000000000000000000 THUNDERBIRD_3_0a3_BUILD1
|
||||||
|
0000000000000000000000000000000000000000 THUNDERBIRD_3_0a3_RELEASE
|
||||||
|
0cd41f5990807fb6ab52cb59ba3c8e8247281045 GECKO_1_9_1_BASE
|
||||||
|
8df5a90281cd4d75835e4b7696da200555eed15f GECKO_1_9_1_BASE
|
||||||
|
8a601ed6bc4c7b3d1e35aa9e81f257512d984bd5 FENNEC_A2
|
||||||
|
d7d64f68423b68a671f623f123e90057ebc49dac UPDATE_PACKAGING_R7
|
||||||
|
fb32f6e1859c07846a01b4478a7b1678019e0b45 UPDATE_PACKAGING_R7
|
||||||
|
f817a4378f32b1ad0a7c4b5a9949586dba816da5 FENNEC_M11
|
||||||
|
5c1e7c779b6edc8ff912001990edc579f80597f4 FENNEC_B1
|
||||||
|
fe9cc55b8db7f56f7e68a246acba363743854979 UPDATE_PACKAGING_R8
|
||||||
|
6fd4bb500d425c406c1b52f66e5b195b20ae5e0a chromium-import-r15462
|
||||||
|
6fd4bb500d425c406c1b52f66e5b195b20ae5e0a chromium-import-latest
|
||||||
|
376b78fc72230aaf2ca4e279a8f4ef1efd4a1d9f GECKO_1_9_2_BASE
|
||||||
|
941ad9d7d079246481f365c3cfbfc75a5bbefc94 last-mozilla-central
|
||||||
|
2bae3bbf866e7de2a4b2377e7c2f52cc9ac14a22 last-mozilla-central
|
||||||
|
2bae3bbf866e7de2a4b2377e7c2f52cc9ac14a22 last-mozilla-central
|
||||||
|
65c1582465efe99899189519fccaf7b2826fcb2e last-mozilla-central
|
||||||
|
65c1582465efe99899189519fccaf7b2826fcb2e last-mozilla-central
|
||||||
|
27937722da69ad0e8fd140a00671413068226a5b last-mozilla-central
|
||||||
|
27937722da69ad0e8fd140a00671413068226a5b last-mozilla-central
|
||||||
|
a732c6d3c078f80635255c78bfaadffa5828a8a5 last-mozilla-central
|
||||||
|
a732c6d3c078f80635255c78bfaadffa5828a8a5 last-mozilla-central
|
||||||
|
925595f3c08634cc42e33158ea6858bb55623ef7 last-mozilla-central
|
||||||
|
dba2abb7db57078c5a4810884834d3056a5d56c2 last-mozilla-central
|
||||||
|
138f593553b66c9f815e8f57870c19d6347f7702 UPDATE_PACKAGING_R9
|
||||||
|
138f593553b66c9f815e8f57870c19d6347f7702 UPDATE_PACKAGING_R10
|
||||||
|
138f593553b66c9f815e8f57870c19d6347f7702 UPDATE_PACKAGING_R11
|
||||||
|
0327e126ea245112c0aa7283fee154e084866fb5 bsmedberg-static-xpcom-registration-base
|
||||||
|
0327e126ea245112c0aa7283fee154e084866fb5 bsmedberg-static-xpcom-registration-base
|
||||||
|
2f83edbbeef0de7dd901411d270da61106c8afae bsmedberg-static-xpcom-registration-base
|
||||||
|
138f593553b66c9f815e8f57870c19d6347f7702 UPDATE_PACKAGING_R12
|
||||||
|
138f593553b66c9f815e8f57870c19d6347f7702 UPDATE_PACKAGING_R13
|
||||||
|
138f593553b66c9f815e8f57870c19d6347f7702 UPDATE_PACKAGING_R11_1_MU
|
||||||
|
e56ecd8b3a68c158025207c5fd081d043e28f5ce GECKO_2_0_BASE
|
||||||
|
e273946b74c8d631ed86bd74ba9afe0e67b12378 GECKO_2_1_BASE
|
||||||
|
b70744835d94e54eec97b8fd186c96da5708a506 PRE_MOBILE_MERGE
|
||||||
|
b70744835d94e54eec97b8fd186c96da5708a506 PRE_MOBILE_MERGE_20110406
|
||||||
|
a71bd564ebf5bf4f93d13e84114f759c263130b0 MOBILE_MERGE_DONE
|
||||||
|
a71bd564ebf5bf4f93d13e84114f759c263130b0 MOBILE_MERGE_DONE_20110406
|
||||||
|
a95d426422816513477e5863add1b00ac7041dcb AURORA_BASE_20110412
|
||||||
|
138f593553b66c9f815e8f57870c19d6347f7702 UPDATE_PACKAGING_R14
|
||||||
|
9eae975b3d6fb7748fe5a3c0113d449b1c7cc0b2 AURORA_BASE_20110524
|
||||||
|
138f593553b66c9f815e8f57870c19d6347f7702 UPDATE_PACKAGING_R14
|
||||||
|
462c726144bc1fb45b61e774f64ac5d61b4e047c UPDATE_PACKAGING_R14
|
||||||
|
5eb553dd2ceae5f88d80f27afc5ef3935c5d43b0 AURORA_BASE_20110705
|
||||||
|
41b84b87c816403e1b74963d8094cff0406c989e AURORA_BASE_20110816
|
||||||
|
c0983049bcaa9551e5f276d5a77ce154c151e0b0 AURORA_BASE_20110927
|
||||||
|
462c726144bc1fb45b61e774f64ac5d61b4e047c UPDATE_PACKAGING_R15
|
||||||
|
54bfd8bf682e295ffd7f22fa921ca343957b6c1c AURORA_BASE_20111108
|
||||||
|
a8506ab2c65480cf2f85f54e203ea746522c62bb AURORA_BASE_20111220
|
||||||
|
462c726144bc1fb45b61e774f64ac5d61b4e047c UPDATE_PACKAGING_R16
|
||||||
|
bbc7014db2de49e2301680d2a86be8a53108a88a AURORA_BASE_20120131
|
||||||
|
bbc7014db2de49e2301680d2a86be8a53108a88a AURORA_BASE_20120131
|
||||||
|
0000000000000000000000000000000000000000 AURORA_BASE_20120131
|
||||||
|
0000000000000000000000000000000000000000 AURORA_BASE_20120131
|
||||||
|
bbc7014db2de49e2301680d2a86be8a53108a88a AURORA_BASE_20120131
|
||||||
|
b6627f28b7ec17e1b46a594df0f780d3a40847e4 FIREFOX_AURORA_13_BASE
|
||||||
|
357da346ceb705d196a46574804c7c4ec44ac186 FIREFOX_AURORA_14_BASE
|
||||||
|
26dcd1b1a20893ad99341c61c6b1239ff1523858 FIREFOX_AURORA_15_BASE
|
||||||
|
0accd12a8e7e217836ea3f1ee7c411913fc75d8e FIREFOX_AURORA_16_BASE
|
||||||
|
0000000000000000000000000000000000000000 FIREFOX_AURORA_16_BASE
|
||||||
|
9697eadafa13b4e9233b39aaeecfeac79503cb54 FIREFOX_AURORA_16_BASE
|
||||||
|
9697eadafa13b4e9233b39aaeecfeac79503cb54 FIREFOX_AURORA_16_BASE
|
||||||
|
6fdf9985acfe6f939da584b2559464ab22264fe7 FIREFOX_AURORA_16_BASE
|
||||||
|
fd72dbbd692012224145be1bf13df1d7675fd277 FIREFOX_AURORA_17_BASE
|
||||||
|
2704e441363fe2a48e992dfac694482dfd82664a FIREFOX_AURORA_18_BASE
|
||||||
|
cf8750abee06cde395c659f8ecd8ae019d7512e3 FIREFOX_AURORA_19_BASE
|
||||||
|
5bb309998e7050c9ee80b0147de1e473f008e221 FIREFOX_AURORA_20_BASE
|
||||||
|
cc37417e2c284aed960f98ffa479de4ccdd5c7c3 FIREFOX_AURORA_21_BASE
|
||||||
|
1c070ab0f9db59f13423b9c1db60419f7a9098f9 FIREFOX_AURORA_22_BASE
|
||||||
|
d7ce9089999719d5186595d160f25123a4e63e39 FIREFOX_AURORA_23_BASE
|
||||||
|
8d3810543edccf4fbe458178b88dd4a6e420b010 FIREFOX_AURORA_24_BASE
|
||||||
|
ad0ae007aa9e03cd74e9005cd6652e544139b3b5 FIREFOX_AURORA_25_BASE
|
||||||
|
2520866d58740851d862c7c59246a4e3f8b4a176 FIREFOX_AURORA_26_BASE
|
||||||
|
05025f4889a0bf4dc99ce0c244c750adc002f015 FIREFOX_AURORA_27_BASE
|
||||||
|
ba2cc1eda988a1614d8986ae145d28e1268409b9 FIREFOX_AURORA_29_BASE-m
|
||||||
|
ba2cc1eda988a1614d8986ae145d28e1268409b9 Tagging for mozilla-central version bumps CLOSED TREE DONTBUILD
|
||||||
|
ba2cc1eda988a1614d8986ae145d28e1268409b9 Tagging for mozilla-central version bumps CLOSED TREE DONTBUILD
|
||||||
|
0000000000000000000000000000000000000000 Tagging for mozilla-central version bumps CLOSED TREE DONTBUILD
|
||||||
|
ba2cc1eda988a1614d8986ae145d28e1268409b9 FIREFOX_AURORA_29_BASE-m
|
||||||
|
0000000000000000000000000000000000000000 FIREFOX_AURORA_29_BASE-m
|
||||||
|
ba2cc1eda988a1614d8986ae145d28e1268409b9 FIREFOX_AURORA_29_BASE
|
||||||
|
9f12a9fab080f2d363d7424e25b9ffe85ebc3414 FIREFOX_AURORA_28_BASE
|
||||||
|
07f5580d8a54e8311fa7641c907065a88de19e08 FIREFOX_AURORA_29_END
|
||||||
|
3776f72f1967a7068879501eb7c08920032785b8 B2G_1_4_20140317_MERGEDAY
|
||||||
|
aa70a6ce178a6839cd9e55761c4ac31d43ee7bd9 FIREFOX_BETA_29_END
|
||||||
|
ba4a8f81efdcf000414f192342ccbd14c9626c36 RELEASE_BASE_20140602
|
||||||
|
9f12a9fab080f2d363d7424e25b9ffe85ebc3414 FIREFOX_AURORA_28_BASE
|
||||||
|
83c9853e136451474dfa6d1aaa60a7fca7d2d83a FIREFOX_AURORA_30_BASE
|
||||||
|
cfde3603b0206e119abea76fdd6e134b634348f1 FIREFOX_AURORA_31_BASE
|
||||||
|
ab25447610b532eb4c32524a7dbc56a21eeaabb8 FIREFOX_BETA_30_BASE
|
||||||
|
ab25447610b532eb4c32524a7dbc56a21eeaabb8 FIREFOX_AURORA_30_END
|
||||||
|
6c18811bcd1b319801fd97aeb09c41b963863968 FIREFOX_BETA_30_END
|
||||||
|
1772e55568e420f8c7fbf7b9434157e9f419c8f1 FIREFOX_RELEASE_31_BASE
|
||||||
|
40b1b0712d7b53219a0404e78eec4e6a2796423e FIREFOX_RELEASE_30_END
|
||||||
|
9f12a9fab080f2d363d7424e25b9ffe85ebc3414 FIREFOX_AURORA_28_BASE
|
||||||
|
16f3cac5e8fe471e12f76d6a94a477b14e78df7c FIREFOX_AURORA_32_BASE
|
||||||
|
f11b164d75442617c4f046177d2ab913ed03a318 FIREFOX_BETA_31_BASE
|
||||||
|
f11b164d75442617c4f046177d2ab913ed03a318 FIREFOX_AURORA_31_END
|
||||||
|
dc2fd26b301375f15c935f00fe6283d3e3bc1efc B2G_2_0_20140609_MERGEDAY
|
||||||
|
d69cd84b6824e018e0906cab0464e11e97a9bdca FIREFOX_BETA_32_BASE
|
||||||
|
d69cd84b6824e018e0906cab0464e11e97a9bdca FIREFOX_BETA_32_BASE
|
||||||
|
0000000000000000000000000000000000000000 FIREFOX_BETA_32_BASE
|
||||||
|
0000000000000000000000000000000000000000 FIREFOX_BETA_32_BASE
|
||||||
|
ac396ad5a32d60ae5b7eebe5416fdd46e9e12be1 FIREFOX_BETA_32_BASE
|
||||||
|
6befadcaa68524d24960d8342e00503e4edc1869 FIREFOX_BETA_31_END
|
||||||
|
92ad4cfa9435fbe136c61071041812f90bc8d89e FIREFOX_RELEASE_32_BASE
|
||||||
|
cd52a7f8954809fd893196dc857f81b0cb61717c FIREFOX_RELEASE_31_END
|
||||||
|
9f12a9fab080f2d363d7424e25b9ffe85ebc3414 FIREFOX_AURORA_28_BASE
|
||||||
|
dc23164ba2a289a8b22902e30990c77d9677c214 FIREFOX_AURORA_33_BASE
|
||||||
|
a104ddcd4cdbf950f1755dfaf5a278d53570655f FIREFOX_AURORA_32_END
|
||||||
|
114b010b6bf1a0efee03f003e54ed6fa00909972 FIREFOX_BETA_33_BASE
|
||||||
|
ebd0ee3e97dc2756d979261b29f173638fe6aeb6 FIREFOX_BETA_32_END
|
||||||
|
e8360a0c7d7483491e064c7cd445a94004af0a83 FIREFOX_RELEASE_33_BASE
|
||||||
|
4641475ee1f3ec3e723e932e0f4f3f3fa7c55a5c FIREFOX_RELEASE_32_END
|
||||||
|
9f12a9fab080f2d363d7424e25b9ffe85ebc3414 FIREFOX_AURORA_28_BASE
|
||||||
|
c360f3d1c00d73b0c1fb0a2c0da525cb55e58b83 FIREFOX_AURORA_34_BASE
|
||||||
|
9f1aad8e807cc283aafbc14caa3d4775e8d0535c FIREFOX_AURORA_33_END
|
||||||
|
5b8210dcf52a795646bf0c8a32082a2ed7c4f537 B2G_2_1_20140902_MERGEDAY
|
||||||
|
e85828ce78a80e2ccda98972d69d5f750335c4ab FIREFOX_BETA_34_BASE
|
||||||
|
8574e35b517785acc905327f4994e96576218fa8 FIREFOX_BETA_33_END
|
||||||
|
e247a7f7c43842941bdb4207ca1b9d8881798997 FIREFOX_RELEASE_34_BASE
|
||||||
|
a47b1b720b67b018a9cb106178de53a363641392 FIREFOX_RELEASE_33_END
|
||||||
|
9f12a9fab080f2d363d7424e25b9ffe85ebc3414 FIREFOX_AURORA_28_BASE
|
||||||
|
cec1a116c4f9a3e887d52e9a26e8bbec200fe162 FIREFOX_AURORA_35_BASE
|
||||||
|
2608561c091ae83cc85e38740feffa5bfc6b5ed4 FIREFOX_AURORA_34_END
|
||||||
|
390a34a40ea4e7f4d24b3ed83778e0f408411fcc FIREFOX_BETA_35_BASE
|
||||||
|
a3cc435fd3c315e5dfe9329d03d5943bb893cced FIREFOX_BETA_34_END
|
||||||
|
fb06fa0600ab95db48212a237c79b650cac213c5 FIREFOX_RELEASE_35_BASE
|
||||||
|
f4217563f1568c478c1ddf1647098946e51bc7f8 FIREFOX_RELEASE_34_END
|
||||||
|
9f12a9fab080f2d363d7424e25b9ffe85ebc3414 FIREFOX_AURORA_28_BASE
|
||||||
|
ca89fe55717059e4e43040d16d260765ffa9dca7 FIREFOX_AURORA_36_BASE
|
||||||
|
6047f510fb73c7dbe9866066fb01ddda3c170c9c FIREFOX_AURORA_37_BASE
|
||||||
|
ca89fe55717059e4e43040d16d260765ffa9dca7 FIREFOX_AURORA_36_BASE
|
||||||
|
0000000000000000000000000000000000000000 FIREFOX_AURORA_36_BASE
|
||||||
|
6047f510fb73c7dbe9866066fb01ddda3c170c9c FIREFOX_AURORA_37_BASE
|
||||||
|
0000000000000000000000000000000000000000 FIREFOX_AURORA_37_BASE
|
||||||
|
0000000000000000000000000000000000000000 FIREFOX_AURORA_36_BASE
|
||||||
|
b297a6727acfd21e757ddd38cd61894812666265 FIREFOX_AURORA_36_BASE
|
||||||
|
0cf828669d5a0911b6f2b83d501eeef5bdf9905e FIREFOX_AURORA_35_END
|
||||||
|
75177371cb85baaa9d623f56d849a5c21d18040f FIREFOX_BETA_36_BASE
|
||||||
|
137baee3dda45c6a3b38be74f5709c24f7c7701a FIREFOX_BETA_35_END
|
||||||
|
948a2c2e31d4b7eaa282ddeb327708605e3cc7fa FIREFOX_RELEASE_36_BASE
|
||||||
|
d57ff45ca4fd7ccf1cb924030abf6c7d108eaab0 FIREFOX_RELEASE_35_END
|
||||||
|
9f12a9fab080f2d363d7424e25b9ffe85ebc3414 FIREFOX_AURORA_28_BASE
|
||||||
|
0000000000000000000000000000000000000000 FIREFOX_AURORA_37_BASE
|
||||||
|
2c951493eef5b50b8085ef78ffe0d7902ff3d593 FIREFOX_AURORA_37_BASE
|
||||||
|
1bc9beda018a42bdd5f63fc9fc46facf0c6f37ec FIREFOX_AURORA_36_END
|
||||||
|
030fa1665346dfa94d1f72a1c7830644664ecf08 FIREFOX_BETA_37_BASE
|
||||||
|
7d4016a05dd32bf2d726975ba9175bb13fc9ea97 FIREFOX_BETA_36_END
|
||||||
|
196c6575593d6e8997402fb458bf8ed2f954fa4a FIREFOX_RELEASE_37_BASE
|
||||||
|
58fe203296af528cc711dc314e4769a902e3852f FIREFOX_RELEASE_36_END
|
||||||
|
9f12a9fab080f2d363d7424e25b9ffe85ebc3414 FIREFOX_AURORA_28_BASE
|
||||||
|
98086da94ccdc88f6de86774ce3d1fa258dc7c44 FIREFOX_AURORA_38_BASE
|
||||||
|
d55b99e8010728b0c802e75e967d2a853122dd30 FIREFOX_AURORA_37_END
|
||||||
|
8bc9656cad94db48cd44f3947f1b3b1d8c57768a FIREFOX_BETA_38_BASE
|
||||||
|
b41c57eefd69242fc9664a3e5c2dcaa46840051c FIREFOX_BETA_37_END
|
||||||
|
fc98815acf5f041c6269fd256a68af8a92ba222a FIREFOX_RELEASE_38_BASE
|
||||||
|
b95583c8e7e7a7ce629b4d4551747e818367d0a0 FIREFOX_RELEASE_37_END
|
||||||
|
f33925facceefe32f6347faed2d805551d82e60b FIREFOX_RELEASE_38_END
|
||||||
|
9f12a9fab080f2d363d7424e25b9ffe85ebc3414 FIREFOX_AURORA_28_BASE
|
||||||
|
1b6bf6612c0f4d4fee81d18bf18016e692f874e1 FIREFOX_AURORA_39_BASE
|
||||||
|
d92bf011e305a4a4ad6bb98192a53b86bd64b813 FIREFOX_AURORA_38_END
|
||||||
|
5e851d50fb9b8d5a28e4fcd4731dd0f17e8fb4b9 FIREFOX_BETA_39_BASE
|
||||||
|
85229fbaf01713caa9ad26c7d3afec271494113c FIREFOX_BETA_38_END
|
||||||
|
5fecfbec2e3c934d4646a739bea60d3c93a35f9e FIREFOX_RELEASE_39_BASE
|
||||||
|
f33925facceefe32f6347faed2d805551d82e60b FIREFOX_RELEASE_38_END
|
||||||
|
971ab60e21d340e0407d2b9eb82fca67a4a9f1cb FIREFOX_RELEASE_38_END
|
||||||
|
9f12a9fab080f2d363d7424e25b9ffe85ebc3414 FIREFOX_AURORA_28_BASE
|
||||||
|
66a95a483d2c77dfc387019336d18093acd6aac2 FIREFOX_AURORA_40_BASE
|
||||||
|
eead3ccdf2d11feefc12907467cebbe07aa91ea9 FIREFOX_AURORA_39_END
|
||||||
|
d77cf39268848f8a7e9b38082348b6cd4d1f3b5e FIREFOX_BETA_40_BASE
|
||||||
|
0b0822cabbb95d8509852f90c0b7df5da0a4cabc FIREFOX_BETA_39_END
|
||||||
|
34e00eb800c52e33059d37f6e41fb255b4bae6b8 FIREFOX_RELEASE_40_BASE
|
||||||
|
ec21f96665f7d3fdd5d7944c90373938390096d7 FIREFOX_RELEASE_39_END
|
||||||
|
9f12a9fab080f2d363d7424e25b9ffe85ebc3414 FIREFOX_AURORA_28_BASE
|
||||||
|
312c68b16549de9cea1557f461d5d234bd5e0a7d FIREFOX_AURORA_41_BASE
|
||||||
|
9d83ab013ab61c7f6e987bf0e7cbab1a1aed1ca8 FIREFOX_AURORA_40_END
|
||||||
|
a019592053c4d93fbbafab8d0bd709529e3746de FIREFOX_BETA_41_BASE
|
||||||
|
f147014ff61a12480d377c8bde1f90891772540f FIREFOX_BETA_40_END
|
||||||
|
6c0329aacb73ab0510c6f1026ef066dfaed9139c FIREFOX_RELEASE_41_BASE
|
||||||
|
9c898cde2175e9e98b916d996ed286a9dff0c853 FIREFOX_RELEASE_40_END
|
||||||
|
9f12a9fab080f2d363d7424e25b9ffe85ebc3414 FIREFOX_AURORA_28_BASE
|
||||||
|
7a19194812eb767bee7cdf8fc36ba9a383c1bead FIREFOX_AURORA_42_BASE
|
||||||
|
d561dc208e61b2f2b4e82ab61710e14f56da4ddb FIREFOX_AURORA_41_END
|
||||||
|
61bbc30704aa104e9929c719c0fd7957f96f00ea FIREFOX_BETA_42_BASE
|
||||||
|
a5bf9cf6777519663e8e1db553727e59d3ad5681 FIREFOX_BETA_41_END
|
||||||
|
3f2ff85b2f16c1fd161dc5ba77a5f3f2c52fd127 FIREFOX_RELEASE_42_BASE
|
||||||
|
dc3a2ec52077a5cea772cdb267380f7debc3080b FIREFOX_RELEASE_41_END
|
||||||
|
9f12a9fab080f2d363d7424e25b9ffe85ebc3414 FIREFOX_AURORA_28_BASE
|
||||||
|
fcef8ded82219c89298b4e376cfbdfba79a1d35a FIREFOX_AURORA_43_BASE
|
||||||
|
b0e20ff87b175424edec414215b325918ccb4792 FIREFOX_AURORA_42_END
|
||||||
|
41fdefd640f368bccdeafe6446d42c0a5ad22797 FIREFOX_BETA_43_BASE
|
||||||
|
0ec8472a93ac0c7ef0e98ebb91ac780bde12d5a5 FIREFOX_BETA_42_END
|
||||||
|
38ffeba26f3e420312e04cb3afb408f4c66a6f2e FIREFOX_RELEASE_43_BASE
|
||||||
|
56320bc06404b926b475051ba643950bd78cf221 FIREFOX_RELEASE_42_END
|
||||||
|
9f12a9fab080f2d363d7424e25b9ffe85ebc3414 FIREFOX_AURORA_28_BASE
|
||||||
|
67a788db9f07822cfef52351bbbe3745dff8bd7f FIREFOX_AURORA_44_BASE
|
||||||
|
9d3bc275a924a84ab5f34df58c566af0f87479d0 FIREFOX_AURORA_43_END
|
||||||
|
b717b80eec62a7ba9b8842487f157b68c1419edd FIREFOX_BETA_44_BASE
|
||||||
|
366dd290472633b06f0942d7737c34e942e0916a FIREFOX_BETA_43_END
|
||||||
|
ef3cfadfccb97588653ae06eefdac28ec447c1f6 FIREFOX_RELEASE_44_BASE
|
||||||
|
af39a90c443c2fda798c2797e196eeb5a8b5cedd FIREFOX_RELEASE_43_END
|
||||||
|
9f12a9fab080f2d363d7424e25b9ffe85ebc3414 FIREFOX_AURORA_28_BASE
|
||||||
|
99137d6d4061f408ae0869122649d8bdf489cc30 FIREFOX_AURORA_45_BASE
|
||||||
|
4fbd53613240c431522521b953d5a62692909e65 FIREFOX_AURORA_44_END
|
||||||
|
3bfa5bc61b626761d487b45c170b115259f69d6b FIREFOX_BETA_45_BASE
|
||||||
|
6a7547e4a0f0e213bb8487c773e16543cbea8c73 FIREFOX_BETA_44_END
|
||||||
|
3a9789adadcd0de9ee31b16a89a11985822c6a11 FENNEC_45_0b1_RELEASE
|
||||||
|
6c0fd1f666e70f2b11f7083f9e7bf4c844a3716a FENNEC_45_0b1_RELEASE
|
||||||
|
3a9789adadcd0de9ee31b16a89a11985822c6a11 FENNEC_45_0b1_BUILD1
|
||||||
|
6c0fd1f666e70f2b11f7083f9e7bf4c844a3716a FENNEC_45_0b1_BUILD1
|
||||||
|
5e1da6523e97d7f8b01004bbe33118ac784b40ea FIREFOX_45_0b1_RELEASE
|
||||||
|
6c0fd1f666e70f2b11f7083f9e7bf4c844a3716a FIREFOX_45_0b1_RELEASE
|
||||||
|
5e1da6523e97d7f8b01004bbe33118ac784b40ea FIREFOX_45_0b1_BUILD1
|
||||||
|
6c0fd1f666e70f2b11f7083f9e7bf4c844a3716a FIREFOX_45_0b1_BUILD1
|
||||||
|
bbe048ab30ad3321a6505697703e5fee20e91343 FIREFOX_RELEASE_45_BASE
|
||||||
|
5fe8de3ca9bbf8bc18259c3490aca55c97e31979 FIREFOX_RELEASE_44_END
|
||||||
|
9f12a9fab080f2d363d7424e25b9ffe85ebc3414 FIREFOX_AURORA_28_BASE
|
||||||
|
67c66c2878aed17ae3096d7db483ddbb2293c503 FIREFOX_AURORA_46_BASE
|
||||||
|
d82221ba4219e4ac04ecfe2a5301703411e176fa FIREFOX_AURORA_45_END
|
||||||
|
89effb961712d4a5f84e90bcdd4e421ed6645eea FIREFOX_BETA_46_BASE
|
||||||
|
78fe98c670fcc9a1548ac655ae9a488d940fd9c8 FIREFOX_BETA_45_END
|
||||||
|
fb3494d06dfb73e26df72ca7a4bc4ef5ebf8795c FIREFOX_46_0b1_RELEASE
|
||||||
|
5904e3eb711dd263a6d2deb63b14e0c44e577054 FIREFOX_46_0b2_BUILD3
|
||||||
|
5904e3eb711dd263a6d2deb63b14e0c44e577054 FIREFOX_46_0b2_RELEASE
|
||||||
|
2f6f69a19150e03ad68062f2ac92342afb1ef787 FIREFOX_46_0b4_BUILD2
|
||||||
|
2f6f69a19150e03ad68062f2ac92342afb1ef787 FIREFOX_46_0b4_RELEASE
|
||||||
|
53d6e6648f97402a740687a82a297c66f5396548 FIREFOX_46_0b5_BUILD2
|
||||||
|
53d6e6648f97402a740687a82a297c66f5396548 FIREFOX_46_0b5_RELEASE
|
||||||
|
97b81104ac035d6a8f6ed59a1aad63fcc23e73c8 FIREFOX_46_0b6_BUILD1
|
||||||
|
97b81104ac035d6a8f6ed59a1aad63fcc23e73c8 FIREFOX_46_0b6_RELEASE
|
||||||
|
191f5eb4cbd72590277296cdb90d355adb347d45 FIREFOX_46_0b7_BUILD2
|
||||||
|
191f5eb4cbd72590277296cdb90d355adb347d45 FIREFOX_46_0b7_RELEASE
|
||||||
|
0334bcac4033f4f163476677165acd406e08fed8 FIREFOX_46_0b8_BUILD1
|
||||||
|
0334bcac4033f4f163476677165acd406e08fed8 FIREFOX_46_0b8_RELEASE
|
||||||
|
b007110e90053e58946b59765605bfca766c30d1 FIREFOX_46_0b9_BUILD1
|
||||||
|
b007110e90053e58946b59765605bfca766c30d1 FIREFOX_46_0b9_RELEASE
|
||||||
|
9ea83990839bd513869018e57bcbedb3454b63bb FIREFOX_46_0b10_BUILD1
|
||||||
|
9ea83990839bd513869018e57bcbedb3454b63bb FIREFOX_46_0b10_RELEASE
|
||||||
|
6c4646c7a6d6506e744c92a8170310191904c98e FIREFOX_RELEASE_46_BASE
|
||||||
|
64b6b8afb34bf8a4416b1d167b48177d0e30bde9 FIREFOX_RELEASE_45_END
|
||||||
|
078baf501b55eaa47f3b189fda4dd28dae1fa257 FIREFOX_46_0_BUILD5
|
||||||
|
078baf501b55eaa47f3b189fda4dd28dae1fa257 FIREFOX_46_0_RELEASE
|
||||||
|
0b8492c110bec959b94e3d54d5bd5ca7f7f97f6c FIREFOX_46_0_1_BUILD1
|
||||||
|
0b8492c110bec959b94e3d54d5bd5ca7f7f97f6c FIREFOX_46_0_1_RELEASE
|
||||||
|
076bf6a0ac85ec6a4f3ee7c3efe653964d92b9f2 FIREFOX_46_0b11_BUILD1
|
||||||
|
076bf6a0ac85ec6a4f3ee7c3efe653964d92b9f2 FIREFOX_46_0b11_RELEASE
|
||||||
|
9f12a9fab080f2d363d7424e25b9ffe85ebc3414 FIREFOX_AURORA_28_BASE
|
||||||
|
68d3781deda0d4d58ec9877862830db89669b3a5 FIREFOX_AURORA_47_BASE
|
||||||
|
43d92f7052e7bab870c9b994d4b0a0f42d26b7a7 FIREFOX_AURORA_46_END
|
||||||
|
8551b253f4061db31e4be7829c2f70c2610caf42 FIREFOX_BETA_47_BASE
|
||||||
|
a2290938ee6cf794896a9347980bcb00ebb24c68 FIREFOX_BETA_46_END
|
||||||
|
5bbf2e7c2fc6ff9010b1948e2f11477f48ee36e2 FIREFOX_47_0b1_BUILD2
|
||||||
|
5bbf2e7c2fc6ff9010b1948e2f11477f48ee36e2 FIREFOX_47_0b1_RELEASE
|
||||||
|
6f82d30fe05e1412e744cb76af86f0c9ffe509d4 FIREFOX_47_0b2_BUILD1
|
||||||
|
6f82d30fe05e1412e744cb76af86f0c9ffe509d4 FIREFOX_47_0b2_RELEASE
|
||||||
|
609000bcc11211d7c27ceea36fa2d2262fa0523f FIREFOX_47_0b3_BUILD1
|
||||||
|
609000bcc11211d7c27ceea36fa2d2262fa0523f FIREFOX_47_0b3_RELEASE
|
||||||
|
2991f214d4f4d8a3c5cfd95e6223f0660006767d FIREFOX_47_0b4_BUILD1
|
||||||
|
2991f214d4f4d8a3c5cfd95e6223f0660006767d FIREFOX_47_0b4_RELEASE
|
||||||
|
93a53170dedffdff45bf9eb8dac6e5ef7a13c4ba FIREFOX_47_0b5_BUILD1
|
||||||
|
93a53170dedffdff45bf9eb8dac6e5ef7a13c4ba FIREFOX_47_0b5_RELEASE
|
||||||
|
7d1f3450acc47025876964c1eca854ae027934f3 FIREFOX_47_0b6_BUILD1
|
||||||
|
7d1f3450acc47025876964c1eca854ae027934f3 FIREFOX_47_0b6_RELEASE
|
||||||
|
0723a0212f5e0b30d7532d4e35eba7759fb54507 FIREFOX_47_0b7_BUILD1
|
||||||
|
0723a0212f5e0b30d7532d4e35eba7759fb54507 FIREFOX_47_0b7_RELEASE
|
||||||
|
cb27eacbe04abc5f91a0379c23617715aab432ec FIREFOX_47_0b8_BUILD1
|
||||||
|
cb27eacbe04abc5f91a0379c23617715aab432ec FIREFOX_47_0b8_RELEASE
|
||||||
|
2ee4473c729acb2ba7dc723e7affe79ce14bff85 FIREFOX_47_0b9_BUILD1
|
||||||
|
2ee4473c729acb2ba7dc723e7affe79ce14bff85 FIREFOX_47_0b9_RELEASE
|
||||||
|
cf6ec12bd62001b93387ffb184a8841644255b5e FIREFOX_RELEASE_47_BASE
|
||||||
|
32d716995e14ae1e8eb128fde0881b121b7b53d0 FIREFOX_RELEASE_46_END
|
||||||
|
b0310cb90fd0158abd0e92850a47768649ba3d77 FIREFOX_47_0_BUILD3
|
||||||
|
b0310cb90fd0158abd0e92850a47768649ba3d77 FIREFOX_47_0_RELEASE
|
||||||
|
7f5abf95991bda0bc2b8e0d774a8866b726b312b FIREFOX_47_0_1_BUILD1
|
||||||
|
7f5abf95991bda0bc2b8e0d774a8866b726b312b FIREFOX_47_0_1_RELEASE
|
||||||
|
9f12a9fab080f2d363d7424e25b9ffe85ebc3414 FIREFOX_AURORA_28_BASE
|
||||||
|
1c6385ae1fe7e37d8f23f958ce14582f07af729e FIREFOX_AURORA_48_BASE
|
||||||
|
037f67a2d6c87e32f60b2753f19e4bed69cb60b3 FIREFOX_AURORA_47_END
|
||||||
|
961e7105e527f5b44e2b3cb6e24f6da33756f6ab FIREFOX_BETA_48_BASE
|
||||||
|
a86835580095325bf5c85483fad952f5c99d973e FIREFOX_BETA_47_END
|
||||||
|
55124c7343021091a61fdddac9f22628ca09642a FIREFOX_48_0b1_BUILD2
|
||||||
|
55124c7343021091a61fdddac9f22628ca09642a FIREFOX_48_0b1_RELEASE
|
||||||
|
9798772706750302d87a689cbbf056ae04244f80 FIREFOX_48_0b2_BUILD2
|
||||||
|
9798772706750302d87a689cbbf056ae04244f80 FIREFOX_48_0b2_RELEASE
|
||||||
|
13b02b96281e550c3cdbdf4eaed034aa1edefd69 FIREFOX_48_0b3_BUILD1
|
||||||
|
13b02b96281e550c3cdbdf4eaed034aa1edefd69 FIREFOX_48_0b3_RELEASE
|
||||||
|
676a32cdd41fd372f4c6df3a4954939f73a6ef02 FIREFOX_48_0b4_BUILD1
|
||||||
|
676a32cdd41fd372f4c6df3a4954939f73a6ef02 FIREFOX_48_0b4_RELEASE
|
||||||
|
dd7af1fa4ece1cb3158d08c80dfcbf1c6ca830fb FIREFOX_48_0b5_BUILD1
|
||||||
|
dd7af1fa4ece1cb3158d08c80dfcbf1c6ca830fb FIREFOX_48_0b5_RELEASE
|
||||||
|
d142c49033c015f67272562b37dbe2912cfc7f14 FIREFOX_48_0b6_BUILD1
|
||||||
|
d142c49033c015f67272562b37dbe2912cfc7f14 FIREFOX_48_0b6_RELEASE
|
||||||
|
9d734024ed35d74449601cc04917b327e0973c0d FIREFOX_48_0b7_BUILD1
|
||||||
|
9d734024ed35d74449601cc04917b327e0973c0d FIREFOX_48_0b7_RELEASE
|
||||||
|
d2ab9c39bd1059d74acb3d9ac87dbfbba913427b FIREFOX_48_0b9_BUILD1
|
||||||
|
d2ab9c39bd1059d74acb3d9ac87dbfbba913427b FIREFOX_48_0b9_RELEASE
|
||||||
|
05853bb06a8739b77c2937f418cdf4e1610d0d9f FIREFOX_48_0b10_BUILD1
|
||||||
|
05853bb06a8739b77c2937f418cdf4e1610d0d9f FIREFOX_48_0b10_RELEASE
|
||||||
|
f3d7abb885c267a7657e3b8ea06c18f76eb69641 FIREFOX_RELEASE_48_BASE
|
||||||
|
2366ae84e268c386a292185bddb0e4a24c2e1d07 FIREFOX_RELEASE_47_END
|
||||||
|
c1de04f39fa956cfce83f6065b0e709369215ed5 FIREFOX_48_0_BUILD2
|
||||||
|
c1de04f39fa956cfce83f6065b0e709369215ed5 FIREFOX_48_0_RELEASE
|
||||||
|
f36f7ace6f487e06f315f343d560b205fa8bd736 FIREFOX_48_0_1_BUILD3
|
||||||
|
f36f7ace6f487e06f315f343d560b205fa8bd736 FIREFOX_48_0_1_RELEASE
|
||||||
|
d4af0671004007e58d316b3e49679b66879c205a FIREFOX_48_0_2_BUILD1
|
||||||
|
d4af0671004007e58d316b3e49679b66879c205a FIREFOX_48_0_2_RELEASE
|
||||||
|
9f12a9fab080f2d363d7424e25b9ffe85ebc3414 FIREFOX_AURORA_28_BASE
|
||||||
|
a8fe75f38163d0af067fea60e951a844fb328db9 FIREFOX_AURORA_48_END
|
||||||
|
d2f65d99fd51e5ee2f34d892115cc5d6c39a8ea9 FIREFOX_BETA_49_BASE
|
||||||
|
958cee08361af9ed370be06695973bcda3d3aa46 FIREFOX_BETA_48_END
|
||||||
|
c14631e328bbbd3aabaf06b51597060b55938ba8 FIREFOX_49_0b1_BUILD3
|
||||||
|
c14631e328bbbd3aabaf06b51597060b55938ba8 FIREFOX_49_0b1_RELEASE
|
||||||
|
b1bdd0f3482ae07d38a2ec5fbf190a2c4f2310ee FIREFOX_49_0b2_BUILD1
|
||||||
|
b1bdd0f3482ae07d38a2ec5fbf190a2c4f2310ee FIREFOX_49_0b2_RELEASE
|
||||||
|
36af692196a1c92cc935cf6569e03fdf5dc5e426 FIREFOX_49_0b3_BUILD1
|
||||||
|
36af692196a1c92cc935cf6569e03fdf5dc5e426 FIREFOX_49_0b3_RELEASE
|
||||||
|
ab7b68014a1e20c423aa9b50ca76fd8edccb272c FIREFOX_49_0b4_BUILD1
|
||||||
|
ab7b68014a1e20c423aa9b50ca76fd8edccb272c FIREFOX_49_0b4_RELEASE
|
||||||
|
91505c2a68fb868bcab1e3dc03ffc2e89bf71cac FIREFOX_49_0b5_BUILD1
|
||||||
|
91505c2a68fb868bcab1e3dc03ffc2e89bf71cac FIREFOX_49_0b5_RELEASE
|
||||||
|
e6d6eb0ce3c42b4ebca91b1b1b64b716b2acb9fd FIREFOX_49_0b6_BUILD1
|
||||||
|
e6d6eb0ce3c42b4ebca91b1b1b64b716b2acb9fd FIREFOX_49_0b6_RELEASE
|
||||||
|
b44c72b85a800d9c6e719579d480bb2c3a87a753 FIREFOX_49_0b7_BUILD1
|
||||||
|
b44c72b85a800d9c6e719579d480bb2c3a87a753 FIREFOX_49_0b7_RELEASE
|
||||||
|
68d24e6f784c7e375cf6c84c5c92496464d4f7e0 FIREFOX_49_0b8_BUILD1
|
||||||
|
68d24e6f784c7e375cf6c84c5c92496464d4f7e0 FIREFOX_49_0b8_RELEASE
|
||||||
|
e3cc699ccef2abb7075c39e7b9a081718eb9c159 FIREFOX_49_0b9_BUILD1
|
||||||
|
e3cc699ccef2abb7075c39e7b9a081718eb9c159 FIREFOX_49_0b9_RELEASE
|
||||||
|
77a60bbacb97c2f36815b2c395958a354aa581c9 FIREFOX_49_0b10_BUILD1
|
||||||
|
77a60bbacb97c2f36815b2c395958a354aa581c9 FIREFOX_49_0b10_RELEASE
|
||||||
|
5d1f8216843a6374f3bd2bd74ab2532da67d74ee FIREFOX_RELEASE_49_BASE
|
||||||
|
31ca1b4c28a9f64e49d59ed01d08469a9af41951 FIREFOX_RELEASE_48_END
|
||||||
|
416dc3163a1f27b8783ed14660d1b373e830df2f FIREFOX_49_0_BUILD4
|
||||||
|
416dc3163a1f27b8783ed14660d1b373e830df2f FIREFOX_49_0_RELEASE
|
||||||
|
2d931a5eaf8aeee925eca2aea42582a1fb9793c8 FIREFOX_49_0_1_BUILD3
|
||||||
|
2d931a5eaf8aeee925eca2aea42582a1fb9793c8 FIREFOX_49_0_1_RELEASE
|
||||||
|
7356baae8e736a6c9444bdd21562df806a39766b FIREFOX_49_0_2_BUILD2
|
||||||
|
7356baae8e736a6c9444bdd21562df806a39766b FIREFOX_49_0_2_RELEASE
|
||||||
|
9f12a9fab080f2d363d7424e25b9ffe85ebc3414 FIREFOX_AURORA_28_BASE
|
||||||
|
d98f20c25feeac4dd7ebbd1c022957df1ef58af4 FIREFOX_AURORA_49_BASE
|
||||||
|
465d150bc8be5bbf9f02a8607d4552b6a5e1697c FIREFOX_AURORA_50_BASE
|
||||||
|
fa80a27f26dfc653d23392c71f562b1827d82174 FIREFOX_AURORA_49_END
|
||||||
|
c174d0c3195371011b3bf8044512c06c26f5c741 FIREFOX_BETA_50_BASE
|
||||||
|
ddeb7907bc1e854738b164bab5ff71c3dcf1d786 FIREFOX_BETA_49_END
|
||||||
|
91faf7ec36cd18a8ebdc0e2edac966e5bbb15da2 FIREFOX_50_0b1_BUILD2
|
||||||
|
91faf7ec36cd18a8ebdc0e2edac966e5bbb15da2 FIREFOX_50_0b1_RELEASE
|
||||||
|
865939f4946d80fa532aaa168515a2fe69f9a774 FIREFOX_50_0b2_BUILD1
|
||||||
|
865939f4946d80fa532aaa168515a2fe69f9a774 FIREFOX_50_0b2_RELEASE
|
||||||
|
6a7c1c8db5548d077c7fa36bce41af629ba52bd8 FIREFOX_50_0b3_BUILD1
|
||||||
|
6a7c1c8db5548d077c7fa36bce41af629ba52bd8 FIREFOX_50_0b3_RELEASE
|
||||||
|
f4b45ea3c0c836e5a457c8009bff423447e54803 FIREFOX_50_0b4_BUILD1
|
||||||
|
f4b45ea3c0c836e5a457c8009bff423447e54803 FIREFOX_50_0b4_RELEASE
|
||||||
|
49776d31766dd130969f9ec4ea3354a43e8e6d9d FIREFOX_50_0b5_BUILD1
|
||||||
|
49776d31766dd130969f9ec4ea3354a43e8e6d9d FIREFOX_50_0b5_RELEASE
|
||||||
|
70abfe99097824fd510544b188f24c588fd6d5a0 FIREFOX_50_0b6_BUILD1
|
||||||
|
70abfe99097824fd510544b188f24c588fd6d5a0 FIREFOX_50_0b6_RELEASE
|
||||||
|
6efc0964ec62bc4abfdc4cb1dc7cc461c3238634 FIREFOX_50_0b7_BUILD1
|
||||||
|
6efc0964ec62bc4abfdc4cb1dc7cc461c3238634 FIREFOX_50_0b7_RELEASE
|
||||||
|
b7adb2f10487f6f886e047670ba720a248edcb44 FIREFOX_50_0b8_BUILD1
|
||||||
|
b7adb2f10487f6f886e047670ba720a248edcb44 FIREFOX_50_0b8_RELEASE
|
||||||
|
2bb6dc758711c00d84246d74b57e5aa6cae4b447 FIREFOX_50_0b9_BUILD1
|
||||||
|
2bb6dc758711c00d84246d74b57e5aa6cae4b447 FIREFOX_50_0b9_RELEASE
|
||||||
|
38cfded1705240c5d20baff4aef99bdd0a13bcec FIREFOX_50_0b10_BUILD1
|
||||||
|
38cfded1705240c5d20baff4aef99bdd0a13bcec FIREFOX_50_0b10_RELEASE
|
||||||
|
829a3f99f2606759305e3db204185242566a4ca6 FIREFOX_50_0b11_BUILD1
|
||||||
|
829a3f99f2606759305e3db204185242566a4ca6 FIREFOX_50_0b11_RELEASE
|
||||||
|
d7598ee90bc6085d430b2e9e75c13358ef00a5f4 FIREFOX_RELEASE_50_BASE
|
||||||
|
dd6c8d2be972cbf8729c01292639b8a03ce94728 FIREFOX_RELEASE_49_END
|
||||||
|
dc617d65c9f0cdbbe4351cc1e5c288b05f25f8f7 FIREFOX_50_0_BUILD2
|
||||||
|
dc617d65c9f0cdbbe4351cc1e5c288b05f25f8f7 FIREFOX_50_0_RELEASE
|
||||||
|
8612c3320053b796678921f8f23358e3e9df997e FIREFOX_50_1_0_BUILD2
|
||||||
|
8612c3320053b796678921f8f23358e3e9df997e FIREFOX_50_1_0_RELEASE
|
||||||
|
9f12a9fab080f2d363d7424e25b9ffe85ebc3414 FIREFOX_AURORA_28_BASE
|
||||||
|
fc69febcbf6c0dcc4b3dfc7a346d8d348798a65f FIREFOX_AURORA_51_BASE
|
||||||
|
3fdfaaed6e0fad2d81fc28e49903ff6f0a43b12e FIREFOX_AURORA_50_END
|
||||||
|
2d9b6132e7d75327e063a15d8e5e279077adf987 FIREFOX_BETA_51_BASE
|
||||||
|
24b8f08f77565f859898b45f62d2132ccc64c6d8 FIREFOX_BETA_50_END
|
||||||
|
749a8d32b74eae516b9427f28aad4ec1c11e0a54 FIREFOX_51_0b1_BUILD2
|
||||||
|
749a8d32b74eae516b9427f28aad4ec1c11e0a54 FIREFOX_51_0b1_RELEASE
|
||||||
|
6296ed3dbefd133bba324230ec4f5a07d37041e1 FIREFOX_51_0b2_BUILD1
|
||||||
|
6296ed3dbefd133bba324230ec4f5a07d37041e1 FIREFOX_51_0b2_RELEASE
|
||||||
|
f37e99ebc6e0c682003b52573f415e5fd78d425a FIREFOX_51_0b3_BUILD1
|
||||||
|
f37e99ebc6e0c682003b52573f415e5fd78d425a FIREFOX_51_0b3_RELEASE
|
||||||
|
1b954c82dd04faf1926804d89c0d130dc6b9ab93 FIREFOX_51_0b4_BUILD1
|
||||||
|
1b954c82dd04faf1926804d89c0d130dc6b9ab93 FIREFOX_51_0b4_RELEASE
|
||||||
|
9afe68360fa82c16b760b448b2156230a90caf11 FIREFOX_51_0b5_BUILD1
|
||||||
|
9afe68360fa82c16b760b448b2156230a90caf11 FIREFOX_51_0b5_RELEASE
|
||||||
|
2dec3c6c7c90e2e27093b8a3512c1b32a8263a8f FIREFOX_51_0b6_BUILD1
|
||||||
|
2dec3c6c7c90e2e27093b8a3512c1b32a8263a8f FIREFOX_51_0b6_RELEASE
|
||||||
|
829fcc7f60f04dffff4d29b007ef8015a1cd2c99 FIREFOX_51_0b7_BUILD1
|
||||||
|
829fcc7f60f04dffff4d29b007ef8015a1cd2c99 FIREFOX_51_0b7_RELEASE
|
||||||
|
ae5275b8c53ba76cb98576e4e2a3031b0d659ba3 FIREFOX_51_0b8_BUILD1
|
||||||
|
ae5275b8c53ba76cb98576e4e2a3031b0d659ba3 FIREFOX_51_0b8_RELEASE
|
||||||
|
6e4843d1510be426212d31fec03ad4f2d70b1977 FIREFOX_51_0b9_BUILD1
|
||||||
|
6e4843d1510be426212d31fec03ad4f2d70b1977 FIREFOX_51_0b9_RELEASE
|
||||||
|
4fbf5d14ce92bd45e0c7881dad20a66896402683 FIREFOX_51_0b10_BUILD1
|
||||||
|
4fbf5d14ce92bd45e0c7881dad20a66896402683 FIREFOX_51_0b10_RELEASE
|
||||||
|
0a17d39220700e742bf37a960967480b2f8159f1 FIREFOX_51_0b11_BUILD1
|
||||||
|
0a17d39220700e742bf37a960967480b2f8159f1 FIREFOX_51_0b11_RELEASE
|
||||||
|
9ddd4fee07842e72ba49f1583ec5f596f6e60e72 FIREFOX_51_0b12_BUILD1
|
||||||
|
9ddd4fee07842e72ba49f1583ec5f596f6e60e72 FIREFOX_51_0b12_RELEASE
|
||||||
|
ce55e4d276031458f0730d481acff05d7c797038 FIREFOX_51_0b13_BUILD1
|
||||||
|
ce55e4d276031458f0730d481acff05d7c797038 FIREFOX_51_0b13_RELEASE
|
||||||
|
09142d07fd735e375fc1ae46886a52d6aef43b60 FIREFOX_51_0b14_BUILD1
|
||||||
|
09142d07fd735e375fc1ae46886a52d6aef43b60 FIREFOX_51_0b14_RELEASE
|
||||||
|
15467610e733e3549ea86cdf940b0fccd87eff89 FIREFOX_RELEASE_51_BASE
|
||||||
|
b1e53b9be6d4834f5b3a58c132dfc5f5c73d2bcd FIREFOX_RELEASE_50_END
|
||||||
|
ea82b5e20cbbd103f8fa65f0df0386ee4135cc47 FIREFOX_51_0_BUILD2
|
||||||
|
ea82b5e20cbbd103f8fa65f0df0386ee4135cc47 FIREFOX_51_0_RELEASE
|
||||||
|
327e081221b064b05a302d7877c6e4be2949a617 FIREFOX_51_0_1_BUILD3
|
||||||
|
327e081221b064b05a302d7877c6e4be2949a617 FIREFOX_51_0_1_RELEASE
|
||||||
|
9f12a9fab080f2d363d7424e25b9ffe85ebc3414 FIREFOX_AURORA_28_BASE
|
||||||
|
1196bf3032e1bce1fb07a01fd9082a767426c5fb FIREFOX_AURORA_52_BASE
|
||||||
|
3223a6411d8c8b9ec8bcbc607c990bf099ade099 FIREFOX_AURORA_51_END
|
||||||
|
24a81d93e07cc96300f8e1f5c69034dd4743bd63 FIREFOX_BETA_52_BASE
|
||||||
|
8e692dd4176cba81ce020b29ae8b352dc1db724a FIREFOX_BETA_51_END
|
||||||
|
78ae21055d9f303be257abe155ba9dee466c0651 FIREFOX_52_0b1_BUILD2
|
||||||
|
78ae21055d9f303be257abe155ba9dee466c0651 FIREFOX_52_0b1_RELEASE
|
||||||
|
0f339c1e154f75c484fe2fac507a9a225990d212 FIREFOX_52_0b2_BUILD1
|
||||||
|
0f339c1e154f75c484fe2fac507a9a225990d212 FIREFOX_52_0b2_RELEASE
|
||||||
|
d171c36d484800b1bb00db1612460a7120dd2fdf FIREFOX_52_0b3_BUILD1
|
||||||
|
d171c36d484800b1bb00db1612460a7120dd2fdf FIREFOX_52_0b3_RELEASE
|
||||||
|
501a3fa83897af9598adfd6f794b5d5ea82fe237 FIREFOX_52_0b4_BUILD1
|
||||||
|
501a3fa83897af9598adfd6f794b5d5ea82fe237 FIREFOX_52_0b4_RELEASE
|
||||||
|
49b3ad9f467d48194dab8121f82e4c938b70b484 FIREFOX_52_0b5_BUILD1
|
||||||
|
49b3ad9f467d48194dab8121f82e4c938b70b484 FIREFOX_52_0b5_RELEASE
|
||||||
|
7b8aa893944b94d35e47314e52e0abff576c5ce2 FIREFOX_52_0b6_BUILD1
|
||||||
|
7b8aa893944b94d35e47314e52e0abff576c5ce2 FIREFOX_52_0b6_RELEASE
|
||||||
|
820bc5bd3120853d611af1056f4a2b35528bb927 FIREFOX_52_0b7_BUILD1
|
||||||
|
820bc5bd3120853d611af1056f4a2b35528bb927 FIREFOX_52_0b7_RELEASE
|
||||||
|
3b31bcb88fe341172e93cc8b1143e617c0988694 FIREFOX_52_0b8_BUILD1
|
||||||
|
3b31bcb88fe341172e93cc8b1143e617c0988694 FIREFOX_52_0b8_RELEASE
|
||||||
|
61519976b35f2947eeaabefcad83186b7e004167 FIREFOX_52_0b9_BUILD2
|
||||||
|
61519976b35f2947eeaabefcad83186b7e004167 FIREFOX_52_0b9_RELEASE
|
||||||
|
4bd2e5d2ac0d0b15b4446fca5647bfa821b52d46 FIREFOX_RELEASE_52_BASE
|
||||||
|
1f0fc9316e65cd171b03d4382b4c0f7443a258dc FIREFOX_RELEASE_51_END
|
||||||
|
2183f7cb4f886e5f0b619dcff101bee72210ef38 FIREFOX_ESR_52_BASE
|
||||||
|
15d9d940341f02ef6dcad96899d284619d3d48db FIREFOX_52_0esr_BUILD4
|
||||||
|
15d9d940341f02ef6dcad96899d284619d3d48db FIREFOX_52_0esr_RELEASE
|
||||||
|
3462b933db3cac9b994b32dfc6350f3d549bf2de FIREFOX_52_0_1esr_BUILD2
|
||||||
|
3462b933db3cac9b994b32dfc6350f3d549bf2de FIREFOX_52_0_1esr_RELEASE
|
||||||
|
afa66bcf9203e691f164e5e8a9cc8fad783ccddc FIREFOX_52_0_2esr_BUILD1
|
||||||
|
afa66bcf9203e691f164e5e8a9cc8fad783ccddc FIREFOX_52_0_2esr_RELEASE
|
||||||
|
3ea0e075203185d7f2d42f439455e97735bd1b20 FIREFOX_52_1_0esr_BUILD3
|
||||||
|
3ea0e075203185d7f2d42f439455e97735bd1b20 FIREFOX_52_1_0esr_RELEASE
|
||||||
|
120111e65bc4e9b99da97e9d046765de95fbac8c FIREFOX_52_1_1esr_BUILD1
|
||||||
|
120111e65bc4e9b99da97e9d046765de95fbac8c FIREFOX_52_1_1esr_RELEASE
|
||||||
|
0dc7c28f20648d597b11b60e90be9a15687656aa FIREFOX_52_1_2esr_BUILD1
|
||||||
|
0dc7c28f20648d597b11b60e90be9a15687656aa FIREFOX_52_1_2esr_RELEASE
|
||||||
|
f68e0d98a22a4712a3710998081fd0ea5cd00ccb FIREFOX_52_2_0esr_BUILD1
|
||||||
|
f68e0d98a22a4712a3710998081fd0ea5cd00ccb FIREFOX_52_2_0esr_RELEASE
|
||||||
|
512efd480dac58acf9eebd5f25a76b32917ab56d FIREFOX_52_2_1esr_BUILD2
|
||||||
|
512efd480dac58acf9eebd5f25a76b32917ab56d FIREFOX_52_2_1esr_RELEASE
|
||||||
|
20a1a6ad46d5a4ec83d9800614fc288bf79e14a8 FIREFOX_52_3_0esr_BUILD2
|
||||||
|
20a1a6ad46d5a4ec83d9800614fc288bf79e14a8 FIREFOX_52_3_0esr_RELEASE
|
||||||
|
285cde3988335103bd8d60cc09d6fa36db3c4d78 FIREFOX_52_4_0esr_BUILD2
|
||||||
|
285cde3988335103bd8d60cc09d6fa36db3c4d78 FIREFOX_52_4_0esr_RELEASE
|
||||||
|
e4fec62e5347a77a9a313d6019a2b372e8011a74 FIREFOX_52_4_1esr_BUILD1
|
||||||
|
e4fec62e5347a77a9a313d6019a2b372e8011a74 FIREFOX_52_4_1esr_RELEASE
|
||||||
|
cf34a0574e585fab44fbec1718aca5375790cd97 FIREFOX_52_5_0esr_BUILD2
|
||||||
|
cf34a0574e585fab44fbec1718aca5375790cd97 FIREFOX_52_5_0esr_RELEASE
|
||||||
|
b0a57c57b5ef0150e8afc3219bceadb1d6f1584e FIREFOX_52_5_2esr_BUILD2
|
||||||
|
b0a57c57b5ef0150e8afc3219bceadb1d6f1584e FIREFOX_52_5_2esr_RELEASE
|
||||||
31
.lldbinit
Normal file
31
.lldbinit
Normal file
|
|
@ -0,0 +1,31 @@
|
||||||
|
# .lldbinit file for debugging Mozilla
|
||||||
|
|
||||||
|
# -----------------------------------------------------------------------------
|
||||||
|
# For documentation on all of the commands and type summaries defined here
|
||||||
|
# and in the accompanying Python scripts, see python/lldbutils/README.txt.
|
||||||
|
# -----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
# Import the module that defines complex Gecko debugging commands. This assumes
|
||||||
|
# you are either running lldb from the top level source directory, the objdir,
|
||||||
|
# or the dist/bin directory. (.lldbinit files in the objdir and dist/bin set
|
||||||
|
# topsrcdir appropriately.)
|
||||||
|
script topsrcdir = topsrcdir if locals().has_key("topsrcdir") else os.getcwd(); sys.path.append(os.path.join(topsrcdir, "python/lldbutils")); import lldbutils; lldbutils.init()
|
||||||
|
|
||||||
|
# Mozilla's use of UNIFIED_SOURCES to include multiple source files into a
|
||||||
|
# single compiled file breaks lldb breakpoint setting. This works around that.
|
||||||
|
# See http://lldb.llvm.org/troubleshooting.html for more info.
|
||||||
|
settings set target.inline-breakpoint-strategy always
|
||||||
|
|
||||||
|
# Show the dynamic type of an object when using "expr". This, for example,
|
||||||
|
# will show a variable declared as "nsIFrame *" that points to an nsBlockFrame
|
||||||
|
# object as being of type "nsBlockFrame *" rather than "nsIFrame *".
|
||||||
|
settings set target.prefer-dynamic-value run-target
|
||||||
|
|
||||||
|
# Show the string value in atoms.
|
||||||
|
type summary add nsIAtom --summary-string "${var.mString}"
|
||||||
|
|
||||||
|
# Show the value of text nodes.
|
||||||
|
type summary add nsTextNode --summary-string "${var.mText}"
|
||||||
|
|
||||||
|
# Dump the current JS stack.
|
||||||
|
command alias js expr DumpJSStack()
|
||||||
125
.taskcluster.yml
Normal file
125
.taskcluster.yml
Normal file
|
|
@ -0,0 +1,125 @@
|
||||||
|
---
|
||||||
|
version: 0
|
||||||
|
metadata:
|
||||||
|
name: 'Taskcluster tasks for Gecko'
|
||||||
|
description: "The taskcluster task graph for Gecko trees"
|
||||||
|
owner: mozilla-taskcluster-maintenance@mozilla.com
|
||||||
|
source: {{{source}}}
|
||||||
|
|
||||||
|
scopes:
|
||||||
|
# Note the below scopes are insecure however these get overriden on the server
|
||||||
|
# side to whatever scopes are set by mozilla-taskcluster.
|
||||||
|
- queue:*
|
||||||
|
- docker-worker:*
|
||||||
|
- scheduler:*
|
||||||
|
|
||||||
|
# Available mustache parameters (see the mozilla-taskcluster source):
|
||||||
|
#
|
||||||
|
# - owner: push user (email address)
|
||||||
|
# - source: URL of this YAML file
|
||||||
|
# - url: repository URL
|
||||||
|
# - project: alias for the destination repository (basename of
|
||||||
|
# the repo url)
|
||||||
|
# - level: SCM level of the destination repository
|
||||||
|
# (1 = try, 3 = core)
|
||||||
|
# - revision: (short) hg revision of the head of the push
|
||||||
|
# - revision_hash: (long) hg revision of the head of the push
|
||||||
|
# - comment: comment of the push
|
||||||
|
# - pushlog_id: id in the pushlog table of the repository
|
||||||
|
#
|
||||||
|
# and functions:
|
||||||
|
# - as_slugid: convert a label into a slugId
|
||||||
|
# - from_now: generate a timestamp at a fixed offset from now
|
||||||
|
|
||||||
|
# The resulting tasks' taskGroupId will be equal to the taskId of the first
|
||||||
|
# task listed here, which should be the decision task. This gives other tools
|
||||||
|
# an easy way to determine the ID of the decision task that created a
|
||||||
|
# particular group.
|
||||||
|
|
||||||
|
tasks:
|
||||||
|
- taskId: '{{#as_slugid}}decision task{{/as_slugid}}'
|
||||||
|
task:
|
||||||
|
created: '{{now}}'
|
||||||
|
deadline: '{{#from_now}}1 day{{/from_now}}'
|
||||||
|
expires: '{{#from_now}}365 day{{/from_now}}'
|
||||||
|
metadata:
|
||||||
|
owner: mozilla-taskcluster-maintenance@mozilla.com
|
||||||
|
source: {{{source}}}
|
||||||
|
name: "Gecko Decision Task"
|
||||||
|
description: |
|
||||||
|
The task that creates all of the other tasks in the task graph
|
||||||
|
|
||||||
|
workerType: "gecko-decision"
|
||||||
|
provisionerId: "aws-provisioner-v1"
|
||||||
|
|
||||||
|
tags:
|
||||||
|
createdForUser: {{owner}}
|
||||||
|
|
||||||
|
scopes:
|
||||||
|
# Bug 1269443: cache scopes, etc. must be listed explicitly
|
||||||
|
- "docker-worker:cache:level-{{level}}-*"
|
||||||
|
- "docker-worker:cache:tooltool-cache"
|
||||||
|
# mozilla-taskcluster will append the appropriate assume:repo:<repo>
|
||||||
|
# scope here.
|
||||||
|
|
||||||
|
routes:
|
||||||
|
- "index.gecko.v2.{{project}}.latest.firefox.decision"
|
||||||
|
- "tc-treeherder.v2.{{project}}.{{revision}}.{{pushlog_id}}"
|
||||||
|
- "tc-treeherder-stage.v2.{{project}}.{{revision}}.{{pushlog_id}}"
|
||||||
|
|
||||||
|
payload:
|
||||||
|
env:
|
||||||
|
# checkout-gecko uses these to check out the source; the inputs
|
||||||
|
# to `mach taskgraph decision` are all on the command line.
|
||||||
|
GECKO_BASE_REPOSITORY: 'https://hg.mozilla.org/mozilla-unified'
|
||||||
|
GECKO_HEAD_REPOSITORY: '{{{url}}}'
|
||||||
|
GECKO_HEAD_REF: '{{revision}}'
|
||||||
|
GECKO_HEAD_REV: '{{revision}}'
|
||||||
|
HG_STORE_PATH: /home/worker/checkouts/hg-store
|
||||||
|
|
||||||
|
cache:
|
||||||
|
level-{{level}}-checkouts: /home/worker/checkouts
|
||||||
|
|
||||||
|
features:
|
||||||
|
taskclusterProxy: true
|
||||||
|
chainOfTrust: true
|
||||||
|
|
||||||
|
# Note: This task is built server side without the context or tooling that
|
||||||
|
# exist in tree so we must hard code the version
|
||||||
|
image: 'taskcluster/decision:0.1.7'
|
||||||
|
|
||||||
|
maxRunTime: 1800
|
||||||
|
|
||||||
|
# TODO use mozilla-unified for the base repository once the tc-vcs
|
||||||
|
# tar.gz archives are created or tc-vcs isn't being used.
|
||||||
|
command:
|
||||||
|
- /home/worker/bin/run-task
|
||||||
|
- '--vcs-checkout=/home/worker/checkouts/gecko'
|
||||||
|
- '--'
|
||||||
|
- bash
|
||||||
|
- -cx
|
||||||
|
- >
|
||||||
|
cd /home/worker/checkouts/gecko &&
|
||||||
|
ln -s /home/worker/artifacts artifacts &&
|
||||||
|
./mach --log-no-times taskgraph decision
|
||||||
|
--pushlog-id='{{pushlog_id}}'
|
||||||
|
--pushdate='{{pushdate}}'
|
||||||
|
--project='{{project}}'
|
||||||
|
--message={{#shellquote}}{{{comment}}}{{/shellquote}}
|
||||||
|
--owner='{{owner}}'
|
||||||
|
--level='{{level}}'
|
||||||
|
--base-repository='https://hg.mozilla.org/mozilla-central'
|
||||||
|
--head-repository='{{{url}}}'
|
||||||
|
--head-ref='{{revision}}'
|
||||||
|
--head-rev='{{revision}}'
|
||||||
|
--revision-hash='{{revision_hash}}'
|
||||||
|
|
||||||
|
artifacts:
|
||||||
|
'public':
|
||||||
|
type: 'directory'
|
||||||
|
path: '/home/worker/artifacts'
|
||||||
|
expires: '{{#from_now}}364 days{{/from_now}}'
|
||||||
|
|
||||||
|
extra:
|
||||||
|
treeherder:
|
||||||
|
symbol: D
|
||||||
47
.ycm_extra_conf.py
Normal file
47
.ycm_extra_conf.py
Normal file
|
|
@ -0,0 +1,47 @@
|
||||||
|
# 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/.
|
||||||
|
|
||||||
|
import imp
|
||||||
|
import os
|
||||||
|
import shlex
|
||||||
|
import sys
|
||||||
|
try:
|
||||||
|
from StringIO import StringIO
|
||||||
|
except ImportError:
|
||||||
|
from io import StringIO
|
||||||
|
|
||||||
|
old_bytecode = sys.dont_write_bytecode
|
||||||
|
sys.dont_write_bytecode = True
|
||||||
|
|
||||||
|
path = os.path.join(os.path.dirname(__file__), 'mach')
|
||||||
|
|
||||||
|
if not os.path.exists(path):
|
||||||
|
path = os.path.join(os.path.dirname(__file__), 'config.status')
|
||||||
|
config = imp.load_module('_buildconfig', open(path), path, ('', 'r', imp.PY_SOURCE))
|
||||||
|
path = os.path.join(config.topsrcdir, 'mach')
|
||||||
|
mach_module = imp.load_module('_mach', open(path), path, ('', 'r', imp.PY_SOURCE))
|
||||||
|
|
||||||
|
sys.dont_write_bytecode = old_bytecode
|
||||||
|
|
||||||
|
def FlagsForFile(filename):
|
||||||
|
mach = mach_module.get_mach()
|
||||||
|
out = StringIO()
|
||||||
|
|
||||||
|
# Mach calls sys.stdout.fileno(), so we need to fake it when capturing it.
|
||||||
|
# Returning an invalid file descriptor does the trick.
|
||||||
|
out.fileno = lambda: -1
|
||||||
|
out.encoding = None
|
||||||
|
mach.run(['compileflags', filename], stdout=out, stderr=out)
|
||||||
|
|
||||||
|
flag_list = shlex.split(out.getvalue())
|
||||||
|
|
||||||
|
# This flag is added by Fennec for android build and causes ycmd to fail to parse the file.
|
||||||
|
# Removing this flag is a workaround until ycmd starts to handle this flag properly.
|
||||||
|
# https://github.com/Valloric/YouCompleteMe/issues/1490
|
||||||
|
final_flags = [x for x in flag_list if not x.startswith('-march=armv')]
|
||||||
|
|
||||||
|
return {
|
||||||
|
'flags': final_flags,
|
||||||
|
'do_cache': True
|
||||||
|
}
|
||||||
5
Android.mk
Normal file
5
Android.mk
Normal file
|
|
@ -0,0 +1,5 @@
|
||||||
|
# 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/.
|
||||||
|
|
||||||
|
# empty file to block B2G/Gonk from trying to build anything inside mozilla-central
|
||||||
25
CLOBBER
Normal file
25
CLOBBER
Normal file
|
|
@ -0,0 +1,25 @@
|
||||||
|
# To trigger a clobber replace ALL of the textual description below,
|
||||||
|
# giving a bug number and a one line description of why a clobber is
|
||||||
|
# required. Modifying this file will make configure check that a
|
||||||
|
# clobber has been performed before the build can continue.
|
||||||
|
#
|
||||||
|
# MERGE NOTE: When merging two branches that require a CLOBBER, you should
|
||||||
|
# merge both CLOBBER descriptions, to ensure that users on
|
||||||
|
# both branches correctly see the clobber warning.
|
||||||
|
#
|
||||||
|
# O <-- Users coming from both parents need to Clobber
|
||||||
|
# / \
|
||||||
|
# O O
|
||||||
|
# | |
|
||||||
|
# O <-- Clobber O <-- Clobber
|
||||||
|
#
|
||||||
|
# Note: The description below will be part of the error message shown to users.
|
||||||
|
#
|
||||||
|
# Modifying this file will now automatically clobber the buildbot machines \o/
|
||||||
|
#
|
||||||
|
|
||||||
|
# Are you updating CLOBBER because you think it's needed for your WebIDL
|
||||||
|
# changes to stick? As of bug 928195, this shouldn't be necessary! Please
|
||||||
|
# don't change CLOBBER for WebIDL changes any more.
|
||||||
|
|
||||||
|
Merge day clobber
|
||||||
14
GNUmakefile
Normal file
14
GNUmakefile
Normal file
|
|
@ -0,0 +1,14 @@
|
||||||
|
# This Makefile is used as a shim to aid people with muscle memory
|
||||||
|
# so that they can type "make".
|
||||||
|
#
|
||||||
|
# This file and all of its targets should not be used by anything important.
|
||||||
|
|
||||||
|
all: build
|
||||||
|
|
||||||
|
build:
|
||||||
|
./mach build
|
||||||
|
|
||||||
|
clean:
|
||||||
|
./mach clobber
|
||||||
|
|
||||||
|
.PHONY: all build clean
|
||||||
43
LEGAL
Normal file
43
LEGAL
Normal file
|
|
@ -0,0 +1,43 @@
|
||||||
|
Please be apprised of the following Legal Notices:
|
||||||
|
|
||||||
|
A) The U.S. District Court for the Eastern District of Virginia has
|
||||||
|
ruled that the Netscape Navigator code does not infringe Wang's U.S.
|
||||||
|
Patent No. 4,751,669 ("the '669 Patent") because: 1) HTML is not
|
||||||
|
Videotex as defined by the '669 patent; 2) web servers are not central
|
||||||
|
suppliers; and 3) Navigator does not "connect," as defined by the '669
|
||||||
|
Patent, to web servers on the Internet. Wang may appeal this decision to
|
||||||
|
the Federal Circuit. Wang contended that its Patent disclosing a
|
||||||
|
"Videotex" system, is infringed by the following functionality in the
|
||||||
|
Netscape Navigator code: 1) the animated logo and status line indicators
|
||||||
|
--See Claims 1,8 and 9; 2) the "File Save As" function --See Claims
|
||||||
|
23-27; 3) Bookmarks and Rename Bookmarks in the Properties window --See
|
||||||
|
Claims 20-22; 4) storing HTML, GIF, and JPEG files and adding filename
|
||||||
|
extensions --See Claim 38
|
||||||
|
|
||||||
|
B) Intermind owns pending U.S. patent applications on communications
|
||||||
|
systems which employ metadata ("channel objects") to define a control
|
||||||
|
structure for information transfer. The Netscape code does not infringe
|
||||||
|
as released; however, modifications which utilize channel objects as
|
||||||
|
described by Intermind should be considered carefully. The following is
|
||||||
|
a statement from Intermind: "Intermind's claims fundamentally involve
|
||||||
|
the use of a control structure to automate communications. ...The
|
||||||
|
essence of Intermind's top claim is that two devices sender and receiver
|
||||||
|
have persistent storage, communicate over a network, and exchange a
|
||||||
|
control structure including metadata which describes: 1) what
|
||||||
|
information is to be updated, 2) when to update this information, and 3)
|
||||||
|
how to transfer the updated information. In addition, at least the
|
||||||
|
receiving device must be able to process the metadata in order to
|
||||||
|
perform the update determination and transfer. Any digital
|
||||||
|
communications system which incorporates all of these elements will be
|
||||||
|
covered by Intermind's patents." See Intermind.com.
|
||||||
|
|
||||||
|
C) Stac, Inc., and its licensing agent Hi/fn, own several patents which
|
||||||
|
disclose data compression methods implementing an LZS compression
|
||||||
|
algorithm, including U.S. Patent Nos. 4,701,745 and 5,016, 009 ("the
|
||||||
|
Stac Patents"). The Netscape Communicator code does not perform
|
||||||
|
compression. If you modify the Netscape source code to perform
|
||||||
|
compression, please take notice of the Stac Patents.
|
||||||
|
|
||||||
|
D) Netscape Communications Corporation ("Netscape") does not guarantee
|
||||||
|
that any source code or executable code available from the mozilla.org
|
||||||
|
domain is Year 2000 compliant.
|
||||||
9
LICENSE
Normal file
9
LICENSE
Normal file
|
|
@ -0,0 +1,9 @@
|
||||||
|
Please see the file toolkit/content/license.html for the copyright licensing
|
||||||
|
conditions attached to this codebase, including copies of the licenses
|
||||||
|
concerned.
|
||||||
|
|
||||||
|
You are not granted rights or licenses to the trademarks of the
|
||||||
|
Mozilla Foundation or any party, including without limitation the
|
||||||
|
Firefox name or logo.
|
||||||
|
|
||||||
|
For more information, see: http://www.mozilla.org/foundation/licensing.html
|
||||||
416
Makefile.in
Normal file
416
Makefile.in
Normal file
|
|
@ -0,0 +1,416 @@
|
||||||
|
#
|
||||||
|
# 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/.
|
||||||
|
|
||||||
|
ifeq (,$(MAKE_VERSION))
|
||||||
|
$(error GNU Make is required)
|
||||||
|
endif
|
||||||
|
make_min_ver := 3.81
|
||||||
|
ifneq ($(make_min_ver),$(firstword $(sort $(make_min_ver) $(MAKE_VERSION))))
|
||||||
|
$(error GNU Make $(make_min_ver) or higher is required)
|
||||||
|
endif
|
||||||
|
|
||||||
|
export TOPLEVEL_BUILD := 1
|
||||||
|
|
||||||
|
default::
|
||||||
|
|
||||||
|
ifndef TEST_MOZBUILD
|
||||||
|
ifdef MOZ_BUILD_APP
|
||||||
|
include $(wildcard $(topsrcdir)/$(MOZ_BUILD_APP)/build.mk)
|
||||||
|
endif
|
||||||
|
endif
|
||||||
|
|
||||||
|
include $(topsrcdir)/config/config.mk
|
||||||
|
|
||||||
|
GARBAGE_DIRS += _javagen _profile staticlib
|
||||||
|
DIST_GARBAGE = config.cache config.log config.status* config-defs.h \
|
||||||
|
config/autoconf.mk \
|
||||||
|
mozilla-config.h \
|
||||||
|
netwerk/necko-config.h xpcom/xpcom-config.h xpcom/xpcom-private.h \
|
||||||
|
.mozconfig.mk
|
||||||
|
|
||||||
|
ifndef MOZ_PROFILE_USE
|
||||||
|
buildid.h source-repo.h: FORCE
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifdef JS_STANDALONE
|
||||||
|
configure_dir = $(topsrcdir)/js/src
|
||||||
|
else
|
||||||
|
configure_dir = $(topsrcdir)
|
||||||
|
endif
|
||||||
|
|
||||||
|
BUILD_BACKEND_FILES := $(addprefix backend.,$(addsuffix Backend,$(BUILD_BACKENDS)))
|
||||||
|
|
||||||
|
ifndef TEST_MOZBUILD
|
||||||
|
ifndef MOZ_PROFILE_USE
|
||||||
|
# We need to explicitly put BUILD_BACKEND_FILES here otherwise the rule in
|
||||||
|
# rules.mk doesn't run early enough.
|
||||||
|
$(TIERS) binaries:: CLOBBER $(configure_dir)/configure config.status $(BUILD_BACKEND_FILES)
|
||||||
|
ifndef JS_STANDALONE
|
||||||
|
ifdef COMPILE_ENVIRONMENT
|
||||||
|
$(TIERS) binaries:: $(topsrcdir)/js/src/configure js/src/config.status
|
||||||
|
endif
|
||||||
|
endif
|
||||||
|
endif
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifdef JS_STANDALONE
|
||||||
|
.PHONY: CLOBBER
|
||||||
|
CLOBBER:
|
||||||
|
else
|
||||||
|
CLOBBER: $(topsrcdir)/CLOBBER
|
||||||
|
@echo 'STOP! The CLOBBER file has changed.'
|
||||||
|
@echo 'Please run the build through a sanctioned build wrapper, such as'
|
||||||
|
@echo '"mach build" or client.mk.'
|
||||||
|
@exit 1
|
||||||
|
endif
|
||||||
|
|
||||||
|
$(topsrcdir)/configure: $(topsrcdir)/configure.in $(topsrcdir)/old-configure.in
|
||||||
|
$(topsrcdir)/js/src/configure: $(topsrcdir)/js/src/configure.in $(topsrcdir)/js/src/old-configure.in
|
||||||
|
$(topsrcdir)/configure $(topsrcdir)/js/src/configure:
|
||||||
|
@echo 'STOP! $? has changed, and your configure is out of date.'
|
||||||
|
@echo 'Please rerun autoconf and re-configure your build directory.'
|
||||||
|
@echo 'To ignore this message, touch "$@",'
|
||||||
|
@echo 'but your build might not succeed.'
|
||||||
|
@exit 1
|
||||||
|
|
||||||
|
config.status: $(configure_dir)/configure $(configure_dir)/old-configure
|
||||||
|
js/src/config.status: $(topsrcdir)/js/src/configure $(topsrcdir)/js/src/old-configure
|
||||||
|
config.status js/src/config.status:
|
||||||
|
@echo 'STOP! $? has changed and needs to be run again.'
|
||||||
|
@echo 'Please rerun it.'
|
||||||
|
@echo 'To ignore this message, touch "$(CURDIR)/$@",'
|
||||||
|
@echo 'but your build might not succeed.'
|
||||||
|
@exit 1
|
||||||
|
|
||||||
|
# Regenerate the build backend if it is out of date. We only have this rule in
|
||||||
|
# this main make file because having it in rules.mk and applied to partial tree
|
||||||
|
# builds resulted in a world of hurt. Gory details are in bug 877308.
|
||||||
|
#
|
||||||
|
# The mach build driver will ensure the backend is up to date for partial tree
|
||||||
|
# builds. This cleanly avoids most of the pain.
|
||||||
|
|
||||||
|
ifndef TEST_MOZBUILD
|
||||||
|
|
||||||
|
.PHONY: backend
|
||||||
|
backend: $(BUILD_BACKEND_FILES)
|
||||||
|
|
||||||
|
# A traditional rule would look like this:
|
||||||
|
# backend.%:
|
||||||
|
# @echo do stuff
|
||||||
|
#
|
||||||
|
# But with -j<n>, and multiple items in BUILD_BACKEND_FILES, the command would
|
||||||
|
# run multiple times in parallel.
|
||||||
|
#
|
||||||
|
# "Fortunately", make has some weird semantics for pattern rules: if there are
|
||||||
|
# multiple targets in a pattern rule and each of them is matched at most once,
|
||||||
|
# the command will only run once. So:
|
||||||
|
# backend%RecursiveMakeBackend backend%FasterMakeBackend:
|
||||||
|
# @echo do stuff
|
||||||
|
# backend: backend.RecursiveMakeBackend backend.FasterMakeBackend
|
||||||
|
# would only execute the command once.
|
||||||
|
#
|
||||||
|
# Credit where due: http://stackoverflow.com/questions/2973445/gnu-makefile-rule-generating-a-few-targets-from-a-single-source-file/3077254#3077254
|
||||||
|
$(subst .,%,$(BUILD_BACKEND_FILES)):
|
||||||
|
@echo 'Build configuration changed. Regenerating backend.'
|
||||||
|
$(PYTHON) config.status
|
||||||
|
|
||||||
|
Makefile: $(BUILD_BACKEND_FILES)
|
||||||
|
@$(TOUCH) $@
|
||||||
|
|
||||||
|
define build_backend_rule
|
||||||
|
$(1)_files := $$(shell cat $(1).in)
|
||||||
|
$(1): $$($(1)_files)
|
||||||
|
$$($(1)_files):
|
||||||
|
|
||||||
|
endef
|
||||||
|
$(foreach file,$(BUILD_BACKEND_FILES),$(eval $(call build_backend_rule,$(file))))
|
||||||
|
|
||||||
|
default:: $(BUILD_BACKEND_FILES)
|
||||||
|
endif
|
||||||
|
|
||||||
|
install_manifests := \
|
||||||
|
$(addprefix dist/,branding idl include public private sdk xpi-stage) \
|
||||||
|
_tests \
|
||||||
|
$(NULL)
|
||||||
|
# Skip the dist/bin install manifest when using the hybrid
|
||||||
|
# FasterMake/RecursiveMake backend. This is a hack until bug 1241744 moves
|
||||||
|
# xpidl handling to FasterMake in that case, mechanically making the dist/bin
|
||||||
|
# install manifest non-existent (non-existent manifests being skipped)
|
||||||
|
ifeq (,$(filter FasterMake+RecursiveMake,$(BUILD_BACKENDS)))
|
||||||
|
install_manifests += dist/bin
|
||||||
|
endif
|
||||||
|
install_manifest_depends = \
|
||||||
|
CLOBBER \
|
||||||
|
$(configure_dir)/configure \
|
||||||
|
config.status \
|
||||||
|
$(BUILD_BACKEND_FILES) \
|
||||||
|
$(NULL)
|
||||||
|
|
||||||
|
ifndef JS_STANDALONE
|
||||||
|
ifdef COMPILE_ENVIRONMENT
|
||||||
|
install_manifest_depends += \
|
||||||
|
$(topsrcdir)/js/src/configure \
|
||||||
|
js/src/config.status \
|
||||||
|
$(NULL)
|
||||||
|
endif
|
||||||
|
endif
|
||||||
|
|
||||||
|
.PHONY: install-manifests
|
||||||
|
install-manifests: $(addprefix install-,$(install_manifests))
|
||||||
|
|
||||||
|
# If we're using the hybrid FasterMake/RecursiveMake backend, we want
|
||||||
|
# to recurse in the faster/ directory in parallel of install manifests.
|
||||||
|
# But dist/idl needs to happen before (cf. dependencies in
|
||||||
|
# config/faster/rules.mk)
|
||||||
|
ifneq (,$(filter FasterMake+RecursiveMake,$(BUILD_BACKENDS)))
|
||||||
|
install-manifests: faster
|
||||||
|
.PHONY: faster
|
||||||
|
faster: install-dist/idl
|
||||||
|
$(MAKE) -C faster FASTER_RECURSIVE_MAKE=1
|
||||||
|
endif
|
||||||
|
|
||||||
|
.PHONY: tup
|
||||||
|
tup:
|
||||||
|
$(call BUILDSTATUS,TIERS make tup)
|
||||||
|
$(call BUILDSTATUS,TIER_START make)
|
||||||
|
$(MAKE) install-manifests buildid.h source-repo.h
|
||||||
|
$(call BUILDSTATUS,TIER_FINISH make)
|
||||||
|
$(call BUILDSTATUS,TIER_START tup)
|
||||||
|
@$(TUP) $(if $(findstring s,$(filter-out --%,$(MAKEFLAGS))),,--verbose)
|
||||||
|
$(call BUILDSTATUS,TIER_FINISH tup)
|
||||||
|
|
||||||
|
# process_install_manifest needs to be invoked with --no-remove when building
|
||||||
|
# js as standalone because automated builds are building nspr separately and
|
||||||
|
# that would remove the resulting files.
|
||||||
|
# Eventually, a standalone js build would just be able to build nspr itself,
|
||||||
|
# removing the need for the former.
|
||||||
|
ifdef JS_STANDALONE
|
||||||
|
NO_REMOVE=1
|
||||||
|
endif
|
||||||
|
|
||||||
|
.PHONY: $(addprefix install-,$(subst /,_,$(install_manifests)))
|
||||||
|
$(addprefix install-,$(install_manifests)): install-%: $(install_manifest_depends)
|
||||||
|
ifneq (,$(filter FasterMake+RecursiveMake,$(BUILD_BACKENDS)))
|
||||||
|
@# If we're using the hybrid FasterMake/RecursiveMake backend, we want
|
||||||
|
@# to ensure the FasterMake end doesn't have install manifests for the
|
||||||
|
@# same directory, because that would blow up
|
||||||
|
$(if $(wildcard _build_manifests/install/$(subst /,_,$*)),$(if $(wildcard faster/install_$(subst /,_,$*)*),$(error FasterMake and RecursiveMake ends of the hybrid build system want to handle $*)))
|
||||||
|
endif
|
||||||
|
$(addprefix $(call py_action,process_install_manifest,$(if $(NO_REMOVE),--no-remove )$*) ,$(wildcard _build_manifests/install/$(subst /,_,$*)))
|
||||||
|
|
||||||
|
# Dummy wrapper rule to allow the faster backend to piggy back
|
||||||
|
$(addprefix install-,$(subst /,_,$(filter dist/%,$(install_manifests)))): install-dist_%: install-dist/% ;
|
||||||
|
|
||||||
|
.PHONY: install-tests
|
||||||
|
install-tests: install-test-files
|
||||||
|
|
||||||
|
# We no longer run "make install-tests" directly before running tests, but we still
|
||||||
|
# want to depend on things like config.status, hence this target.
|
||||||
|
.PHONY: run-tests-deps
|
||||||
|
run-tests-deps: $(install_manifest_depends)
|
||||||
|
|
||||||
|
# Force --no-remove, because $objdir/_tests is handled by multiple manifests.
|
||||||
|
.PHONY: install-test-files
|
||||||
|
install-test-files:
|
||||||
|
$(call py_action,process_install_manifest,--no-remove _tests _build_manifests/install/_test_files)
|
||||||
|
|
||||||
|
include $(topsrcdir)/build/moz-automation.mk
|
||||||
|
|
||||||
|
# dist and _tests should be purged during cleaning. However, we don't want them
|
||||||
|
# purged during PGO builds because they contain some auto-generated files.
|
||||||
|
ifneq ($(filter-out maybe_clobber_profiledbuild,$(MAKECMDGOALS)),)
|
||||||
|
GARBAGE_DIRS += dist _tests
|
||||||
|
endif
|
||||||
|
|
||||||
|
# Windows PGO builds don't perform a clean before the 2nd pass. So, we want
|
||||||
|
# to preserve content for the 2nd pass on Windows. Everywhere else, we always
|
||||||
|
# process the install manifests as part of export.
|
||||||
|
# For the binaries rule, not all the install manifests matter, so force only
|
||||||
|
# the interesting ones to be done.
|
||||||
|
ifdef MOZ_PROFILE_USE
|
||||||
|
ifndef NO_PROFILE_GUIDED_OPTIMIZE
|
||||||
|
ifneq ($(OS_ARCH)_$(GNU_CC), WINNT_)
|
||||||
|
recurse_pre-export:: install-manifests
|
||||||
|
binaries::
|
||||||
|
@$(MAKE) install-manifests NO_REMOVE=1 install_manifests=dist/include
|
||||||
|
endif
|
||||||
|
endif
|
||||||
|
else # !MOZ_PROFILE_USE (normal build)
|
||||||
|
recurse_pre-export:: install-manifests
|
||||||
|
binaries::
|
||||||
|
@$(MAKE) install-manifests NO_REMOVE=1 install_manifests=dist/include
|
||||||
|
endif
|
||||||
|
|
||||||
|
# For historical reasons that are unknown, $(DIST)/sdk is always blown away
|
||||||
|
# with no regard for PGO passes. This decision could probably be revisited.
|
||||||
|
recurse_pre-export:: install-dist/sdk
|
||||||
|
|
||||||
|
recurse_artifact:
|
||||||
|
$(topsrcdir)/mach --log-no-times artifact install
|
||||||
|
|
||||||
|
ifndef JS_STANDALONE
|
||||||
|
ifdef ENABLE_TESTS
|
||||||
|
# Additional makefile targets to call automated test suites
|
||||||
|
include $(topsrcdir)/testing/testsuite-targets.mk
|
||||||
|
endif
|
||||||
|
endif
|
||||||
|
|
||||||
|
default all::
|
||||||
|
$(call BUILDSTATUS,TIERS $(TIERS) $(if $(MOZ_AUTOMATION),$(MOZ_AUTOMATION_TIERS)))
|
||||||
|
|
||||||
|
include $(topsrcdir)/config/rules.mk
|
||||||
|
|
||||||
|
distclean::
|
||||||
|
$(RM) $(DIST_GARBAGE)
|
||||||
|
|
||||||
|
ifeq ($(OS_ARCH),WINNT)
|
||||||
|
# we want to copy PDB files on Windows
|
||||||
|
MAKE_SYM_STORE_ARGS := -c --vcs-info
|
||||||
|
ifdef PDBSTR_PATH
|
||||||
|
MAKE_SYM_STORE_ARGS += -i
|
||||||
|
endif
|
||||||
|
ifdef MSVC_HAS_DIA_SDK
|
||||||
|
DUMP_SYMS_BIN ?= $(DIST)/host/bin/dump_syms.exe
|
||||||
|
else
|
||||||
|
DUMP_SYMS_BIN ?= $(topsrcdir)/toolkit/crashreporter/tools/win32/dump_syms_vc$(_MSC_VER).exe
|
||||||
|
endif
|
||||||
|
# PDB files don't get moved to dist, so we need to scan the whole objdir
|
||||||
|
MAKE_SYM_STORE_PATH := .
|
||||||
|
endif
|
||||||
|
ifeq ($(OS_ARCH),Darwin)
|
||||||
|
# need to pass arch flags for universal builds
|
||||||
|
ifdef UNIVERSAL_BINARY
|
||||||
|
MAKE_SYM_STORE_ARGS := -c --vcs-info
|
||||||
|
MAKE_SYM_STORE_PATH := $(DIST)/bin $(UNIFY_DIST)/bin
|
||||||
|
else
|
||||||
|
MAKE_SYM_STORE_ARGS := -c -a $(OS_TEST) --vcs-info
|
||||||
|
MAKE_SYM_STORE_PATH := $(DIST)/bin
|
||||||
|
endif
|
||||||
|
DUMP_SYMS_BIN ?= $(DIST)/host/bin/dump_syms
|
||||||
|
endif
|
||||||
|
ifeq (,$(filter-out Linux SunOS,$(OS_ARCH)))
|
||||||
|
MAKE_SYM_STORE_ARGS := -c --vcs-info
|
||||||
|
DUMP_SYMS_BIN ?= $(DIST)/host/bin/dump_syms
|
||||||
|
MAKE_SYM_STORE_PATH := $(DIST)/bin
|
||||||
|
endif
|
||||||
|
MAKE_SYM_STORE_ARGS += --install-manifest=$(DEPTH)/_build_manifests/install/dist_include,$(DIST)/include
|
||||||
|
|
||||||
|
SYM_STORE_SOURCE_DIRS := $(topsrcdir)
|
||||||
|
|
||||||
|
ifdef MOZ_CRASHREPORTER
|
||||||
|
include $(topsrcdir)/toolkit/mozapps/installer/package-name.mk
|
||||||
|
|
||||||
|
SYMBOL_INDEX_NAME = \
|
||||||
|
$(MOZ_APP_NAME)-$(MOZ_APP_VERSION)-$(OS_TARGET)-$(BUILDID)-$(CPU_ARCH)-symbols.txt
|
||||||
|
endif
|
||||||
|
|
||||||
|
.PHONY: generatesymbols
|
||||||
|
generatesymbols:
|
||||||
|
echo building symbol store
|
||||||
|
$(RM) -r $(DIST)/crashreporter-symbols
|
||||||
|
$(RM) '$(DIST)/$(SYMBOL_ARCHIVE_BASENAME).zip'
|
||||||
|
$(RM) '$(DIST)/$(SYMBOL_FULL_ARCHIVE_BASENAME).zip'
|
||||||
|
$(NSINSTALL) -D $(DIST)/crashreporter-symbols
|
||||||
|
OBJCOPY='$(OBJCOPY)' \
|
||||||
|
$(PYTHON) $(topsrcdir)/toolkit/crashreporter/tools/symbolstore.py \
|
||||||
|
$(MAKE_SYM_STORE_ARGS) \
|
||||||
|
$(foreach dir,$(SYM_STORE_SOURCE_DIRS),-s $(dir)) \
|
||||||
|
$(DUMP_SYMS_BIN) \
|
||||||
|
$(DIST)/crashreporter-symbols \
|
||||||
|
$(MAKE_SYM_STORE_PATH) | grep -iv test > \
|
||||||
|
$(DIST)/crashreporter-symbols/$(SYMBOL_INDEX_NAME)
|
||||||
|
echo packing symbols
|
||||||
|
$(NSINSTALL) -D $(DIST)/$(PKG_PATH)
|
||||||
|
|
||||||
|
.PHONY: symbolsfullarchive
|
||||||
|
symbolsfullarchive: generatesymbols
|
||||||
|
cd $(DIST)/crashreporter-symbols && \
|
||||||
|
zip -r5D '../$(PKG_PATH)$(SYMBOL_FULL_ARCHIVE_BASENAME).zip' . -x '*test*' -x '*Test*'
|
||||||
|
|
||||||
|
.PHONY: symbolsarchive
|
||||||
|
symbolsarchive: generatesymbols
|
||||||
|
cd $(DIST)/crashreporter-symbols && \
|
||||||
|
grep 'sym' $(SYMBOL_INDEX_NAME) > $(SYMBOL_INDEX_NAME).tmp && \
|
||||||
|
mv $(SYMBOL_INDEX_NAME).tmp $(SYMBOL_INDEX_NAME)
|
||||||
|
cd $(DIST)/crashreporter-symbols && \
|
||||||
|
zip -r5D '../$(PKG_PATH)$(SYMBOL_ARCHIVE_BASENAME).zip' . -i '*.sym' -i '*.txt'
|
||||||
|
|
||||||
|
ifdef MOZ_CRASHREPORTER
|
||||||
|
buildsymbols: symbolsfullarchive symbolsarchive
|
||||||
|
else
|
||||||
|
buildsymbols:
|
||||||
|
endif
|
||||||
|
|
||||||
|
uploadsymbols:
|
||||||
|
ifdef MOZ_CRASHREPORTER
|
||||||
|
ifdef SOCORRO_SYMBOL_UPLOAD_TOKEN_FILE
|
||||||
|
$(PYTHON) -u $(topsrcdir)/toolkit/crashreporter/tools/upload_symbols.py '$(DIST)/$(PKG_PATH)$(SYMBOL_FULL_ARCHIVE_BASENAME).zip'
|
||||||
|
endif
|
||||||
|
endif
|
||||||
|
|
||||||
|
.PHONY: update-packaging
|
||||||
|
update-packaging:
|
||||||
|
$(MAKE) -C tools/update-packaging
|
||||||
|
|
||||||
|
.PHONY: pretty-package
|
||||||
|
pretty-package:
|
||||||
|
unset MOZ_SIGN_CMD && $(MAKE) package MOZ_PKG_PRETTYNAMES=1
|
||||||
|
|
||||||
|
.PHONY: pretty-package-tests
|
||||||
|
pretty-package-tests:
|
||||||
|
unset MOZ_SIGN_CMD && $(MAKE) package-tests MOZ_PKG_PRETTYNAMES=1
|
||||||
|
|
||||||
|
.PHONY: pretty-l10n-check
|
||||||
|
pretty-l10n-check:
|
||||||
|
unset MOZ_SIGN_CMD && $(MAKE) l10n-check MOZ_PKG_PRETTYNAMES=1
|
||||||
|
|
||||||
|
.PHONY: pretty-update-packaging
|
||||||
|
pretty-update-packaging:
|
||||||
|
unset MOZ_SIGN_CMD && $(MAKE) -C tools/update-packaging MOZ_PKG_PRETTYNAMES=1
|
||||||
|
|
||||||
|
.PHONY: pretty-installer
|
||||||
|
pretty-installer:
|
||||||
|
unset MOZ_SIGN_CMD && $(MAKE) installer MOZ_PKG_PRETTYNAMES=1
|
||||||
|
|
||||||
|
#XXX: this is a hack, since we don't want to clobber for MSVC
|
||||||
|
# PGO support, but we can't do this test in client.mk
|
||||||
|
ifneq ($(OS_ARCH)_$(GNU_CC), WINNT_)
|
||||||
|
# No point in clobbering if PGO has been explicitly disabled.
|
||||||
|
ifndef NO_PROFILE_GUIDED_OPTIMIZE
|
||||||
|
maybe_clobber_profiledbuild: clean
|
||||||
|
else
|
||||||
|
maybe_clobber_profiledbuild:
|
||||||
|
endif
|
||||||
|
else
|
||||||
|
maybe_clobber_profiledbuild:
|
||||||
|
$(RM) $(DIST)/bin/*.pgc
|
||||||
|
find $(DIST)/$(MOZ_APP_NAME) -name '*.pgc' -exec mv {} $(DIST)/bin \;
|
||||||
|
endif
|
||||||
|
|
||||||
|
.PHONY: maybe_clobber_profiledbuild
|
||||||
|
|
||||||
|
# Look for R_386_PC32 relocations in shared libs, these
|
||||||
|
# break x86_64 builds and SELinux users.
|
||||||
|
ifeq ($(OS_TARGET)_$(TARGET_XPCOM_ABI),Linux_x86-gcc3)
|
||||||
|
check::
|
||||||
|
@relcount=`find $(DIST)/bin -name '*.so' | xargs objdump -R | grep R_386_PC32 | wc -l` && if test $$relcount -gt 0; then echo 'FAILED: R_386_PC32 relocations detected in a shared library. Did you use a system header without adding it to config/system-headers?'; exit 1; else echo 'PASSED'; fi
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifdef JS_STANDALONE
|
||||||
|
# Delegate js-specific rules to js
|
||||||
|
check-%:
|
||||||
|
$(MAKE) -C js/src $@
|
||||||
|
|
||||||
|
source-package install:
|
||||||
|
$(MAKE) -C js/src $@
|
||||||
|
|
||||||
|
# Every export rule depends on config/export, but the rule for config/export
|
||||||
|
# doesn't exist when building js non-standalone.
|
||||||
|
.PHONY: config/export
|
||||||
|
config/export:
|
||||||
|
|
||||||
|
endif
|
||||||
|
|
||||||
|
# There used to be build interdependencies here. They are now in config/recurse.mk
|
||||||
27
README.txt
Normal file
27
README.txt
Normal file
|
|
@ -0,0 +1,27 @@
|
||||||
|
An explanation of the Mozilla Source Code Directory Structure and links to
|
||||||
|
project pages with documentation can be found at:
|
||||||
|
|
||||||
|
https://developer.mozilla.org/en/Mozilla_Source_Code_Directory_Structure
|
||||||
|
|
||||||
|
For information on how to build Mozilla from the source code, see:
|
||||||
|
|
||||||
|
http://developer.mozilla.org/en/docs/Build_Documentation
|
||||||
|
|
||||||
|
To have your bug fix / feature added to Mozilla, you should create a patch and
|
||||||
|
submit it to Bugzilla (https://bugzilla.mozilla.org). Instructions are at:
|
||||||
|
|
||||||
|
http://developer.mozilla.org/en/docs/Creating_a_patch
|
||||||
|
http://developer.mozilla.org/en/docs/Getting_your_patch_in_the_tree
|
||||||
|
|
||||||
|
If you have a question about developing Mozilla, and can't find the solution
|
||||||
|
on http://developer.mozilla.org, you can try asking your question in a
|
||||||
|
mozilla.* Usenet group, or on IRC at irc.mozilla.org. [The Mozilla news groups
|
||||||
|
are accessible on Google Groups, or news.mozilla.org with a NNTP reader.]
|
||||||
|
|
||||||
|
You can download nightly development builds from the Mozilla FTP server.
|
||||||
|
Keep in mind that nightly builds, which are used by Mozilla developers for
|
||||||
|
testing, may be buggy. Firefox nightlies, for example, can be found at:
|
||||||
|
|
||||||
|
https://archive.mozilla.org/pub/firefox/nightly/latest-mozilla-central/
|
||||||
|
- or -
|
||||||
|
http://nightly.mozilla.org/
|
||||||
17
accessible/.eslintrc.js
Normal file
17
accessible/.eslintrc.js
Normal file
|
|
@ -0,0 +1,17 @@
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
"extends": [
|
||||||
|
"../.eslintrc.js"
|
||||||
|
],
|
||||||
|
"globals": {
|
||||||
|
"Cc": true,
|
||||||
|
"Ci": true,
|
||||||
|
"Components": true,
|
||||||
|
"console": true,
|
||||||
|
"Cu": true,
|
||||||
|
"dump": true,
|
||||||
|
"Services": true,
|
||||||
|
"XPCOMUtils": true
|
||||||
|
}
|
||||||
|
};
|
||||||
68
accessible/aom/AccessibleNode.cpp
Normal file
68
accessible/aom/AccessibleNode.cpp
Normal file
|
|
@ -0,0 +1,68 @@
|
||||||
|
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||||
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
|
#include "AccessibleNode.h"
|
||||||
|
#include "mozilla/dom/AccessibleNodeBinding.h"
|
||||||
|
#include "mozilla/dom/BindingDeclarations.h"
|
||||||
|
|
||||||
|
#include "Accessible-inl.h"
|
||||||
|
#include "nsAccessibilityService.h"
|
||||||
|
#include "DocAccessible.h"
|
||||||
|
|
||||||
|
using namespace mozilla;
|
||||||
|
using namespace mozilla::a11y;
|
||||||
|
using namespace mozilla::dom;
|
||||||
|
|
||||||
|
NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_0(AccessibleNode)
|
||||||
|
|
||||||
|
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(AccessibleNode)
|
||||||
|
NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
|
||||||
|
NS_INTERFACE_MAP_ENTRY(nsISupports)
|
||||||
|
NS_INTERFACE_MAP_END
|
||||||
|
|
||||||
|
NS_IMPL_CYCLE_COLLECTING_ADDREF(AccessibleNode)
|
||||||
|
NS_IMPL_CYCLE_COLLECTING_RELEASE(AccessibleNode)
|
||||||
|
|
||||||
|
AccessibleNode::AccessibleNode(nsINode* aNode) : mDOMNode(aNode)
|
||||||
|
{
|
||||||
|
DocAccessible* doc =
|
||||||
|
GetOrCreateAccService()->GetDocAccessible(mDOMNode->OwnerDoc());
|
||||||
|
if (doc) {
|
||||||
|
mIntl = doc->GetAccessible(mDOMNode);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
AccessibleNode::~AccessibleNode()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/* virtual */ JSObject*
|
||||||
|
AccessibleNode::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
|
||||||
|
{
|
||||||
|
return AccessibleNodeBinding::Wrap(aCx, this, aGivenProto);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* virtual */ ParentObject
|
||||||
|
AccessibleNode::GetParentObject() const
|
||||||
|
{
|
||||||
|
return mDOMNode->GetParentObject();
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
AccessibleNode::GetRole(nsAString& aRole)
|
||||||
|
{
|
||||||
|
if (mIntl) {
|
||||||
|
GetOrCreateAccService()->GetStringRole(mIntl->Role(), aRole);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
aRole.AssignLiteral("unknown");
|
||||||
|
}
|
||||||
|
|
||||||
|
nsINode*
|
||||||
|
AccessibleNode::GetDOMNode()
|
||||||
|
{
|
||||||
|
return mDOMNode;
|
||||||
|
}
|
||||||
53
accessible/aom/AccessibleNode.h
Normal file
53
accessible/aom/AccessibleNode.h
Normal file
|
|
@ -0,0 +1,53 @@
|
||||||
|
/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
|
||||||
|
/* vim: set ts=2 et sw=2 tw=40: */
|
||||||
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||||
|
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
|
#ifndef A11Y_AOM_ACCESSIBLENODE_H
|
||||||
|
#define A11Y_AOM_ACCESSIBLENODE_H
|
||||||
|
|
||||||
|
#include "nsWrapperCache.h"
|
||||||
|
#include "mozilla/RefPtr.h"
|
||||||
|
|
||||||
|
class nsINode;
|
||||||
|
|
||||||
|
namespace mozilla {
|
||||||
|
|
||||||
|
namespace a11y {
|
||||||
|
class Accessible;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace dom {
|
||||||
|
|
||||||
|
struct ParentObject;
|
||||||
|
|
||||||
|
class AccessibleNode : public nsISupports,
|
||||||
|
public nsWrapperCache
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
explicit AccessibleNode(nsINode* aNode);
|
||||||
|
|
||||||
|
NS_DECL_CYCLE_COLLECTING_ISUPPORTS;
|
||||||
|
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(AccessibleNode);
|
||||||
|
|
||||||
|
virtual JSObject* WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override final;
|
||||||
|
virtual dom::ParentObject GetParentObject() const final;
|
||||||
|
|
||||||
|
void GetRole(nsAString& aRole);
|
||||||
|
nsINode* GetDOMNode();
|
||||||
|
|
||||||
|
protected:
|
||||||
|
AccessibleNode(const AccessibleNode& aCopy) = delete;
|
||||||
|
AccessibleNode& operator=(const AccessibleNode& aCopy) = delete;
|
||||||
|
virtual ~AccessibleNode();
|
||||||
|
|
||||||
|
RefPtr<a11y::Accessible> mIntl;
|
||||||
|
RefPtr<nsINode> mDOMNode;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // dom
|
||||||
|
} // mozilla
|
||||||
|
|
||||||
|
|
||||||
|
#endif // A11Y_JSAPI_ACCESSIBLENODE
|
||||||
40
accessible/aom/moz.build
Normal file
40
accessible/aom/moz.build
Normal file
|
|
@ -0,0 +1,40 @@
|
||||||
|
# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
|
||||||
|
# vim: set filetype=python:
|
||||||
|
# This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||||
|
|
||||||
|
EXPORTS.mozilla.dom += [
|
||||||
|
'AccessibleNode.h',
|
||||||
|
]
|
||||||
|
|
||||||
|
UNIFIED_SOURCES += [
|
||||||
|
'AccessibleNode.cpp',
|
||||||
|
]
|
||||||
|
|
||||||
|
LOCAL_INCLUDES += [
|
||||||
|
'/accessible/base',
|
||||||
|
'/accessible/generic',
|
||||||
|
]
|
||||||
|
|
||||||
|
if 'gtk' in CONFIG['MOZ_WIDGET_TOOLKIT']:
|
||||||
|
LOCAL_INCLUDES += [
|
||||||
|
'/accessible/atk',
|
||||||
|
]
|
||||||
|
elif CONFIG['MOZ_WIDGET_TOOLKIT'] == 'windows':
|
||||||
|
LOCAL_INCLUDES += [
|
||||||
|
'/accessible/windows/ia2',
|
||||||
|
'/accessible/windows/msaa',
|
||||||
|
]
|
||||||
|
elif CONFIG['MOZ_WIDGET_TOOLKIT'] == 'cocoa':
|
||||||
|
LOCAL_INCLUDES += [
|
||||||
|
'/accessible/mac',
|
||||||
|
]
|
||||||
|
else:
|
||||||
|
LOCAL_INCLUDES += [
|
||||||
|
'/accessible/other',
|
||||||
|
]
|
||||||
|
|
||||||
|
include('/ipc/chromium/chromium-config.mozbuild')
|
||||||
|
|
||||||
|
FINAL_LIBRARY = 'xul'
|
||||||
21
accessible/atk/ARIAGridAccessibleWrap.h
Normal file
21
accessible/atk/ARIAGridAccessibleWrap.h
Normal file
|
|
@ -0,0 +1,21 @@
|
||||||
|
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||||
|
/* vim: set ts=2 et sw=2 tw=80: */
|
||||||
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
|
#ifndef MOZILLA_A11Y_ARIAGRIDACCESSIBLEWRAP_H
|
||||||
|
#define MOZILLA_A11Y_ARIAGRIDACCESSIBLEWRAP_H
|
||||||
|
|
||||||
|
#include "ARIAGridAccessible.h"
|
||||||
|
|
||||||
|
namespace mozilla {
|
||||||
|
namespace a11y {
|
||||||
|
|
||||||
|
typedef class ARIAGridAccessible ARIAGridAccessibleWrap;
|
||||||
|
typedef class ARIAGridCellAccessible ARIAGridCellAccessibleWrap;
|
||||||
|
|
||||||
|
} // namespace a11y
|
||||||
|
} // namespace mozilla
|
||||||
|
|
||||||
|
#endif
|
||||||
1759
accessible/atk/AccessibleWrap.cpp
Normal file
1759
accessible/atk/AccessibleWrap.cpp
Normal file
File diff suppressed because it is too large
Load diff
92
accessible/atk/AccessibleWrap.h
Normal file
92
accessible/atk/AccessibleWrap.h
Normal file
|
|
@ -0,0 +1,92 @@
|
||||||
|
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||||
|
/* vim: set ts=2 et sw=2 tw=80: */
|
||||||
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
|
#ifndef __NS_ACCESSIBLE_WRAP_H__
|
||||||
|
#define __NS_ACCESSIBLE_WRAP_H__
|
||||||
|
|
||||||
|
#include "nsCOMPtr.h"
|
||||||
|
#include "Accessible.h"
|
||||||
|
|
||||||
|
struct _AtkObject;
|
||||||
|
typedef struct _AtkObject AtkObject;
|
||||||
|
|
||||||
|
enum AtkProperty {
|
||||||
|
PROP_0, // gobject convention
|
||||||
|
PROP_NAME,
|
||||||
|
PROP_DESCRIPTION,
|
||||||
|
PROP_PARENT, // ancestry has changed
|
||||||
|
PROP_ROLE,
|
||||||
|
PROP_LAYER,
|
||||||
|
PROP_MDI_ZORDER,
|
||||||
|
PROP_TABLE_CAPTION,
|
||||||
|
PROP_TABLE_COLUMN_DESCRIPTION,
|
||||||
|
PROP_TABLE_COLUMN_HEADER,
|
||||||
|
PROP_TABLE_ROW_DESCRIPTION,
|
||||||
|
PROP_TABLE_ROW_HEADER,
|
||||||
|
PROP_TABLE_SUMMARY,
|
||||||
|
PROP_LAST // gobject convention
|
||||||
|
};
|
||||||
|
|
||||||
|
struct AtkPropertyChange {
|
||||||
|
int32_t type; // property type as listed above
|
||||||
|
void *oldvalue;
|
||||||
|
void *newvalue;
|
||||||
|
};
|
||||||
|
|
||||||
|
namespace mozilla {
|
||||||
|
namespace a11y {
|
||||||
|
|
||||||
|
class MaiHyperlink;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* AccessibleWrap, and its descendents in atk directory provide the
|
||||||
|
* implementation of AtkObject.
|
||||||
|
*/
|
||||||
|
class AccessibleWrap : public Accessible
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
AccessibleWrap(nsIContent* aContent, DocAccessible* aDoc);
|
||||||
|
virtual ~AccessibleWrap();
|
||||||
|
void ShutdownAtkObject();
|
||||||
|
|
||||||
|
virtual void Shutdown() override;
|
||||||
|
|
||||||
|
// return the atk object for this AccessibleWrap
|
||||||
|
virtual void GetNativeInterface(void** aOutAccessible) override;
|
||||||
|
virtual nsresult HandleAccEvent(AccEvent* aEvent) override;
|
||||||
|
|
||||||
|
AtkObject * GetAtkObject(void);
|
||||||
|
static AtkObject* GetAtkObject(Accessible* aAccessible);
|
||||||
|
|
||||||
|
bool IsValidObject();
|
||||||
|
|
||||||
|
static const char * ReturnString(nsAString &aString) {
|
||||||
|
static nsCString returnedString;
|
||||||
|
returnedString = NS_ConvertUTF16toUTF8(aString);
|
||||||
|
return returnedString.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
static void GetKeyBinding(Accessible* aAccessible, nsAString& aResult);
|
||||||
|
|
||||||
|
static Accessible* GetColumnHeader(TableAccessible* aAccessible,
|
||||||
|
int32_t aColIdx);
|
||||||
|
static Accessible* GetRowHeader(TableAccessible* aAccessible,
|
||||||
|
int32_t aRowIdx);
|
||||||
|
protected:
|
||||||
|
|
||||||
|
nsresult FireAtkStateChangeEvent(AccEvent* aEvent, AtkObject *aObject);
|
||||||
|
nsresult FireAtkTextChangedEvent(AccEvent* aEvent, AtkObject *aObject);
|
||||||
|
|
||||||
|
AtkObject *mAtkObject;
|
||||||
|
|
||||||
|
private:
|
||||||
|
uint16_t CreateMaiInterfaces();
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace a11y
|
||||||
|
} // namespace mozilla
|
||||||
|
|
||||||
|
#endif /* __NS_ACCESSIBLE_WRAP_H__ */
|
||||||
167
accessible/atk/ApplicationAccessibleWrap.cpp
Normal file
167
accessible/atk/ApplicationAccessibleWrap.cpp
Normal file
|
|
@ -0,0 +1,167 @@
|
||||||
|
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||||
|
/* vim: set ts=2 et sw=2 tw=80: */
|
||||||
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
|
#include "ApplicationAccessibleWrap.h"
|
||||||
|
|
||||||
|
#include "nsCOMPtr.h"
|
||||||
|
#include "nsMai.h"
|
||||||
|
#include "nsAccessibilityService.h"
|
||||||
|
|
||||||
|
#include <gtk/gtk.h>
|
||||||
|
#include <atk/atk.h>
|
||||||
|
|
||||||
|
using namespace mozilla;
|
||||||
|
using namespace mozilla::a11y;
|
||||||
|
|
||||||
|
|
||||||
|
// ApplicationAccessibleWrap
|
||||||
|
|
||||||
|
ApplicationAccessibleWrap::ApplicationAccessibleWrap():
|
||||||
|
ApplicationAccessible()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
ApplicationAccessibleWrap::~ApplicationAccessibleWrap()
|
||||||
|
{
|
||||||
|
AccessibleWrap::ShutdownAtkObject();
|
||||||
|
}
|
||||||
|
|
||||||
|
gboolean
|
||||||
|
toplevel_event_watcher(GSignalInvocationHint* ihint,
|
||||||
|
guint n_param_values,
|
||||||
|
const GValue* param_values,
|
||||||
|
gpointer data)
|
||||||
|
{
|
||||||
|
static GQuark sQuark_gecko_acc_obj = 0;
|
||||||
|
|
||||||
|
if (!sQuark_gecko_acc_obj)
|
||||||
|
sQuark_gecko_acc_obj = g_quark_from_static_string("GeckoAccObj");
|
||||||
|
|
||||||
|
if (nsAccessibilityService::IsShutdown())
|
||||||
|
return TRUE;
|
||||||
|
|
||||||
|
GObject* object = reinterpret_cast<GObject*>(g_value_get_object(param_values));
|
||||||
|
if (!GTK_IS_WINDOW(object))
|
||||||
|
return TRUE;
|
||||||
|
|
||||||
|
AtkObject* child = gtk_widget_get_accessible(GTK_WIDGET(object));
|
||||||
|
|
||||||
|
// GTK native dialog
|
||||||
|
if (!IS_MAI_OBJECT(child) &&
|
||||||
|
(atk_object_get_role(child) == ATK_ROLE_DIALOG)) {
|
||||||
|
|
||||||
|
if (data == reinterpret_cast<gpointer>(nsIAccessibleEvent::EVENT_SHOW)) {
|
||||||
|
|
||||||
|
// Attach the dialog accessible to app accessible tree
|
||||||
|
Accessible* windowAcc = GetAccService()->AddNativeRootAccessible(child);
|
||||||
|
g_object_set_qdata(G_OBJECT(child), sQuark_gecko_acc_obj,
|
||||||
|
reinterpret_cast<gpointer>(windowAcc));
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
// Deattach the dialog accessible
|
||||||
|
Accessible* windowAcc =
|
||||||
|
reinterpret_cast<Accessible*>
|
||||||
|
(g_object_get_qdata(G_OBJECT(child), sQuark_gecko_acc_obj));
|
||||||
|
if (windowAcc) {
|
||||||
|
GetAccService()->RemoveNativeRootAccessible(windowAcc);
|
||||||
|
g_object_set_qdata(G_OBJECT(child), sQuark_gecko_acc_obj, nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
ENameValueFlag
|
||||||
|
ApplicationAccessibleWrap::Name(nsString& aName)
|
||||||
|
{
|
||||||
|
// ATK doesn't provide a way to obtain an application name (for example,
|
||||||
|
// Firefox or Thunderbird) like IA2 does. Thus let's return an application
|
||||||
|
// name as accessible name that was used to get a branding name (for example,
|
||||||
|
// Minefield aka nightly Firefox or Daily aka nightly Thunderbird).
|
||||||
|
AppName(aName);
|
||||||
|
return eNameOK;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
ApplicationAccessibleWrap::GetNativeInterface(void** aOutAccessible)
|
||||||
|
{
|
||||||
|
*aOutAccessible = nullptr;
|
||||||
|
|
||||||
|
if (!mAtkObject) {
|
||||||
|
mAtkObject =
|
||||||
|
reinterpret_cast<AtkObject*>(g_object_new(MAI_TYPE_ATK_OBJECT, nullptr));
|
||||||
|
if (!mAtkObject)
|
||||||
|
return;
|
||||||
|
|
||||||
|
atk_object_initialize(mAtkObject, this);
|
||||||
|
mAtkObject->role = ATK_ROLE_INVALID;
|
||||||
|
mAtkObject->layer = ATK_LAYER_INVALID;
|
||||||
|
}
|
||||||
|
|
||||||
|
*aOutAccessible = mAtkObject;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct AtkRootAccessibleAddedEvent {
|
||||||
|
AtkObject *app_accessible;
|
||||||
|
AtkObject *root_accessible;
|
||||||
|
uint32_t index;
|
||||||
|
};
|
||||||
|
|
||||||
|
gboolean fireRootAccessibleAddedCB(gpointer data)
|
||||||
|
{
|
||||||
|
AtkRootAccessibleAddedEvent* eventData = (AtkRootAccessibleAddedEvent*)data;
|
||||||
|
g_signal_emit_by_name(eventData->app_accessible, "children_changed::add",
|
||||||
|
eventData->index, eventData->root_accessible, nullptr);
|
||||||
|
g_object_unref(eventData->app_accessible);
|
||||||
|
g_object_unref(eventData->root_accessible);
|
||||||
|
free(data);
|
||||||
|
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
ApplicationAccessibleWrap::InsertChildAt(uint32_t aIdx, Accessible* aChild)
|
||||||
|
{
|
||||||
|
if (!ApplicationAccessible::InsertChildAt(aIdx, aChild))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
AtkObject* atkAccessible = AccessibleWrap::GetAtkObject(aChild);
|
||||||
|
atk_object_set_parent(atkAccessible, mAtkObject);
|
||||||
|
|
||||||
|
uint32_t count = mChildren.Length();
|
||||||
|
|
||||||
|
// Emit children_changed::add in a timeout
|
||||||
|
// to make sure aRootAccWrap is fully initialized.
|
||||||
|
AtkRootAccessibleAddedEvent* eventData = (AtkRootAccessibleAddedEvent*)
|
||||||
|
malloc(sizeof(AtkRootAccessibleAddedEvent));
|
||||||
|
if (eventData) {
|
||||||
|
eventData->app_accessible = mAtkObject;
|
||||||
|
eventData->root_accessible = atkAccessible;
|
||||||
|
eventData->index = count -1;
|
||||||
|
g_object_ref(mAtkObject);
|
||||||
|
g_object_ref(atkAccessible);
|
||||||
|
g_timeout_add(0, fireRootAccessibleAddedCB, eventData);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
ApplicationAccessibleWrap::RemoveChild(Accessible* aChild)
|
||||||
|
{
|
||||||
|
int32_t index = aChild->IndexInParent();
|
||||||
|
|
||||||
|
AtkObject* atkAccessible = AccessibleWrap::GetAtkObject(aChild);
|
||||||
|
atk_object_set_parent(atkAccessible, nullptr);
|
||||||
|
g_signal_emit_by_name(mAtkObject, "children_changed::remove", index,
|
||||||
|
atkAccessible, nullptr);
|
||||||
|
|
||||||
|
return ApplicationAccessible::RemoveChild(aChild);
|
||||||
|
}
|
||||||
|
|
||||||
35
accessible/atk/ApplicationAccessibleWrap.h
Normal file
35
accessible/atk/ApplicationAccessibleWrap.h
Normal file
|
|
@ -0,0 +1,35 @@
|
||||||
|
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||||
|
/* vim: set ts=2 et sw=2 tw=80: */
|
||||||
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
|
#ifndef mozilla_a11y_ApplicationAccessibleWrap_h__
|
||||||
|
#define mozilla_a11y_ApplicationAccessibleWrap_h__
|
||||||
|
|
||||||
|
#include "ApplicationAccessible.h"
|
||||||
|
|
||||||
|
namespace mozilla {
|
||||||
|
namespace a11y {
|
||||||
|
|
||||||
|
class ApplicationAccessibleWrap: public ApplicationAccessible
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
ApplicationAccessibleWrap();
|
||||||
|
virtual ~ApplicationAccessibleWrap();
|
||||||
|
|
||||||
|
// Accessible
|
||||||
|
virtual mozilla::a11y::ENameValueFlag Name(nsString& aName) override;
|
||||||
|
virtual bool InsertChildAt(uint32_t aIdx, Accessible* aChild) override;
|
||||||
|
virtual bool RemoveChild(Accessible* aChild) override;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the atk object for app root accessible.
|
||||||
|
*/
|
||||||
|
virtual void GetNativeInterface(void** aOutAccessible) override;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace a11y
|
||||||
|
} // namespace mozilla
|
||||||
|
|
||||||
|
#endif /* __NS_APP_ROOT_ACCESSIBLE_H__ */
|
||||||
126
accessible/atk/AtkSocketAccessible.cpp
Normal file
126
accessible/atk/AtkSocketAccessible.cpp
Normal file
|
|
@ -0,0 +1,126 @@
|
||||||
|
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||||
|
/* vim: set ts=2 et sw=2 tw=80: */
|
||||||
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
|
#include <atk/atk.h>
|
||||||
|
#include "AtkSocketAccessible.h"
|
||||||
|
|
||||||
|
#include "InterfaceInitFuncs.h"
|
||||||
|
#include "nsMai.h"
|
||||||
|
#include "mozilla/Likely.h"
|
||||||
|
|
||||||
|
using namespace mozilla::a11y;
|
||||||
|
|
||||||
|
AtkSocketEmbedType AtkSocketAccessible::g_atk_socket_embed = nullptr;
|
||||||
|
GType AtkSocketAccessible::g_atk_socket_type = G_TYPE_INVALID;
|
||||||
|
const char* AtkSocketAccessible::sATKSocketEmbedSymbol = "atk_socket_embed";
|
||||||
|
const char* AtkSocketAccessible::sATKSocketGetTypeSymbol = "atk_socket_get_type";
|
||||||
|
|
||||||
|
bool AtkSocketAccessible::gCanEmbed = FALSE;
|
||||||
|
|
||||||
|
extern "C" void mai_atk_component_iface_init(AtkComponentIface* aIface);
|
||||||
|
|
||||||
|
G_DEFINE_TYPE_EXTENDED(MaiAtkSocket, mai_atk_socket,
|
||||||
|
AtkSocketAccessible::g_atk_socket_type, 0,
|
||||||
|
G_IMPLEMENT_INTERFACE(ATK_TYPE_COMPONENT,
|
||||||
|
mai_atk_component_iface_init))
|
||||||
|
|
||||||
|
void
|
||||||
|
mai_atk_socket_class_init(MaiAtkSocketClass* aAcc)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
mai_atk_socket_init(MaiAtkSocket* aAcc)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
static AtkObject*
|
||||||
|
mai_atk_socket_new(AccessibleWrap* aAccWrap)
|
||||||
|
{
|
||||||
|
NS_ENSURE_TRUE(aAccWrap, nullptr);
|
||||||
|
|
||||||
|
MaiAtkSocket* acc = nullptr;
|
||||||
|
acc = static_cast<MaiAtkSocket*>(g_object_new(MAI_TYPE_ATK_SOCKET, nullptr));
|
||||||
|
NS_ENSURE_TRUE(acc, nullptr);
|
||||||
|
|
||||||
|
acc->accWrap = aAccWrap;
|
||||||
|
return ATK_OBJECT(acc);
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
static AtkObject*
|
||||||
|
RefAccessibleAtPoint(AtkComponent* aComponent, gint aX, gint aY,
|
||||||
|
AtkCoordType aCoordType)
|
||||||
|
{
|
||||||
|
NS_ENSURE_TRUE(MAI_IS_ATK_SOCKET(aComponent), nullptr);
|
||||||
|
|
||||||
|
return refAccessibleAtPointHelper(ATK_OBJECT(MAI_ATK_SOCKET(aComponent)),
|
||||||
|
aX, aY, aCoordType);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
GetExtents(AtkComponent* aComponent, gint* aX, gint* aY, gint* aWidth,
|
||||||
|
gint* aHeight, AtkCoordType aCoordType)
|
||||||
|
{
|
||||||
|
*aX = *aY = *aWidth = *aHeight = 0;
|
||||||
|
|
||||||
|
if (!MAI_IS_ATK_SOCKET(aComponent))
|
||||||
|
return;
|
||||||
|
|
||||||
|
getExtentsHelper(ATK_OBJECT(MAI_ATK_SOCKET(aComponent)),
|
||||||
|
aX, aY, aWidth, aHeight, aCoordType);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
mai_atk_component_iface_init(AtkComponentIface* aIface)
|
||||||
|
{
|
||||||
|
NS_ASSERTION(aIface, "Invalid Interface");
|
||||||
|
if (MOZ_UNLIKELY(!aIface))
|
||||||
|
return;
|
||||||
|
|
||||||
|
aIface->ref_accessible_at_point = RefAccessibleAtPoint;
|
||||||
|
aIface->get_extents = GetExtents;
|
||||||
|
}
|
||||||
|
|
||||||
|
AtkSocketAccessible::AtkSocketAccessible(nsIContent* aContent,
|
||||||
|
DocAccessible* aDoc,
|
||||||
|
const nsCString& aPlugId) :
|
||||||
|
AccessibleWrap(aContent, aDoc)
|
||||||
|
{
|
||||||
|
mAtkObject = mai_atk_socket_new(this);
|
||||||
|
if (!mAtkObject)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// Embeds the children of an AtkPlug, specified by plugId, as the children of
|
||||||
|
// this socket.
|
||||||
|
// Using G_TYPE macros instead of ATK_SOCKET macros to avoid undefined
|
||||||
|
// symbols.
|
||||||
|
if (gCanEmbed && G_TYPE_CHECK_INSTANCE_TYPE(mAtkObject, g_atk_socket_type) &&
|
||||||
|
!aPlugId.IsVoid()) {
|
||||||
|
AtkSocket* accSocket =
|
||||||
|
G_TYPE_CHECK_INSTANCE_CAST(mAtkObject, g_atk_socket_type, AtkSocket);
|
||||||
|
g_atk_socket_embed(accSocket, (gchar*)aPlugId.get());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
AtkSocketAccessible::GetNativeInterface(void** aOutAccessible)
|
||||||
|
{
|
||||||
|
*aOutAccessible = mAtkObject;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
AtkSocketAccessible::Shutdown()
|
||||||
|
{
|
||||||
|
if (mAtkObject) {
|
||||||
|
if (MAI_IS_ATK_SOCKET(mAtkObject))
|
||||||
|
MAI_ATK_SOCKET(mAtkObject)->accWrap = nullptr;
|
||||||
|
g_object_unref(mAtkObject);
|
||||||
|
mAtkObject = nullptr;
|
||||||
|
}
|
||||||
|
AccessibleWrap::Shutdown();
|
||||||
|
}
|
||||||
56
accessible/atk/AtkSocketAccessible.h
Normal file
56
accessible/atk/AtkSocketAccessible.h
Normal file
|
|
@ -0,0 +1,56 @@
|
||||||
|
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||||
|
/* vim: set ts=2 et sw=2 tw=80: */
|
||||||
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
|
#ifndef _AtkSocketAccessible_H_
|
||||||
|
#define _AtkSocketAccessible_H_
|
||||||
|
|
||||||
|
#include "AccessibleWrap.h"
|
||||||
|
|
||||||
|
// This file gets included by nsAccessibilityService.cpp, which can't include
|
||||||
|
// atk.h (or glib.h), so we can't rely on it being included.
|
||||||
|
#ifdef __ATK_H__
|
||||||
|
extern "C" typedef void (*AtkSocketEmbedType) (AtkSocket*, gchar*);
|
||||||
|
#else
|
||||||
|
extern "C" typedef void (*AtkSocketEmbedType) (void*, void*);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
namespace mozilla {
|
||||||
|
namespace a11y {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Provides a AccessibleWrap wrapper around AtkSocket for out-of-process
|
||||||
|
* accessibles.
|
||||||
|
*/
|
||||||
|
class AtkSocketAccessible : public AccessibleWrap
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
// Soft references to AtkSocket
|
||||||
|
static AtkSocketEmbedType g_atk_socket_embed;
|
||||||
|
#ifdef __ATK_H__
|
||||||
|
static GType g_atk_socket_type;
|
||||||
|
#endif
|
||||||
|
static const char* sATKSocketEmbedSymbol;
|
||||||
|
static const char* sATKSocketGetTypeSymbol;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* True if the current Atk version supports AtkSocket and it was correctly
|
||||||
|
* loaded.
|
||||||
|
*/
|
||||||
|
static bool gCanEmbed;
|
||||||
|
|
||||||
|
AtkSocketAccessible(nsIContent* aContent, DocAccessible* aDoc,
|
||||||
|
const nsCString& aPlugId);
|
||||||
|
|
||||||
|
virtual void Shutdown() override;
|
||||||
|
|
||||||
|
virtual void GetNativeInterface(void** aOutAccessible) override;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace a11y
|
||||||
|
} // namespace mozilla
|
||||||
|
|
||||||
|
#endif
|
||||||
25
accessible/atk/DocAccessibleWrap.cpp
Normal file
25
accessible/atk/DocAccessibleWrap.cpp
Normal file
|
|
@ -0,0 +1,25 @@
|
||||||
|
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||||
|
/* vim: set ts=2 et sw=2 tw=80: */
|
||||||
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
|
#include "nsMai.h"
|
||||||
|
#include "DocAccessibleWrap.h"
|
||||||
|
|
||||||
|
using namespace mozilla::a11y;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// DocAccessibleWrap
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
DocAccessibleWrap::
|
||||||
|
DocAccessibleWrap(nsIDocument* aDocument, nsIPresShell* aPresShell) :
|
||||||
|
DocAccessible(aDocument, aPresShell), mActivated(false)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
DocAccessibleWrap::~DocAccessibleWrap()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
31
accessible/atk/DocAccessibleWrap.h
Normal file
31
accessible/atk/DocAccessibleWrap.h
Normal file
|
|
@ -0,0 +1,31 @@
|
||||||
|
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||||
|
/* vim: set ts=2 et sw=2 tw=80: */
|
||||||
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
|
/* For documentation of the accessibility architecture,
|
||||||
|
* see http://lxr.mozilla.org/seamonkey/source/accessible/accessible-docs.html
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef mozilla_a11y_DocAccessibleWrap_h__
|
||||||
|
#define mozilla_a11y_DocAccessibleWrap_h__
|
||||||
|
|
||||||
|
#include "DocAccessible.h"
|
||||||
|
|
||||||
|
namespace mozilla {
|
||||||
|
namespace a11y {
|
||||||
|
|
||||||
|
class DocAccessibleWrap : public DocAccessible
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
DocAccessibleWrap(nsIDocument* aDocument, nsIPresShell* aPresShell);
|
||||||
|
virtual ~DocAccessibleWrap();
|
||||||
|
|
||||||
|
bool mActivated;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace a11y
|
||||||
|
} // namespace mozilla
|
||||||
|
|
||||||
|
#endif
|
||||||
23
accessible/atk/HTMLTableAccessibleWrap.h
Normal file
23
accessible/atk/HTMLTableAccessibleWrap.h
Normal file
|
|
@ -0,0 +1,23 @@
|
||||||
|
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||||
|
/* vim: set ts=2 et sw=2 tw=80: */
|
||||||
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
|
#ifndef mozilla_a11y_HTMLTableAccessibleWrap_h__
|
||||||
|
#define mozilla_a11y_HTMLTableAccessibleWrap_h__
|
||||||
|
|
||||||
|
#include "HTMLTableAccessible.h"
|
||||||
|
|
||||||
|
namespace mozilla {
|
||||||
|
namespace a11y {
|
||||||
|
|
||||||
|
typedef class HTMLTableAccessible HTMLTableAccessibleWrap;
|
||||||
|
typedef class HTMLTableCellAccessible HTMLTableCellAccessibleWrap;
|
||||||
|
typedef class HTMLTableHeaderCellAccessible HTMLTableHeaderCellAccessibleWrap;
|
||||||
|
|
||||||
|
} // namespace a11y
|
||||||
|
} // namespace mozilla
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
21
accessible/atk/HyperTextAccessibleWrap.h
Normal file
21
accessible/atk/HyperTextAccessibleWrap.h
Normal file
|
|
@ -0,0 +1,21 @@
|
||||||
|
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||||
|
/* vim: set ts=2 et sw=2 tw=80: */
|
||||||
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
|
#ifndef mozilla_a11y_HyperTextAccessibleWrap_h__
|
||||||
|
#define mozilla_a11y_HyperTextAccessibleWrap_h__
|
||||||
|
|
||||||
|
#include "HyperTextAccessible.h"
|
||||||
|
|
||||||
|
namespace mozilla {
|
||||||
|
namespace a11y {
|
||||||
|
|
||||||
|
typedef class HyperTextAccessible HyperTextAccessibleWrap;
|
||||||
|
|
||||||
|
} // namespace a11y
|
||||||
|
} // namespace mozilla
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
21
accessible/atk/ImageAccessibleWrap.h
Normal file
21
accessible/atk/ImageAccessibleWrap.h
Normal file
|
|
@ -0,0 +1,21 @@
|
||||||
|
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||||
|
/* vim: set ts=2 et sw=2 tw=80: */
|
||||||
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
|
#ifndef mozilla_a11y_ImageAccessibleWrap_h__
|
||||||
|
#define mozilla_a11y_ImageAccessibleWrap_h__
|
||||||
|
|
||||||
|
#include "ImageAccessible.h"
|
||||||
|
|
||||||
|
namespace mozilla {
|
||||||
|
namespace a11y {
|
||||||
|
|
||||||
|
typedef class ImageAccessible ImageAccessibleWrap;
|
||||||
|
|
||||||
|
} // namespace a11y
|
||||||
|
} // namespace mozilla
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
44
accessible/atk/InterfaceInitFuncs.h
Normal file
44
accessible/atk/InterfaceInitFuncs.h
Normal file
|
|
@ -0,0 +1,44 @@
|
||||||
|
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||||
|
/* vim: set ts=2 et sw=2 tw=80: */
|
||||||
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* * License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||||
|
* * You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
|
#ifndef ATK_INTERFACE_INIT_FUNCS_H_
|
||||||
|
#define ATK_INTERFACE_INIT_FUNCS_H_
|
||||||
|
|
||||||
|
#include <atk/atk.h>
|
||||||
|
|
||||||
|
namespace mozilla {
|
||||||
|
namespace a11y {
|
||||||
|
|
||||||
|
class AccessibleWrap;
|
||||||
|
|
||||||
|
} // namespace a11y
|
||||||
|
} // namespace mozilla
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
void actionInterfaceInitCB(AtkActionIface* aIface);
|
||||||
|
void componentInterfaceInitCB(AtkComponentIface* aIface);
|
||||||
|
void documentInterfaceInitCB(AtkDocumentIface *aIface);
|
||||||
|
void editableTextInterfaceInitCB(AtkEditableTextIface* aIface);
|
||||||
|
void hyperlinkImplInterfaceInitCB(AtkHyperlinkImplIface *aIface);
|
||||||
|
void hypertextInterfaceInitCB(AtkHypertextIface* aIface);
|
||||||
|
void imageInterfaceInitCB(AtkImageIface* aIface);
|
||||||
|
void selectionInterfaceInitCB(AtkSelectionIface* aIface);
|
||||||
|
void tableInterfaceInitCB(AtkTableIface *aIface);
|
||||||
|
void tableCellInterfaceInitCB(AtkTableCellIface *aIface);
|
||||||
|
void textInterfaceInitCB(AtkTextIface* aIface);
|
||||||
|
void valueInterfaceInitCB(AtkValueIface *aIface);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* XXX these should live in a file of utils for atk.
|
||||||
|
*/
|
||||||
|
AtkObject* refAccessibleAtPointHelper(AtkObject* aAtkObj,
|
||||||
|
gint aX, gint aY, AtkCoordType aCoordType);
|
||||||
|
void getExtentsHelper(AtkObject* aAtkObj,
|
||||||
|
gint* aX, gint* aY, gint* aWidth, gint* aHeight,
|
||||||
|
AtkCoordType aCoordType);
|
||||||
|
|
||||||
|
#endif // ATK_INTERFACE_INIT_FUNCS_H_
|
||||||
377
accessible/atk/Platform.cpp
Normal file
377
accessible/atk/Platform.cpp
Normal file
|
|
@ -0,0 +1,377 @@
|
||||||
|
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||||
|
/* vim: set ts=2 et sw=2 tw=80: */
|
||||||
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
|
#include "Platform.h"
|
||||||
|
|
||||||
|
#include "nsIAccessibleEvent.h"
|
||||||
|
#include "nsIGConfService.h"
|
||||||
|
#include "nsIServiceManager.h"
|
||||||
|
#include "nsMai.h"
|
||||||
|
#include "AtkSocketAccessible.h"
|
||||||
|
#include "prenv.h"
|
||||||
|
#include "prlink.h"
|
||||||
|
|
||||||
|
#ifdef MOZ_ENABLE_DBUS
|
||||||
|
#include <dbus/dbus.h>
|
||||||
|
#endif
|
||||||
|
#include <gtk/gtk.h>
|
||||||
|
|
||||||
|
#if (MOZ_WIDGET_GTK == 3)
|
||||||
|
extern "C" __attribute__((weak,visibility("default"))) int atk_bridge_adaptor_init(int*, char **[]);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
using namespace mozilla;
|
||||||
|
using namespace mozilla::a11y;
|
||||||
|
|
||||||
|
int atkMajorVersion = 1, atkMinorVersion = 12;
|
||||||
|
|
||||||
|
GType (*gAtkTableCellGetTypeFunc)();
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
typedef GType (* AtkGetTypeType) (void);
|
||||||
|
typedef void (*GnomeAccessibilityInit) (void);
|
||||||
|
typedef void (*GnomeAccessibilityShutdown) (void);
|
||||||
|
}
|
||||||
|
|
||||||
|
static PRLibrary* sATKLib = nullptr;
|
||||||
|
static const char sATKLibName[] = "libatk-1.0.so.0";
|
||||||
|
static const char sATKHyperlinkImplGetTypeSymbol[] =
|
||||||
|
"atk_hyperlink_impl_get_type";
|
||||||
|
|
||||||
|
gboolean toplevel_event_watcher(GSignalInvocationHint*, guint, const GValue*,
|
||||||
|
gpointer);
|
||||||
|
static bool sToplevel_event_hook_added = false;
|
||||||
|
static gulong sToplevel_show_hook = 0;
|
||||||
|
static gulong sToplevel_hide_hook = 0;
|
||||||
|
|
||||||
|
GType g_atk_hyperlink_impl_type = G_TYPE_INVALID;
|
||||||
|
|
||||||
|
struct GnomeAccessibilityModule
|
||||||
|
{
|
||||||
|
const char *libName;
|
||||||
|
PRLibrary *lib;
|
||||||
|
const char *initName;
|
||||||
|
GnomeAccessibilityInit init;
|
||||||
|
const char *shutdownName;
|
||||||
|
GnomeAccessibilityShutdown shutdown;
|
||||||
|
};
|
||||||
|
|
||||||
|
static GnomeAccessibilityModule sAtkBridge = {
|
||||||
|
#ifdef AIX
|
||||||
|
"libatk-bridge.a(libatk-bridge.so.0)", nullptr,
|
||||||
|
#else
|
||||||
|
"libatk-bridge.so", nullptr,
|
||||||
|
#endif
|
||||||
|
"gnome_accessibility_module_init", nullptr,
|
||||||
|
"gnome_accessibility_module_shutdown", nullptr
|
||||||
|
};
|
||||||
|
|
||||||
|
#if (MOZ_WIDGET_GTK == 2)
|
||||||
|
static GnomeAccessibilityModule sGail = {
|
||||||
|
"libgail.so", nullptr,
|
||||||
|
"gnome_accessibility_module_init", nullptr,
|
||||||
|
"gnome_accessibility_module_shutdown", nullptr
|
||||||
|
};
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static nsresult
|
||||||
|
LoadGtkModule(GnomeAccessibilityModule& aModule)
|
||||||
|
{
|
||||||
|
NS_ENSURE_ARG(aModule.libName);
|
||||||
|
|
||||||
|
if (!(aModule.lib = PR_LoadLibrary(aModule.libName))) {
|
||||||
|
//try to load the module with "gtk-2.0/modules" appended
|
||||||
|
char *curLibPath = PR_GetLibraryPath();
|
||||||
|
nsAutoCString libPath(curLibPath);
|
||||||
|
#if defined(LINUX) && defined(__x86_64__)
|
||||||
|
libPath.AppendLiteral(":/usr/lib64:/usr/lib");
|
||||||
|
#else
|
||||||
|
libPath.AppendLiteral(":/usr/lib");
|
||||||
|
#endif
|
||||||
|
PR_FreeLibraryName(curLibPath);
|
||||||
|
|
||||||
|
int16_t loc1 = 0, loc2 = 0;
|
||||||
|
int16_t subLen = 0;
|
||||||
|
while (loc2 >= 0) {
|
||||||
|
loc2 = libPath.FindChar(':', loc1);
|
||||||
|
if (loc2 < 0)
|
||||||
|
subLen = libPath.Length() - loc1;
|
||||||
|
else
|
||||||
|
subLen = loc2 - loc1;
|
||||||
|
nsAutoCString sub(Substring(libPath, loc1, subLen));
|
||||||
|
#if (MOZ_WIDGET_GTK == 2)
|
||||||
|
sub.AppendLiteral("/gtk-2.0/modules/");
|
||||||
|
#else
|
||||||
|
sub.AppendLiteral("/gtk-3.0/modules/");
|
||||||
|
#endif
|
||||||
|
sub.Append(aModule.libName);
|
||||||
|
aModule.lib = PR_LoadLibrary(sub.get());
|
||||||
|
if (aModule.lib)
|
||||||
|
break;
|
||||||
|
|
||||||
|
loc1 = loc2+1;
|
||||||
|
}
|
||||||
|
if (!aModule.lib)
|
||||||
|
return NS_ERROR_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
//we have loaded the library, try to get the function ptrs
|
||||||
|
if (!(aModule.init = PR_FindFunctionSymbol(aModule.lib,
|
||||||
|
aModule.initName)) ||
|
||||||
|
!(aModule.shutdown = PR_FindFunctionSymbol(aModule.lib,
|
||||||
|
aModule.shutdownName))) {
|
||||||
|
|
||||||
|
//fail, :(
|
||||||
|
PR_UnloadLibrary(aModule.lib);
|
||||||
|
aModule.lib = nullptr;
|
||||||
|
return NS_ERROR_FAILURE;
|
||||||
|
}
|
||||||
|
return NS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
a11y::PlatformInit()
|
||||||
|
{
|
||||||
|
if (!ShouldA11yBeEnabled())
|
||||||
|
return;
|
||||||
|
|
||||||
|
sATKLib = PR_LoadLibrary(sATKLibName);
|
||||||
|
if (!sATKLib)
|
||||||
|
return;
|
||||||
|
|
||||||
|
AtkGetTypeType pfn_atk_hyperlink_impl_get_type =
|
||||||
|
(AtkGetTypeType) PR_FindFunctionSymbol(sATKLib, sATKHyperlinkImplGetTypeSymbol);
|
||||||
|
if (pfn_atk_hyperlink_impl_get_type)
|
||||||
|
g_atk_hyperlink_impl_type = pfn_atk_hyperlink_impl_get_type();
|
||||||
|
|
||||||
|
AtkGetTypeType pfn_atk_socket_get_type = (AtkGetTypeType)
|
||||||
|
PR_FindFunctionSymbol(sATKLib, AtkSocketAccessible::sATKSocketGetTypeSymbol);
|
||||||
|
if (pfn_atk_socket_get_type) {
|
||||||
|
AtkSocketAccessible::g_atk_socket_type = pfn_atk_socket_get_type();
|
||||||
|
AtkSocketAccessible::g_atk_socket_embed = (AtkSocketEmbedType)
|
||||||
|
PR_FindFunctionSymbol(sATKLib, AtkSocketAccessible ::sATKSocketEmbedSymbol);
|
||||||
|
AtkSocketAccessible::gCanEmbed =
|
||||||
|
AtkSocketAccessible::g_atk_socket_type != G_TYPE_INVALID &&
|
||||||
|
AtkSocketAccessible::g_atk_socket_embed;
|
||||||
|
}
|
||||||
|
|
||||||
|
gAtkTableCellGetTypeFunc = (GType (*)())
|
||||||
|
PR_FindFunctionSymbol(sATKLib, "atk_table_cell_get_type");
|
||||||
|
|
||||||
|
const char* (*atkGetVersion)() =
|
||||||
|
(const char* (*)()) PR_FindFunctionSymbol(sATKLib, "atk_get_version");
|
||||||
|
if (atkGetVersion) {
|
||||||
|
const char* version = atkGetVersion();
|
||||||
|
if (version) {
|
||||||
|
char* endPtr = nullptr;
|
||||||
|
atkMajorVersion = strtol(version, &endPtr, 10);
|
||||||
|
if (*endPtr == '.')
|
||||||
|
atkMinorVersion = strtol(endPtr + 1, &endPtr, 10);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#if (MOZ_WIDGET_GTK == 2)
|
||||||
|
// Load and initialize gail library.
|
||||||
|
nsresult rv = LoadGtkModule(sGail);
|
||||||
|
if (NS_SUCCEEDED(rv))
|
||||||
|
(*sGail.init)();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Initialize the MAI Utility class, it will overwrite gail_util.
|
||||||
|
g_type_class_unref(g_type_class_ref(mai_util_get_type()));
|
||||||
|
|
||||||
|
// Init atk-bridge now
|
||||||
|
PR_SetEnv("NO_AT_BRIDGE=0");
|
||||||
|
#if (MOZ_WIDGET_GTK == 3)
|
||||||
|
if (atk_bridge_adaptor_init) {
|
||||||
|
atk_bridge_adaptor_init(nullptr, nullptr);
|
||||||
|
} else
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
nsresult rv = LoadGtkModule(sAtkBridge);
|
||||||
|
if (NS_SUCCEEDED(rv)) {
|
||||||
|
(*sAtkBridge.init)();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!sToplevel_event_hook_added) {
|
||||||
|
sToplevel_event_hook_added = true;
|
||||||
|
sToplevel_show_hook =
|
||||||
|
g_signal_add_emission_hook(g_signal_lookup("show", GTK_TYPE_WINDOW),
|
||||||
|
0, toplevel_event_watcher,
|
||||||
|
reinterpret_cast<gpointer>(nsIAccessibleEvent::EVENT_SHOW),
|
||||||
|
nullptr);
|
||||||
|
sToplevel_hide_hook =
|
||||||
|
g_signal_add_emission_hook(g_signal_lookup("hide", GTK_TYPE_WINDOW), 0,
|
||||||
|
toplevel_event_watcher,
|
||||||
|
reinterpret_cast<gpointer>(nsIAccessibleEvent::EVENT_HIDE),
|
||||||
|
nullptr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
a11y::PlatformShutdown()
|
||||||
|
{
|
||||||
|
if (sToplevel_event_hook_added) {
|
||||||
|
sToplevel_event_hook_added = false;
|
||||||
|
g_signal_remove_emission_hook(g_signal_lookup("show", GTK_TYPE_WINDOW),
|
||||||
|
sToplevel_show_hook);
|
||||||
|
g_signal_remove_emission_hook(g_signal_lookup("hide", GTK_TYPE_WINDOW),
|
||||||
|
sToplevel_hide_hook);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sAtkBridge.lib) {
|
||||||
|
// Do not shutdown/unload atk-bridge,
|
||||||
|
// an exit function registered will take care of it
|
||||||
|
// if (sAtkBridge.shutdown)
|
||||||
|
// (*sAtkBridge.shutdown)();
|
||||||
|
// PR_UnloadLibrary(sAtkBridge.lib);
|
||||||
|
sAtkBridge.lib = nullptr;
|
||||||
|
sAtkBridge.init = nullptr;
|
||||||
|
sAtkBridge.shutdown = nullptr;
|
||||||
|
}
|
||||||
|
#if (MOZ_WIDGET_GTK == 2)
|
||||||
|
if (sGail.lib) {
|
||||||
|
// Do not shutdown gail because
|
||||||
|
// 1) Maybe it's not init-ed by us. e.g. GtkEmbed
|
||||||
|
// 2) We need it to avoid assert in spi_atk_tidy_windows
|
||||||
|
// if (sGail.shutdown)
|
||||||
|
// (*sGail.shutdown)();
|
||||||
|
// PR_UnloadLibrary(sGail.lib);
|
||||||
|
sGail.lib = nullptr;
|
||||||
|
sGail.init = nullptr;
|
||||||
|
sGail.shutdown = nullptr;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
// if (sATKLib) {
|
||||||
|
// PR_UnloadLibrary(sATKLib);
|
||||||
|
// sATKLib = nullptr;
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
|
||||||
|
static const char sAccEnv [] = "GNOME_ACCESSIBILITY";
|
||||||
|
#ifdef MOZ_ENABLE_DBUS
|
||||||
|
static DBusPendingCall *sPendingCall = nullptr;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
void
|
||||||
|
a11y::PreInit()
|
||||||
|
{
|
||||||
|
#ifdef MOZ_ENABLE_DBUS
|
||||||
|
static bool sChecked = FALSE;
|
||||||
|
if (sChecked)
|
||||||
|
return;
|
||||||
|
|
||||||
|
sChecked = TRUE;
|
||||||
|
|
||||||
|
// dbus is only checked if GNOME_ACCESSIBILITY is unset
|
||||||
|
// also make sure that a session bus address is available to prevent dbus from
|
||||||
|
// starting a new one. Dbus confuses the test harness when it creates a new
|
||||||
|
// process (see bug 693343)
|
||||||
|
if (PR_GetEnv(sAccEnv) || !PR_GetEnv("DBUS_SESSION_BUS_ADDRESS"))
|
||||||
|
return;
|
||||||
|
|
||||||
|
DBusConnection* bus = dbus_bus_get(DBUS_BUS_SESSION, nullptr);
|
||||||
|
if (!bus)
|
||||||
|
return;
|
||||||
|
|
||||||
|
dbus_connection_set_exit_on_disconnect(bus, FALSE);
|
||||||
|
|
||||||
|
static const char* iface = "org.a11y.Status";
|
||||||
|
static const char* member = "IsEnabled";
|
||||||
|
DBusMessage *message;
|
||||||
|
message = dbus_message_new_method_call("org.a11y.Bus", "/org/a11y/bus",
|
||||||
|
"org.freedesktop.DBus.Properties",
|
||||||
|
"Get");
|
||||||
|
if (!message)
|
||||||
|
goto dbus_done;
|
||||||
|
|
||||||
|
dbus_message_append_args(message, DBUS_TYPE_STRING, &iface,
|
||||||
|
DBUS_TYPE_STRING, &member, DBUS_TYPE_INVALID);
|
||||||
|
dbus_connection_send_with_reply(bus, message, &sPendingCall, 1000);
|
||||||
|
dbus_message_unref(message);
|
||||||
|
|
||||||
|
dbus_done:
|
||||||
|
dbus_connection_unref(bus);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
a11y::ShouldA11yBeEnabled()
|
||||||
|
{
|
||||||
|
static bool sChecked = false, sShouldEnable = false;
|
||||||
|
if (sChecked)
|
||||||
|
return sShouldEnable;
|
||||||
|
|
||||||
|
sChecked = true;
|
||||||
|
|
||||||
|
EPlatformDisabledState disabledState = PlatformDisabledState();
|
||||||
|
if (disabledState == ePlatformIsDisabled)
|
||||||
|
return sShouldEnable = false;
|
||||||
|
|
||||||
|
// check if accessibility enabled/disabled by environment variable
|
||||||
|
const char* envValue = PR_GetEnv(sAccEnv);
|
||||||
|
if (envValue)
|
||||||
|
return sShouldEnable = !!atoi(envValue);
|
||||||
|
|
||||||
|
#ifdef MOZ_ENABLE_DBUS
|
||||||
|
PreInit();
|
||||||
|
bool dbusSuccess = false;
|
||||||
|
DBusMessage *reply = nullptr;
|
||||||
|
if (!sPendingCall)
|
||||||
|
goto dbus_done;
|
||||||
|
|
||||||
|
dbus_pending_call_block(sPendingCall);
|
||||||
|
reply = dbus_pending_call_steal_reply(sPendingCall);
|
||||||
|
dbus_pending_call_unref(sPendingCall);
|
||||||
|
sPendingCall = nullptr;
|
||||||
|
if (!reply ||
|
||||||
|
dbus_message_get_type(reply) != DBUS_MESSAGE_TYPE_METHOD_RETURN ||
|
||||||
|
strcmp(dbus_message_get_signature (reply), DBUS_TYPE_VARIANT_AS_STRING))
|
||||||
|
goto dbus_done;
|
||||||
|
|
||||||
|
DBusMessageIter iter, iter_variant, iter_struct;
|
||||||
|
dbus_bool_t dResult;
|
||||||
|
dbus_message_iter_init(reply, &iter);
|
||||||
|
dbus_message_iter_recurse (&iter, &iter_variant);
|
||||||
|
switch (dbus_message_iter_get_arg_type(&iter_variant)) {
|
||||||
|
case DBUS_TYPE_STRUCT:
|
||||||
|
// at-spi2-core 2.2.0-2.2.1 had a bug where it returned a struct
|
||||||
|
dbus_message_iter_recurse(&iter_variant, &iter_struct);
|
||||||
|
if (dbus_message_iter_get_arg_type(&iter_struct) == DBUS_TYPE_BOOLEAN) {
|
||||||
|
dbus_message_iter_get_basic(&iter_struct, &dResult);
|
||||||
|
sShouldEnable = dResult;
|
||||||
|
dbusSuccess = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
case DBUS_TYPE_BOOLEAN:
|
||||||
|
dbus_message_iter_get_basic(&iter_variant, &dResult);
|
||||||
|
sShouldEnable = dResult;
|
||||||
|
dbusSuccess = true;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
dbus_done:
|
||||||
|
if (reply)
|
||||||
|
dbus_message_unref(reply);
|
||||||
|
|
||||||
|
if (dbusSuccess)
|
||||||
|
return sShouldEnable;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
//check gconf-2 setting
|
||||||
|
#define GCONF_A11Y_KEY "/desktop/gnome/interface/accessibility"
|
||||||
|
nsresult rv = NS_OK;
|
||||||
|
nsCOMPtr<nsIGConfService> gconf =
|
||||||
|
do_GetService(NS_GCONFSERVICE_CONTRACTID, &rv);
|
||||||
|
if (NS_SUCCEEDED(rv) && gconf)
|
||||||
|
gconf->GetBool(NS_LITERAL_CSTRING(GCONF_A11Y_KEY), &sShouldEnable);
|
||||||
|
|
||||||
|
return sShouldEnable;
|
||||||
|
}
|
||||||
24
accessible/atk/RootAccessibleWrap.cpp
Normal file
24
accessible/atk/RootAccessibleWrap.cpp
Normal file
|
|
@ -0,0 +1,24 @@
|
||||||
|
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||||
|
/* vim: set ts=2 et sw=2 tw=80: */
|
||||||
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
|
#include "RootAccessibleWrap.h"
|
||||||
|
|
||||||
|
#include "nsMai.h"
|
||||||
|
|
||||||
|
using namespace mozilla::a11y;
|
||||||
|
|
||||||
|
GtkWindowAccessible::GtkWindowAccessible(AtkObject* aAccessible) :
|
||||||
|
DummyAccessible()
|
||||||
|
{
|
||||||
|
g_object_ref(aAccessible);
|
||||||
|
mAtkObject = aAccessible;
|
||||||
|
}
|
||||||
|
|
||||||
|
GtkWindowAccessible::~GtkWindowAccessible()
|
||||||
|
{
|
||||||
|
g_object_unref(mAtkObject);
|
||||||
|
mAtkObject = nullptr;
|
||||||
|
}
|
||||||
34
accessible/atk/RootAccessibleWrap.h
Normal file
34
accessible/atk/RootAccessibleWrap.h
Normal file
|
|
@ -0,0 +1,34 @@
|
||||||
|
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||||
|
/* vim: set ts=2 et sw=2 tw=80: */
|
||||||
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
|
#ifndef mozilla_a11y_RootAccessibleWrap_h__
|
||||||
|
#define mozilla_a11y_RootAccessibleWrap_h__
|
||||||
|
|
||||||
|
#include "BaseAccessibles.h"
|
||||||
|
#include "RootAccessible.h"
|
||||||
|
|
||||||
|
namespace mozilla {
|
||||||
|
namespace a11y {
|
||||||
|
|
||||||
|
typedef RootAccessible RootAccessibleWrap;
|
||||||
|
|
||||||
|
/* GtkWindowAccessible is the accessible class for gtk+ native window.
|
||||||
|
* The instance of GtkWindowAccessible is a child of MaiAppRoot instance.
|
||||||
|
* It is added into root when the toplevel window is created, and removed
|
||||||
|
* from root when the toplevel window is destroyed.
|
||||||
|
*/
|
||||||
|
class GtkWindowAccessible final : public DummyAccessible
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
explicit GtkWindowAccessible(AtkObject* aAccessible);
|
||||||
|
virtual ~GtkWindowAccessible();
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace a11y
|
||||||
|
} // namespace mozilla
|
||||||
|
|
||||||
|
#endif /* mozilla_a11y_Root_Accessible_Wrap_h__ */
|
||||||
|
|
||||||
20
accessible/atk/TextLeafAccessibleWrap.h
Normal file
20
accessible/atk/TextLeafAccessibleWrap.h
Normal file
|
|
@ -0,0 +1,20 @@
|
||||||
|
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||||
|
/* vim: set ts=2 et sw=2 tw=80: */
|
||||||
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
|
#ifndef mozilla_a11y_TextLeafAccessibleWrap_h__
|
||||||
|
#define mozilla_a11y_TextLeafAccessibleWrap_h__
|
||||||
|
|
||||||
|
#include "TextLeafAccessible.h"
|
||||||
|
|
||||||
|
namespace mozilla {
|
||||||
|
namespace a11y {
|
||||||
|
|
||||||
|
typedef class TextLeafAccessible TextLeafAccessibleWrap;
|
||||||
|
|
||||||
|
} // namespace a11y
|
||||||
|
} // namespace mozilla
|
||||||
|
|
||||||
|
#endif
|
||||||
411
accessible/atk/UtilInterface.cpp
Normal file
411
accessible/atk/UtilInterface.cpp
Normal file
|
|
@ -0,0 +1,411 @@
|
||||||
|
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||||
|
/* vim: set ts=2 et sw=2 tw=80: */
|
||||||
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
|
#include "ApplicationAccessibleWrap.h"
|
||||||
|
#include "mozilla/Likely.h"
|
||||||
|
#include "nsAccessibilityService.h"
|
||||||
|
#include "nsMai.h"
|
||||||
|
|
||||||
|
#include <atk/atk.h>
|
||||||
|
#include <gtk/gtk.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
using namespace mozilla;
|
||||||
|
using namespace mozilla::a11y;
|
||||||
|
|
||||||
|
typedef AtkUtil MaiUtil;
|
||||||
|
typedef AtkUtilClass MaiUtilClass;
|
||||||
|
|
||||||
|
#define MAI_VERSION MOZILLA_VERSION
|
||||||
|
#define MAI_NAME "Gecko"
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
static guint (*gail_add_global_event_listener)(GSignalEmissionHook listener,
|
||||||
|
const gchar* event_type);
|
||||||
|
static void (*gail_remove_global_event_listener) (guint remove_listener);
|
||||||
|
static void (*gail_remove_key_event_listener) (guint remove_listener);
|
||||||
|
static AtkObject* (*gail_get_root)();
|
||||||
|
}
|
||||||
|
|
||||||
|
struct MaiUtilListenerInfo
|
||||||
|
{
|
||||||
|
gint key;
|
||||||
|
guint signal_id;
|
||||||
|
gulong hook_id;
|
||||||
|
// For window create/destory/minimize/maximize/restore/activate/deactivate
|
||||||
|
// events, we'll chain gail_util's add/remove_global_event_listener.
|
||||||
|
// So we store the listenerid returned by gail's add_global_event_listener
|
||||||
|
// in this structure to call gail's remove_global_event_listener later.
|
||||||
|
guint gail_listenerid;
|
||||||
|
};
|
||||||
|
|
||||||
|
static GHashTable* sListener_list = nullptr;
|
||||||
|
static gint sListener_idx = 1;
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
static guint
|
||||||
|
add_listener (GSignalEmissionHook listener,
|
||||||
|
const gchar *object_type,
|
||||||
|
const gchar *signal,
|
||||||
|
const gchar *hook_data,
|
||||||
|
guint gail_listenerid = 0)
|
||||||
|
{
|
||||||
|
GType type;
|
||||||
|
guint signal_id;
|
||||||
|
gint rc = 0;
|
||||||
|
|
||||||
|
type = g_type_from_name(object_type);
|
||||||
|
if (type) {
|
||||||
|
signal_id = g_signal_lookup(signal, type);
|
||||||
|
if (signal_id > 0) {
|
||||||
|
MaiUtilListenerInfo *listener_info;
|
||||||
|
|
||||||
|
rc = sListener_idx;
|
||||||
|
|
||||||
|
listener_info = (MaiUtilListenerInfo *)
|
||||||
|
g_malloc(sizeof(MaiUtilListenerInfo));
|
||||||
|
listener_info->key = sListener_idx;
|
||||||
|
listener_info->hook_id =
|
||||||
|
g_signal_add_emission_hook(signal_id, 0, listener,
|
||||||
|
g_strdup(hook_data),
|
||||||
|
(GDestroyNotify)g_free);
|
||||||
|
listener_info->signal_id = signal_id;
|
||||||
|
listener_info->gail_listenerid = gail_listenerid;
|
||||||
|
|
||||||
|
g_hash_table_insert(sListener_list, &(listener_info->key),
|
||||||
|
listener_info);
|
||||||
|
sListener_idx++;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
g_warning("Invalid signal type %s\n", signal);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
g_warning("Invalid object type %s\n", object_type);
|
||||||
|
}
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
static guint
|
||||||
|
mai_util_add_global_event_listener(GSignalEmissionHook listener,
|
||||||
|
const gchar *event_type)
|
||||||
|
{
|
||||||
|
guint rc = 0;
|
||||||
|
gchar **split_string;
|
||||||
|
|
||||||
|
split_string = g_strsplit (event_type, ":", 3);
|
||||||
|
|
||||||
|
if (split_string) {
|
||||||
|
if (!strcmp ("window", split_string[0])) {
|
||||||
|
guint gail_listenerid = 0;
|
||||||
|
if (gail_add_global_event_listener) {
|
||||||
|
// call gail's function to track gtk native window events
|
||||||
|
gail_listenerid =
|
||||||
|
gail_add_global_event_listener(listener, event_type);
|
||||||
|
}
|
||||||
|
|
||||||
|
rc = add_listener (listener, "MaiAtkObject", split_string[1],
|
||||||
|
event_type, gail_listenerid);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
rc = add_listener (listener, split_string[1], split_string[2],
|
||||||
|
event_type);
|
||||||
|
}
|
||||||
|
g_strfreev(split_string);
|
||||||
|
}
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
mai_util_remove_global_event_listener(guint remove_listener)
|
||||||
|
{
|
||||||
|
if (remove_listener > 0) {
|
||||||
|
MaiUtilListenerInfo *listener_info;
|
||||||
|
gint tmp_idx = remove_listener;
|
||||||
|
|
||||||
|
listener_info = (MaiUtilListenerInfo *)
|
||||||
|
g_hash_table_lookup(sListener_list, &tmp_idx);
|
||||||
|
|
||||||
|
if (listener_info != nullptr) {
|
||||||
|
if (gail_remove_global_event_listener &&
|
||||||
|
listener_info->gail_listenerid) {
|
||||||
|
gail_remove_global_event_listener(listener_info->gail_listenerid);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Hook id of 0 and signal id of 0 are invalid */
|
||||||
|
if (listener_info->hook_id != 0 && listener_info->signal_id != 0) {
|
||||||
|
/* Remove the emission hook */
|
||||||
|
g_signal_remove_emission_hook(listener_info->signal_id,
|
||||||
|
listener_info->hook_id);
|
||||||
|
|
||||||
|
/* Remove the element from the hash */
|
||||||
|
g_hash_table_remove(sListener_list, &tmp_idx);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
g_warning("Invalid listener hook_id %ld or signal_id %d\n",
|
||||||
|
listener_info->hook_id, listener_info->signal_id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// atk-bridge is initialized with gail (e.g. yelp)
|
||||||
|
// try gail_remove_global_event_listener
|
||||||
|
if (gail_remove_global_event_listener) {
|
||||||
|
return gail_remove_global_event_listener(remove_listener);
|
||||||
|
}
|
||||||
|
|
||||||
|
g_warning("No listener with the specified listener id %d",
|
||||||
|
remove_listener);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
g_warning("Invalid listener_id %d", remove_listener);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static AtkKeyEventStruct *
|
||||||
|
atk_key_event_from_gdk_event_key (GdkEventKey *key)
|
||||||
|
{
|
||||||
|
AtkKeyEventStruct *event = g_new0(AtkKeyEventStruct, 1);
|
||||||
|
switch (key->type) {
|
||||||
|
case GDK_KEY_PRESS:
|
||||||
|
event->type = ATK_KEY_EVENT_PRESS;
|
||||||
|
break;
|
||||||
|
case GDK_KEY_RELEASE:
|
||||||
|
event->type = ATK_KEY_EVENT_RELEASE;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
g_assert_not_reached ();
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
event->state = key->state;
|
||||||
|
event->keyval = key->keyval;
|
||||||
|
event->length = key->length;
|
||||||
|
if (key->string && key->string [0] &&
|
||||||
|
(key->state & GDK_CONTROL_MASK ||
|
||||||
|
g_unichar_isgraph (g_utf8_get_char (key->string)))) {
|
||||||
|
event->string = key->string;
|
||||||
|
}
|
||||||
|
else if (key->type == GDK_KEY_PRESS ||
|
||||||
|
key->type == GDK_KEY_RELEASE) {
|
||||||
|
event->string = gdk_keyval_name (key->keyval);
|
||||||
|
}
|
||||||
|
event->keycode = key->hardware_keycode;
|
||||||
|
event->timestamp = key->time;
|
||||||
|
|
||||||
|
return event;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct MaiKeyEventInfo
|
||||||
|
{
|
||||||
|
AtkKeyEventStruct *key_event;
|
||||||
|
gpointer func_data;
|
||||||
|
};
|
||||||
|
|
||||||
|
union AtkKeySnoopFuncPointer
|
||||||
|
{
|
||||||
|
AtkKeySnoopFunc func_ptr;
|
||||||
|
gpointer data;
|
||||||
|
};
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
notify_hf(gpointer key, gpointer value, gpointer data)
|
||||||
|
{
|
||||||
|
MaiKeyEventInfo *info = (MaiKeyEventInfo *)data;
|
||||||
|
AtkKeySnoopFuncPointer atkKeySnoop;
|
||||||
|
atkKeySnoop.data = value;
|
||||||
|
return (atkKeySnoop.func_ptr)(info->key_event, info->func_data) ? TRUE : FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
insert_hf(gpointer key, gpointer value, gpointer data)
|
||||||
|
{
|
||||||
|
GHashTable *new_table = (GHashTable *) data;
|
||||||
|
g_hash_table_insert (new_table, key, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
static GHashTable* sKey_listener_list = nullptr;
|
||||||
|
|
||||||
|
static gint
|
||||||
|
mai_key_snooper(GtkWidget *the_widget, GdkEventKey *event, gpointer func_data)
|
||||||
|
{
|
||||||
|
/* notify each AtkKeySnoopFunc in turn... */
|
||||||
|
|
||||||
|
MaiKeyEventInfo *info = g_new0(MaiKeyEventInfo, 1);
|
||||||
|
gint consumed = 0;
|
||||||
|
if (sKey_listener_list) {
|
||||||
|
GHashTable *new_hash = g_hash_table_new(nullptr, nullptr);
|
||||||
|
g_hash_table_foreach (sKey_listener_list, insert_hf, new_hash);
|
||||||
|
info->key_event = atk_key_event_from_gdk_event_key (event);
|
||||||
|
info->func_data = func_data;
|
||||||
|
consumed = g_hash_table_foreach_steal (new_hash, notify_hf, info);
|
||||||
|
g_hash_table_destroy (new_hash);
|
||||||
|
g_free(info->key_event);
|
||||||
|
}
|
||||||
|
g_free(info);
|
||||||
|
return (consumed ? 1 : 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static guint sKey_snooper_id = 0;
|
||||||
|
|
||||||
|
static guint
|
||||||
|
mai_util_add_key_event_listener(AtkKeySnoopFunc listener, gpointer data)
|
||||||
|
{
|
||||||
|
if (MOZ_UNLIKELY(!listener)) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static guint key = 0;
|
||||||
|
|
||||||
|
if (!sKey_listener_list) {
|
||||||
|
sKey_listener_list = g_hash_table_new(nullptr, nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
// If we have no registered event listeners then we need to (re)install the
|
||||||
|
// key event snooper.
|
||||||
|
if (g_hash_table_size(sKey_listener_list) == 0) {
|
||||||
|
sKey_snooper_id = gtk_key_snooper_install(mai_key_snooper, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
AtkKeySnoopFuncPointer atkKeySnoop;
|
||||||
|
atkKeySnoop.func_ptr = listener;
|
||||||
|
key++;
|
||||||
|
g_hash_table_insert(sKey_listener_list, GUINT_TO_POINTER(key),
|
||||||
|
atkKeySnoop.data);
|
||||||
|
return key;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
mai_util_remove_key_event_listener (guint remove_listener)
|
||||||
|
{
|
||||||
|
if (!sKey_listener_list) {
|
||||||
|
// atk-bridge is initialized with gail (e.g. yelp)
|
||||||
|
// try gail_remove_key_event_listener
|
||||||
|
return gail_remove_key_event_listener(remove_listener);
|
||||||
|
}
|
||||||
|
|
||||||
|
g_hash_table_remove(sKey_listener_list, GUINT_TO_POINTER (remove_listener));
|
||||||
|
if (g_hash_table_size(sKey_listener_list) == 0) {
|
||||||
|
gtk_key_snooper_remove(sKey_snooper_id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static AtkObject*
|
||||||
|
mai_util_get_root()
|
||||||
|
{
|
||||||
|
ApplicationAccessible* app = ApplicationAcc();
|
||||||
|
if (app)
|
||||||
|
return app->GetAtkObject();
|
||||||
|
|
||||||
|
// We've shutdown, try to use gail instead
|
||||||
|
// (to avoid assert in spi_atk_tidy_windows())
|
||||||
|
// XXX tbsaunde then why didn't we replace the gail atk_util impl?
|
||||||
|
if (gail_get_root)
|
||||||
|
return gail_get_root();
|
||||||
|
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const gchar*
|
||||||
|
mai_util_get_toolkit_name()
|
||||||
|
{
|
||||||
|
return MAI_NAME;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const gchar*
|
||||||
|
mai_util_get_toolkit_version()
|
||||||
|
{
|
||||||
|
return MAI_VERSION;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
_listener_info_destroy(gpointer data)
|
||||||
|
{
|
||||||
|
g_free(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
window_added (AtkObject *atk_obj,
|
||||||
|
guint index,
|
||||||
|
AtkObject *child)
|
||||||
|
{
|
||||||
|
if (!IS_MAI_OBJECT(child))
|
||||||
|
return;
|
||||||
|
|
||||||
|
static guint id = g_signal_lookup ("create", MAI_TYPE_ATK_OBJECT);
|
||||||
|
g_signal_emit (child, id, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
window_removed (AtkObject *atk_obj,
|
||||||
|
guint index,
|
||||||
|
AtkObject *child)
|
||||||
|
{
|
||||||
|
if (!IS_MAI_OBJECT(child))
|
||||||
|
return;
|
||||||
|
|
||||||
|
static guint id = g_signal_lookup ("destroy", MAI_TYPE_ATK_OBJECT);
|
||||||
|
g_signal_emit (child, id, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
UtilInterfaceInit(MaiUtilClass* klass)
|
||||||
|
{
|
||||||
|
AtkUtilClass *atk_class;
|
||||||
|
gpointer data;
|
||||||
|
|
||||||
|
data = g_type_class_peek(ATK_TYPE_UTIL);
|
||||||
|
atk_class = ATK_UTIL_CLASS(data);
|
||||||
|
|
||||||
|
// save gail function pointer
|
||||||
|
gail_add_global_event_listener = atk_class->add_global_event_listener;
|
||||||
|
gail_remove_global_event_listener = atk_class->remove_global_event_listener;
|
||||||
|
gail_remove_key_event_listener = atk_class->remove_key_event_listener;
|
||||||
|
gail_get_root = atk_class->get_root;
|
||||||
|
|
||||||
|
atk_class->add_global_event_listener =
|
||||||
|
mai_util_add_global_event_listener;
|
||||||
|
atk_class->remove_global_event_listener =
|
||||||
|
mai_util_remove_global_event_listener;
|
||||||
|
atk_class->add_key_event_listener = mai_util_add_key_event_listener;
|
||||||
|
atk_class->remove_key_event_listener = mai_util_remove_key_event_listener;
|
||||||
|
atk_class->get_root = mai_util_get_root;
|
||||||
|
atk_class->get_toolkit_name = mai_util_get_toolkit_name;
|
||||||
|
atk_class->get_toolkit_version = mai_util_get_toolkit_version;
|
||||||
|
|
||||||
|
sListener_list = g_hash_table_new_full(g_int_hash, g_int_equal, nullptr,
|
||||||
|
_listener_info_destroy);
|
||||||
|
// Keep track of added/removed windows.
|
||||||
|
AtkObject *root = atk_get_root ();
|
||||||
|
g_signal_connect (root, "children-changed::add", (GCallback) window_added, nullptr);
|
||||||
|
g_signal_connect (root, "children-changed::remove", (GCallback) window_removed, nullptr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
GType
|
||||||
|
mai_util_get_type()
|
||||||
|
{
|
||||||
|
static GType type = 0;
|
||||||
|
|
||||||
|
if (!type) {
|
||||||
|
static const GTypeInfo tinfo = {
|
||||||
|
sizeof(MaiUtilClass),
|
||||||
|
(GBaseInitFunc) nullptr, /* base init */
|
||||||
|
(GBaseFinalizeFunc) nullptr, /* base finalize */
|
||||||
|
(GClassInitFunc) UtilInterfaceInit, /* class init */
|
||||||
|
(GClassFinalizeFunc) nullptr, /* class finalize */
|
||||||
|
nullptr, /* class data */
|
||||||
|
sizeof(MaiUtil), /* instance size */
|
||||||
|
0, /* nb preallocs */
|
||||||
|
(GInstanceInitFunc) nullptr, /* instance init */
|
||||||
|
nullptr /* value table */
|
||||||
|
};
|
||||||
|
|
||||||
|
type = g_type_register_static(ATK_TYPE_UTIL,
|
||||||
|
"MaiUtil", &tinfo, GTypeFlags(0));
|
||||||
|
}
|
||||||
|
return type;
|
||||||
|
}
|
||||||
|
|
||||||
21
accessible/atk/XULListboxAccessibleWrap.h
Normal file
21
accessible/atk/XULListboxAccessibleWrap.h
Normal file
|
|
@ -0,0 +1,21 @@
|
||||||
|
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||||
|
/* vim: set ts=2 et sw=2 tw=80: */
|
||||||
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
|
#ifndef mozilla_a11y_XULListboxAccessibleWrap_h__
|
||||||
|
#define mozilla_a11y_XULListboxAccessibleWrap_h__
|
||||||
|
|
||||||
|
#include "XULListboxAccessible.h"
|
||||||
|
|
||||||
|
namespace mozilla {
|
||||||
|
namespace a11y {
|
||||||
|
|
||||||
|
typedef class XULListboxAccessible XULListboxAccessibleWrap;
|
||||||
|
typedef class XULListCellAccessible XULListCellAccessibleWrap;
|
||||||
|
|
||||||
|
} // namespace a11y
|
||||||
|
} // namespace mozilla
|
||||||
|
|
||||||
|
#endif
|
||||||
20
accessible/atk/XULMenuAccessibleWrap.h
Normal file
20
accessible/atk/XULMenuAccessibleWrap.h
Normal file
|
|
@ -0,0 +1,20 @@
|
||||||
|
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||||
|
/* vim: set ts=2 et sw=2 tw=80: */
|
||||||
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
|
#ifndef mozilla_a11y_XULMenuAccessibleWrap_h__
|
||||||
|
#define mozilla_a11y_XULMenuAccessibleWrap_h__
|
||||||
|
|
||||||
|
#include "XULMenuAccessible.h"
|
||||||
|
|
||||||
|
namespace mozilla {
|
||||||
|
namespace a11y {
|
||||||
|
|
||||||
|
typedef class XULMenuitemAccessible XULMenuitemAccessibleWrap;
|
||||||
|
|
||||||
|
} // namespace a11y
|
||||||
|
} // namespace mozilla
|
||||||
|
|
||||||
|
#endif
|
||||||
22
accessible/atk/XULTreeGridAccessibleWrap.h
Normal file
22
accessible/atk/XULTreeGridAccessibleWrap.h
Normal file
|
|
@ -0,0 +1,22 @@
|
||||||
|
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||||
|
/* vim: set ts=2 et sw=2 tw=80: */
|
||||||
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
|
#ifndef mozilla_a11y_XULTreeGridAccessibleWrap_h__
|
||||||
|
#define mozilla_a11y_XULTreeGridAccessibleWrap_h__
|
||||||
|
|
||||||
|
#include "XULTreeGridAccessible.h"
|
||||||
|
|
||||||
|
namespace mozilla {
|
||||||
|
namespace a11y {
|
||||||
|
|
||||||
|
typedef class XULTreeGridAccessible XULTreeGridAccessibleWrap;
|
||||||
|
typedef class XULTreeGridCellAccessible XULTreeGridCellAccessibleWrap;
|
||||||
|
|
||||||
|
} // namespace a11y
|
||||||
|
} // namespace mozilla
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
63
accessible/atk/moz.build
Normal file
63
accessible/atk/moz.build
Normal file
|
|
@ -0,0 +1,63 @@
|
||||||
|
# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
|
||||||
|
# vim: set filetype=python:
|
||||||
|
# This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||||
|
|
||||||
|
EXPORTS.mozilla.a11y += [
|
||||||
|
'AccessibleWrap.h',
|
||||||
|
'HyperTextAccessibleWrap.h',
|
||||||
|
]
|
||||||
|
|
||||||
|
SOURCES += [
|
||||||
|
'AccessibleWrap.cpp',
|
||||||
|
'ApplicationAccessibleWrap.cpp',
|
||||||
|
'AtkSocketAccessible.cpp',
|
||||||
|
'DocAccessibleWrap.cpp',
|
||||||
|
'nsMaiHyperlink.cpp',
|
||||||
|
'nsMaiInterfaceAction.cpp',
|
||||||
|
'nsMaiInterfaceComponent.cpp',
|
||||||
|
'nsMaiInterfaceDocument.cpp',
|
||||||
|
'nsMaiInterfaceEditableText.cpp',
|
||||||
|
'nsMaiInterfaceHyperlinkImpl.cpp',
|
||||||
|
'nsMaiInterfaceHypertext.cpp',
|
||||||
|
'nsMaiInterfaceImage.cpp',
|
||||||
|
'nsMaiInterfaceSelection.cpp',
|
||||||
|
'nsMaiInterfaceTable.cpp',
|
||||||
|
'nsMaiInterfaceTableCell.cpp',
|
||||||
|
'nsMaiInterfaceText.cpp',
|
||||||
|
'nsMaiInterfaceValue.cpp',
|
||||||
|
'Platform.cpp',
|
||||||
|
'RootAccessibleWrap.cpp',
|
||||||
|
'UtilInterface.cpp',
|
||||||
|
]
|
||||||
|
|
||||||
|
LOCAL_INCLUDES += [
|
||||||
|
'/accessible/base',
|
||||||
|
'/accessible/generic',
|
||||||
|
'/accessible/html',
|
||||||
|
'/accessible/ipc',
|
||||||
|
'/accessible/ipc/other',
|
||||||
|
'/accessible/xpcom',
|
||||||
|
'/accessible/xul',
|
||||||
|
'/other-licenses/atk-1.0',
|
||||||
|
]
|
||||||
|
|
||||||
|
FINAL_LIBRARY = 'xul'
|
||||||
|
|
||||||
|
if 'gtk' in CONFIG['MOZ_WIDGET_TOOLKIT']:
|
||||||
|
CFLAGS += CONFIG['TK_CFLAGS']
|
||||||
|
CXXFLAGS += CONFIG['TK_CFLAGS']
|
||||||
|
|
||||||
|
if CONFIG['MOZ_ENABLE_DBUS']:
|
||||||
|
CXXFLAGS += CONFIG['MOZ_DBUS_CFLAGS']
|
||||||
|
|
||||||
|
include('/ipc/chromium/chromium-config.mozbuild')
|
||||||
|
|
||||||
|
if CONFIG['CLANG_CXX'] or CONFIG['GNU_CXX']:
|
||||||
|
# Used in G_DEFINE_TYPE_EXTENDED macro, probably fixed in newer glib /
|
||||||
|
# gobject headers. See bug 1243331 comment 3.
|
||||||
|
CXXFLAGS += [
|
||||||
|
'-Wno-error=shadow',
|
||||||
|
'-Wno-unused-local-typedefs',
|
||||||
|
]
|
||||||
149
accessible/atk/nsMai.h
Normal file
149
accessible/atk/nsMai.h
Normal file
|
|
@ -0,0 +1,149 @@
|
||||||
|
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||||
|
/* vim: set ts=2 et sw=2 tw=80: */
|
||||||
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
|
#ifndef __NS_MAI_H__
|
||||||
|
#define __NS_MAI_H__
|
||||||
|
|
||||||
|
#include <atk/atk.h>
|
||||||
|
#include <glib.h>
|
||||||
|
#include <glib-object.h>
|
||||||
|
|
||||||
|
#include "AccessibleOrProxy.h"
|
||||||
|
#include "AccessibleWrap.h"
|
||||||
|
|
||||||
|
namespace mozilla {
|
||||||
|
namespace a11y {
|
||||||
|
class ProxyAccessible;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#define MAI_TYPE_ATK_OBJECT (mai_atk_object_get_type ())
|
||||||
|
#define MAI_ATK_OBJECT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), \
|
||||||
|
MAI_TYPE_ATK_OBJECT, MaiAtkObject))
|
||||||
|
#define MAI_ATK_OBJECT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), \
|
||||||
|
MAI_TYPE_ATK_OBJECT, \
|
||||||
|
MaiAtkObjectClass))
|
||||||
|
#define IS_MAI_OBJECT(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), \
|
||||||
|
MAI_TYPE_ATK_OBJECT))
|
||||||
|
#define IS_MAI_OBJECT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), \
|
||||||
|
MAI_TYPE_ATK_OBJECT))
|
||||||
|
#define MAI_ATK_OBJECT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), \
|
||||||
|
MAI_TYPE_ATK_OBJECT, \
|
||||||
|
MaiAtkObjectClass))
|
||||||
|
GType mai_atk_object_get_type(void);
|
||||||
|
GType mai_util_get_type();
|
||||||
|
extern "C" GType mai_atk_socket_get_type(void);
|
||||||
|
|
||||||
|
/* MaiAtkSocket */
|
||||||
|
|
||||||
|
#define MAI_TYPE_ATK_SOCKET (mai_atk_socket_get_type ())
|
||||||
|
#define MAI_ATK_SOCKET(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj),\
|
||||||
|
MAI_TYPE_ATK_SOCKET, MaiAtkSocket))
|
||||||
|
#define MAI_IS_ATK_SOCKET(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj),\
|
||||||
|
MAI_TYPE_ATK_SOCKET))
|
||||||
|
#define MAI_ATK_SOCKET_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass),\
|
||||||
|
MAI_TYPE_ATK_SOCKET,\
|
||||||
|
MaiAtkSocketClass))
|
||||||
|
#define MAI_IS_ATK_SOCKET_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass),\
|
||||||
|
MAI_TYPE_ATK_SOCKET))
|
||||||
|
#define MAI_ATK_SOCKET_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj),\
|
||||||
|
MAI_TYPE_ATK_SOCKET,\
|
||||||
|
MaiAtkSocketClass))
|
||||||
|
|
||||||
|
typedef struct _MaiAtkSocket
|
||||||
|
{
|
||||||
|
AtkSocket parent;
|
||||||
|
|
||||||
|
mozilla::a11y::AccessibleWrap* accWrap;
|
||||||
|
} MaiAtkSocket;
|
||||||
|
|
||||||
|
typedef struct _MaiAtkSocketClass
|
||||||
|
{
|
||||||
|
AtkSocketClass parent_class;
|
||||||
|
} MaiAtkSocketClass;
|
||||||
|
|
||||||
|
// This is a pointer to the atk_table_cell_get_type function if we are using
|
||||||
|
// a version of atk that defines that.
|
||||||
|
extern "C" GType (*gAtkTableCellGetTypeFunc)();
|
||||||
|
|
||||||
|
mozilla::a11y::AccessibleWrap* GetAccessibleWrap(AtkObject* aAtkObj);
|
||||||
|
mozilla::a11y::ProxyAccessible* GetProxy(AtkObject* aAtkObj);
|
||||||
|
mozilla::a11y::AccessibleOrProxy GetInternalObj(AtkObject* aObj);
|
||||||
|
AtkObject* GetWrapperFor(mozilla::a11y::ProxyAccessible* aProxy);
|
||||||
|
AtkObject* GetWrapperFor(mozilla::a11y::AccessibleOrProxy aObj);
|
||||||
|
|
||||||
|
extern int atkMajorVersion, atkMinorVersion;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return true if the loaded version of libatk-1.0.so is at least
|
||||||
|
* aMajor.aMinor.0.
|
||||||
|
*/
|
||||||
|
static inline bool
|
||||||
|
IsAtkVersionAtLeast(int aMajor, int aMinor)
|
||||||
|
{
|
||||||
|
return aMajor < atkMajorVersion ||
|
||||||
|
(aMajor == atkMajorVersion && aMinor <= atkMinorVersion);
|
||||||
|
}
|
||||||
|
|
||||||
|
// This is or'd with the pointer in MaiAtkObject::accWrap if the wrap-ee is a
|
||||||
|
// proxy.
|
||||||
|
static const uintptr_t IS_PROXY = 1;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This MaiAtkObject is a thin wrapper, in the MAI namespace, for AtkObject
|
||||||
|
*/
|
||||||
|
struct MaiAtkObject
|
||||||
|
{
|
||||||
|
AtkObject parent;
|
||||||
|
/*
|
||||||
|
* The AccessibleWrap whose properties and features are exported
|
||||||
|
* via this object instance.
|
||||||
|
*/
|
||||||
|
mozilla::a11y::AccessibleOrProxy accWrap;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Get the AtkHyperlink for this atk object.
|
||||||
|
*/
|
||||||
|
AtkHyperlink* GetAtkHyperlink();
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Shutdown this AtkObject.
|
||||||
|
*/
|
||||||
|
void Shutdown();
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Notify atk of a state change on this AtkObject.
|
||||||
|
*/
|
||||||
|
void FireStateChangeEvent(uint64_t aState, bool aEnabled);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Notify ATK of a text change within this ATK object.
|
||||||
|
*/
|
||||||
|
void FireTextChangeEvent(const nsString& aStr, int32_t aStart, uint32_t aLen,
|
||||||
|
bool aIsInsert, bool aIsFromUser);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Notify ATK of a shown or hidden subtree rooted at aObject whose parent is
|
||||||
|
* aParent
|
||||||
|
*/
|
||||||
|
void FireAtkShowHideEvent(AtkObject* aParent, bool aIsAdded, bool aFromUser);
|
||||||
|
|
||||||
|
private:
|
||||||
|
/*
|
||||||
|
* do we have text-remove and text-insert signals if not we need to use
|
||||||
|
* text-changed see AccessibleWrap::FireAtkTextChangedEvent() and
|
||||||
|
* bug 619002
|
||||||
|
*/
|
||||||
|
enum EAvailableAtkSignals {
|
||||||
|
eUnknown,
|
||||||
|
eHaveNewAtkTextSignals,
|
||||||
|
eNoNewAtkSignals
|
||||||
|
};
|
||||||
|
|
||||||
|
static EAvailableAtkSignals gAvailableAtkSignals;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif /* __NS_MAI_H__ */
|
||||||
262
accessible/atk/nsMaiHyperlink.cpp
Normal file
262
accessible/atk/nsMaiHyperlink.cpp
Normal file
|
|
@ -0,0 +1,262 @@
|
||||||
|
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||||
|
/* vim: set ts=2 et sw=2 tw=80: */
|
||||||
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
|
#include "nsIURI.h"
|
||||||
|
#include "nsMaiHyperlink.h"
|
||||||
|
#include "mozilla/a11y/ProxyAccessible.h"
|
||||||
|
|
||||||
|
using namespace mozilla::a11y;
|
||||||
|
|
||||||
|
/* MaiAtkHyperlink */
|
||||||
|
|
||||||
|
#define MAI_TYPE_ATK_HYPERLINK (mai_atk_hyperlink_get_type ())
|
||||||
|
#define MAI_ATK_HYPERLINK(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj),\
|
||||||
|
MAI_TYPE_ATK_HYPERLINK, MaiAtkHyperlink))
|
||||||
|
#define MAI_ATK_HYPERLINK_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass),\
|
||||||
|
MAI_TYPE_ATK_HYPERLINK, MaiAtkHyperlinkClass))
|
||||||
|
#define MAI_IS_ATK_HYPERLINK(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj),\
|
||||||
|
MAI_TYPE_ATK_HYPERLINK))
|
||||||
|
#define MAI_IS_ATK_HYPERLINK_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass),\
|
||||||
|
MAI_TYPE_ATK_HYPERLINK))
|
||||||
|
#define MAI_ATK_HYPERLINK_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj),\
|
||||||
|
MAI_TYPE_ATK_HYPERLINK, MaiAtkHyperlinkClass))
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This MaiAtkHyperlink is a thin wrapper, in the MAI namespace,
|
||||||
|
* for AtkHyperlink
|
||||||
|
*/
|
||||||
|
|
||||||
|
struct MaiAtkHyperlink
|
||||||
|
{
|
||||||
|
AtkHyperlink parent;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The MaiHyperlink whose properties and features are exported via this
|
||||||
|
* hyperlink instance.
|
||||||
|
*/
|
||||||
|
MaiHyperlink *maiHyperlink;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct MaiAtkHyperlinkClass
|
||||||
|
{
|
||||||
|
AtkHyperlinkClass parent_class;
|
||||||
|
};
|
||||||
|
|
||||||
|
GType mai_atk_hyperlink_get_type(void);
|
||||||
|
|
||||||
|
G_BEGIN_DECLS
|
||||||
|
/* callbacks for AtkHyperlink */
|
||||||
|
static void classInitCB(AtkHyperlinkClass *aClass);
|
||||||
|
static void finalizeCB(GObject *aObj);
|
||||||
|
|
||||||
|
/* callbacks for AtkHyperlink virtual functions */
|
||||||
|
static gchar *getUriCB(AtkHyperlink *aLink, gint aLinkIndex);
|
||||||
|
static AtkObject *getObjectCB(AtkHyperlink *aLink, gint aLinkIndex);
|
||||||
|
static gint getEndIndexCB(AtkHyperlink *aLink);
|
||||||
|
static gint getStartIndexCB(AtkHyperlink *aLink);
|
||||||
|
static gboolean isValidCB(AtkHyperlink *aLink);
|
||||||
|
static gint getAnchorCountCB(AtkHyperlink *aLink);
|
||||||
|
G_END_DECLS
|
||||||
|
|
||||||
|
static gpointer parent_class = nullptr;
|
||||||
|
|
||||||
|
static MaiHyperlink*
|
||||||
|
GetMaiHyperlink(AtkHyperlink *aHyperlink)
|
||||||
|
{
|
||||||
|
NS_ENSURE_TRUE(MAI_IS_ATK_HYPERLINK(aHyperlink), nullptr);
|
||||||
|
MaiHyperlink * maiHyperlink =
|
||||||
|
MAI_ATK_HYPERLINK(aHyperlink)->maiHyperlink;
|
||||||
|
NS_ENSURE_TRUE(maiHyperlink != nullptr, nullptr);
|
||||||
|
NS_ENSURE_TRUE(maiHyperlink->GetAtkHyperlink() == aHyperlink, nullptr);
|
||||||
|
return maiHyperlink;
|
||||||
|
}
|
||||||
|
|
||||||
|
GType
|
||||||
|
mai_atk_hyperlink_get_type(void)
|
||||||
|
{
|
||||||
|
static GType type = 0;
|
||||||
|
|
||||||
|
if (!type) {
|
||||||
|
static const GTypeInfo tinfo = {
|
||||||
|
sizeof(MaiAtkHyperlinkClass),
|
||||||
|
(GBaseInitFunc)nullptr,
|
||||||
|
(GBaseFinalizeFunc)nullptr,
|
||||||
|
(GClassInitFunc)classInitCB,
|
||||||
|
(GClassFinalizeFunc)nullptr,
|
||||||
|
nullptr, /* class data */
|
||||||
|
sizeof(MaiAtkHyperlink), /* instance size */
|
||||||
|
0, /* nb preallocs */
|
||||||
|
(GInstanceInitFunc)nullptr,
|
||||||
|
nullptr /* value table */
|
||||||
|
};
|
||||||
|
|
||||||
|
type = g_type_register_static(ATK_TYPE_HYPERLINK,
|
||||||
|
"MaiAtkHyperlink",
|
||||||
|
&tinfo, GTypeFlags(0));
|
||||||
|
}
|
||||||
|
return type;
|
||||||
|
}
|
||||||
|
|
||||||
|
MaiHyperlink::MaiHyperlink(AccessibleOrProxy aHyperLink) :
|
||||||
|
mHyperlink(aHyperLink),
|
||||||
|
mMaiAtkHyperlink(nullptr)
|
||||||
|
{
|
||||||
|
mMaiAtkHyperlink =
|
||||||
|
reinterpret_cast<AtkHyperlink *>
|
||||||
|
(g_object_new(mai_atk_hyperlink_get_type(), nullptr));
|
||||||
|
NS_ASSERTION(mMaiAtkHyperlink, "OUT OF MEMORY");
|
||||||
|
if (!mMaiAtkHyperlink)
|
||||||
|
return;
|
||||||
|
|
||||||
|
MAI_ATK_HYPERLINK(mMaiAtkHyperlink)->maiHyperlink = this;
|
||||||
|
}
|
||||||
|
|
||||||
|
MaiHyperlink::~MaiHyperlink()
|
||||||
|
{
|
||||||
|
if (mMaiAtkHyperlink) {
|
||||||
|
MAI_ATK_HYPERLINK(mMaiAtkHyperlink)->maiHyperlink = nullptr;
|
||||||
|
g_object_unref(mMaiAtkHyperlink);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* static functions for ATK callbacks */
|
||||||
|
|
||||||
|
void
|
||||||
|
classInitCB(AtkHyperlinkClass *aClass)
|
||||||
|
{
|
||||||
|
GObjectClass *gobject_class = G_OBJECT_CLASS(aClass);
|
||||||
|
|
||||||
|
parent_class = g_type_class_peek_parent(aClass);
|
||||||
|
|
||||||
|
aClass->get_uri = getUriCB;
|
||||||
|
aClass->get_object = getObjectCB;
|
||||||
|
aClass->get_end_index = getEndIndexCB;
|
||||||
|
aClass->get_start_index = getStartIndexCB;
|
||||||
|
aClass->is_valid = isValidCB;
|
||||||
|
aClass->get_n_anchors = getAnchorCountCB;
|
||||||
|
|
||||||
|
gobject_class->finalize = finalizeCB;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
finalizeCB(GObject *aObj)
|
||||||
|
{
|
||||||
|
NS_ASSERTION(MAI_IS_ATK_HYPERLINK(aObj), "Invalid MaiAtkHyperlink");
|
||||||
|
if (!MAI_IS_ATK_HYPERLINK(aObj))
|
||||||
|
return;
|
||||||
|
|
||||||
|
MaiAtkHyperlink *maiAtkHyperlink = MAI_ATK_HYPERLINK(aObj);
|
||||||
|
maiAtkHyperlink->maiHyperlink = nullptr;
|
||||||
|
|
||||||
|
/* call parent finalize function */
|
||||||
|
if (G_OBJECT_CLASS (parent_class)->finalize)
|
||||||
|
G_OBJECT_CLASS (parent_class)->finalize(aObj);
|
||||||
|
}
|
||||||
|
|
||||||
|
gchar *
|
||||||
|
getUriCB(AtkHyperlink *aLink, gint aLinkIndex)
|
||||||
|
{
|
||||||
|
MaiHyperlink* maiLink = GetMaiHyperlink(aLink);
|
||||||
|
if (!maiLink)
|
||||||
|
return nullptr;
|
||||||
|
|
||||||
|
nsAutoCString cautoStr;
|
||||||
|
if (Accessible* hyperlink = maiLink->GetAccHyperlink()) {
|
||||||
|
nsCOMPtr<nsIURI> uri = hyperlink->AnchorURIAt(aLinkIndex);
|
||||||
|
if (!uri)
|
||||||
|
return nullptr;
|
||||||
|
|
||||||
|
nsresult rv = uri->GetSpec(cautoStr);
|
||||||
|
NS_ENSURE_SUCCESS(rv, nullptr);
|
||||||
|
|
||||||
|
return g_strdup(cautoStr.get());
|
||||||
|
}
|
||||||
|
|
||||||
|
bool valid;
|
||||||
|
maiLink->Proxy()->AnchorURIAt(aLinkIndex, cautoStr, &valid);
|
||||||
|
if (!valid)
|
||||||
|
return nullptr;
|
||||||
|
|
||||||
|
return g_strdup(cautoStr.get());
|
||||||
|
}
|
||||||
|
|
||||||
|
AtkObject *
|
||||||
|
getObjectCB(AtkHyperlink *aLink, gint aLinkIndex)
|
||||||
|
{
|
||||||
|
MaiHyperlink* maiLink = GetMaiHyperlink(aLink);
|
||||||
|
if (!maiLink) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Accessible* hyperlink = maiLink->GetAccHyperlink()) {
|
||||||
|
Accessible* anchor = hyperlink->AnchorAt(aLinkIndex);
|
||||||
|
NS_ENSURE_TRUE(anchor, nullptr);
|
||||||
|
|
||||||
|
return AccessibleWrap::GetAtkObject(anchor);
|
||||||
|
}
|
||||||
|
|
||||||
|
ProxyAccessible* anchor = maiLink->Proxy()->AnchorAt(aLinkIndex);
|
||||||
|
return anchor ? GetWrapperFor(anchor) : nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
gint
|
||||||
|
getEndIndexCB(AtkHyperlink *aLink)
|
||||||
|
{
|
||||||
|
MaiHyperlink* maiLink = GetMaiHyperlink(aLink);
|
||||||
|
if (!maiLink)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (Accessible* hyperlink = maiLink->GetAccHyperlink())
|
||||||
|
return static_cast<gint>(hyperlink->EndOffset());
|
||||||
|
|
||||||
|
bool valid = false;
|
||||||
|
uint32_t endIdx = maiLink->Proxy()->EndOffset(&valid);
|
||||||
|
return valid ? static_cast<gint>(endIdx) : -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
gint
|
||||||
|
getStartIndexCB(AtkHyperlink *aLink)
|
||||||
|
{
|
||||||
|
MaiHyperlink* maiLink = GetMaiHyperlink(aLink);
|
||||||
|
if (!maiLink)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
if (Accessible* hyperlink = maiLink->GetAccHyperlink())
|
||||||
|
return static_cast<gint>(hyperlink->StartOffset());
|
||||||
|
|
||||||
|
bool valid = false;
|
||||||
|
uint32_t startIdx = maiLink->Proxy()->StartOffset(&valid);
|
||||||
|
return valid ? static_cast<gint>(startIdx) : -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
gboolean
|
||||||
|
isValidCB(AtkHyperlink *aLink)
|
||||||
|
{
|
||||||
|
MaiHyperlink* maiLink = GetMaiHyperlink(aLink);
|
||||||
|
if (!maiLink)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (Accessible* hyperlink = maiLink->GetAccHyperlink())
|
||||||
|
return static_cast<gboolean>(hyperlink->IsLinkValid());
|
||||||
|
|
||||||
|
return static_cast<gboolean>(maiLink->Proxy()->IsLinkValid());
|
||||||
|
}
|
||||||
|
|
||||||
|
gint
|
||||||
|
getAnchorCountCB(AtkHyperlink *aLink)
|
||||||
|
{
|
||||||
|
MaiHyperlink* maiLink = GetMaiHyperlink(aLink);
|
||||||
|
if (!maiLink)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
if (Accessible* hyperlink = maiLink->GetAccHyperlink())
|
||||||
|
return static_cast<gint>(hyperlink->AnchorCount());
|
||||||
|
|
||||||
|
bool valid = false;
|
||||||
|
uint32_t anchorCount = maiLink->Proxy()->AnchorCount(&valid);
|
||||||
|
return valid ? static_cast<gint>(anchorCount) : -1;
|
||||||
|
}
|
||||||
55
accessible/atk/nsMaiHyperlink.h
Normal file
55
accessible/atk/nsMaiHyperlink.h
Normal file
|
|
@ -0,0 +1,55 @@
|
||||||
|
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||||
|
/* vim: set ts=2 et sw=2 tw=80: */
|
||||||
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
|
#ifndef __MAI_HYPERLINK_H__
|
||||||
|
#define __MAI_HYPERLINK_H__
|
||||||
|
|
||||||
|
#include "nsMai.h"
|
||||||
|
#include "Accessible.h"
|
||||||
|
|
||||||
|
struct _AtkHyperlink;
|
||||||
|
typedef struct _AtkHyperlink AtkHyperlink;
|
||||||
|
|
||||||
|
namespace mozilla {
|
||||||
|
namespace a11y {
|
||||||
|
|
||||||
|
/*
|
||||||
|
* MaiHyperlink is a auxiliary class for MaiInterfaceHyperText.
|
||||||
|
*/
|
||||||
|
|
||||||
|
class MaiHyperlink
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
explicit MaiHyperlink(AccessibleOrProxy aHyperLink);
|
||||||
|
~MaiHyperlink();
|
||||||
|
|
||||||
|
public:
|
||||||
|
AtkHyperlink* GetAtkHyperlink() const { return mMaiAtkHyperlink; }
|
||||||
|
Accessible* GetAccHyperlink()
|
||||||
|
{
|
||||||
|
if (!mHyperlink.IsAccessible())
|
||||||
|
return nullptr;
|
||||||
|
|
||||||
|
Accessible* link = mHyperlink.AsAccessible();
|
||||||
|
if (!link) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
NS_ASSERTION(link->IsLink(), "Why isn't it a link!");
|
||||||
|
return link;
|
||||||
|
}
|
||||||
|
|
||||||
|
ProxyAccessible* Proxy() const { return mHyperlink.AsProxy(); }
|
||||||
|
|
||||||
|
protected:
|
||||||
|
AccessibleOrProxy mHyperlink;
|
||||||
|
AtkHyperlink* mMaiAtkHyperlink;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace a11y
|
||||||
|
} // namespace mozilla
|
||||||
|
|
||||||
|
#endif /* __MAI_HYPERLINK_H__ */
|
||||||
105
accessible/atk/nsMaiInterfaceAction.cpp
Normal file
105
accessible/atk/nsMaiInterfaceAction.cpp
Normal file
|
|
@ -0,0 +1,105 @@
|
||||||
|
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||||
|
/* vim: set ts=2 et sw=2 tw=80: */
|
||||||
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
|
#include "InterfaceInitFuncs.h"
|
||||||
|
|
||||||
|
#include "Accessible-inl.h"
|
||||||
|
#include "nsMai.h"
|
||||||
|
#include "Role.h"
|
||||||
|
#include "mozilla/Likely.h"
|
||||||
|
#include "ProxyAccessible.h"
|
||||||
|
#include "nsString.h"
|
||||||
|
|
||||||
|
using namespace mozilla::a11y;
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
doActionCB(AtkAction *aAction, gint aActionIndex)
|
||||||
|
{
|
||||||
|
AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aAction));
|
||||||
|
if (accWrap) {
|
||||||
|
return accWrap->DoAction(aActionIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
ProxyAccessible* proxy = GetProxy(ATK_OBJECT(aAction));
|
||||||
|
return proxy && proxy->DoAction(aActionIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
static gint
|
||||||
|
getActionCountCB(AtkAction *aAction)
|
||||||
|
{
|
||||||
|
AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aAction));
|
||||||
|
if (accWrap) {
|
||||||
|
return accWrap->ActionCount();
|
||||||
|
}
|
||||||
|
|
||||||
|
ProxyAccessible* proxy = GetProxy(ATK_OBJECT(aAction));
|
||||||
|
return proxy ? proxy->ActionCount() : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const gchar*
|
||||||
|
getActionDescriptionCB(AtkAction *aAction, gint aActionIndex)
|
||||||
|
{
|
||||||
|
nsAutoString description;
|
||||||
|
AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aAction));
|
||||||
|
if (accWrap) {
|
||||||
|
accWrap->ActionDescriptionAt(aActionIndex, description);
|
||||||
|
} else if (ProxyAccessible* proxy = GetProxy(ATK_OBJECT(aAction))) {
|
||||||
|
proxy->ActionDescriptionAt(aActionIndex, description);
|
||||||
|
} else {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
return AccessibleWrap::ReturnString(description);
|
||||||
|
}
|
||||||
|
|
||||||
|
static const gchar*
|
||||||
|
getActionNameCB(AtkAction *aAction, gint aActionIndex)
|
||||||
|
{
|
||||||
|
nsAutoString autoStr;
|
||||||
|
AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aAction));
|
||||||
|
if (accWrap) {
|
||||||
|
accWrap->ActionNameAt(aActionIndex, autoStr);
|
||||||
|
} else if (ProxyAccessible* proxy = GetProxy(ATK_OBJECT(aAction))) {
|
||||||
|
proxy->ActionNameAt(aActionIndex, autoStr);
|
||||||
|
} else {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
return AccessibleWrap::ReturnString(autoStr);
|
||||||
|
}
|
||||||
|
|
||||||
|
static const gchar*
|
||||||
|
getKeyBindingCB(AtkAction *aAction, gint aActionIndex)
|
||||||
|
{
|
||||||
|
nsAutoString keyBindingsStr;
|
||||||
|
AccessibleWrap* acc = GetAccessibleWrap(ATK_OBJECT(aAction));
|
||||||
|
if (acc) {
|
||||||
|
AccessibleWrap::GetKeyBinding(acc, keyBindingsStr);
|
||||||
|
} else if (ProxyAccessible* proxy = GetProxy(ATK_OBJECT(aAction))) {
|
||||||
|
proxy->AtkKeyBinding(keyBindingsStr);
|
||||||
|
} else {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
return AccessibleWrap::ReturnString(keyBindingsStr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
actionInterfaceInitCB(AtkActionIface* aIface)
|
||||||
|
{
|
||||||
|
NS_ASSERTION(aIface, "Invalid aIface");
|
||||||
|
if (MOZ_UNLIKELY(!aIface))
|
||||||
|
return;
|
||||||
|
|
||||||
|
aIface->do_action = doActionCB;
|
||||||
|
aIface->get_n_actions = getActionCountCB;
|
||||||
|
aIface->get_description = getActionDescriptionCB;
|
||||||
|
aIface->get_keybinding = getKeyBindingCB;
|
||||||
|
aIface->get_name = getActionNameCB;
|
||||||
|
}
|
||||||
151
accessible/atk/nsMaiInterfaceComponent.cpp
Normal file
151
accessible/atk/nsMaiInterfaceComponent.cpp
Normal file
|
|
@ -0,0 +1,151 @@
|
||||||
|
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||||
|
/* vim: set ts=2 et sw=2 tw=80: */
|
||||||
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
|
#include "InterfaceInitFuncs.h"
|
||||||
|
|
||||||
|
#include "AccessibleWrap.h"
|
||||||
|
#include "nsAccUtils.h"
|
||||||
|
#include "nsCoreUtils.h"
|
||||||
|
#include "nsMai.h"
|
||||||
|
#include "mozilla/Likely.h"
|
||||||
|
#include "mozilla/a11y/ProxyAccessible.h"
|
||||||
|
|
||||||
|
using namespace mozilla::a11y;
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
|
||||||
|
static AtkObject*
|
||||||
|
refAccessibleAtPointCB(AtkComponent* aComponent, gint aAccX, gint aAccY,
|
||||||
|
AtkCoordType aCoordType)
|
||||||
|
{
|
||||||
|
return refAccessibleAtPointHelper(ATK_OBJECT(aComponent),
|
||||||
|
aAccX, aAccY, aCoordType);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
getExtentsCB(AtkComponent* aComponent, gint* aX, gint* aY,
|
||||||
|
gint* aWidth, gint* aHeight, AtkCoordType aCoordType)
|
||||||
|
{
|
||||||
|
getExtentsHelper(ATK_OBJECT(aComponent),
|
||||||
|
aX, aY, aWidth, aHeight, aCoordType);
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
grabFocusCB(AtkComponent* aComponent)
|
||||||
|
{
|
||||||
|
AtkObject* atkObject = ATK_OBJECT(aComponent);
|
||||||
|
AccessibleWrap* accWrap = GetAccessibleWrap(atkObject);
|
||||||
|
if (accWrap) {
|
||||||
|
accWrap->TakeFocus();
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
ProxyAccessible* proxy = GetProxy(atkObject);
|
||||||
|
if (proxy) {
|
||||||
|
proxy->TakeFocus();
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
AtkObject*
|
||||||
|
refAccessibleAtPointHelper(AtkObject* aAtkObj, gint aX, gint aY,
|
||||||
|
AtkCoordType aCoordType)
|
||||||
|
{
|
||||||
|
AccessibleWrap* accWrap = GetAccessibleWrap(aAtkObj);
|
||||||
|
if (accWrap) {
|
||||||
|
if (accWrap->IsDefunct() || nsAccUtils::MustPrune(accWrap)) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Accessible::ChildAtPoint(x,y) is in screen pixels.
|
||||||
|
if (aCoordType == ATK_XY_WINDOW) {
|
||||||
|
nsIntPoint winCoords =
|
||||||
|
nsCoreUtils::GetScreenCoordsForWindow(accWrap->GetNode());
|
||||||
|
aX += winCoords.x;
|
||||||
|
aY += winCoords.y;
|
||||||
|
}
|
||||||
|
|
||||||
|
Accessible* accAtPoint = accWrap->ChildAtPoint(aX, aY,
|
||||||
|
Accessible::eDirectChild);
|
||||||
|
if (!accAtPoint) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
AtkObject* atkObj = AccessibleWrap::GetAtkObject(accAtPoint);
|
||||||
|
if (atkObj) {
|
||||||
|
g_object_ref(atkObj);
|
||||||
|
}
|
||||||
|
|
||||||
|
return atkObj;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ProxyAccessible* proxy = GetProxy(aAtkObj)) {
|
||||||
|
ProxyAccessible* result =
|
||||||
|
proxy->AccessibleAtPoint(aX, aY, aCoordType == ATK_XY_WINDOW);
|
||||||
|
AtkObject* atkObj = result ? GetWrapperFor(result) : nullptr;
|
||||||
|
if (atkObj) {
|
||||||
|
g_object_ref(atkObj);
|
||||||
|
}
|
||||||
|
return atkObj;
|
||||||
|
}
|
||||||
|
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
getExtentsHelper(AtkObject* aAtkObj,
|
||||||
|
gint* aX, gint* aY, gint* aWidth, gint* aHeight,
|
||||||
|
AtkCoordType aCoordType)
|
||||||
|
{
|
||||||
|
AccessibleWrap* accWrap = GetAccessibleWrap(aAtkObj);
|
||||||
|
*aX = *aY = *aWidth = *aHeight = 0;
|
||||||
|
|
||||||
|
if (accWrap) {
|
||||||
|
if (accWrap->IsDefunct()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
nsIntRect screenRect = accWrap->Bounds();
|
||||||
|
if (screenRect.IsEmpty())
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (aCoordType == ATK_XY_WINDOW) {
|
||||||
|
nsIntPoint winCoords =
|
||||||
|
nsCoreUtils::GetScreenCoordsForWindow(accWrap->GetNode());
|
||||||
|
screenRect.x -= winCoords.x;
|
||||||
|
screenRect.y -= winCoords.y;
|
||||||
|
}
|
||||||
|
|
||||||
|
*aX = screenRect.x;
|
||||||
|
*aY = screenRect.y;
|
||||||
|
*aWidth = screenRect.width;
|
||||||
|
*aHeight = screenRect.height;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ProxyAccessible* proxy = GetProxy(aAtkObj)) {
|
||||||
|
proxy->Extents(aCoordType == ATK_XY_WINDOW, aX, aY, aWidth, aHeight);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
componentInterfaceInitCB(AtkComponentIface* aIface)
|
||||||
|
{
|
||||||
|
NS_ASSERTION(aIface, "Invalid Interface");
|
||||||
|
if(MOZ_UNLIKELY(!aIface))
|
||||||
|
return;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Use default implementation in atk for contains, get_position,
|
||||||
|
* and get_size
|
||||||
|
*/
|
||||||
|
aIface->ref_accessible_at_point = refAccessibleAtPointCB;
|
||||||
|
aIface->get_extents = getExtentsCB;
|
||||||
|
aIface->grab_focus = grabFocusCB;
|
||||||
|
}
|
||||||
151
accessible/atk/nsMaiInterfaceDocument.cpp
Normal file
151
accessible/atk/nsMaiInterfaceDocument.cpp
Normal file
|
|
@ -0,0 +1,151 @@
|
||||||
|
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||||
|
/* vim: set ts=2 et sw=2 tw=80: */
|
||||||
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
|
#include "InterfaceInitFuncs.h"
|
||||||
|
|
||||||
|
#include "Accessible-inl.h"
|
||||||
|
#include "AccessibleWrap.h"
|
||||||
|
#include "DocAccessible.h"
|
||||||
|
#include "nsMai.h"
|
||||||
|
#include "ProxyAccessible.h"
|
||||||
|
#include "mozilla/Likely.h"
|
||||||
|
|
||||||
|
using namespace mozilla::a11y;
|
||||||
|
|
||||||
|
static const char* const kDocTypeName = "W3C-doctype";
|
||||||
|
static const char* const kDocUrlName = "DocURL";
|
||||||
|
static const char* const kMimeTypeName = "MimeType";
|
||||||
|
|
||||||
|
// below functions are vfuncs on an ATK interface so they need to be C call
|
||||||
|
extern "C" {
|
||||||
|
|
||||||
|
static const gchar* getDocumentLocaleCB(AtkDocument* aDocument);
|
||||||
|
static AtkAttributeSet* getDocumentAttributesCB(AtkDocument* aDocument);
|
||||||
|
static const gchar* getDocumentAttributeValueCB(AtkDocument* aDocument,
|
||||||
|
const gchar* aAttrName);
|
||||||
|
|
||||||
|
void
|
||||||
|
documentInterfaceInitCB(AtkDocumentIface *aIface)
|
||||||
|
{
|
||||||
|
NS_ASSERTION(aIface, "Invalid Interface");
|
||||||
|
if(MOZ_UNLIKELY(!aIface))
|
||||||
|
return;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* We don't support get_document or set_attribute right now.
|
||||||
|
* get_document_type is deprecated, we return DocType in
|
||||||
|
* get_document_attribute_value and get_document_attributes instead.
|
||||||
|
*/
|
||||||
|
aIface->get_document_attributes = getDocumentAttributesCB;
|
||||||
|
aIface->get_document_attribute_value = getDocumentAttributeValueCB;
|
||||||
|
aIface->get_document_locale = getDocumentLocaleCB;
|
||||||
|
}
|
||||||
|
|
||||||
|
const gchar *
|
||||||
|
getDocumentLocaleCB(AtkDocument *aDocument)
|
||||||
|
{
|
||||||
|
nsAutoString locale;
|
||||||
|
AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aDocument));
|
||||||
|
if (accWrap) {
|
||||||
|
accWrap->Language(locale);
|
||||||
|
} else if (ProxyAccessible* proxy = GetProxy(ATK_OBJECT(aDocument))) {
|
||||||
|
proxy->Language(locale);
|
||||||
|
}
|
||||||
|
|
||||||
|
return locale.IsEmpty() ? nullptr : AccessibleWrap::ReturnString(locale);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline GSList *
|
||||||
|
prependToList(GSList *aList, const char *const aName, const nsAutoString &aValue)
|
||||||
|
{
|
||||||
|
if (aValue.IsEmpty()) {
|
||||||
|
return aList;
|
||||||
|
}
|
||||||
|
|
||||||
|
// libspi will free these
|
||||||
|
AtkAttribute *atkAttr = (AtkAttribute *)g_malloc(sizeof(AtkAttribute));
|
||||||
|
atkAttr->name = g_strdup(aName);
|
||||||
|
atkAttr->value = g_strdup(NS_ConvertUTF16toUTF8(aValue).get());
|
||||||
|
return g_slist_prepend(aList, atkAttr);
|
||||||
|
}
|
||||||
|
|
||||||
|
AtkAttributeSet *
|
||||||
|
getDocumentAttributesCB(AtkDocument *aDocument)
|
||||||
|
{
|
||||||
|
nsAutoString url;
|
||||||
|
nsAutoString w3cDocType;
|
||||||
|
nsAutoString mimeType;
|
||||||
|
AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aDocument));
|
||||||
|
if (accWrap) {
|
||||||
|
if (!accWrap->IsDoc()) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
DocAccessible* document = accWrap->AsDoc();
|
||||||
|
document->URL(url);
|
||||||
|
document->DocType(w3cDocType);
|
||||||
|
document->MimeType(mimeType);
|
||||||
|
} else if (ProxyAccessible* proxy = GetProxy(ATK_OBJECT(aDocument))) {
|
||||||
|
proxy->URLDocTypeMimeType(url, w3cDocType, mimeType);
|
||||||
|
} else {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
// according to atkobject.h, AtkAttributeSet is a GSList
|
||||||
|
GSList* attributes = nullptr;
|
||||||
|
attributes = prependToList(attributes, kDocUrlName, url);
|
||||||
|
attributes = prependToList(attributes, kDocTypeName, w3cDocType);
|
||||||
|
attributes = prependToList(attributes, kMimeTypeName, mimeType);
|
||||||
|
|
||||||
|
return attributes;
|
||||||
|
}
|
||||||
|
|
||||||
|
const gchar *
|
||||||
|
getDocumentAttributeValueCB(AtkDocument *aDocument,
|
||||||
|
const gchar *aAttrName)
|
||||||
|
{
|
||||||
|
ProxyAccessible* proxy = nullptr;
|
||||||
|
DocAccessible* document = nullptr;
|
||||||
|
AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aDocument));
|
||||||
|
if (accWrap) {
|
||||||
|
if (!accWrap->IsDoc()) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
document = accWrap->AsDoc();
|
||||||
|
} else {
|
||||||
|
proxy = GetProxy(ATK_OBJECT(aDocument));
|
||||||
|
if (!proxy) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
nsAutoString attrValue;
|
||||||
|
if (!strcasecmp(aAttrName, kDocTypeName)) {
|
||||||
|
if (document) {
|
||||||
|
document->DocType(attrValue);
|
||||||
|
} else {
|
||||||
|
proxy->DocType(attrValue);
|
||||||
|
}
|
||||||
|
} else if (!strcasecmp(aAttrName, kDocUrlName)) {
|
||||||
|
if (document) {
|
||||||
|
document->URL(attrValue);
|
||||||
|
} else {
|
||||||
|
proxy->URL(attrValue);
|
||||||
|
}
|
||||||
|
} else if (!strcasecmp(aAttrName, kMimeTypeName)) {
|
||||||
|
if (document) {
|
||||||
|
document->MimeType(attrValue);
|
||||||
|
} else {
|
||||||
|
proxy->MimeType(attrValue);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
return attrValue.IsEmpty() ? nullptr : AccessibleWrap::ReturnString(attrValue);
|
||||||
|
}
|
||||||
|
}
|
||||||
134
accessible/atk/nsMaiInterfaceEditableText.cpp
Normal file
134
accessible/atk/nsMaiInterfaceEditableText.cpp
Normal file
|
|
@ -0,0 +1,134 @@
|
||||||
|
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||||
|
/* vim: set ts=2 et sw=2 tw=80: */
|
||||||
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
|
#include "InterfaceInitFuncs.h"
|
||||||
|
|
||||||
|
#include "Accessible-inl.h"
|
||||||
|
#include "HyperTextAccessible-inl.h"
|
||||||
|
#include "nsMai.h"
|
||||||
|
#include "ProxyAccessible.h"
|
||||||
|
#include "nsString.h"
|
||||||
|
#include "mozilla/Likely.h"
|
||||||
|
|
||||||
|
using namespace mozilla::a11y;
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
static void
|
||||||
|
setTextContentsCB(AtkEditableText *aText, const gchar *aString)
|
||||||
|
{
|
||||||
|
AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aText));
|
||||||
|
if (accWrap) {
|
||||||
|
HyperTextAccessible* text = accWrap->AsHyperText();
|
||||||
|
if (!text || !text->IsTextRole()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
NS_ConvertUTF8toUTF16 strContent(aString);
|
||||||
|
text->ReplaceText(strContent);
|
||||||
|
} else if (ProxyAccessible* proxy = GetProxy(ATK_OBJECT(aText))) {
|
||||||
|
NS_ConvertUTF8toUTF16 strContent(aString);
|
||||||
|
proxy->ReplaceText(strContent);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
insertTextCB(AtkEditableText *aText,
|
||||||
|
const gchar *aString, gint aLength, gint *aPosition)
|
||||||
|
{
|
||||||
|
AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aText));
|
||||||
|
if (accWrap) {
|
||||||
|
HyperTextAccessible* text = accWrap->AsHyperText();
|
||||||
|
if (!text || !text->IsTextRole()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
NS_ConvertUTF8toUTF16 strContent(aString);
|
||||||
|
text->InsertText(strContent, *aPosition);
|
||||||
|
} else if (ProxyAccessible* proxy = GetProxy(ATK_OBJECT(aText))) {
|
||||||
|
NS_ConvertUTF8toUTF16 strContent(aString);
|
||||||
|
proxy->InsertText(strContent, *aPosition);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
copyTextCB(AtkEditableText *aText, gint aStartPos, gint aEndPos)
|
||||||
|
{
|
||||||
|
AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aText));
|
||||||
|
if (accWrap) {
|
||||||
|
HyperTextAccessible* text = accWrap->AsHyperText();
|
||||||
|
if (!text || !text->IsTextRole()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
text->CopyText(aStartPos, aEndPos);
|
||||||
|
} else if (ProxyAccessible* proxy = GetProxy(ATK_OBJECT(aText))) {
|
||||||
|
proxy->CopyText(aStartPos, aEndPos);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
cutTextCB(AtkEditableText *aText, gint aStartPos, gint aEndPos)
|
||||||
|
{
|
||||||
|
AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aText));
|
||||||
|
if (accWrap) {
|
||||||
|
HyperTextAccessible* text = accWrap->AsHyperText();
|
||||||
|
if (!text || !text->IsTextRole()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
text->CutText(aStartPos, aEndPos);
|
||||||
|
} else if (ProxyAccessible* proxy = GetProxy(ATK_OBJECT(aText))) {
|
||||||
|
proxy->CutText(aStartPos, aEndPos);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
deleteTextCB(AtkEditableText *aText, gint aStartPos, gint aEndPos)
|
||||||
|
{
|
||||||
|
AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aText));
|
||||||
|
if (accWrap) {
|
||||||
|
HyperTextAccessible* text = accWrap->AsHyperText();
|
||||||
|
if (!text || !text->IsTextRole()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
text->DeleteText(aStartPos, aEndPos);
|
||||||
|
} else if (ProxyAccessible* proxy = GetProxy(ATK_OBJECT(aText))) {
|
||||||
|
proxy->DeleteText(aStartPos, aEndPos);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
pasteTextCB(AtkEditableText *aText, gint aPosition)
|
||||||
|
{
|
||||||
|
AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aText));
|
||||||
|
if (accWrap) {
|
||||||
|
HyperTextAccessible* text = accWrap->AsHyperText();
|
||||||
|
if (!text || !text->IsTextRole()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
text->PasteText(aPosition);
|
||||||
|
} else if (ProxyAccessible* proxy = GetProxy(ATK_OBJECT(aText))) {
|
||||||
|
proxy->PasteText(aPosition);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
editableTextInterfaceInitCB(AtkEditableTextIface* aIface)
|
||||||
|
{
|
||||||
|
NS_ASSERTION(aIface, "Invalid aIface");
|
||||||
|
if (MOZ_UNLIKELY(!aIface))
|
||||||
|
return;
|
||||||
|
|
||||||
|
aIface->set_text_contents = setTextContentsCB;
|
||||||
|
aIface->insert_text = insertTextCB;
|
||||||
|
aIface->copy_text = copyTextCB;
|
||||||
|
aIface->cut_text = cutTextCB;
|
||||||
|
aIface->delete_text = deleteTextCB;
|
||||||
|
aIface->paste_text = pasteTextCB;
|
||||||
|
}
|
||||||
37
accessible/atk/nsMaiInterfaceHyperlinkImpl.cpp
Normal file
37
accessible/atk/nsMaiInterfaceHyperlinkImpl.cpp
Normal file
|
|
@ -0,0 +1,37 @@
|
||||||
|
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||||
|
/* vim: set ts=2 et sw=2 tw=80: */
|
||||||
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
|
#include "InterfaceInitFuncs.h"
|
||||||
|
|
||||||
|
#include "nsMaiHyperlink.h"
|
||||||
|
#include "mozilla/Likely.h"
|
||||||
|
|
||||||
|
using namespace mozilla::a11y;
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
static AtkHyperlink*
|
||||||
|
getHyperlinkCB(AtkHyperlinkImpl* aImpl)
|
||||||
|
{
|
||||||
|
AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aImpl));
|
||||||
|
if (!accWrap && !GetProxy(ATK_OBJECT(aImpl)))
|
||||||
|
return nullptr;
|
||||||
|
|
||||||
|
if (accWrap)
|
||||||
|
NS_ASSERTION(accWrap->IsLink(), "why isn't it a link!");
|
||||||
|
|
||||||
|
return MAI_ATK_OBJECT(aImpl)->GetAtkHyperlink();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
hyperlinkImplInterfaceInitCB(AtkHyperlinkImplIface *aIface)
|
||||||
|
{
|
||||||
|
NS_ASSERTION(aIface, "no interface!");
|
||||||
|
if (MOZ_UNLIKELY(!aIface))
|
||||||
|
return;
|
||||||
|
|
||||||
|
aIface->get_hyperlink = getHyperlinkCB;
|
||||||
|
}
|
||||||
94
accessible/atk/nsMaiInterfaceHypertext.cpp
Normal file
94
accessible/atk/nsMaiInterfaceHypertext.cpp
Normal file
|
|
@ -0,0 +1,94 @@
|
||||||
|
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||||
|
/* vim: set ts=2 et sw=2 tw=80: */
|
||||||
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
|
#include "InterfaceInitFuncs.h"
|
||||||
|
|
||||||
|
#include "Accessible-inl.h"
|
||||||
|
#include "HyperTextAccessible.h"
|
||||||
|
#include "nsMai.h"
|
||||||
|
#include "nsMaiHyperlink.h"
|
||||||
|
#include "ProxyAccessible.h"
|
||||||
|
#include "mozilla/Likely.h"
|
||||||
|
|
||||||
|
|
||||||
|
using namespace mozilla::a11y;
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
|
||||||
|
static AtkHyperlink*
|
||||||
|
getLinkCB(AtkHypertext *aText, gint aLinkIndex)
|
||||||
|
{
|
||||||
|
AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aText));
|
||||||
|
AtkObject* atkHyperLink = nullptr;
|
||||||
|
if (accWrap) {
|
||||||
|
HyperTextAccessible* hyperText = accWrap->AsHyperText();
|
||||||
|
NS_ENSURE_TRUE(hyperText, nullptr);
|
||||||
|
|
||||||
|
Accessible* hyperLink = hyperText->LinkAt(aLinkIndex);
|
||||||
|
if (!hyperLink || !hyperLink->IsLink()) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
atkHyperLink = AccessibleWrap::GetAtkObject(hyperLink);
|
||||||
|
} else if (ProxyAccessible* proxy = GetProxy(ATK_OBJECT(aText))) {
|
||||||
|
ProxyAccessible* proxyLink = proxy->LinkAt(aLinkIndex);
|
||||||
|
if (!proxyLink)
|
||||||
|
return nullptr;
|
||||||
|
|
||||||
|
atkHyperLink = GetWrapperFor(proxyLink);
|
||||||
|
}
|
||||||
|
|
||||||
|
NS_ENSURE_TRUE(IS_MAI_OBJECT(atkHyperLink), nullptr);
|
||||||
|
return MAI_ATK_OBJECT(atkHyperLink)->GetAtkHyperlink();
|
||||||
|
}
|
||||||
|
|
||||||
|
static gint
|
||||||
|
getLinkCountCB(AtkHypertext *aText)
|
||||||
|
{
|
||||||
|
AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aText));
|
||||||
|
if (accWrap) {
|
||||||
|
HyperTextAccessible* hyperText = accWrap->AsHyperText();
|
||||||
|
NS_ENSURE_TRUE(hyperText, -1);
|
||||||
|
return hyperText->LinkCount();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ProxyAccessible* proxy = GetProxy(ATK_OBJECT(aText))) {
|
||||||
|
return proxy->LinkCount();
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static gint
|
||||||
|
getLinkIndexCB(AtkHypertext *aText, gint aCharIndex)
|
||||||
|
{
|
||||||
|
AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aText));
|
||||||
|
if (accWrap) {
|
||||||
|
HyperTextAccessible* hyperText = accWrap->AsHyperText();
|
||||||
|
NS_ENSURE_TRUE(hyperText, -1);
|
||||||
|
|
||||||
|
return hyperText->LinkIndexAtOffset(aCharIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ProxyAccessible* proxy = GetProxy(ATK_OBJECT(aText))) {
|
||||||
|
return proxy->LinkIndexAtOffset(aCharIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
hypertextInterfaceInitCB(AtkHypertextIface* aIface)
|
||||||
|
{
|
||||||
|
NS_ASSERTION(aIface, "no interface!");
|
||||||
|
if (MOZ_UNLIKELY(!aIface))
|
||||||
|
return;
|
||||||
|
|
||||||
|
aIface->get_link = getLinkCB;
|
||||||
|
aIface->get_n_links = getLinkCountCB;
|
||||||
|
aIface->get_link_index = getLinkIndexCB;
|
||||||
|
}
|
||||||
77
accessible/atk/nsMaiInterfaceImage.cpp
Normal file
77
accessible/atk/nsMaiInterfaceImage.cpp
Normal file
|
|
@ -0,0 +1,77 @@
|
||||||
|
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||||
|
/* vim: set ts=2 et sw=2 tw=80: */
|
||||||
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
|
#include "InterfaceInitFuncs.h"
|
||||||
|
|
||||||
|
#include "AccessibleWrap.h"
|
||||||
|
#include "ImageAccessible.h"
|
||||||
|
#include "mozilla/Likely.h"
|
||||||
|
#include "nsMai.h"
|
||||||
|
#include "nsIAccessibleTypes.h"
|
||||||
|
#include "nsIURI.h"
|
||||||
|
#include "ProxyAccessible.h"
|
||||||
|
|
||||||
|
using namespace mozilla;
|
||||||
|
using namespace mozilla::a11y;
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
const gchar* getDescriptionCB(AtkObject* aAtkObj);
|
||||||
|
|
||||||
|
static void
|
||||||
|
getImagePositionCB(AtkImage* aImage, gint* aAccX, gint* aAccY,
|
||||||
|
AtkCoordType aCoordType)
|
||||||
|
{
|
||||||
|
nsIntPoint pos;
|
||||||
|
uint32_t geckoCoordType = (aCoordType == ATK_XY_WINDOW) ?
|
||||||
|
nsIAccessibleCoordinateType::COORDTYPE_WINDOW_RELATIVE :
|
||||||
|
nsIAccessibleCoordinateType::COORDTYPE_SCREEN_RELATIVE;
|
||||||
|
|
||||||
|
AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aImage));
|
||||||
|
if (accWrap && accWrap->IsImage()) {
|
||||||
|
ImageAccessible* image = accWrap->AsImage();
|
||||||
|
pos = image->Position(geckoCoordType);
|
||||||
|
} else if (ProxyAccessible* proxy = GetProxy(ATK_OBJECT(aImage))) {
|
||||||
|
pos = proxy->ImagePosition(geckoCoordType);
|
||||||
|
}
|
||||||
|
|
||||||
|
*aAccX = pos.x;
|
||||||
|
*aAccY = pos.y;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const gchar*
|
||||||
|
getImageDescriptionCB(AtkImage* aImage)
|
||||||
|
{
|
||||||
|
return getDescriptionCB(ATK_OBJECT(aImage));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
getImageSizeCB(AtkImage* aImage, gint* aAccWidth, gint* aAccHeight)
|
||||||
|
{
|
||||||
|
nsIntSize size;
|
||||||
|
AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aImage));
|
||||||
|
if (accWrap && accWrap->IsImage()) {
|
||||||
|
size = accWrap->AsImage()->Size();
|
||||||
|
} else if (ProxyAccessible* proxy = GetProxy(ATK_OBJECT(aImage))) {
|
||||||
|
size = proxy->ImageSize();
|
||||||
|
}
|
||||||
|
|
||||||
|
*aAccWidth = size.width;
|
||||||
|
*aAccHeight = size.height;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // extern "C"
|
||||||
|
|
||||||
|
void
|
||||||
|
imageInterfaceInitCB(AtkImageIface* aIface)
|
||||||
|
{
|
||||||
|
NS_ASSERTION(aIface, "no interface!");
|
||||||
|
if (MOZ_UNLIKELY(!aIface))
|
||||||
|
return;
|
||||||
|
|
||||||
|
aIface->get_image_position = getImagePositionCB;
|
||||||
|
aIface->get_image_description = getImageDescriptionCB;
|
||||||
|
aIface->get_image_size = getImageSizeCB;
|
||||||
|
}
|
||||||
152
accessible/atk/nsMaiInterfaceSelection.cpp
Normal file
152
accessible/atk/nsMaiInterfaceSelection.cpp
Normal file
|
|
@ -0,0 +1,152 @@
|
||||||
|
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||||
|
/* vim: set ts=2 et sw=2 tw=80: */
|
||||||
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
|
#include "InterfaceInitFuncs.h"
|
||||||
|
|
||||||
|
#include "Accessible-inl.h"
|
||||||
|
#include "AccessibleWrap.h"
|
||||||
|
#include "nsMai.h"
|
||||||
|
#include "ProxyAccessible.h"
|
||||||
|
#include "mozilla/Likely.h"
|
||||||
|
|
||||||
|
#include <atk/atk.h>
|
||||||
|
|
||||||
|
using namespace mozilla::a11y;
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
addSelectionCB(AtkSelection *aSelection, gint i)
|
||||||
|
{
|
||||||
|
AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aSelection));
|
||||||
|
if (accWrap && accWrap->IsSelect()) {
|
||||||
|
return accWrap->AddItemToSelection(i);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ProxyAccessible* proxy = GetProxy(ATK_OBJECT(aSelection))) {
|
||||||
|
return proxy->AddItemToSelection(i);
|
||||||
|
}
|
||||||
|
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
clearSelectionCB(AtkSelection *aSelection)
|
||||||
|
{
|
||||||
|
AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aSelection));
|
||||||
|
if (accWrap && accWrap->IsSelect()) {
|
||||||
|
return accWrap->UnselectAll();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ProxyAccessible* proxy = GetProxy(ATK_OBJECT(aSelection))) {
|
||||||
|
return proxy->UnselectAll();
|
||||||
|
}
|
||||||
|
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static AtkObject*
|
||||||
|
refSelectionCB(AtkSelection *aSelection, gint i)
|
||||||
|
{
|
||||||
|
AtkObject* atkObj = nullptr;
|
||||||
|
AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aSelection));
|
||||||
|
if (accWrap && accWrap->IsSelect()) {
|
||||||
|
Accessible* selectedItem = accWrap->GetSelectedItem(i);
|
||||||
|
if (!selectedItem) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
atkObj = AccessibleWrap::GetAtkObject(selectedItem);
|
||||||
|
} else if (ProxyAccessible* proxy = GetProxy(ATK_OBJECT(aSelection))) {
|
||||||
|
ProxyAccessible* selectedItem = proxy->GetSelectedItem(i);
|
||||||
|
if (selectedItem) {
|
||||||
|
atkObj = GetWrapperFor(selectedItem);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (atkObj) {
|
||||||
|
g_object_ref(atkObj);
|
||||||
|
}
|
||||||
|
|
||||||
|
return atkObj;
|
||||||
|
}
|
||||||
|
|
||||||
|
static gint
|
||||||
|
getSelectionCountCB(AtkSelection *aSelection)
|
||||||
|
{
|
||||||
|
AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aSelection));
|
||||||
|
if (accWrap && accWrap->IsSelect()) {
|
||||||
|
return accWrap->SelectedItemCount();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ProxyAccessible* proxy = GetProxy(ATK_OBJECT(aSelection))) {
|
||||||
|
return proxy->SelectedItemCount();
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
isChildSelectedCB(AtkSelection *aSelection, gint i)
|
||||||
|
{
|
||||||
|
AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aSelection));
|
||||||
|
if (accWrap && accWrap->IsSelect()) {
|
||||||
|
return accWrap->IsItemSelected(i);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ProxyAccessible* proxy = GetProxy(ATK_OBJECT(aSelection))) {
|
||||||
|
return proxy->IsItemSelected(i);
|
||||||
|
}
|
||||||
|
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
removeSelectionCB(AtkSelection *aSelection, gint i)
|
||||||
|
{
|
||||||
|
AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aSelection));
|
||||||
|
if (accWrap && accWrap->IsSelect()) {
|
||||||
|
return accWrap->RemoveItemFromSelection(i);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ProxyAccessible* proxy = GetProxy(ATK_OBJECT(aSelection))) {
|
||||||
|
return proxy->RemoveItemFromSelection(i);
|
||||||
|
}
|
||||||
|
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
selectAllSelectionCB(AtkSelection *aSelection)
|
||||||
|
{
|
||||||
|
AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aSelection));
|
||||||
|
if (accWrap && accWrap->IsSelect()) {
|
||||||
|
return accWrap->SelectAll();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ProxyAccessible* proxy = GetProxy(ATK_OBJECT(aSelection))) {
|
||||||
|
return proxy->SelectAll();
|
||||||
|
}
|
||||||
|
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
selectionInterfaceInitCB(AtkSelectionIface* aIface)
|
||||||
|
{
|
||||||
|
NS_ASSERTION(aIface, "Invalid aIface");
|
||||||
|
if (MOZ_UNLIKELY(!aIface))
|
||||||
|
return;
|
||||||
|
|
||||||
|
aIface->add_selection = addSelectionCB;
|
||||||
|
aIface->clear_selection = clearSelectionCB;
|
||||||
|
aIface->ref_selection = refSelectionCB;
|
||||||
|
aIface->get_selection_count = getSelectionCountCB;
|
||||||
|
aIface->is_child_selected = isChildSelectedCB;
|
||||||
|
aIface->remove_selection = removeSelectionCB;
|
||||||
|
aIface->select_all_selection = selectAllSelectionCB;
|
||||||
|
}
|
||||||
391
accessible/atk/nsMaiInterfaceTable.cpp
Normal file
391
accessible/atk/nsMaiInterfaceTable.cpp
Normal file
|
|
@ -0,0 +1,391 @@
|
||||||
|
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||||
|
/* vim: set ts=2 et sw=2 tw=80: */
|
||||||
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
|
#include "InterfaceInitFuncs.h"
|
||||||
|
|
||||||
|
#include "Accessible-inl.h"
|
||||||
|
#include "AccessibleWrap.h"
|
||||||
|
#include "nsAccUtils.h"
|
||||||
|
#include "TableAccessible.h"
|
||||||
|
#include "TableCellAccessible.h"
|
||||||
|
#include "nsMai.h"
|
||||||
|
#include "ProxyAccessible.h"
|
||||||
|
#include "nsArrayUtils.h"
|
||||||
|
|
||||||
|
#include "mozilla/Likely.h"
|
||||||
|
|
||||||
|
using namespace mozilla::a11y;
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
static AtkObject*
|
||||||
|
refAtCB(AtkTable* aTable, gint aRowIdx, gint aColIdx)
|
||||||
|
{
|
||||||
|
if (aRowIdx < 0 || aColIdx < 0) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
AtkObject* cellAtkObj = nullptr;
|
||||||
|
AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aTable));
|
||||||
|
if (accWrap) {
|
||||||
|
Accessible* cell = accWrap->AsTable()->CellAt(aRowIdx, aColIdx);
|
||||||
|
if (!cell) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
cellAtkObj = AccessibleWrap::GetAtkObject(cell);
|
||||||
|
} else if (ProxyAccessible* proxy = GetProxy(ATK_OBJECT(aTable))) {
|
||||||
|
ProxyAccessible* cell = proxy->TableCellAt(aRowIdx, aColIdx);
|
||||||
|
if (!cell) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
cellAtkObj = GetWrapperFor(cell);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cellAtkObj) {
|
||||||
|
g_object_ref(cellAtkObj);
|
||||||
|
}
|
||||||
|
|
||||||
|
return cellAtkObj;
|
||||||
|
}
|
||||||
|
|
||||||
|
static gint
|
||||||
|
getIndexAtCB(AtkTable* aTable, gint aRowIdx, gint aColIdx)
|
||||||
|
{
|
||||||
|
if (aRowIdx < 0 || aColIdx < 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aTable));
|
||||||
|
if (accWrap) {
|
||||||
|
return static_cast<gint>(accWrap->AsTable()->CellIndexAt(aRowIdx, aColIdx));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ProxyAccessible* proxy = GetProxy(ATK_OBJECT(aTable))) {
|
||||||
|
return static_cast<gint>(proxy->TableCellIndexAt(aRowIdx, aColIdx));
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static gint
|
||||||
|
getColumnAtIndexCB(AtkTable *aTable, gint aIdx)
|
||||||
|
{
|
||||||
|
if (aIdx < 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aTable));
|
||||||
|
if (accWrap) {
|
||||||
|
return static_cast<gint>(accWrap->AsTable()->ColIndexAt(aIdx));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ProxyAccessible* proxy = GetProxy(ATK_OBJECT(aTable))) {
|
||||||
|
return static_cast<gint>(proxy->TableColumnIndexAt(aIdx));
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static gint
|
||||||
|
getRowAtIndexCB(AtkTable *aTable, gint aIdx)
|
||||||
|
{
|
||||||
|
if (aIdx < 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aTable));
|
||||||
|
if (accWrap) {
|
||||||
|
return static_cast<gint>(accWrap->AsTable()->RowIndexAt(aIdx));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ProxyAccessible* proxy = GetProxy(ATK_OBJECT(aTable))) {
|
||||||
|
return static_cast<gint>(proxy->TableRowIndexAt(aIdx));
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static gint
|
||||||
|
getColumnCountCB(AtkTable *aTable)
|
||||||
|
{
|
||||||
|
AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aTable));
|
||||||
|
if (accWrap) {
|
||||||
|
return static_cast<gint>(accWrap->AsTable()->ColCount());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ProxyAccessible* proxy = GetProxy(ATK_OBJECT(aTable))) {
|
||||||
|
return static_cast<gint>(proxy->TableColumnCount());
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static gint
|
||||||
|
getRowCountCB(AtkTable *aTable)
|
||||||
|
{
|
||||||
|
AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aTable));
|
||||||
|
if (accWrap) {
|
||||||
|
return static_cast<gint>(accWrap->AsTable()->RowCount());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ProxyAccessible* proxy = GetProxy(ATK_OBJECT(aTable))) {
|
||||||
|
return static_cast<gint>(proxy->TableRowCount());
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static gint
|
||||||
|
getColumnExtentAtCB(AtkTable *aTable, gint aRowIdx, gint aColIdx)
|
||||||
|
{
|
||||||
|
if (aRowIdx < 0 || aColIdx < 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aTable));
|
||||||
|
if (accWrap) {
|
||||||
|
return static_cast<gint>(accWrap->AsTable()->ColExtentAt(aRowIdx, aColIdx));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ProxyAccessible* proxy = GetProxy(ATK_OBJECT(aTable))) {
|
||||||
|
return static_cast<gint>(proxy->TableColumnExtentAt(aRowIdx, aColIdx));
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static gint
|
||||||
|
getRowExtentAtCB(AtkTable *aTable, gint aRowIdx, gint aColIdx)
|
||||||
|
{
|
||||||
|
AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aTable));
|
||||||
|
if (accWrap) {
|
||||||
|
return static_cast<gint>(accWrap->AsTable()->RowExtentAt(aRowIdx, aColIdx));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ProxyAccessible* proxy = GetProxy(ATK_OBJECT(aTable))) {
|
||||||
|
return static_cast<gint>(proxy->TableRowExtentAt(aRowIdx, aColIdx));
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static AtkObject*
|
||||||
|
getCaptionCB(AtkTable* aTable)
|
||||||
|
{
|
||||||
|
AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aTable));
|
||||||
|
if (accWrap) {
|
||||||
|
Accessible* caption = accWrap->AsTable()->Caption();
|
||||||
|
return caption ? AccessibleWrap::GetAtkObject(caption) : nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ProxyAccessible* proxy = GetProxy(ATK_OBJECT(aTable))) {
|
||||||
|
ProxyAccessible* caption = proxy->TableCaption();
|
||||||
|
return caption ? GetWrapperFor(caption) : nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const gchar*
|
||||||
|
getColumnDescriptionCB(AtkTable *aTable, gint aColumn)
|
||||||
|
{
|
||||||
|
nsAutoString autoStr;
|
||||||
|
AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aTable));
|
||||||
|
if (accWrap) {
|
||||||
|
accWrap->AsTable()->ColDescription(aColumn, autoStr);
|
||||||
|
} else if (ProxyAccessible* proxy = GetProxy(ATK_OBJECT(aTable))) {
|
||||||
|
proxy->TableColumnDescription(aColumn, autoStr);
|
||||||
|
} else {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
return AccessibleWrap::ReturnString(autoStr);
|
||||||
|
}
|
||||||
|
|
||||||
|
static AtkObject*
|
||||||
|
getColumnHeaderCB(AtkTable *aTable, gint aColIdx)
|
||||||
|
{
|
||||||
|
AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aTable));
|
||||||
|
if (accWrap) {
|
||||||
|
Accessible* header =
|
||||||
|
AccessibleWrap::GetColumnHeader(accWrap->AsTable(), aColIdx);
|
||||||
|
return header ? AccessibleWrap::GetAtkObject(header) : nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ProxyAccessible* proxy = GetProxy(ATK_OBJECT(aTable))) {
|
||||||
|
ProxyAccessible* header = proxy->AtkTableColumnHeader(aColIdx);
|
||||||
|
return header ? GetWrapperFor(header) : nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const gchar*
|
||||||
|
getRowDescriptionCB(AtkTable *aTable, gint aRow)
|
||||||
|
{
|
||||||
|
nsAutoString autoStr;
|
||||||
|
AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aTable));
|
||||||
|
if (accWrap) {
|
||||||
|
accWrap->AsTable()->RowDescription(aRow, autoStr);
|
||||||
|
} else if (ProxyAccessible* proxy = GetProxy(ATK_OBJECT(aTable))) {
|
||||||
|
proxy->TableRowDescription(aRow, autoStr);
|
||||||
|
} else {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
return AccessibleWrap::ReturnString(autoStr);
|
||||||
|
}
|
||||||
|
|
||||||
|
static AtkObject*
|
||||||
|
getRowHeaderCB(AtkTable *aTable, gint aRowIdx)
|
||||||
|
{
|
||||||
|
AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aTable));
|
||||||
|
if (accWrap) {
|
||||||
|
Accessible* header =
|
||||||
|
AccessibleWrap::GetRowHeader(accWrap->AsTable(), aRowIdx);
|
||||||
|
return header ? AccessibleWrap::GetAtkObject(header) : nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ProxyAccessible* proxy = GetProxy(ATK_OBJECT(aTable))) {
|
||||||
|
ProxyAccessible* header = proxy->AtkTableRowHeader(aRowIdx);
|
||||||
|
return header ? GetWrapperFor(header) : nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
static AtkObject*
|
||||||
|
getSummaryCB(AtkTable *aTable)
|
||||||
|
{
|
||||||
|
// Neither html:table nor xul:tree nor ARIA grid/tree have an ability to
|
||||||
|
// link an accessible object to specify a summary. There is closes method
|
||||||
|
// in TableAccessible::summary to get a summary as a string which is not
|
||||||
|
// mapped directly to ATK.
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
static gint
|
||||||
|
getSelectedColumnsCB(AtkTable *aTable, gint** aSelected)
|
||||||
|
{
|
||||||
|
*aSelected = nullptr;
|
||||||
|
|
||||||
|
AutoTArray<uint32_t, 10> cols;
|
||||||
|
AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aTable));
|
||||||
|
if (accWrap) {
|
||||||
|
accWrap->AsTable()->SelectedColIndices(&cols);
|
||||||
|
} else if (ProxyAccessible* proxy = GetProxy(ATK_OBJECT(aTable))) {
|
||||||
|
proxy->TableSelectedColumnIndices(&cols);
|
||||||
|
} else {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cols.IsEmpty())
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
gint* atkColumns = g_new(gint, cols.Length());
|
||||||
|
if (!atkColumns) {
|
||||||
|
NS_WARNING("OUT OF MEMORY");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy(atkColumns, cols.Elements(), cols.Length() * sizeof(uint32_t));
|
||||||
|
*aSelected = atkColumns;
|
||||||
|
return cols.Length();
|
||||||
|
}
|
||||||
|
|
||||||
|
static gint
|
||||||
|
getSelectedRowsCB(AtkTable *aTable, gint **aSelected)
|
||||||
|
{
|
||||||
|
AutoTArray<uint32_t, 10> rows;
|
||||||
|
AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aTable));
|
||||||
|
if (accWrap) {
|
||||||
|
accWrap->AsTable()->SelectedRowIndices(&rows);
|
||||||
|
} else if (ProxyAccessible* proxy = GetProxy(ATK_OBJECT(aTable))) {
|
||||||
|
proxy->TableSelectedRowIndices(&rows);
|
||||||
|
} else {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
gint* atkRows = g_new(gint, rows.Length());
|
||||||
|
if (!atkRows) {
|
||||||
|
NS_WARNING("OUT OF MEMORY");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy(atkRows, rows.Elements(), rows.Length() * sizeof(uint32_t));
|
||||||
|
*aSelected = atkRows;
|
||||||
|
return rows.Length();
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
isColumnSelectedCB(AtkTable *aTable, gint aColIdx)
|
||||||
|
{
|
||||||
|
AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aTable));
|
||||||
|
if (accWrap) {
|
||||||
|
return static_cast<gboolean>(accWrap->AsTable()->IsColSelected(aColIdx));
|
||||||
|
} else if (ProxyAccessible* proxy = GetProxy(ATK_OBJECT(aTable))) {
|
||||||
|
return static_cast<gboolean>(proxy->TableColumnSelected(aColIdx));
|
||||||
|
}
|
||||||
|
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
isRowSelectedCB(AtkTable *aTable, gint aRowIdx)
|
||||||
|
{
|
||||||
|
AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aTable));
|
||||||
|
if (accWrap) {
|
||||||
|
return static_cast<gboolean>(accWrap->AsTable()->IsRowSelected(aRowIdx));
|
||||||
|
} else if (ProxyAccessible* proxy = GetProxy(ATK_OBJECT(aTable))) {
|
||||||
|
return static_cast<gboolean>(proxy->TableRowSelected(aRowIdx));
|
||||||
|
}
|
||||||
|
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
isCellSelectedCB(AtkTable *aTable, gint aRowIdx, gint aColIdx)
|
||||||
|
{
|
||||||
|
AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aTable));
|
||||||
|
if (accWrap) {
|
||||||
|
return static_cast<gboolean>(accWrap->AsTable()->
|
||||||
|
IsCellSelected(aRowIdx, aColIdx));
|
||||||
|
} else if (ProxyAccessible* proxy = GetProxy(ATK_OBJECT(aTable))) {
|
||||||
|
return static_cast<gboolean>(proxy->TableCellSelected(aRowIdx, aColIdx));
|
||||||
|
}
|
||||||
|
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
tableInterfaceInitCB(AtkTableIface* aIface)
|
||||||
|
{
|
||||||
|
NS_ASSERTION(aIface, "no interface!");
|
||||||
|
if (MOZ_UNLIKELY(!aIface))
|
||||||
|
return;
|
||||||
|
|
||||||
|
aIface->ref_at = refAtCB;
|
||||||
|
aIface->get_index_at = getIndexAtCB;
|
||||||
|
aIface->get_column_at_index = getColumnAtIndexCB;
|
||||||
|
aIface->get_row_at_index = getRowAtIndexCB;
|
||||||
|
aIface->get_n_columns = getColumnCountCB;
|
||||||
|
aIface->get_n_rows = getRowCountCB;
|
||||||
|
aIface->get_column_extent_at = getColumnExtentAtCB;
|
||||||
|
aIface->get_row_extent_at = getRowExtentAtCB;
|
||||||
|
aIface->get_caption = getCaptionCB;
|
||||||
|
aIface->get_column_description = getColumnDescriptionCB;
|
||||||
|
aIface->get_column_header = getColumnHeaderCB;
|
||||||
|
aIface->get_row_description = getRowDescriptionCB;
|
||||||
|
aIface->get_row_header = getRowHeaderCB;
|
||||||
|
aIface->get_summary = getSummaryCB;
|
||||||
|
aIface->get_selected_columns = getSelectedColumnsCB;
|
||||||
|
aIface->get_selected_rows = getSelectedRowsCB;
|
||||||
|
aIface->is_column_selected = isColumnSelectedCB;
|
||||||
|
aIface->is_row_selected = isRowSelectedCB;
|
||||||
|
aIface->is_selected = isCellSelectedCB;
|
||||||
|
}
|
||||||
216
accessible/atk/nsMaiInterfaceTableCell.cpp
Normal file
216
accessible/atk/nsMaiInterfaceTableCell.cpp
Normal file
|
|
@ -0,0 +1,216 @@
|
||||||
|
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||||
|
/* vim: set ts=2 et sw=2 tw=80: */
|
||||||
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
|
#include "InterfaceInitFuncs.h"
|
||||||
|
|
||||||
|
#include "Accessible-inl.h"
|
||||||
|
#include "AccessibleWrap.h"
|
||||||
|
#include "nsAccUtils.h"
|
||||||
|
#include "TableAccessible.h"
|
||||||
|
#include "TableCellAccessible.h"
|
||||||
|
#include "nsMai.h"
|
||||||
|
#include "ProxyAccessible.h"
|
||||||
|
#include "nsArrayUtils.h"
|
||||||
|
|
||||||
|
#include "mozilla/Likely.h"
|
||||||
|
|
||||||
|
using namespace mozilla::a11y;
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
static gint
|
||||||
|
GetColumnSpanCB(AtkTableCell* aCell)
|
||||||
|
{
|
||||||
|
AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aCell));
|
||||||
|
if (accWrap) {
|
||||||
|
return accWrap->AsTableCell()->ColExtent();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ProxyAccessible* proxy = GetProxy(ATK_OBJECT(aCell))) {
|
||||||
|
return proxy->ColExtent();
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
GetRowSpanCB(AtkTableCell* aCell)
|
||||||
|
{
|
||||||
|
AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aCell));
|
||||||
|
if (accWrap) {
|
||||||
|
return accWrap->AsTableCell()->RowExtent();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ProxyAccessible* proxy = GetProxy(ATK_OBJECT(aCell))) {
|
||||||
|
return proxy->RowExtent();
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
GetPositionCB(AtkTableCell* aCell, gint* aRow, gint* aCol)
|
||||||
|
{
|
||||||
|
if (AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aCell))) {
|
||||||
|
TableCellAccessible* cell = accWrap->AsTableCell();
|
||||||
|
*aRow = cell->RowIdx();
|
||||||
|
*aCol = cell->ColIdx();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ProxyAccessible* proxy = GetProxy(ATK_OBJECT(aCell))) {
|
||||||
|
uint32_t rowIdx = 0, colIdx = 0;
|
||||||
|
proxy->GetPosition(&rowIdx, &colIdx);
|
||||||
|
*aCol = colIdx;
|
||||||
|
*aRow = rowIdx;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
GetColumnRowSpanCB(AtkTableCell* aCell, gint* aCol, gint* aRow,
|
||||||
|
gint* aColExtent, gint* aRowExtent) {
|
||||||
|
if (AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aCell))) {
|
||||||
|
TableCellAccessible* cellAcc = accWrap->AsTableCell();
|
||||||
|
*aCol = cellAcc->ColIdx();
|
||||||
|
*aRow = cellAcc->RowIdx();
|
||||||
|
*aColExtent = cellAcc->ColExtent();
|
||||||
|
*aRowExtent = cellAcc->ColExtent();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ProxyAccessible* proxy = GetProxy(ATK_OBJECT(aCell))) {
|
||||||
|
uint32_t colIdx = 0, rowIdx = 0, colExtent = 0, rowExtent = 0;
|
||||||
|
proxy->GetColRowExtents(&colIdx, &rowIdx, &colExtent, &rowExtent);
|
||||||
|
*aCol = colIdx;
|
||||||
|
*aRow = rowIdx;
|
||||||
|
*aColExtent = colExtent;
|
||||||
|
*aRowExtent = rowExtent;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static AtkObject*
|
||||||
|
GetTableCB(AtkTableCell* aTableCell)
|
||||||
|
{
|
||||||
|
AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aTableCell));
|
||||||
|
if (accWrap) {
|
||||||
|
TableAccessible* table = accWrap->AsTableCell()->Table();
|
||||||
|
if (!table) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
Accessible* tableAcc = table->AsAccessible();
|
||||||
|
return tableAcc ? AccessibleWrap::GetAtkObject(tableAcc) : nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ProxyAccessible* proxy = GetProxy(ATK_OBJECT(aTableCell))) {
|
||||||
|
ProxyAccessible* table = proxy->TableOfACell();
|
||||||
|
return table ? GetWrapperFor(table) : nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
static GPtrArray*
|
||||||
|
GetColumnHeaderCellsCB(AtkTableCell* aCell)
|
||||||
|
{
|
||||||
|
if (AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aCell))) {
|
||||||
|
AutoTArray<Accessible*, 10> headers;
|
||||||
|
accWrap->AsTableCell()->ColHeaderCells(&headers);
|
||||||
|
if (headers.IsEmpty()) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
GPtrArray* atkHeaders = g_ptr_array_sized_new(headers.Length());
|
||||||
|
for (Accessible* header: headers) {
|
||||||
|
AtkObject* atkHeader = AccessibleWrap::GetAtkObject(header);
|
||||||
|
g_object_ref(atkHeader);
|
||||||
|
g_ptr_array_add(atkHeaders, atkHeader);
|
||||||
|
}
|
||||||
|
|
||||||
|
return atkHeaders;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ProxyAccessible* proxy = GetProxy(ATK_OBJECT(aCell))) {
|
||||||
|
AutoTArray<ProxyAccessible*, 10> headers;
|
||||||
|
proxy->ColHeaderCells(&headers);
|
||||||
|
if (headers.IsEmpty()) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
GPtrArray* atkHeaders = g_ptr_array_sized_new(headers.Length());
|
||||||
|
for (ProxyAccessible* header: headers) {
|
||||||
|
AtkObject* atkHeader = GetWrapperFor(header);
|
||||||
|
g_object_ref(atkHeader);
|
||||||
|
g_ptr_array_add(atkHeaders, atkHeader);
|
||||||
|
}
|
||||||
|
|
||||||
|
return atkHeaders;
|
||||||
|
}
|
||||||
|
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
static GPtrArray*
|
||||||
|
GetRowHeaderCellsCB(AtkTableCell* aCell)
|
||||||
|
{
|
||||||
|
if (AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aCell))) {
|
||||||
|
AutoTArray<Accessible*, 10> headers;
|
||||||
|
accWrap->AsTableCell()->RowHeaderCells(&headers);
|
||||||
|
if (headers.IsEmpty()) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
GPtrArray* atkHeaders = g_ptr_array_sized_new(headers.Length());
|
||||||
|
for (Accessible* header: headers) {
|
||||||
|
AtkObject* atkHeader = AccessibleWrap::GetAtkObject(header);
|
||||||
|
g_object_ref(atkHeader);
|
||||||
|
g_ptr_array_add(atkHeaders, atkHeader);
|
||||||
|
}
|
||||||
|
|
||||||
|
return atkHeaders;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ProxyAccessible* proxy = GetProxy(ATK_OBJECT(aCell))) {
|
||||||
|
AutoTArray<ProxyAccessible*, 10> headers;
|
||||||
|
proxy->RowHeaderCells(&headers);
|
||||||
|
if (headers.IsEmpty()) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
GPtrArray* atkHeaders = g_ptr_array_sized_new(headers.Length());
|
||||||
|
for (ProxyAccessible* header: headers) {
|
||||||
|
AtkObject* atkHeader = GetWrapperFor(header);
|
||||||
|
g_object_ref(atkHeader);
|
||||||
|
g_ptr_array_add(atkHeaders, atkHeader);
|
||||||
|
}
|
||||||
|
|
||||||
|
return atkHeaders;
|
||||||
|
}
|
||||||
|
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
tableCellInterfaceInitCB(AtkTableCellIface* aIface)
|
||||||
|
{
|
||||||
|
NS_ASSERTION(aIface, "no interface!");
|
||||||
|
if (MOZ_UNLIKELY(!aIface))
|
||||||
|
return;
|
||||||
|
|
||||||
|
aIface->get_column_span = GetColumnSpanCB;
|
||||||
|
aIface->get_column_header_cells = GetColumnHeaderCellsCB;
|
||||||
|
aIface->get_position = GetPositionCB;
|
||||||
|
aIface->get_row_span = GetRowSpanCB;
|
||||||
|
aIface->get_row_header_cells = GetRowHeaderCellsCB;
|
||||||
|
aIface->get_row_column_span = GetColumnRowSpanCB;
|
||||||
|
aIface->get_table = GetTableCB;
|
||||||
|
}
|
||||||
629
accessible/atk/nsMaiInterfaceText.cpp
Normal file
629
accessible/atk/nsMaiInterfaceText.cpp
Normal file
|
|
@ -0,0 +1,629 @@
|
||||||
|
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||||
|
/* vim: set ts=2 et sw=2 tw=80: */
|
||||||
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
|
#include "InterfaceInitFuncs.h"
|
||||||
|
#include "mozilla/a11y/PDocAccessible.h"
|
||||||
|
#include "Accessible-inl.h"
|
||||||
|
#include "HyperTextAccessible-inl.h"
|
||||||
|
#include "nsMai.h"
|
||||||
|
#include "ProxyAccessible.h"
|
||||||
|
|
||||||
|
#include "nsIAccessibleTypes.h"
|
||||||
|
#include "nsIPersistentProperties2.h"
|
||||||
|
#include "nsISimpleEnumerator.h"
|
||||||
|
|
||||||
|
#include "mozilla/Likely.h"
|
||||||
|
|
||||||
|
using namespace mozilla;
|
||||||
|
using namespace mozilla::a11y;
|
||||||
|
|
||||||
|
static const char* sAtkTextAttrNames[ATK_TEXT_ATTR_LAST_DEFINED];
|
||||||
|
|
||||||
|
void
|
||||||
|
ConvertTextAttributeToAtkAttribute(const nsACString& aName,
|
||||||
|
const nsAString& aValue,
|
||||||
|
AtkAttributeSet** aAttributeSet)
|
||||||
|
{
|
||||||
|
// Handle attributes where atk has its own name.
|
||||||
|
const char* atkName = nullptr;
|
||||||
|
nsAutoString atkValue;
|
||||||
|
if (aName.EqualsLiteral("color")) {
|
||||||
|
// The format of the atk attribute is r,g,b and the gecko one is
|
||||||
|
// rgb(r, g, b).
|
||||||
|
atkValue = Substring(aValue, 4, aValue.Length() - 5);
|
||||||
|
atkValue.StripWhitespace();
|
||||||
|
atkName = sAtkTextAttrNames[ATK_TEXT_ATTR_FG_COLOR];
|
||||||
|
} else if (aName.EqualsLiteral("background-color")) {
|
||||||
|
// The format of the atk attribute is r,g,b and the gecko one is
|
||||||
|
// rgb(r, g, b).
|
||||||
|
atkValue = Substring(aValue, 4, aValue.Length() - 5);
|
||||||
|
atkValue.StripWhitespace();
|
||||||
|
atkName = sAtkTextAttrNames[ATK_TEXT_ATTR_BG_COLOR];
|
||||||
|
} else if (aName.EqualsLiteral("font-family")) {
|
||||||
|
atkValue = aValue;
|
||||||
|
atkName = sAtkTextAttrNames[ATK_TEXT_ATTR_FAMILY_NAME];
|
||||||
|
} else if (aName.EqualsLiteral("font-size")) {
|
||||||
|
// ATK wants the number of pixels without px at the end.
|
||||||
|
atkValue = StringHead(aValue, aValue.Length() - 2);
|
||||||
|
atkName = sAtkTextAttrNames[ATK_TEXT_ATTR_SIZE];
|
||||||
|
} else if (aName.EqualsLiteral("font-weight")) {
|
||||||
|
atkValue = aValue;
|
||||||
|
atkName = sAtkTextAttrNames[ATK_TEXT_ATTR_WEIGHT];
|
||||||
|
} else if (aName.EqualsLiteral("invalid")) {
|
||||||
|
atkValue = aValue;
|
||||||
|
atkName = sAtkTextAttrNames[ATK_TEXT_ATTR_INVALID];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (atkName) {
|
||||||
|
AtkAttribute* objAttr =
|
||||||
|
static_cast<AtkAttribute*>(g_malloc(sizeof(AtkAttribute)));
|
||||||
|
objAttr->name = g_strdup(atkName);
|
||||||
|
objAttr->value = g_strdup(NS_ConvertUTF16toUTF8(atkValue).get());
|
||||||
|
*aAttributeSet = g_slist_prepend(*aAttributeSet, objAttr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static AtkAttributeSet*
|
||||||
|
ConvertToAtkTextAttributeSet(nsTArray<Attribute>& aAttributes)
|
||||||
|
{
|
||||||
|
AtkAttributeSet* objAttributeSet = nullptr;
|
||||||
|
for (size_t i = 0; i < aAttributes.Length(); ++i) {
|
||||||
|
AtkAttribute* objAttr = (AtkAttribute *)g_malloc(sizeof(AtkAttribute));
|
||||||
|
objAttr->name = g_strdup(aAttributes[i].Name().get());
|
||||||
|
objAttr->value =
|
||||||
|
g_strdup(NS_ConvertUTF16toUTF8(aAttributes[i].Value()).get());
|
||||||
|
objAttributeSet = g_slist_prepend(objAttributeSet, objAttr);
|
||||||
|
ConvertTextAttributeToAtkAttribute(aAttributes[i].Name(),
|
||||||
|
aAttributes[i].Value(),
|
||||||
|
&objAttributeSet);
|
||||||
|
}
|
||||||
|
return objAttributeSet;
|
||||||
|
}
|
||||||
|
|
||||||
|
static AtkAttributeSet*
|
||||||
|
ConvertToAtkTextAttributeSet(nsIPersistentProperties* aAttributes)
|
||||||
|
{
|
||||||
|
if (!aAttributes)
|
||||||
|
return nullptr;
|
||||||
|
|
||||||
|
AtkAttributeSet* objAttributeSet = nullptr;
|
||||||
|
nsCOMPtr<nsISimpleEnumerator> propEnum;
|
||||||
|
nsresult rv = aAttributes->Enumerate(getter_AddRefs(propEnum));
|
||||||
|
NS_ENSURE_SUCCESS(rv, nullptr);
|
||||||
|
|
||||||
|
bool hasMore = false;
|
||||||
|
while (NS_SUCCEEDED(propEnum->HasMoreElements(&hasMore)) && hasMore) {
|
||||||
|
nsCOMPtr<nsISupports> sup;
|
||||||
|
rv = propEnum->GetNext(getter_AddRefs(sup));
|
||||||
|
NS_ENSURE_SUCCESS(rv, objAttributeSet);
|
||||||
|
|
||||||
|
nsCOMPtr<nsIPropertyElement> propElem(do_QueryInterface(sup));
|
||||||
|
NS_ENSURE_TRUE(propElem, objAttributeSet);
|
||||||
|
|
||||||
|
nsAutoCString name;
|
||||||
|
rv = propElem->GetKey(name);
|
||||||
|
NS_ENSURE_SUCCESS(rv, objAttributeSet);
|
||||||
|
|
||||||
|
nsAutoString value;
|
||||||
|
rv = propElem->GetValue(value);
|
||||||
|
NS_ENSURE_SUCCESS(rv, objAttributeSet);
|
||||||
|
|
||||||
|
AtkAttribute* objAttr = (AtkAttribute*)g_malloc(sizeof(AtkAttribute));
|
||||||
|
objAttr->name = g_strdup(name.get());
|
||||||
|
objAttr->value = g_strdup(NS_ConvertUTF16toUTF8(value).get());
|
||||||
|
objAttributeSet = g_slist_prepend(objAttributeSet, objAttr);
|
||||||
|
|
||||||
|
ConvertTextAttributeToAtkAttribute(name, value, &objAttributeSet);
|
||||||
|
}
|
||||||
|
|
||||||
|
// libatk-adaptor will free it
|
||||||
|
return objAttributeSet;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
ConvertTexttoAsterisks(AccessibleWrap* accWrap, nsAString& aString)
|
||||||
|
{
|
||||||
|
// convert each char to "*" when it's "password text"
|
||||||
|
if (accWrap->NativeRole() == roles::PASSWORD_TEXT) {
|
||||||
|
for (uint32_t i = 0; i < aString.Length(); i++)
|
||||||
|
aString.Replace(i, 1, NS_LITERAL_STRING("*"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
|
||||||
|
static gchar*
|
||||||
|
getTextCB(AtkText *aText, gint aStartOffset, gint aEndOffset)
|
||||||
|
{
|
||||||
|
AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aText));
|
||||||
|
nsAutoString autoStr;
|
||||||
|
if (accWrap) {
|
||||||
|
HyperTextAccessible* text = accWrap->AsHyperText();
|
||||||
|
if (!text || !text->IsTextRole())
|
||||||
|
return nullptr;
|
||||||
|
|
||||||
|
text->TextSubstring(aStartOffset, aEndOffset, autoStr);
|
||||||
|
|
||||||
|
ConvertTexttoAsterisks(accWrap, autoStr);
|
||||||
|
} else if (ProxyAccessible* proxy = GetProxy(ATK_OBJECT(aText))) {
|
||||||
|
proxy->TextSubstring(aStartOffset, aEndOffset, autoStr);
|
||||||
|
}
|
||||||
|
|
||||||
|
NS_ConvertUTF16toUTF8 cautoStr(autoStr);
|
||||||
|
|
||||||
|
//copy and return, libspi will free it.
|
||||||
|
return (cautoStr.get()) ? g_strdup(cautoStr.get()) : nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
static gchar*
|
||||||
|
getTextAfterOffsetCB(AtkText *aText, gint aOffset,
|
||||||
|
AtkTextBoundary aBoundaryType,
|
||||||
|
gint *aStartOffset, gint *aEndOffset)
|
||||||
|
{
|
||||||
|
nsAutoString autoStr;
|
||||||
|
int32_t startOffset = 0, endOffset = 0;
|
||||||
|
AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aText));
|
||||||
|
if (accWrap) {
|
||||||
|
HyperTextAccessible* text = accWrap->AsHyperText();
|
||||||
|
if (!text || !text->IsTextRole())
|
||||||
|
return nullptr;
|
||||||
|
|
||||||
|
text->TextAfterOffset(aOffset, aBoundaryType, &startOffset, &endOffset, autoStr);
|
||||||
|
ConvertTexttoAsterisks(accWrap, autoStr);
|
||||||
|
} else if (ProxyAccessible* proxy = GetProxy(ATK_OBJECT(aText))) {
|
||||||
|
proxy->GetTextAfterOffset(aOffset, aBoundaryType, autoStr, &startOffset,
|
||||||
|
&endOffset);
|
||||||
|
}
|
||||||
|
|
||||||
|
*aStartOffset = startOffset;
|
||||||
|
*aEndOffset = endOffset;
|
||||||
|
|
||||||
|
NS_ConvertUTF16toUTF8 cautoStr(autoStr);
|
||||||
|
return (cautoStr.get()) ? g_strdup(cautoStr.get()) : nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
static gchar*
|
||||||
|
getTextAtOffsetCB(AtkText *aText, gint aOffset,
|
||||||
|
AtkTextBoundary aBoundaryType,
|
||||||
|
gint *aStartOffset, gint *aEndOffset)
|
||||||
|
{
|
||||||
|
nsAutoString autoStr;
|
||||||
|
int32_t startOffset = 0, endOffset = 0;
|
||||||
|
AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aText));
|
||||||
|
if (accWrap) {
|
||||||
|
HyperTextAccessible* text = accWrap->AsHyperText();
|
||||||
|
if (!text || !text->IsTextRole())
|
||||||
|
return nullptr;
|
||||||
|
|
||||||
|
text->TextAtOffset(aOffset, aBoundaryType, &startOffset, &endOffset, autoStr);
|
||||||
|
ConvertTexttoAsterisks(accWrap, autoStr);
|
||||||
|
} else if (ProxyAccessible* proxy = GetProxy(ATK_OBJECT(aText))) {
|
||||||
|
proxy->GetTextAtOffset(aOffset, aBoundaryType, autoStr, &startOffset,
|
||||||
|
&endOffset);
|
||||||
|
}
|
||||||
|
|
||||||
|
*aStartOffset = startOffset;
|
||||||
|
*aEndOffset = endOffset;
|
||||||
|
|
||||||
|
NS_ConvertUTF16toUTF8 cautoStr(autoStr);
|
||||||
|
return (cautoStr.get()) ? g_strdup(cautoStr.get()) : nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
static gunichar
|
||||||
|
getCharacterAtOffsetCB(AtkText* aText, gint aOffset)
|
||||||
|
{
|
||||||
|
AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aText));
|
||||||
|
if (accWrap) {
|
||||||
|
HyperTextAccessible* text = accWrap->AsHyperText();
|
||||||
|
if (!text || !text->IsTextRole()) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// char16_t is unsigned short in Mozilla, gnuichar is guint32 in glib.
|
||||||
|
return static_cast<gunichar>(text->CharAt(aOffset));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ProxyAccessible* proxy = GetProxy(ATK_OBJECT(aText))) {
|
||||||
|
return static_cast<gunichar>(proxy->CharAt(aOffset));
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static gchar*
|
||||||
|
getTextBeforeOffsetCB(AtkText *aText, gint aOffset,
|
||||||
|
AtkTextBoundary aBoundaryType,
|
||||||
|
gint *aStartOffset, gint *aEndOffset)
|
||||||
|
{
|
||||||
|
nsAutoString autoStr;
|
||||||
|
int32_t startOffset = 0, endOffset = 0;
|
||||||
|
AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aText));
|
||||||
|
if (accWrap) {
|
||||||
|
HyperTextAccessible* text = accWrap->AsHyperText();
|
||||||
|
if (!text || !text->IsTextRole())
|
||||||
|
return nullptr;
|
||||||
|
|
||||||
|
text->TextBeforeOffset(aOffset, aBoundaryType,
|
||||||
|
&startOffset, &endOffset, autoStr);
|
||||||
|
ConvertTexttoAsterisks(accWrap, autoStr);
|
||||||
|
} else if (ProxyAccessible* proxy = GetProxy(ATK_OBJECT(aText))) {
|
||||||
|
proxy->GetTextBeforeOffset(aOffset, aBoundaryType, autoStr, &startOffset,
|
||||||
|
&endOffset);
|
||||||
|
}
|
||||||
|
|
||||||
|
*aStartOffset = startOffset;
|
||||||
|
*aEndOffset = endOffset;
|
||||||
|
|
||||||
|
NS_ConvertUTF16toUTF8 cautoStr(autoStr);
|
||||||
|
return (cautoStr.get()) ? g_strdup(cautoStr.get()) : nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
static gint
|
||||||
|
getCaretOffsetCB(AtkText *aText)
|
||||||
|
{
|
||||||
|
AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aText));
|
||||||
|
if (accWrap) {
|
||||||
|
HyperTextAccessible* text = accWrap->AsHyperText();
|
||||||
|
if (!text || !text->IsTextRole()) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return static_cast<gint>(text->CaretOffset());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ProxyAccessible* proxy = GetProxy(ATK_OBJECT(aText))) {
|
||||||
|
return static_cast<gint>(proxy->CaretOffset());
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static AtkAttributeSet*
|
||||||
|
getRunAttributesCB(AtkText *aText, gint aOffset,
|
||||||
|
gint *aStartOffset,
|
||||||
|
gint *aEndOffset)
|
||||||
|
{
|
||||||
|
*aStartOffset = -1;
|
||||||
|
*aEndOffset = -1;
|
||||||
|
int32_t startOffset = 0, endOffset = 0;
|
||||||
|
|
||||||
|
AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aText));
|
||||||
|
if (accWrap) {
|
||||||
|
HyperTextAccessible* text = accWrap->AsHyperText();
|
||||||
|
if (!text || !text->IsTextRole()) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
nsCOMPtr<nsIPersistentProperties> attributes =
|
||||||
|
text->TextAttributes(false, aOffset, &startOffset, &endOffset);
|
||||||
|
|
||||||
|
*aStartOffset = startOffset;
|
||||||
|
*aEndOffset = endOffset;
|
||||||
|
|
||||||
|
return ConvertToAtkTextAttributeSet(attributes);
|
||||||
|
}
|
||||||
|
|
||||||
|
ProxyAccessible* proxy = GetProxy(ATK_OBJECT(aText));
|
||||||
|
if (!proxy) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
AutoTArray<Attribute, 10> attrs;
|
||||||
|
proxy->TextAttributes(false, aOffset, &attrs, &startOffset, &endOffset);
|
||||||
|
*aStartOffset = startOffset;
|
||||||
|
*aEndOffset = endOffset;
|
||||||
|
return ConvertToAtkTextAttributeSet(attrs);
|
||||||
|
}
|
||||||
|
|
||||||
|
static AtkAttributeSet*
|
||||||
|
getDefaultAttributesCB(AtkText *aText)
|
||||||
|
{
|
||||||
|
AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aText));
|
||||||
|
if (accWrap) {
|
||||||
|
HyperTextAccessible* text = accWrap->AsHyperText();
|
||||||
|
if (!text || !text->IsTextRole()) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
nsCOMPtr<nsIPersistentProperties> attributes = text->DefaultTextAttributes();
|
||||||
|
return ConvertToAtkTextAttributeSet(attributes);
|
||||||
|
}
|
||||||
|
|
||||||
|
ProxyAccessible* proxy = GetProxy(ATK_OBJECT(aText));
|
||||||
|
if (!proxy) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
AutoTArray<Attribute, 10> attrs;
|
||||||
|
proxy->DefaultTextAttributes(&attrs);
|
||||||
|
return ConvertToAtkTextAttributeSet(attrs);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
getCharacterExtentsCB(AtkText *aText, gint aOffset,
|
||||||
|
gint *aX, gint *aY,
|
||||||
|
gint *aWidth, gint *aHeight,
|
||||||
|
AtkCoordType aCoords)
|
||||||
|
{
|
||||||
|
if(!aX || !aY || !aWidth || !aHeight) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
nsIntRect rect;
|
||||||
|
uint32_t geckoCoordType;
|
||||||
|
if (aCoords == ATK_XY_SCREEN) {
|
||||||
|
geckoCoordType = nsIAccessibleCoordinateType::COORDTYPE_SCREEN_RELATIVE;
|
||||||
|
} else {
|
||||||
|
geckoCoordType = nsIAccessibleCoordinateType::COORDTYPE_WINDOW_RELATIVE;
|
||||||
|
}
|
||||||
|
|
||||||
|
AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aText));
|
||||||
|
if (accWrap) {
|
||||||
|
HyperTextAccessible* text = accWrap->AsHyperText();
|
||||||
|
if (!text || !text->IsTextRole()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
rect = text->CharBounds(aOffset, geckoCoordType);
|
||||||
|
} else if (ProxyAccessible* proxy = GetProxy(ATK_OBJECT(aText))) {
|
||||||
|
rect = proxy->CharBounds(aOffset, geckoCoordType);
|
||||||
|
} else {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
*aX = rect.x;
|
||||||
|
*aY = rect.y;
|
||||||
|
*aWidth = rect.width;
|
||||||
|
*aHeight = rect.height;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
getRangeExtentsCB(AtkText *aText, gint aStartOffset, gint aEndOffset,
|
||||||
|
AtkCoordType aCoords, AtkTextRectangle *aRect)
|
||||||
|
{
|
||||||
|
if (!aRect) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
nsIntRect rect;
|
||||||
|
uint32_t geckoCoordType;
|
||||||
|
if (aCoords == ATK_XY_SCREEN) {
|
||||||
|
geckoCoordType = nsIAccessibleCoordinateType::COORDTYPE_SCREEN_RELATIVE;
|
||||||
|
} else {
|
||||||
|
geckoCoordType = nsIAccessibleCoordinateType::COORDTYPE_WINDOW_RELATIVE;
|
||||||
|
}
|
||||||
|
|
||||||
|
AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aText));
|
||||||
|
if(accWrap) {
|
||||||
|
HyperTextAccessible* text = accWrap->AsHyperText();
|
||||||
|
if (!text || !text->IsTextRole()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
rect = text->TextBounds(aStartOffset, aEndOffset, geckoCoordType);
|
||||||
|
} else if (ProxyAccessible* proxy = GetProxy(ATK_OBJECT(aText))) {
|
||||||
|
rect = proxy->TextBounds(aStartOffset, aEndOffset, geckoCoordType);
|
||||||
|
} else {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
aRect->x = rect.x;
|
||||||
|
aRect->y = rect.y;
|
||||||
|
aRect->width = rect.width;
|
||||||
|
aRect->height = rect.height;
|
||||||
|
}
|
||||||
|
|
||||||
|
static gint
|
||||||
|
getCharacterCountCB(AtkText *aText)
|
||||||
|
{
|
||||||
|
AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aText));
|
||||||
|
if (accWrap) {
|
||||||
|
HyperTextAccessible* textAcc = accWrap->AsHyperText();
|
||||||
|
return
|
||||||
|
textAcc->IsDefunct() ? 0 : static_cast<gint>(textAcc->CharacterCount());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ProxyAccessible* proxy = GetProxy(ATK_OBJECT(aText))) {
|
||||||
|
return proxy->CharacterCount();
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static gint
|
||||||
|
getOffsetAtPointCB(AtkText *aText,
|
||||||
|
gint aX, gint aY,
|
||||||
|
AtkCoordType aCoords)
|
||||||
|
{
|
||||||
|
AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aText));
|
||||||
|
if (accWrap) {
|
||||||
|
HyperTextAccessible* text = accWrap->AsHyperText();
|
||||||
|
if (!text || !text->IsTextRole()) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return static_cast<gint>(
|
||||||
|
text->OffsetAtPoint(aX, aY,
|
||||||
|
(aCoords == ATK_XY_SCREEN ?
|
||||||
|
nsIAccessibleCoordinateType::COORDTYPE_SCREEN_RELATIVE :
|
||||||
|
nsIAccessibleCoordinateType::COORDTYPE_WINDOW_RELATIVE)));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ProxyAccessible* proxy = GetProxy(ATK_OBJECT(aText))) {
|
||||||
|
return static_cast<gint>(
|
||||||
|
proxy->OffsetAtPoint(aX, aY,
|
||||||
|
(aCoords == ATK_XY_SCREEN ?
|
||||||
|
nsIAccessibleCoordinateType::COORDTYPE_SCREEN_RELATIVE :
|
||||||
|
nsIAccessibleCoordinateType::COORDTYPE_WINDOW_RELATIVE)));
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static gint
|
||||||
|
getTextSelectionCountCB(AtkText *aText)
|
||||||
|
{
|
||||||
|
AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aText));
|
||||||
|
if (accWrap) {
|
||||||
|
HyperTextAccessible* text = accWrap->AsHyperText();
|
||||||
|
if (!text || !text->IsTextRole()) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return text->SelectionCount();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ProxyAccessible* proxy = GetProxy(ATK_OBJECT(aText))) {
|
||||||
|
return proxy->SelectionCount();
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static gchar*
|
||||||
|
getTextSelectionCB(AtkText *aText, gint aSelectionNum,
|
||||||
|
gint *aStartOffset, gint *aEndOffset)
|
||||||
|
{
|
||||||
|
AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aText));
|
||||||
|
int32_t startOffset = 0, endOffset = 0;
|
||||||
|
if (accWrap) {
|
||||||
|
HyperTextAccessible* text = accWrap->AsHyperText();
|
||||||
|
if (!text || !text->IsTextRole()) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
text->SelectionBoundsAt(aSelectionNum, &startOffset, &endOffset);
|
||||||
|
*aStartOffset = startOffset;
|
||||||
|
*aEndOffset = endOffset;
|
||||||
|
|
||||||
|
return getTextCB(aText, *aStartOffset, *aEndOffset);
|
||||||
|
} else if (ProxyAccessible* proxy = GetProxy(ATK_OBJECT(aText))) {
|
||||||
|
nsString data;
|
||||||
|
proxy->SelectionBoundsAt(aSelectionNum, data, &startOffset, &endOffset);
|
||||||
|
*aStartOffset = startOffset;
|
||||||
|
*aEndOffset = endOffset;
|
||||||
|
|
||||||
|
NS_ConvertUTF16toUTF8 dataAsUTF8(data);
|
||||||
|
return (dataAsUTF8.get()) ? g_strdup(dataAsUTF8.get()) : nullptr;
|
||||||
|
}
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
// set methods
|
||||||
|
static gboolean
|
||||||
|
addTextSelectionCB(AtkText *aText,
|
||||||
|
gint aStartOffset,
|
||||||
|
gint aEndOffset)
|
||||||
|
{
|
||||||
|
AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aText));
|
||||||
|
if (accWrap) {
|
||||||
|
HyperTextAccessible* text = accWrap->AsHyperText();
|
||||||
|
if (!text || !text->IsTextRole()) {
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
return text->AddToSelection(aStartOffset, aEndOffset);
|
||||||
|
} else if (ProxyAccessible* proxy = GetProxy(ATK_OBJECT(aText))) {
|
||||||
|
return proxy->AddToSelection(aStartOffset, aEndOffset);
|
||||||
|
}
|
||||||
|
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
removeTextSelectionCB(AtkText *aText,
|
||||||
|
gint aSelectionNum)
|
||||||
|
{
|
||||||
|
AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aText));
|
||||||
|
if (accWrap) {
|
||||||
|
HyperTextAccessible* text = accWrap->AsHyperText();
|
||||||
|
if (!text || !text->IsTextRole()) {
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
return text->RemoveFromSelection(aSelectionNum);
|
||||||
|
} else if (ProxyAccessible* proxy = GetProxy(ATK_OBJECT(aText))) {
|
||||||
|
return proxy->RemoveFromSelection(aSelectionNum);
|
||||||
|
}
|
||||||
|
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
setTextSelectionCB(AtkText *aText, gint aSelectionNum,
|
||||||
|
gint aStartOffset, gint aEndOffset)
|
||||||
|
{
|
||||||
|
AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aText));
|
||||||
|
if (accWrap) {
|
||||||
|
HyperTextAccessible* text = accWrap->AsHyperText();
|
||||||
|
if (!text || !text->IsTextRole()) {
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
return text->SetSelectionBoundsAt(aSelectionNum, aStartOffset, aEndOffset);
|
||||||
|
} else if (ProxyAccessible* proxy = GetProxy(ATK_OBJECT(aText))) {
|
||||||
|
return proxy->SetSelectionBoundsAt(aSelectionNum, aStartOffset, aEndOffset);
|
||||||
|
}
|
||||||
|
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
setCaretOffsetCB(AtkText *aText, gint aOffset)
|
||||||
|
{
|
||||||
|
AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aText));
|
||||||
|
if (accWrap) {
|
||||||
|
HyperTextAccessible* text = accWrap->AsHyperText();
|
||||||
|
if (!text || !text->IsTextRole() || !text->IsValidOffset(aOffset)) {
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
text->SetCaretOffset(aOffset);
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ProxyAccessible* proxy = GetProxy(ATK_OBJECT(aText))) {
|
||||||
|
proxy->SetCaretOffset(aOffset);
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
textInterfaceInitCB(AtkTextIface* aIface)
|
||||||
|
{
|
||||||
|
NS_ASSERTION(aIface, "Invalid aIface");
|
||||||
|
if (MOZ_UNLIKELY(!aIface))
|
||||||
|
return;
|
||||||
|
|
||||||
|
aIface->get_text = getTextCB;
|
||||||
|
aIface->get_text_after_offset = getTextAfterOffsetCB;
|
||||||
|
aIface->get_text_at_offset = getTextAtOffsetCB;
|
||||||
|
aIface->get_character_at_offset = getCharacterAtOffsetCB;
|
||||||
|
aIface->get_text_before_offset = getTextBeforeOffsetCB;
|
||||||
|
aIface->get_caret_offset = getCaretOffsetCB;
|
||||||
|
aIface->get_run_attributes = getRunAttributesCB;
|
||||||
|
aIface->get_default_attributes = getDefaultAttributesCB;
|
||||||
|
aIface->get_character_extents = getCharacterExtentsCB;
|
||||||
|
aIface->get_range_extents = getRangeExtentsCB;
|
||||||
|
aIface->get_character_count = getCharacterCountCB;
|
||||||
|
aIface->get_offset_at_point = getOffsetAtPointCB;
|
||||||
|
aIface->get_n_selections = getTextSelectionCountCB;
|
||||||
|
aIface->get_selection = getTextSelectionCB;
|
||||||
|
|
||||||
|
// set methods
|
||||||
|
aIface->add_selection = addTextSelectionCB;
|
||||||
|
aIface->remove_selection = removeTextSelectionCB;
|
||||||
|
aIface->set_selection = setTextSelectionCB;
|
||||||
|
aIface->set_caret_offset = setCaretOffsetCB;
|
||||||
|
|
||||||
|
// Cache the string values of the atk text attribute names.
|
||||||
|
for (uint32_t i = 0; i < ArrayLength(sAtkTextAttrNames); i++)
|
||||||
|
sAtkTextAttrNames[i] =
|
||||||
|
atk_text_attribute_get_name(static_cast<AtkTextAttribute>(i));
|
||||||
|
}
|
||||||
133
accessible/atk/nsMaiInterfaceValue.cpp
Normal file
133
accessible/atk/nsMaiInterfaceValue.cpp
Normal file
|
|
@ -0,0 +1,133 @@
|
||||||
|
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||||
|
/* vim: set ts=2 et sw=2 tw=80: */
|
||||||
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
|
#include "InterfaceInitFuncs.h"
|
||||||
|
|
||||||
|
#include "AccessibleWrap.h"
|
||||||
|
#include "nsMai.h"
|
||||||
|
#include "ProxyAccessible.h"
|
||||||
|
#include "mozilla/FloatingPoint.h"
|
||||||
|
#include "mozilla/Likely.h"
|
||||||
|
|
||||||
|
using namespace mozilla;
|
||||||
|
using namespace mozilla::a11y;
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
|
||||||
|
static void
|
||||||
|
getCurrentValueCB(AtkValue *obj, GValue *value)
|
||||||
|
{
|
||||||
|
ProxyAccessible* proxy = nullptr;
|
||||||
|
AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(obj));
|
||||||
|
if (!accWrap) {
|
||||||
|
proxy = GetProxy(ATK_OBJECT(obj));
|
||||||
|
if (!proxy) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
memset (value, 0, sizeof (GValue));
|
||||||
|
double accValue = accWrap ? accWrap->CurValue() : proxy->CurValue();
|
||||||
|
if (IsNaN(accValue))
|
||||||
|
return;
|
||||||
|
|
||||||
|
g_value_init (value, G_TYPE_DOUBLE);
|
||||||
|
g_value_set_double (value, accValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
getMaximumValueCB(AtkValue *obj, GValue *value)
|
||||||
|
{
|
||||||
|
ProxyAccessible* proxy = nullptr;
|
||||||
|
AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(obj));
|
||||||
|
if (!accWrap) {
|
||||||
|
proxy = GetProxy(ATK_OBJECT(obj));
|
||||||
|
if (!proxy) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
memset(value, 0, sizeof (GValue));
|
||||||
|
double accValue = accWrap ? accWrap->MaxValue() : proxy->MaxValue();
|
||||||
|
if (IsNaN(accValue))
|
||||||
|
return;
|
||||||
|
|
||||||
|
g_value_init(value, G_TYPE_DOUBLE);
|
||||||
|
g_value_set_double(value, accValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
getMinimumValueCB(AtkValue *obj, GValue *value)
|
||||||
|
{
|
||||||
|
ProxyAccessible* proxy = nullptr;
|
||||||
|
AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(obj));
|
||||||
|
if (!accWrap) {
|
||||||
|
proxy = GetProxy(ATK_OBJECT(obj));
|
||||||
|
if (!proxy) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
memset(value, 0, sizeof (GValue));
|
||||||
|
double accValue = accWrap ? accWrap->MinValue() : proxy->MinValue();
|
||||||
|
if (IsNaN(accValue))
|
||||||
|
return;
|
||||||
|
|
||||||
|
g_value_init(value, G_TYPE_DOUBLE);
|
||||||
|
g_value_set_double(value, accValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
getMinimumIncrementCB(AtkValue *obj, GValue *minimumIncrement)
|
||||||
|
{
|
||||||
|
ProxyAccessible* proxy = nullptr;
|
||||||
|
AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(obj));
|
||||||
|
if (!accWrap) {
|
||||||
|
proxy = GetProxy(ATK_OBJECT(obj));
|
||||||
|
if (!proxy) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
memset(minimumIncrement, 0, sizeof (GValue));
|
||||||
|
double accValue = accWrap ? accWrap->Step() : proxy->Step();
|
||||||
|
if (IsNaN(accValue))
|
||||||
|
accValue = 0; // zero if the minimum increment is undefined
|
||||||
|
|
||||||
|
g_value_init(minimumIncrement, G_TYPE_DOUBLE);
|
||||||
|
g_value_set_double(minimumIncrement, accValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
setCurrentValueCB(AtkValue *obj, const GValue *value)
|
||||||
|
{
|
||||||
|
ProxyAccessible* proxy = nullptr;
|
||||||
|
AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(obj));
|
||||||
|
if (!accWrap) {
|
||||||
|
proxy = GetProxy(ATK_OBJECT(obj));
|
||||||
|
if (!proxy) {
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
double accValue =g_value_get_double(value);
|
||||||
|
return accWrap ? accWrap->SetCurValue(accValue) : proxy->SetCurValue(accValue);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
valueInterfaceInitCB(AtkValueIface* aIface)
|
||||||
|
{
|
||||||
|
NS_ASSERTION(aIface, "Invalid aIface");
|
||||||
|
if (MOZ_UNLIKELY(!aIface))
|
||||||
|
return;
|
||||||
|
|
||||||
|
aIface->get_current_value = getCurrentValueCB;
|
||||||
|
aIface->get_maximum_value = getMaximumValueCB;
|
||||||
|
aIface->get_minimum_value = getMinimumValueCB;
|
||||||
|
aIface->get_minimum_increment = getMinimumIncrementCB;
|
||||||
|
aIface->set_current_value = setCurrentValueCB;
|
||||||
|
}
|
||||||
117
accessible/atk/nsStateMap.h
Normal file
117
accessible/atk/nsStateMap.h
Normal file
|
|
@ -0,0 +1,117 @@
|
||||||
|
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||||
|
/* vim: set ts=2 et sw=2 tw=80: */
|
||||||
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
|
#include <atk/atk.h>
|
||||||
|
#include "AccessibleWrap.h"
|
||||||
|
|
||||||
|
/******************************************************************************
|
||||||
|
The following accessible states aren't translated, just ignored:
|
||||||
|
STATE_READONLY: Supported indirectly via EXT_STATE_EDITABLE
|
||||||
|
STATE_HOTTRACKED: No ATK equivalent. No known use case.
|
||||||
|
The nsIAccessible state is not currently supported.
|
||||||
|
STATE_FLOATING: No ATK equivalent. No known use case.
|
||||||
|
The nsIAccessible state is not currently supported.
|
||||||
|
STATE_MOVEABLE: No ATK equivalent. No known use case.
|
||||||
|
The nsIAccessible state is not currently supported.
|
||||||
|
STATE_SELFVOICING: No ATK equivalent -- the object has self-TTS.
|
||||||
|
The nsIAccessible state is not currently supported.
|
||||||
|
STATE_LINKED: The object is formatted as a hyperlink. Supported via ATK_ROLE_LINK.
|
||||||
|
STATE_EXTSELECTABLE: Indicates that an object extends its selection.
|
||||||
|
This is supported via STATE_MULTISELECTABLE.
|
||||||
|
STATE_PROTECTED: The object is a password-protected edit control.
|
||||||
|
Supported via ATK_ROLE_PASSWORD_TEXT
|
||||||
|
STATE_HASPOPUP: Object displays a pop-up menu or window when invoked.
|
||||||
|
No ATK equivalent. The accessible state is not
|
||||||
|
currently supported.
|
||||||
|
STATE_PINNED: The object is pinned, usually indicating it is fixed in
|
||||||
|
place and has permanence. No ATK equivalent. The
|
||||||
|
accessible state is not currently supported.
|
||||||
|
|
||||||
|
The following ATK states are not supported:
|
||||||
|
ATK_STATE_ARMED: No clear use case, used briefly when button is activated
|
||||||
|
ATK_STATE_HAS_TOOLTIP: No clear use case, no IA2 equivalent
|
||||||
|
ATK_STATE_ICONIFIED: Mozilla does not have elements which are collapsable into icons
|
||||||
|
ATK_STATE_TRUNCATED: No clear use case. Indicates that an object's onscreen content is truncated,
|
||||||
|
e.g. a text value in a spreadsheet cell. No IA2 state.
|
||||||
|
******************************************************************************/
|
||||||
|
|
||||||
|
enum EStateMapEntryType {
|
||||||
|
kMapDirectly,
|
||||||
|
kMapOpposite, // For example, UNAVAILABLE is the opposite of ENABLED
|
||||||
|
kNoStateChange, // Don't fire state change event
|
||||||
|
kNoSuchState
|
||||||
|
};
|
||||||
|
|
||||||
|
const AtkStateType kNone = ATK_STATE_INVALID;
|
||||||
|
|
||||||
|
struct AtkStateMap {
|
||||||
|
AtkStateType atkState;
|
||||||
|
EStateMapEntryType stateMapEntryType;
|
||||||
|
|
||||||
|
static int32_t GetStateIndexFor(uint64_t aState)
|
||||||
|
{
|
||||||
|
int32_t stateIndex = -1;
|
||||||
|
while (aState > 0) {
|
||||||
|
++ stateIndex;
|
||||||
|
aState >>= 1;
|
||||||
|
}
|
||||||
|
return stateIndex; // Returns -1 if not mapped
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
// Map array from cross platform states to ATK states
|
||||||
|
static const AtkStateMap gAtkStateMap[] = { // Cross Platform States
|
||||||
|
{ kNone, kMapOpposite }, // states::UNAVAILABLE = 1 << 0
|
||||||
|
{ ATK_STATE_SELECTED, kMapDirectly }, // states::SELECTED = 1 << 1
|
||||||
|
{ ATK_STATE_FOCUSED, kMapDirectly }, // states::FOCUSED = 1 << 2
|
||||||
|
{ ATK_STATE_PRESSED, kMapDirectly }, // states::PRESSED = 1 << 3
|
||||||
|
{ ATK_STATE_CHECKED, kMapDirectly }, // states::CHECKED = 1 << 4
|
||||||
|
{ ATK_STATE_INDETERMINATE, kMapDirectly }, // states::MIXED = 1 << 5
|
||||||
|
{ kNone, kMapDirectly }, // states::READONLY = 1 << 6
|
||||||
|
{ kNone, kMapDirectly }, // states::HOTTRACKED = 1 << 7
|
||||||
|
{ ATK_STATE_DEFAULT, kMapDirectly }, // states::DEFAULT = 1 << 8
|
||||||
|
{ ATK_STATE_EXPANDED, kMapDirectly }, // states::EXPANDED = 1 << 9
|
||||||
|
{ kNone, kNoStateChange }, // states::COLLAPSED = 1 << 10
|
||||||
|
{ ATK_STATE_BUSY, kMapDirectly }, // states::BUSY = 1 << 11
|
||||||
|
{ kNone, kMapDirectly }, // states::FLOATING = 1 << 12
|
||||||
|
{ ATK_STATE_CHECKABLE, kMapDirectly }, // states::CHECKABLE = 1 << 13
|
||||||
|
{ ATK_STATE_ANIMATED, kMapDirectly }, // states::ANIMATED = 1 << 14
|
||||||
|
{ ATK_STATE_VISIBLE, kMapOpposite }, // states::INVISIBLE = 1 << 15
|
||||||
|
{ ATK_STATE_SHOWING, kMapOpposite }, // states::OFFSCREEN = 1 << 16
|
||||||
|
{ ATK_STATE_RESIZABLE, kMapDirectly }, // states::SIZEABLE = 1 << 17
|
||||||
|
{ kNone, kMapDirectly }, // states::MOVEABLE = 1 << 18
|
||||||
|
{ kNone, kMapDirectly }, // states::SELFVOICING = 1 << 19
|
||||||
|
{ ATK_STATE_FOCUSABLE, kMapDirectly }, // states::FOCUSABLE = 1 << 20
|
||||||
|
{ ATK_STATE_SELECTABLE, kMapDirectly }, // states::SELECTABLE = 1 << 21
|
||||||
|
{ kNone, kMapDirectly }, // states::LINKED = 1 << 22
|
||||||
|
{ ATK_STATE_VISITED, kMapDirectly }, // states::TRAVERSED = 1 << 23
|
||||||
|
{ ATK_STATE_MULTISELECTABLE, kMapDirectly }, // states::MULTISELECTABLE = 1 << 24
|
||||||
|
{ kNone, kMapDirectly }, // states::EXTSELECTABLE = 1 << 25
|
||||||
|
{ ATK_STATE_REQUIRED, kMapDirectly }, // states::STATE_REQUIRED = 1 << 26
|
||||||
|
{ kNone, kMapDirectly }, // states::ALERT_MEDIUM = 1 << 27
|
||||||
|
{ ATK_STATE_INVALID_ENTRY, kMapDirectly }, // states::INVALID = 1 << 28
|
||||||
|
{ kNone, kMapDirectly }, // states::PROTECTED = 1 << 29
|
||||||
|
{ kNone, kMapDirectly }, // states::HASPOPUP = 1 << 30
|
||||||
|
{ ATK_STATE_SUPPORTS_AUTOCOMPLETION, kMapDirectly }, // states::SUPPORTS_AUTOCOMPLETION = 1 << 31
|
||||||
|
{ ATK_STATE_DEFUNCT, kMapDirectly }, // states::DEFUNCT = 1 << 32
|
||||||
|
{ ATK_STATE_SELECTABLE_TEXT, kMapDirectly }, // states::SELECTABLE_TEXT = 1 << 33
|
||||||
|
{ ATK_STATE_EDITABLE, kMapDirectly }, // states::EDITABLE = 1 << 34
|
||||||
|
{ ATK_STATE_ACTIVE, kMapDirectly }, // states::ACTIVE = 1 << 35
|
||||||
|
{ ATK_STATE_MODAL, kMapDirectly }, // states::MODAL = 1 << 36
|
||||||
|
{ ATK_STATE_MULTI_LINE, kMapDirectly }, // states::MULTI_LINE = 1 << 37
|
||||||
|
{ ATK_STATE_HORIZONTAL, kMapDirectly }, // states::HORIZONTAL = 1 << 38
|
||||||
|
{ ATK_STATE_OPAQUE, kMapDirectly }, // states::OPAQUE = 1 << 39
|
||||||
|
{ ATK_STATE_SINGLE_LINE, kMapDirectly }, // states::SINGLE_LINE = 1 << 40
|
||||||
|
{ ATK_STATE_TRANSIENT, kMapDirectly }, // states::TRANSIENT = 1 << 41
|
||||||
|
{ ATK_STATE_VERTICAL, kMapDirectly }, // states::VERTICAL = 1 << 42
|
||||||
|
{ ATK_STATE_STALE, kMapDirectly }, // states::STALE = 1 << 43
|
||||||
|
{ ATK_STATE_ENABLED, kMapDirectly }, // states::ENABLED = 1 << 44
|
||||||
|
{ ATK_STATE_SENSITIVE, kMapDirectly }, // states::SENSITIVE = 1 << 45
|
||||||
|
{ ATK_STATE_EXPANDABLE, kMapDirectly }, // states::EXPANDABLE = 1 << 46
|
||||||
|
{ kNone, kMapDirectly }, // states::PINNED = 1 << 47
|
||||||
|
{ kNone, kNoSuchState }, // = 1 << 48
|
||||||
|
};
|
||||||
1008
accessible/base/ARIAMap.cpp
Normal file
1008
accessible/base/ARIAMap.cpp
Normal file
File diff suppressed because it is too large
Load diff
305
accessible/base/ARIAMap.h
Normal file
305
accessible/base/ARIAMap.h
Normal file
|
|
@ -0,0 +1,305 @@
|
||||||
|
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||||
|
/* vim:expandtab:shiftwidth=2:tabstop=2:
|
||||||
|
*/
|
||||||
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
|
#ifndef mozilla_a11y_aria_ARIAMap_h_
|
||||||
|
#define mozilla_a11y_aria_ARIAMap_h_
|
||||||
|
|
||||||
|
#include "ARIAStateMap.h"
|
||||||
|
#include "mozilla/a11y/AccTypes.h"
|
||||||
|
#include "mozilla/a11y/Role.h"
|
||||||
|
|
||||||
|
#include "nsIAtom.h"
|
||||||
|
#include "nsIContent.h"
|
||||||
|
|
||||||
|
class nsINode;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Value constants
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Used to define if role requires to expose Value interface.
|
||||||
|
*/
|
||||||
|
enum EValueRule
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Value interface isn't exposed.
|
||||||
|
*/
|
||||||
|
eNoValue,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Value interface is implemented, supports value, min and max from
|
||||||
|
* aria-valuenow, aria-valuemin and aria-valuemax.
|
||||||
|
*/
|
||||||
|
eHasValueMinMax
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Action constants
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Used to define if the role requires to expose action.
|
||||||
|
*/
|
||||||
|
enum EActionRule
|
||||||
|
{
|
||||||
|
eNoAction,
|
||||||
|
eActivateAction,
|
||||||
|
eClickAction,
|
||||||
|
ePressAction,
|
||||||
|
eCheckUncheckAction,
|
||||||
|
eExpandAction,
|
||||||
|
eJumpAction,
|
||||||
|
eOpenCloseAction,
|
||||||
|
eSelectAction,
|
||||||
|
eSortAction,
|
||||||
|
eSwitchAction
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Live region constants
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Used to define if role exposes default value of aria-live attribute.
|
||||||
|
*/
|
||||||
|
enum ELiveAttrRule
|
||||||
|
{
|
||||||
|
eNoLiveAttr,
|
||||||
|
eOffLiveAttr,
|
||||||
|
ePoliteLiveAttr
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Role constants
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ARIA role overrides role from native markup.
|
||||||
|
*/
|
||||||
|
const bool kUseMapRole = true;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ARIA role doesn't override the role from native markup.
|
||||||
|
*/
|
||||||
|
const bool kUseNativeRole = false;
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// ARIA attribute characteristic masks
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This mask indicates the attribute should not be exposed as an object
|
||||||
|
* attribute via the catch-all logic in Accessible::Attributes().
|
||||||
|
* This means it either isn't mean't to be exposed as an object attribute, or
|
||||||
|
* that it should, but is already handled in other code.
|
||||||
|
*/
|
||||||
|
const uint8_t ATTR_BYPASSOBJ = 0x1 << 0;
|
||||||
|
const uint8_t ATTR_BYPASSOBJ_IF_FALSE = 0x1 << 1;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This mask indicates the attribute is expected to have an NMTOKEN or bool value.
|
||||||
|
* (See for example usage in Accessible::Attributes())
|
||||||
|
*/
|
||||||
|
const uint8_t ATTR_VALTOKEN = 0x1 << 2;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Indicate the attribute is global state or property (refer to
|
||||||
|
* http://www.w3.org/TR/wai-aria/states_and_properties#global_states).
|
||||||
|
*/
|
||||||
|
const uint8_t ATTR_GLOBAL = 0x1 << 3;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// State map entry
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Used in nsRoleMapEntry.state if no nsIAccessibleStates are automatic for
|
||||||
|
* a given role.
|
||||||
|
*/
|
||||||
|
#define kNoReqStates 0
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Role map entry
|
||||||
|
|
||||||
|
/**
|
||||||
|
* For each ARIA role, this maps the nsIAccessible information.
|
||||||
|
*/
|
||||||
|
struct nsRoleMapEntry
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Return true if matches to the given ARIA role.
|
||||||
|
*/
|
||||||
|
bool Is(nsIAtom* aARIARole) const
|
||||||
|
{ return *roleAtom == aARIARole; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return true if ARIA role has the given accessible type.
|
||||||
|
*/
|
||||||
|
bool IsOfType(mozilla::a11y::AccGenericType aType) const
|
||||||
|
{ return accTypes & aType; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return ARIA role.
|
||||||
|
*/
|
||||||
|
const nsDependentAtomString ARIARoleString() const
|
||||||
|
{ return nsDependentAtomString(*roleAtom); }
|
||||||
|
|
||||||
|
// ARIA role: string representation such as "button"
|
||||||
|
nsIAtom** roleAtom;
|
||||||
|
|
||||||
|
// Role mapping rule: maps to enum Role
|
||||||
|
mozilla::a11y::role role;
|
||||||
|
|
||||||
|
// Role rule: whether to use mapped role or native semantics
|
||||||
|
bool roleRule;
|
||||||
|
|
||||||
|
// Value mapping rule: how to compute accessible value
|
||||||
|
EValueRule valueRule;
|
||||||
|
|
||||||
|
// Action mapping rule, how to expose accessible action
|
||||||
|
EActionRule actionRule;
|
||||||
|
|
||||||
|
// 'live' and 'container-live' object attributes mapping rule: how to expose
|
||||||
|
// these object attributes if ARIA 'live' attribute is missed.
|
||||||
|
ELiveAttrRule liveAttRule;
|
||||||
|
|
||||||
|
// Accessible types this role belongs to.
|
||||||
|
uint32_t accTypes;
|
||||||
|
|
||||||
|
// Automatic state mapping rule: always include in states
|
||||||
|
uint64_t state; // or kNoReqStates if no default state for this role
|
||||||
|
|
||||||
|
// ARIA properties supported for this role (in other words, the aria-foo
|
||||||
|
// attribute to accessible states mapping rules).
|
||||||
|
// Currently you cannot have unlimited mappings, because
|
||||||
|
// a variable sized array would not allow the use of
|
||||||
|
// C++'s struct initialization feature.
|
||||||
|
mozilla::a11y::aria::EStateRule attributeMap1;
|
||||||
|
mozilla::a11y::aria::EStateRule attributeMap2;
|
||||||
|
mozilla::a11y::aria::EStateRule attributeMap3;
|
||||||
|
mozilla::a11y::aria::EStateRule attributeMap4;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// ARIA map
|
||||||
|
|
||||||
|
/**
|
||||||
|
* These provide the mappings for WAI-ARIA roles, states and properties using
|
||||||
|
* the structs defined in this file and ARIAStateMap files.
|
||||||
|
*/
|
||||||
|
namespace mozilla {
|
||||||
|
namespace a11y {
|
||||||
|
namespace aria {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Empty role map entry. Used by accessibility service to create an accessible
|
||||||
|
* if the accessible can't use role of used accessible class. For example,
|
||||||
|
* it is used for table cells that aren't contained by table.
|
||||||
|
*/
|
||||||
|
extern nsRoleMapEntry gEmptyRoleMap;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constants for the role map entry index to indicate that the role map entry
|
||||||
|
* isn't in sWAIRoleMaps, but rather is a special entry: nullptr,
|
||||||
|
* gEmptyRoleMap, and sLandmarkRoleMap
|
||||||
|
*/
|
||||||
|
const uint8_t NO_ROLE_MAP_ENTRY_INDEX = UINT8_MAX - 2;
|
||||||
|
const uint8_t EMPTY_ROLE_MAP_ENTRY_INDEX = UINT8_MAX - 1;
|
||||||
|
const uint8_t LANDMARK_ROLE_MAP_ENTRY_INDEX = UINT8_MAX;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the role map entry for a given DOM node. This will use the first
|
||||||
|
* ARIA role if the role attribute provides a space delimited list of roles.
|
||||||
|
*
|
||||||
|
* @param aEl [in] the DOM node to get the role map entry for
|
||||||
|
* @return a pointer to the role map entry for the ARIA role, or nullptr
|
||||||
|
* if none
|
||||||
|
*/
|
||||||
|
const nsRoleMapEntry* GetRoleMap(dom::Element* aEl);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the role map entry pointer's index for a given DOM node. This will use
|
||||||
|
* the first ARIA role if the role attribute provides a space delimited list of
|
||||||
|
* roles.
|
||||||
|
*
|
||||||
|
* @param aEl [in] the DOM node to get the role map entry for
|
||||||
|
* @return the index of the pointer to the role map entry for the ARIA
|
||||||
|
* role, or NO_ROLE_MAP_ENTRY_INDEX if none
|
||||||
|
*/
|
||||||
|
uint8_t GetRoleMapIndex(dom::Element* aEl);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the role map entry pointer for a given role map entry index.
|
||||||
|
*
|
||||||
|
* @param aRoleMapIndex [in] the role map index to get the role map entry
|
||||||
|
* pointer for
|
||||||
|
* @return a pointer to the role map entry for the ARIA role,
|
||||||
|
* or nullptr, if none
|
||||||
|
*/
|
||||||
|
const nsRoleMapEntry* GetRoleMapFromIndex(uint8_t aRoleMapIndex);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the role map entry index for a given role map entry pointer. If the role
|
||||||
|
* map entry is within sWAIRoleMaps, return the index within that array,
|
||||||
|
* otherwise return one of the special index constants listed above.
|
||||||
|
*
|
||||||
|
* @param aRoleMap [in] the role map entry pointer to get the index for
|
||||||
|
* @return the index of the pointer to the role map entry, or
|
||||||
|
* NO_ROLE_MAP_ENTRY_INDEX if none
|
||||||
|
*/
|
||||||
|
uint8_t GetIndexFromRoleMap(const nsRoleMapEntry* aRoleMap);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return accessible state from ARIA universal states applied to the given
|
||||||
|
* element.
|
||||||
|
*/
|
||||||
|
uint64_t UniversalStatesFor(mozilla::dom::Element* aElement);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the ARIA attribute characteristics for a given ARIA attribute.
|
||||||
|
*
|
||||||
|
* @param aAtom ARIA attribute
|
||||||
|
* @return A bitflag representing the attribute characteristics
|
||||||
|
* (see above for possible bit masks, prefixed "ATTR_")
|
||||||
|
*/
|
||||||
|
uint8_t AttrCharacteristicsFor(nsIAtom* aAtom);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return true if the element has defined aria-hidden.
|
||||||
|
*/
|
||||||
|
bool HasDefinedARIAHidden(nsIContent* aContent);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents a simple enumerator for iterating through ARIA attributes
|
||||||
|
* exposed as object attributes on a given accessible.
|
||||||
|
*/
|
||||||
|
class AttrIterator
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
explicit AttrIterator(nsIContent* aContent) :
|
||||||
|
mContent(aContent), mAttrIdx(0)
|
||||||
|
{
|
||||||
|
mAttrCount = mContent->GetAttrCount();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Next(nsAString& aAttrName, nsAString& aAttrValue);
|
||||||
|
|
||||||
|
private:
|
||||||
|
AttrIterator() = delete;
|
||||||
|
AttrIterator(const AttrIterator&) = delete;
|
||||||
|
AttrIterator& operator= (const AttrIterator&) = delete;
|
||||||
|
|
||||||
|
nsIContent* mContent;
|
||||||
|
uint32_t mAttrIdx;
|
||||||
|
uint32_t mAttrCount;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace aria
|
||||||
|
} // namespace a11y
|
||||||
|
} // namespace mozilla
|
||||||
|
|
||||||
|
#endif
|
||||||
376
accessible/base/ARIAStateMap.cpp
Normal file
376
accessible/base/ARIAStateMap.cpp
Normal file
|
|
@ -0,0 +1,376 @@
|
||||||
|
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||||
|
/* vim: set ts=2 et sw=2 tw=80: */
|
||||||
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||||
|
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
|
#include "ARIAMap.h"
|
||||||
|
#include "nsAccUtils.h"
|
||||||
|
#include "States.h"
|
||||||
|
|
||||||
|
#include "mozilla/dom/Element.h"
|
||||||
|
|
||||||
|
using namespace mozilla;
|
||||||
|
using namespace mozilla::a11y;
|
||||||
|
using namespace mozilla::a11y::aria;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Used to store state map rule data for ARIA attribute of enum type.
|
||||||
|
*/
|
||||||
|
struct EnumTypeData
|
||||||
|
{
|
||||||
|
// ARIA attribute name.
|
||||||
|
nsIAtom* const mAttrName;
|
||||||
|
|
||||||
|
// States if the attribute value is matched to the enum value. Used as
|
||||||
|
// nsIContent::AttrValuesArray, last item must be nullptr.
|
||||||
|
nsIAtom* const* const mValues[4];
|
||||||
|
|
||||||
|
// States applied if corresponding enum values are matched.
|
||||||
|
const uint64_t mStates[3];
|
||||||
|
|
||||||
|
// States to clear in case of match.
|
||||||
|
const uint64_t mClearState;
|
||||||
|
};
|
||||||
|
|
||||||
|
enum ETokenType
|
||||||
|
{
|
||||||
|
eBoolType = 0,
|
||||||
|
eMixedType = 1, // can take 'mixed' value
|
||||||
|
eDefinedIfAbsent = 2 // permanent and false state are applied if absent
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Used to store state map rule data for ARIA attribute of token type (including
|
||||||
|
* mixed value).
|
||||||
|
*/
|
||||||
|
struct TokenTypeData
|
||||||
|
{
|
||||||
|
TokenTypeData(nsIAtom* aAttrName, uint32_t aType,
|
||||||
|
uint64_t aPermanentState,
|
||||||
|
uint64_t aTrueState,
|
||||||
|
uint64_t aFalseState = 0) :
|
||||||
|
mAttrName(aAttrName), mType(aType), mPermanentState(aPermanentState),
|
||||||
|
mTrueState(aTrueState), mFalseState(aFalseState)
|
||||||
|
{ }
|
||||||
|
|
||||||
|
// ARIA attribute name.
|
||||||
|
nsIAtom* const mAttrName;
|
||||||
|
|
||||||
|
// Type.
|
||||||
|
const uint32_t mType;
|
||||||
|
|
||||||
|
// State applied if the attribute is defined or mType doesn't have
|
||||||
|
// eDefinedIfAbsent flag set.
|
||||||
|
const uint64_t mPermanentState;
|
||||||
|
|
||||||
|
// States applied if the attribute value is true/false.
|
||||||
|
const uint64_t mTrueState;
|
||||||
|
const uint64_t mFalseState;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Map enum type attribute value to accessible state.
|
||||||
|
*/
|
||||||
|
static void MapEnumType(dom::Element* aElement, uint64_t* aState,
|
||||||
|
const EnumTypeData& aData);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Map token type attribute value to states.
|
||||||
|
*/
|
||||||
|
static void MapTokenType(dom::Element* aContent, uint64_t* aState,
|
||||||
|
const TokenTypeData& aData);
|
||||||
|
|
||||||
|
bool
|
||||||
|
aria::MapToState(EStateRule aRule, dom::Element* aElement, uint64_t* aState)
|
||||||
|
{
|
||||||
|
switch (aRule) {
|
||||||
|
case eARIAAutoComplete:
|
||||||
|
{
|
||||||
|
static const EnumTypeData data = {
|
||||||
|
nsGkAtoms::aria_autocomplete,
|
||||||
|
{ &nsGkAtoms::inlinevalue,
|
||||||
|
&nsGkAtoms::list,
|
||||||
|
&nsGkAtoms::both, nullptr },
|
||||||
|
{ states::SUPPORTS_AUTOCOMPLETION,
|
||||||
|
states::HASPOPUP | states::SUPPORTS_AUTOCOMPLETION,
|
||||||
|
states::HASPOPUP | states::SUPPORTS_AUTOCOMPLETION }, 0
|
||||||
|
};
|
||||||
|
|
||||||
|
MapEnumType(aElement, aState, data);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
case eARIABusy:
|
||||||
|
{
|
||||||
|
static const EnumTypeData data = {
|
||||||
|
nsGkAtoms::aria_busy,
|
||||||
|
{ &nsGkAtoms::_true,
|
||||||
|
&nsGkAtoms::error, nullptr },
|
||||||
|
{ states::BUSY,
|
||||||
|
states::INVALID }, 0
|
||||||
|
};
|
||||||
|
|
||||||
|
MapEnumType(aElement, aState, data);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
case eARIACheckableBool:
|
||||||
|
{
|
||||||
|
static const TokenTypeData data(
|
||||||
|
nsGkAtoms::aria_checked, eBoolType | eDefinedIfAbsent,
|
||||||
|
states::CHECKABLE, states::CHECKED);
|
||||||
|
|
||||||
|
MapTokenType(aElement, aState, data);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
case eARIACheckableMixed:
|
||||||
|
{
|
||||||
|
static const TokenTypeData data(
|
||||||
|
nsGkAtoms::aria_checked, eMixedType | eDefinedIfAbsent,
|
||||||
|
states::CHECKABLE, states::CHECKED);
|
||||||
|
|
||||||
|
MapTokenType(aElement, aState, data);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
case eARIACheckedMixed:
|
||||||
|
{
|
||||||
|
static const TokenTypeData data(
|
||||||
|
nsGkAtoms::aria_checked, eMixedType,
|
||||||
|
states::CHECKABLE, states::CHECKED);
|
||||||
|
|
||||||
|
MapTokenType(aElement, aState, data);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
case eARIADisabled:
|
||||||
|
{
|
||||||
|
static const TokenTypeData data(
|
||||||
|
nsGkAtoms::aria_disabled, eBoolType,
|
||||||
|
0, states::UNAVAILABLE);
|
||||||
|
|
||||||
|
MapTokenType(aElement, aState, data);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
case eARIAExpanded:
|
||||||
|
{
|
||||||
|
static const TokenTypeData data(
|
||||||
|
nsGkAtoms::aria_expanded, eBoolType,
|
||||||
|
0, states::EXPANDED, states::COLLAPSED);
|
||||||
|
|
||||||
|
MapTokenType(aElement, aState, data);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
case eARIAHasPopup:
|
||||||
|
{
|
||||||
|
static const TokenTypeData data(
|
||||||
|
nsGkAtoms::aria_haspopup, eBoolType,
|
||||||
|
0, states::HASPOPUP);
|
||||||
|
|
||||||
|
MapTokenType(aElement, aState, data);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
case eARIAInvalid:
|
||||||
|
{
|
||||||
|
static const TokenTypeData data(
|
||||||
|
nsGkAtoms::aria_invalid, eBoolType,
|
||||||
|
0, states::INVALID);
|
||||||
|
|
||||||
|
MapTokenType(aElement, aState, data);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
case eARIAModal:
|
||||||
|
{
|
||||||
|
static const TokenTypeData data(
|
||||||
|
nsGkAtoms::aria_modal, eBoolType,
|
||||||
|
0, states::MODAL);
|
||||||
|
|
||||||
|
MapTokenType(aElement, aState, data);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
case eARIAMultiline:
|
||||||
|
{
|
||||||
|
static const TokenTypeData data(
|
||||||
|
nsGkAtoms::aria_multiline, eBoolType | eDefinedIfAbsent,
|
||||||
|
0, states::MULTI_LINE, states::SINGLE_LINE);
|
||||||
|
|
||||||
|
MapTokenType(aElement, aState, data);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
case eARIAMultiSelectable:
|
||||||
|
{
|
||||||
|
static const TokenTypeData data(
|
||||||
|
nsGkAtoms::aria_multiselectable, eBoolType,
|
||||||
|
0, states::MULTISELECTABLE | states::EXTSELECTABLE);
|
||||||
|
|
||||||
|
MapTokenType(aElement, aState, data);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
case eARIAOrientation:
|
||||||
|
{
|
||||||
|
static const EnumTypeData data = {
|
||||||
|
nsGkAtoms::aria_orientation,
|
||||||
|
{ &nsGkAtoms::horizontal,
|
||||||
|
&nsGkAtoms::vertical, nullptr },
|
||||||
|
{ states::HORIZONTAL,
|
||||||
|
states::VERTICAL },
|
||||||
|
states::HORIZONTAL | states::VERTICAL
|
||||||
|
};
|
||||||
|
|
||||||
|
MapEnumType(aElement, aState, data);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
case eARIAPressed:
|
||||||
|
{
|
||||||
|
static const TokenTypeData data(
|
||||||
|
nsGkAtoms::aria_pressed, eMixedType,
|
||||||
|
0, states::PRESSED);
|
||||||
|
|
||||||
|
MapTokenType(aElement, aState, data);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
case eARIAReadonly:
|
||||||
|
{
|
||||||
|
static const TokenTypeData data(
|
||||||
|
nsGkAtoms::aria_readonly, eBoolType,
|
||||||
|
0, states::READONLY);
|
||||||
|
|
||||||
|
MapTokenType(aElement, aState, data);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
case eARIAReadonlyOrEditable:
|
||||||
|
{
|
||||||
|
static const TokenTypeData data(
|
||||||
|
nsGkAtoms::aria_readonly, eBoolType | eDefinedIfAbsent,
|
||||||
|
0, states::READONLY, states::EDITABLE);
|
||||||
|
|
||||||
|
MapTokenType(aElement, aState, data);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
case eARIAReadonlyOrEditableIfDefined:
|
||||||
|
{
|
||||||
|
static const TokenTypeData data(
|
||||||
|
nsGkAtoms::aria_readonly, eBoolType,
|
||||||
|
0, states::READONLY, states::EDITABLE);
|
||||||
|
|
||||||
|
MapTokenType(aElement, aState, data);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
case eARIARequired:
|
||||||
|
{
|
||||||
|
static const TokenTypeData data(
|
||||||
|
nsGkAtoms::aria_required, eBoolType,
|
||||||
|
0, states::REQUIRED);
|
||||||
|
|
||||||
|
MapTokenType(aElement, aState, data);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
case eARIASelectable:
|
||||||
|
{
|
||||||
|
static const TokenTypeData data(
|
||||||
|
nsGkAtoms::aria_selected, eBoolType | eDefinedIfAbsent,
|
||||||
|
states::SELECTABLE, states::SELECTED);
|
||||||
|
|
||||||
|
MapTokenType(aElement, aState, data);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
case eARIASelectableIfDefined:
|
||||||
|
{
|
||||||
|
static const TokenTypeData data(
|
||||||
|
nsGkAtoms::aria_selected, eBoolType,
|
||||||
|
states::SELECTABLE, states::SELECTED);
|
||||||
|
|
||||||
|
MapTokenType(aElement, aState, data);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
case eReadonlyUntilEditable:
|
||||||
|
{
|
||||||
|
if (!(*aState & states::EDITABLE))
|
||||||
|
*aState |= states::READONLY;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
case eIndeterminateIfNoValue:
|
||||||
|
{
|
||||||
|
if (!aElement->HasAttr(kNameSpaceID_None, nsGkAtoms::aria_valuenow) &&
|
||||||
|
!aElement->HasAttr(kNameSpaceID_None, nsGkAtoms::aria_valuetext))
|
||||||
|
*aState |= states::MIXED;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
case eFocusableUntilDisabled:
|
||||||
|
{
|
||||||
|
if (!nsAccUtils::HasDefinedARIAToken(aElement, nsGkAtoms::aria_disabled) ||
|
||||||
|
aElement->AttrValueIs(kNameSpaceID_None, nsGkAtoms::aria_disabled,
|
||||||
|
nsGkAtoms::_false, eCaseMatters))
|
||||||
|
*aState |= states::FOCUSABLE;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
MapEnumType(dom::Element* aElement, uint64_t* aState, const EnumTypeData& aData)
|
||||||
|
{
|
||||||
|
switch (aElement->FindAttrValueIn(kNameSpaceID_None, aData.mAttrName,
|
||||||
|
aData.mValues, eCaseMatters)) {
|
||||||
|
case 0:
|
||||||
|
*aState = (*aState & ~aData.mClearState) | aData.mStates[0];
|
||||||
|
return;
|
||||||
|
case 1:
|
||||||
|
*aState = (*aState & ~aData.mClearState) | aData.mStates[1];
|
||||||
|
return;
|
||||||
|
case 2:
|
||||||
|
*aState = (*aState & ~aData.mClearState) | aData.mStates[2];
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
MapTokenType(dom::Element* aElement, uint64_t* aState,
|
||||||
|
const TokenTypeData& aData)
|
||||||
|
{
|
||||||
|
if (nsAccUtils::HasDefinedARIAToken(aElement, aData.mAttrName)) {
|
||||||
|
if ((aData.mType & eMixedType) &&
|
||||||
|
aElement->AttrValueIs(kNameSpaceID_None, aData.mAttrName,
|
||||||
|
nsGkAtoms::mixed, eCaseMatters)) {
|
||||||
|
*aState |= aData.mPermanentState | states::MIXED;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (aElement->AttrValueIs(kNameSpaceID_None, aData.mAttrName,
|
||||||
|
nsGkAtoms::_false, eCaseMatters)) {
|
||||||
|
*aState |= aData.mPermanentState | aData.mFalseState;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
*aState |= aData.mPermanentState | aData.mTrueState;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (aData.mType & eDefinedIfAbsent)
|
||||||
|
*aState |= aData.mPermanentState | aData.mFalseState;
|
||||||
|
}
|
||||||
67
accessible/base/ARIAStateMap.h
Normal file
67
accessible/base/ARIAStateMap.h
Normal file
|
|
@ -0,0 +1,67 @@
|
||||||
|
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||||
|
/* vim: set ts=2 et sw=2 tw=80: */
|
||||||
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||||
|
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
|
#ifndef _mozilla_a11y_aria_ARIAStateMap_h_
|
||||||
|
#define _mozilla_a11y_aria_ARIAStateMap_h_
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
namespace mozilla {
|
||||||
|
|
||||||
|
namespace dom {
|
||||||
|
class Element;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace a11y {
|
||||||
|
namespace aria {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* List of the ARIA state mapping rules.
|
||||||
|
*/
|
||||||
|
enum EStateRule
|
||||||
|
{
|
||||||
|
eARIANone,
|
||||||
|
eARIAAutoComplete,
|
||||||
|
eARIABusy,
|
||||||
|
eARIACheckableBool,
|
||||||
|
eARIACheckableMixed,
|
||||||
|
eARIACheckedMixed,
|
||||||
|
eARIADisabled,
|
||||||
|
eARIAExpanded,
|
||||||
|
eARIAHasPopup,
|
||||||
|
eARIAInvalid,
|
||||||
|
eARIAModal,
|
||||||
|
eARIAMultiline,
|
||||||
|
eARIAMultiSelectable,
|
||||||
|
eARIAOrientation,
|
||||||
|
eARIAPressed,
|
||||||
|
eARIAReadonly,
|
||||||
|
eARIAReadonlyOrEditable,
|
||||||
|
eARIAReadonlyOrEditableIfDefined,
|
||||||
|
eARIARequired,
|
||||||
|
eARIASelectable,
|
||||||
|
eARIASelectableIfDefined,
|
||||||
|
eReadonlyUntilEditable,
|
||||||
|
eIndeterminateIfNoValue,
|
||||||
|
eFocusableUntilDisabled
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Expose the accessible states for the given element accordingly to state
|
||||||
|
* mapping rule.
|
||||||
|
*
|
||||||
|
* @param aRule [in] state mapping rule ID
|
||||||
|
* @param aElement [in] node of the accessible
|
||||||
|
* @param aState [in/out] accessible states
|
||||||
|
* @return true if state map rule ID is valid
|
||||||
|
*/
|
||||||
|
bool MapToState(EStateRule aRule, dom::Element* aElement, uint64_t* aState);
|
||||||
|
|
||||||
|
} // namespace aria
|
||||||
|
} // namespace a11y
|
||||||
|
} // namespace mozilla
|
||||||
|
|
||||||
|
#endif
|
||||||
271
accessible/base/AccEvent.cpp
Normal file
271
accessible/base/AccEvent.cpp
Normal file
|
|
@ -0,0 +1,271 @@
|
||||||
|
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||||
|
/* vim: set ts=2 et sw=2 tw=80: */
|
||||||
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
|
#include "AccEvent.h"
|
||||||
|
|
||||||
|
#include "nsAccUtils.h"
|
||||||
|
#include "DocAccessible.h"
|
||||||
|
#include "xpcAccEvents.h"
|
||||||
|
#include "States.h"
|
||||||
|
#include "xpcAccessibleDocument.h"
|
||||||
|
|
||||||
|
#include "mozilla/EventStateManager.h"
|
||||||
|
#include "mozilla/dom/Selection.h"
|
||||||
|
|
||||||
|
using namespace mozilla;
|
||||||
|
using namespace mozilla::a11y;
|
||||||
|
|
||||||
|
static_assert(static_cast<bool>(eNoUserInput) == false &&
|
||||||
|
static_cast<bool>(eFromUserInput) == true,
|
||||||
|
"EIsFromUserInput cannot be casted to bool");
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// AccEvent
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// AccEvent constructors
|
||||||
|
|
||||||
|
AccEvent::AccEvent(uint32_t aEventType, Accessible* aAccessible,
|
||||||
|
EIsFromUserInput aIsFromUserInput, EEventRule aEventRule) :
|
||||||
|
mEventType(aEventType), mEventRule(aEventRule), mAccessible(aAccessible)
|
||||||
|
{
|
||||||
|
if (aIsFromUserInput == eAutoDetect)
|
||||||
|
mIsFromUserInput = EventStateManager::IsHandlingUserInput();
|
||||||
|
else
|
||||||
|
mIsFromUserInput = aIsFromUserInput == eFromUserInput ? true : false;
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// AccEvent cycle collection
|
||||||
|
|
||||||
|
NS_IMPL_CYCLE_COLLECTION_CLASS(AccEvent)
|
||||||
|
|
||||||
|
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(AccEvent)
|
||||||
|
NS_IMPL_CYCLE_COLLECTION_UNLINK(mAccessible)
|
||||||
|
if (AccTreeMutationEvent* tmEvent = downcast_accEvent(tmp)) {
|
||||||
|
tmEvent->SetNextEvent(nullptr);
|
||||||
|
tmEvent->SetPrevEvent(nullptr);
|
||||||
|
}
|
||||||
|
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
|
||||||
|
|
||||||
|
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(AccEvent)
|
||||||
|
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mAccessible)
|
||||||
|
if (AccTreeMutationEvent* tmEvent = downcast_accEvent(tmp)) {
|
||||||
|
CycleCollectionNoteChild(cb, tmEvent->NextEvent(), "mNext");
|
||||||
|
CycleCollectionNoteChild(cb, tmEvent->PrevEvent(), "mPrevEvent");
|
||||||
|
}
|
||||||
|
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
|
||||||
|
|
||||||
|
NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(AccEvent, AddRef)
|
||||||
|
NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(AccEvent, Release)
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// AccTextChangeEvent
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
// Note: we pass in eAllowDupes to the base class because we don't support text
|
||||||
|
// events coalescence. We fire delayed text change events in DocAccessible but
|
||||||
|
// we continue to base the event off the accessible object rather than just the
|
||||||
|
// node. This means we won't try to create an accessible based on the node when
|
||||||
|
// we are ready to fire the event and so we will no longer assert at that point
|
||||||
|
// if the node was removed from the document. Either way, the AT won't work with
|
||||||
|
// a defunct accessible so the behaviour should be equivalent.
|
||||||
|
AccTextChangeEvent::
|
||||||
|
AccTextChangeEvent(Accessible* aAccessible, int32_t aStart,
|
||||||
|
const nsAString& aModifiedText, bool aIsInserted,
|
||||||
|
EIsFromUserInput aIsFromUserInput)
|
||||||
|
: AccEvent(aIsInserted ?
|
||||||
|
static_cast<uint32_t>(nsIAccessibleEvent::EVENT_TEXT_INSERTED) :
|
||||||
|
static_cast<uint32_t>(nsIAccessibleEvent::EVENT_TEXT_REMOVED),
|
||||||
|
aAccessible, aIsFromUserInput, eAllowDupes)
|
||||||
|
, mStart(aStart)
|
||||||
|
, mIsInserted(aIsInserted)
|
||||||
|
, mModifiedText(aModifiedText)
|
||||||
|
{
|
||||||
|
// XXX We should use IsFromUserInput here, but that isn't always correct
|
||||||
|
// when the text change isn't related to content insertion or removal.
|
||||||
|
mIsFromUserInput = mAccessible->State() &
|
||||||
|
(states::FOCUSED | states::EDITABLE);
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// AccHideEvent
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
AccHideEvent::
|
||||||
|
AccHideEvent(Accessible* aTarget, bool aNeedsShutdown) :
|
||||||
|
AccMutationEvent(::nsIAccessibleEvent::EVENT_HIDE, aTarget),
|
||||||
|
mNeedsShutdown(aNeedsShutdown)
|
||||||
|
{
|
||||||
|
mNextSibling = mAccessible->NextSibling();
|
||||||
|
mPrevSibling = mAccessible->PrevSibling();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// AccShowEvent
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
AccShowEvent::
|
||||||
|
AccShowEvent(Accessible* aTarget) :
|
||||||
|
AccMutationEvent(::nsIAccessibleEvent::EVENT_SHOW, aTarget)
|
||||||
|
{
|
||||||
|
int32_t idx = aTarget->IndexInParent();
|
||||||
|
MOZ_ASSERT(idx >= 0);
|
||||||
|
mInsertionIndex = idx;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// AccTextSelChangeEvent
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
AccTextSelChangeEvent::AccTextSelChangeEvent(HyperTextAccessible* aTarget,
|
||||||
|
dom::Selection* aSelection,
|
||||||
|
int32_t aReason) :
|
||||||
|
AccEvent(nsIAccessibleEvent::EVENT_TEXT_SELECTION_CHANGED, aTarget,
|
||||||
|
eAutoDetect, eCoalesceTextSelChange),
|
||||||
|
mSel(aSelection), mReason(aReason) {}
|
||||||
|
|
||||||
|
AccTextSelChangeEvent::~AccTextSelChangeEvent() { }
|
||||||
|
|
||||||
|
bool
|
||||||
|
AccTextSelChangeEvent::IsCaretMoveOnly() const
|
||||||
|
{
|
||||||
|
return mSel->RangeCount() == 1 && mSel->IsCollapsed() &&
|
||||||
|
((mReason & (nsISelectionListener::COLLAPSETOSTART_REASON |
|
||||||
|
nsISelectionListener::COLLAPSETOEND_REASON)) == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// AccSelChangeEvent
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
AccSelChangeEvent::
|
||||||
|
AccSelChangeEvent(Accessible* aWidget, Accessible* aItem,
|
||||||
|
SelChangeType aSelChangeType) :
|
||||||
|
AccEvent(0, aItem, eAutoDetect, eCoalesceSelectionChange),
|
||||||
|
mWidget(aWidget), mItem(aItem), mSelChangeType(aSelChangeType),
|
||||||
|
mPreceedingCount(0), mPackedEvent(nullptr)
|
||||||
|
{
|
||||||
|
if (aSelChangeType == eSelectionAdd) {
|
||||||
|
if (mWidget->GetSelectedItem(1))
|
||||||
|
mEventType = nsIAccessibleEvent::EVENT_SELECTION_ADD;
|
||||||
|
else
|
||||||
|
mEventType = nsIAccessibleEvent::EVENT_SELECTION;
|
||||||
|
} else {
|
||||||
|
mEventType = nsIAccessibleEvent::EVENT_SELECTION_REMOVE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// AccTableChangeEvent
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
AccTableChangeEvent::
|
||||||
|
AccTableChangeEvent(Accessible* aAccessible, uint32_t aEventType,
|
||||||
|
int32_t aRowOrColIndex, int32_t aNumRowsOrCols) :
|
||||||
|
AccEvent(aEventType, aAccessible),
|
||||||
|
mRowOrColIndex(aRowOrColIndex), mNumRowsOrCols(aNumRowsOrCols)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// AccVCChangeEvent
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
AccVCChangeEvent::
|
||||||
|
AccVCChangeEvent(Accessible* aAccessible,
|
||||||
|
Accessible* aOldAccessible,
|
||||||
|
int32_t aOldStart, int32_t aOldEnd,
|
||||||
|
int16_t aReason, EIsFromUserInput aIsFromUserInput) :
|
||||||
|
AccEvent(::nsIAccessibleEvent::EVENT_VIRTUALCURSOR_CHANGED, aAccessible,
|
||||||
|
aIsFromUserInput),
|
||||||
|
mOldAccessible(aOldAccessible), mOldStart(aOldStart), mOldEnd(aOldEnd),
|
||||||
|
mReason(aReason)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
already_AddRefed<nsIAccessibleEvent>
|
||||||
|
a11y::MakeXPCEvent(AccEvent* aEvent)
|
||||||
|
{
|
||||||
|
DocAccessible* doc = aEvent->Document();
|
||||||
|
Accessible* acc = aEvent->GetAccessible();
|
||||||
|
nsINode* node = acc->GetNode();
|
||||||
|
nsIDOMNode* domNode = node ? node->AsDOMNode() : nullptr;
|
||||||
|
bool fromUser = aEvent->IsFromUserInput();
|
||||||
|
uint32_t type = aEvent->GetEventType();
|
||||||
|
uint32_t eventGroup = aEvent->GetEventGroups();
|
||||||
|
nsCOMPtr<nsIAccessibleEvent> xpEvent;
|
||||||
|
|
||||||
|
if (eventGroup & (1 << AccEvent::eStateChangeEvent)) {
|
||||||
|
AccStateChangeEvent* sc = downcast_accEvent(aEvent);
|
||||||
|
bool extra = false;
|
||||||
|
uint32_t state = nsAccUtils::To32States(sc->GetState(), &extra);
|
||||||
|
xpEvent = new xpcAccStateChangeEvent(type, ToXPC(acc), ToXPCDocument(doc),
|
||||||
|
domNode, fromUser,
|
||||||
|
state, extra, sc->IsStateEnabled());
|
||||||
|
return xpEvent.forget();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (eventGroup & (1 << AccEvent::eTextChangeEvent)) {
|
||||||
|
AccTextChangeEvent* tc = downcast_accEvent(aEvent);
|
||||||
|
nsString text;
|
||||||
|
tc->GetModifiedText(text);
|
||||||
|
xpEvent = new xpcAccTextChangeEvent(type, ToXPC(acc), ToXPCDocument(doc),
|
||||||
|
domNode, fromUser,
|
||||||
|
tc->GetStartOffset(), tc->GetLength(),
|
||||||
|
tc->IsTextInserted(), text);
|
||||||
|
return xpEvent.forget();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (eventGroup & (1 << AccEvent::eHideEvent)) {
|
||||||
|
AccHideEvent* hideEvent = downcast_accEvent(aEvent);
|
||||||
|
xpEvent = new xpcAccHideEvent(type, ToXPC(acc), ToXPCDocument(doc),
|
||||||
|
domNode, fromUser,
|
||||||
|
ToXPC(hideEvent->TargetParent()),
|
||||||
|
ToXPC(hideEvent->TargetNextSibling()),
|
||||||
|
ToXPC(hideEvent->TargetPrevSibling()));
|
||||||
|
return xpEvent.forget();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (eventGroup & (1 << AccEvent::eCaretMoveEvent)) {
|
||||||
|
AccCaretMoveEvent* cm = downcast_accEvent(aEvent);
|
||||||
|
xpEvent = new xpcAccCaretMoveEvent(type, ToXPC(acc), ToXPCDocument(doc),
|
||||||
|
domNode, fromUser,
|
||||||
|
cm->GetCaretOffset());
|
||||||
|
return xpEvent.forget();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (eventGroup & (1 << AccEvent::eVirtualCursorChangeEvent)) {
|
||||||
|
AccVCChangeEvent* vcc = downcast_accEvent(aEvent);
|
||||||
|
xpEvent = new xpcAccVirtualCursorChangeEvent(type,
|
||||||
|
ToXPC(acc), ToXPCDocument(doc),
|
||||||
|
domNode, fromUser,
|
||||||
|
ToXPC(vcc->OldAccessible()),
|
||||||
|
vcc->OldStartOffset(),
|
||||||
|
vcc->OldEndOffset(),
|
||||||
|
vcc->Reason());
|
||||||
|
return xpEvent.forget();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (eventGroup & (1 << AccEvent::eObjectAttrChangedEvent)) {
|
||||||
|
AccObjectAttrChangedEvent* oac = downcast_accEvent(aEvent);
|
||||||
|
xpEvent = new xpcAccObjectAttributeChangedEvent(type,
|
||||||
|
ToXPC(acc),
|
||||||
|
ToXPCDocument(doc), domNode,
|
||||||
|
fromUser,
|
||||||
|
oac->GetAttribute());
|
||||||
|
return xpEvent.forget();
|
||||||
|
}
|
||||||
|
|
||||||
|
xpEvent = new xpcAccEvent(type, ToXPC(acc), ToXPCDocument(doc), domNode, fromUser);
|
||||||
|
return xpEvent.forget();
|
||||||
|
}
|
||||||
570
accessible/base/AccEvent.h
Normal file
570
accessible/base/AccEvent.h
Normal file
|
|
@ -0,0 +1,570 @@
|
||||||
|
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||||
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
|
#ifndef _AccEvent_H_
|
||||||
|
#define _AccEvent_H_
|
||||||
|
|
||||||
|
#include "nsIAccessibleEvent.h"
|
||||||
|
|
||||||
|
#include "mozilla/a11y/Accessible.h"
|
||||||
|
|
||||||
|
class nsEventShell;
|
||||||
|
namespace mozilla {
|
||||||
|
|
||||||
|
namespace dom {
|
||||||
|
class Selection;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace a11y {
|
||||||
|
|
||||||
|
class DocAccessible;
|
||||||
|
|
||||||
|
// Constants used to point whether the event is from user input.
|
||||||
|
enum EIsFromUserInput
|
||||||
|
{
|
||||||
|
// eNoUserInput: event is not from user input
|
||||||
|
eNoUserInput = 0,
|
||||||
|
// eFromUserInput: event is from user input
|
||||||
|
eFromUserInput = 1,
|
||||||
|
// eAutoDetect: the value should be obtained from event state manager
|
||||||
|
eAutoDetect = -1
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generic accessible event.
|
||||||
|
*/
|
||||||
|
class AccEvent
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
// Rule for accessible events.
|
||||||
|
// The rule will be applied when flushing pending events.
|
||||||
|
enum EEventRule {
|
||||||
|
// eAllowDupes : More than one event of the same type is allowed.
|
||||||
|
// This event will always be emitted. This flag is used for events that
|
||||||
|
// don't support coalescence.
|
||||||
|
eAllowDupes,
|
||||||
|
|
||||||
|
// eCoalesceReorder : For reorder events from the same subtree or the same
|
||||||
|
// node, only the umbrella event on the ancestor will be emitted.
|
||||||
|
eCoalesceReorder,
|
||||||
|
|
||||||
|
// eCoalesceOfSameType : For events of the same type, only the newest event
|
||||||
|
// will be processed.
|
||||||
|
eCoalesceOfSameType,
|
||||||
|
|
||||||
|
// eCoalesceSelectionChange: coalescence of selection change events.
|
||||||
|
eCoalesceSelectionChange,
|
||||||
|
|
||||||
|
// eCoalesceStateChange: coalesce state change events.
|
||||||
|
eCoalesceStateChange,
|
||||||
|
|
||||||
|
// eCoalesceTextSelChange: coalescence of text selection change events.
|
||||||
|
eCoalesceTextSelChange,
|
||||||
|
|
||||||
|
// eRemoveDupes : For repeat events, only the newest event in queue
|
||||||
|
// will be emitted.
|
||||||
|
eRemoveDupes,
|
||||||
|
|
||||||
|
// eDoNotEmit : This event is confirmed as a duplicate, do not emit it.
|
||||||
|
eDoNotEmit
|
||||||
|
};
|
||||||
|
|
||||||
|
// Initialize with an accessible.
|
||||||
|
AccEvent(uint32_t aEventType, Accessible* aAccessible,
|
||||||
|
EIsFromUserInput aIsFromUserInput = eAutoDetect,
|
||||||
|
EEventRule aEventRule = eRemoveDupes);
|
||||||
|
|
||||||
|
// AccEvent
|
||||||
|
uint32_t GetEventType() const { return mEventType; }
|
||||||
|
EEventRule GetEventRule() const { return mEventRule; }
|
||||||
|
bool IsFromUserInput() const { return mIsFromUserInput; }
|
||||||
|
EIsFromUserInput FromUserInput() const
|
||||||
|
{ return static_cast<EIsFromUserInput>(mIsFromUserInput); }
|
||||||
|
|
||||||
|
Accessible* GetAccessible() const { return mAccessible; }
|
||||||
|
DocAccessible* Document() const { return mAccessible->Document(); }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Down casting.
|
||||||
|
*/
|
||||||
|
enum EventGroup {
|
||||||
|
eGenericEvent,
|
||||||
|
eStateChangeEvent,
|
||||||
|
eTextChangeEvent,
|
||||||
|
eTreeMutationEvent,
|
||||||
|
eMutationEvent,
|
||||||
|
eReorderEvent,
|
||||||
|
eHideEvent,
|
||||||
|
eShowEvent,
|
||||||
|
eCaretMoveEvent,
|
||||||
|
eTextSelChangeEvent,
|
||||||
|
eSelectionChangeEvent,
|
||||||
|
eTableChangeEvent,
|
||||||
|
eVirtualCursorChangeEvent,
|
||||||
|
eObjectAttrChangedEvent
|
||||||
|
};
|
||||||
|
|
||||||
|
static const EventGroup kEventGroup = eGenericEvent;
|
||||||
|
virtual unsigned int GetEventGroups() const
|
||||||
|
{
|
||||||
|
return 1U << eGenericEvent;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reference counting and cycle collection.
|
||||||
|
*/
|
||||||
|
NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(AccEvent)
|
||||||
|
NS_DECL_CYCLE_COLLECTION_NATIVE_CLASS(AccEvent)
|
||||||
|
|
||||||
|
protected:
|
||||||
|
virtual ~AccEvent() {}
|
||||||
|
|
||||||
|
bool mIsFromUserInput;
|
||||||
|
uint32_t mEventType;
|
||||||
|
EEventRule mEventRule;
|
||||||
|
RefPtr<Accessible> mAccessible;
|
||||||
|
|
||||||
|
friend class EventQueue;
|
||||||
|
friend class EventTree;
|
||||||
|
friend class ::nsEventShell;
|
||||||
|
friend class NotificationController;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Accessible state change event.
|
||||||
|
*/
|
||||||
|
class AccStateChangeEvent: public AccEvent
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
AccStateChangeEvent(Accessible* aAccessible, uint64_t aState,
|
||||||
|
bool aIsEnabled,
|
||||||
|
EIsFromUserInput aIsFromUserInput = eAutoDetect) :
|
||||||
|
AccEvent(nsIAccessibleEvent::EVENT_STATE_CHANGE, aAccessible,
|
||||||
|
aIsFromUserInput, eCoalesceStateChange),
|
||||||
|
mState(aState), mIsEnabled(aIsEnabled) { }
|
||||||
|
|
||||||
|
AccStateChangeEvent(Accessible* aAccessible, uint64_t aState) :
|
||||||
|
AccEvent(::nsIAccessibleEvent::EVENT_STATE_CHANGE, aAccessible,
|
||||||
|
eAutoDetect, eCoalesceStateChange), mState(aState)
|
||||||
|
{ mIsEnabled = (mAccessible->State() & mState) != 0; }
|
||||||
|
|
||||||
|
// AccEvent
|
||||||
|
static const EventGroup kEventGroup = eStateChangeEvent;
|
||||||
|
virtual unsigned int GetEventGroups() const override
|
||||||
|
{
|
||||||
|
return AccEvent::GetEventGroups() | (1U << eStateChangeEvent);
|
||||||
|
}
|
||||||
|
|
||||||
|
// AccStateChangeEvent
|
||||||
|
uint64_t GetState() const { return mState; }
|
||||||
|
bool IsStateEnabled() const { return mIsEnabled; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
uint64_t mState;
|
||||||
|
bool mIsEnabled;
|
||||||
|
|
||||||
|
friend class EventQueue;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Accessible text change event.
|
||||||
|
*/
|
||||||
|
class AccTextChangeEvent: public AccEvent
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
AccTextChangeEvent(Accessible* aAccessible, int32_t aStart,
|
||||||
|
const nsAString& aModifiedText, bool aIsInserted,
|
||||||
|
EIsFromUserInput aIsFromUserInput = eAutoDetect);
|
||||||
|
|
||||||
|
// AccEvent
|
||||||
|
static const EventGroup kEventGroup = eTextChangeEvent;
|
||||||
|
virtual unsigned int GetEventGroups() const override
|
||||||
|
{
|
||||||
|
return AccEvent::GetEventGroups() | (1U << eTextChangeEvent);
|
||||||
|
}
|
||||||
|
|
||||||
|
// AccTextChangeEvent
|
||||||
|
int32_t GetStartOffset() const { return mStart; }
|
||||||
|
uint32_t GetLength() const { return mModifiedText.Length(); }
|
||||||
|
bool IsTextInserted() const { return mIsInserted; }
|
||||||
|
void GetModifiedText(nsAString& aModifiedText)
|
||||||
|
{ aModifiedText = mModifiedText; }
|
||||||
|
const nsString& ModifiedText() const { return mModifiedText; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
int32_t mStart;
|
||||||
|
bool mIsInserted;
|
||||||
|
nsString mModifiedText;
|
||||||
|
|
||||||
|
friend class EventTree;
|
||||||
|
friend class NotificationController;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A base class for events related to tree mutation, either an AccMutation
|
||||||
|
* event, or an AccReorderEvent.
|
||||||
|
*/
|
||||||
|
class AccTreeMutationEvent : public AccEvent
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
AccTreeMutationEvent(uint32_t aEventType, Accessible* aTarget) :
|
||||||
|
AccEvent(aEventType, aTarget, eAutoDetect, eCoalesceReorder), mGeneration(0) {}
|
||||||
|
|
||||||
|
// Event
|
||||||
|
static const EventGroup kEventGroup = eTreeMutationEvent;
|
||||||
|
virtual unsigned int GetEventGroups() const override
|
||||||
|
{
|
||||||
|
return AccEvent::GetEventGroups() | (1U << eTreeMutationEvent);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetNextEvent(AccTreeMutationEvent* aNext) { mNextEvent = aNext; }
|
||||||
|
void SetPrevEvent(AccTreeMutationEvent* aPrev) { mPrevEvent = aPrev; }
|
||||||
|
AccTreeMutationEvent* NextEvent() const { return mNextEvent; }
|
||||||
|
AccTreeMutationEvent* PrevEvent() const { return mPrevEvent; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A sequence number to know when this event was fired.
|
||||||
|
*/
|
||||||
|
uint32_t EventGeneration() const { return mGeneration; }
|
||||||
|
void SetEventGeneration(uint32_t aGeneration) { mGeneration = aGeneration; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
RefPtr<AccTreeMutationEvent> mNextEvent;
|
||||||
|
RefPtr<AccTreeMutationEvent> mPrevEvent;
|
||||||
|
uint32_t mGeneration;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Base class for show and hide accessible events.
|
||||||
|
*/
|
||||||
|
class AccMutationEvent: public AccTreeMutationEvent
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
AccMutationEvent(uint32_t aEventType, Accessible* aTarget) :
|
||||||
|
AccTreeMutationEvent(aEventType, aTarget)
|
||||||
|
{
|
||||||
|
// Don't coalesce these since they are coalesced by reorder event. Coalesce
|
||||||
|
// contained text change events.
|
||||||
|
mParent = mAccessible->Parent();
|
||||||
|
}
|
||||||
|
virtual ~AccMutationEvent() { }
|
||||||
|
|
||||||
|
// Event
|
||||||
|
static const EventGroup kEventGroup = eMutationEvent;
|
||||||
|
virtual unsigned int GetEventGroups() const override
|
||||||
|
{
|
||||||
|
return AccTreeMutationEvent::GetEventGroups() | (1U << eMutationEvent);
|
||||||
|
}
|
||||||
|
|
||||||
|
// MutationEvent
|
||||||
|
bool IsShow() const { return mEventType == nsIAccessibleEvent::EVENT_SHOW; }
|
||||||
|
bool IsHide() const { return mEventType == nsIAccessibleEvent::EVENT_HIDE; }
|
||||||
|
|
||||||
|
Accessible* Parent() const { return mParent; }
|
||||||
|
|
||||||
|
protected:
|
||||||
|
nsCOMPtr<nsINode> mNode;
|
||||||
|
RefPtr<Accessible> mParent;
|
||||||
|
RefPtr<AccTextChangeEvent> mTextChangeEvent;
|
||||||
|
|
||||||
|
friend class EventTree;
|
||||||
|
friend class NotificationController;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Accessible hide event.
|
||||||
|
*/
|
||||||
|
class AccHideEvent: public AccMutationEvent
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
explicit AccHideEvent(Accessible* aTarget, bool aNeedsShutdown = true);
|
||||||
|
|
||||||
|
// Event
|
||||||
|
static const EventGroup kEventGroup = eHideEvent;
|
||||||
|
virtual unsigned int GetEventGroups() const override
|
||||||
|
{
|
||||||
|
return AccMutationEvent::GetEventGroups() | (1U << eHideEvent);
|
||||||
|
}
|
||||||
|
|
||||||
|
// AccHideEvent
|
||||||
|
Accessible* TargetParent() const { return mParent; }
|
||||||
|
Accessible* TargetNextSibling() const { return mNextSibling; }
|
||||||
|
Accessible* TargetPrevSibling() const { return mPrevSibling; }
|
||||||
|
bool NeedsShutdown() const { return mNeedsShutdown; }
|
||||||
|
|
||||||
|
protected:
|
||||||
|
bool mNeedsShutdown;
|
||||||
|
RefPtr<Accessible> mNextSibling;
|
||||||
|
RefPtr<Accessible> mPrevSibling;
|
||||||
|
|
||||||
|
friend class EventTree;
|
||||||
|
friend class NotificationController;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Accessible show event.
|
||||||
|
*/
|
||||||
|
class AccShowEvent: public AccMutationEvent
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
explicit AccShowEvent(Accessible* aTarget);
|
||||||
|
|
||||||
|
// Event
|
||||||
|
static const EventGroup kEventGroup = eShowEvent;
|
||||||
|
virtual unsigned int GetEventGroups() const override
|
||||||
|
{
|
||||||
|
return AccMutationEvent::GetEventGroups() | (1U << eShowEvent);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t InsertionIndex() const { return mInsertionIndex; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
nsTArray<RefPtr<AccHideEvent>> mPrecedingEvents;
|
||||||
|
uint32_t mInsertionIndex;
|
||||||
|
|
||||||
|
friend class EventTree;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class for reorder accessible event. Takes care about
|
||||||
|
*/
|
||||||
|
class AccReorderEvent : public AccTreeMutationEvent
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
explicit AccReorderEvent(Accessible* aTarget) :
|
||||||
|
AccTreeMutationEvent(::nsIAccessibleEvent::EVENT_REORDER, aTarget) { }
|
||||||
|
virtual ~AccReorderEvent() { }
|
||||||
|
|
||||||
|
// Event
|
||||||
|
static const EventGroup kEventGroup = eReorderEvent;
|
||||||
|
virtual unsigned int GetEventGroups() const override
|
||||||
|
{
|
||||||
|
return AccTreeMutationEvent::GetEventGroups() | (1U << eReorderEvent);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Accessible caret move event.
|
||||||
|
*/
|
||||||
|
class AccCaretMoveEvent: public AccEvent
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
AccCaretMoveEvent(Accessible* aAccessible, int32_t aCaretOffset,
|
||||||
|
EIsFromUserInput aIsFromUserInput = eAutoDetect) :
|
||||||
|
AccEvent(::nsIAccessibleEvent::EVENT_TEXT_CARET_MOVED, aAccessible,
|
||||||
|
aIsFromUserInput),
|
||||||
|
mCaretOffset(aCaretOffset) { }
|
||||||
|
virtual ~AccCaretMoveEvent() { }
|
||||||
|
|
||||||
|
// AccEvent
|
||||||
|
static const EventGroup kEventGroup = eCaretMoveEvent;
|
||||||
|
virtual unsigned int GetEventGroups() const override
|
||||||
|
{
|
||||||
|
return AccEvent::GetEventGroups() | (1U << eCaretMoveEvent);
|
||||||
|
}
|
||||||
|
|
||||||
|
// AccCaretMoveEvent
|
||||||
|
int32_t GetCaretOffset() const { return mCaretOffset; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
int32_t mCaretOffset;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Accessible text selection change event.
|
||||||
|
*/
|
||||||
|
class AccTextSelChangeEvent : public AccEvent
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
AccTextSelChangeEvent(HyperTextAccessible* aTarget,
|
||||||
|
dom::Selection* aSelection,
|
||||||
|
int32_t aReason);
|
||||||
|
virtual ~AccTextSelChangeEvent();
|
||||||
|
|
||||||
|
// AccEvent
|
||||||
|
static const EventGroup kEventGroup = eTextSelChangeEvent;
|
||||||
|
virtual unsigned int GetEventGroups() const override
|
||||||
|
{
|
||||||
|
return AccEvent::GetEventGroups() | (1U << eTextSelChangeEvent);
|
||||||
|
}
|
||||||
|
|
||||||
|
// AccTextSelChangeEvent
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return true if the text selection change wasn't caused by pure caret move.
|
||||||
|
*/
|
||||||
|
bool IsCaretMoveOnly() const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
RefPtr<dom::Selection> mSel;
|
||||||
|
int32_t mReason;
|
||||||
|
|
||||||
|
friend class EventQueue;
|
||||||
|
friend class SelectionManager;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Accessible widget selection change event.
|
||||||
|
*/
|
||||||
|
class AccSelChangeEvent : public AccEvent
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
enum SelChangeType {
|
||||||
|
eSelectionAdd,
|
||||||
|
eSelectionRemove
|
||||||
|
};
|
||||||
|
|
||||||
|
AccSelChangeEvent(Accessible* aWidget, Accessible* aItem,
|
||||||
|
SelChangeType aSelChangeType);
|
||||||
|
|
||||||
|
virtual ~AccSelChangeEvent() { }
|
||||||
|
|
||||||
|
// AccEvent
|
||||||
|
static const EventGroup kEventGroup = eSelectionChangeEvent;
|
||||||
|
virtual unsigned int GetEventGroups() const override
|
||||||
|
{
|
||||||
|
return AccEvent::GetEventGroups() | (1U << eSelectionChangeEvent);
|
||||||
|
}
|
||||||
|
|
||||||
|
// AccSelChangeEvent
|
||||||
|
Accessible* Widget() const { return mWidget; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
RefPtr<Accessible> mWidget;
|
||||||
|
RefPtr<Accessible> mItem;
|
||||||
|
SelChangeType mSelChangeType;
|
||||||
|
uint32_t mPreceedingCount;
|
||||||
|
AccSelChangeEvent* mPackedEvent;
|
||||||
|
|
||||||
|
friend class EventQueue;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Accessible table change event.
|
||||||
|
*/
|
||||||
|
class AccTableChangeEvent : public AccEvent
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
AccTableChangeEvent(Accessible* aAccessible, uint32_t aEventType,
|
||||||
|
int32_t aRowOrColIndex, int32_t aNumRowsOrCols);
|
||||||
|
|
||||||
|
// AccEvent
|
||||||
|
static const EventGroup kEventGroup = eTableChangeEvent;
|
||||||
|
virtual unsigned int GetEventGroups() const override
|
||||||
|
{
|
||||||
|
return AccEvent::GetEventGroups() | (1U << eTableChangeEvent);
|
||||||
|
}
|
||||||
|
|
||||||
|
// AccTableChangeEvent
|
||||||
|
uint32_t GetIndex() const { return mRowOrColIndex; }
|
||||||
|
uint32_t GetCount() const { return mNumRowsOrCols; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
uint32_t mRowOrColIndex; // the start row/column after which the rows are inserted/deleted.
|
||||||
|
uint32_t mNumRowsOrCols; // the number of inserted/deleted rows/columns
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Accessible virtual cursor change event.
|
||||||
|
*/
|
||||||
|
class AccVCChangeEvent : public AccEvent
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
AccVCChangeEvent(Accessible* aAccessible,
|
||||||
|
Accessible* aOldAccessible,
|
||||||
|
int32_t aOldStart, int32_t aOldEnd,
|
||||||
|
int16_t aReason,
|
||||||
|
EIsFromUserInput aIsFromUserInput = eFromUserInput);
|
||||||
|
|
||||||
|
virtual ~AccVCChangeEvent() { }
|
||||||
|
|
||||||
|
// AccEvent
|
||||||
|
static const EventGroup kEventGroup = eVirtualCursorChangeEvent;
|
||||||
|
virtual unsigned int GetEventGroups() const override
|
||||||
|
{
|
||||||
|
return AccEvent::GetEventGroups() | (1U << eVirtualCursorChangeEvent);
|
||||||
|
}
|
||||||
|
|
||||||
|
// AccTableChangeEvent
|
||||||
|
Accessible* OldAccessible() const { return mOldAccessible; }
|
||||||
|
int32_t OldStartOffset() const { return mOldStart; }
|
||||||
|
int32_t OldEndOffset() const { return mOldEnd; }
|
||||||
|
int32_t Reason() const { return mReason; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
RefPtr<Accessible> mOldAccessible;
|
||||||
|
int32_t mOldStart;
|
||||||
|
int32_t mOldEnd;
|
||||||
|
int16_t mReason;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Accessible object attribute changed event.
|
||||||
|
*/
|
||||||
|
class AccObjectAttrChangedEvent: public AccEvent
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
AccObjectAttrChangedEvent(Accessible* aAccessible, nsIAtom* aAttribute) :
|
||||||
|
AccEvent(::nsIAccessibleEvent::EVENT_OBJECT_ATTRIBUTE_CHANGED, aAccessible),
|
||||||
|
mAttribute(aAttribute) { }
|
||||||
|
|
||||||
|
// AccEvent
|
||||||
|
static const EventGroup kEventGroup = eObjectAttrChangedEvent;
|
||||||
|
virtual unsigned int GetEventGroups() const override
|
||||||
|
{
|
||||||
|
return AccEvent::GetEventGroups() | (1U << eObjectAttrChangedEvent);
|
||||||
|
}
|
||||||
|
|
||||||
|
// AccObjectAttrChangedEvent
|
||||||
|
nsIAtom* GetAttribute() const { return mAttribute; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
nsCOMPtr<nsIAtom> mAttribute;
|
||||||
|
|
||||||
|
virtual ~AccObjectAttrChangedEvent() { }
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Downcast the generic accessible event object to derived type.
|
||||||
|
*/
|
||||||
|
class downcast_accEvent
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
explicit downcast_accEvent(AccEvent* e) : mRawPtr(e) { }
|
||||||
|
|
||||||
|
template<class Destination>
|
||||||
|
operator Destination*() {
|
||||||
|
if (!mRawPtr)
|
||||||
|
return nullptr;
|
||||||
|
|
||||||
|
return mRawPtr->GetEventGroups() & (1U << Destination::kEventGroup) ?
|
||||||
|
static_cast<Destination*>(mRawPtr) : nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
AccEvent* mRawPtr;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return a new xpcom accessible event for the given internal one.
|
||||||
|
*/
|
||||||
|
already_AddRefed<nsIAccessibleEvent>
|
||||||
|
MakeXPCEvent(AccEvent* aEvent);
|
||||||
|
|
||||||
|
} // namespace a11y
|
||||||
|
} // namespace mozilla
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
227
accessible/base/AccGroupInfo.cpp
Normal file
227
accessible/base/AccGroupInfo.cpp
Normal file
|
|
@ -0,0 +1,227 @@
|
||||||
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
|
#include "AccGroupInfo.h"
|
||||||
|
#include "nsAccUtils.h"
|
||||||
|
|
||||||
|
#include "Role.h"
|
||||||
|
#include "States.h"
|
||||||
|
|
||||||
|
using namespace mozilla::a11y;
|
||||||
|
|
||||||
|
AccGroupInfo::AccGroupInfo(Accessible* aItem, role aRole) :
|
||||||
|
mPosInSet(0), mSetSize(0), mParent(nullptr), mItem(aItem), mRole(aRole)
|
||||||
|
{
|
||||||
|
MOZ_COUNT_CTOR(AccGroupInfo);
|
||||||
|
Update();
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
AccGroupInfo::Update()
|
||||||
|
{
|
||||||
|
Accessible* parent = mItem->Parent();
|
||||||
|
if (!parent)
|
||||||
|
return;
|
||||||
|
|
||||||
|
int32_t indexInParent = mItem->IndexInParent();
|
||||||
|
uint32_t siblingCount = parent->ChildCount();
|
||||||
|
if (indexInParent == -1 ||
|
||||||
|
indexInParent >= static_cast<int32_t>(siblingCount)) {
|
||||||
|
NS_ERROR("Wrong index in parent! Tree invalidation problem.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
int32_t level = nsAccUtils::GetARIAOrDefaultLevel(mItem);
|
||||||
|
|
||||||
|
// Compute position in set.
|
||||||
|
mPosInSet = 1;
|
||||||
|
for (int32_t idx = indexInParent - 1; idx >= 0 ; idx--) {
|
||||||
|
Accessible* sibling = parent->GetChildAt(idx);
|
||||||
|
roles::Role siblingRole = sibling->Role();
|
||||||
|
|
||||||
|
// If the sibling is separator then the group is ended.
|
||||||
|
if (siblingRole == roles::SEPARATOR)
|
||||||
|
break;
|
||||||
|
|
||||||
|
// If sibling is not visible and hasn't the same base role.
|
||||||
|
if (BaseRole(siblingRole) != mRole || sibling->State() & states::INVISIBLE)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// Check if it's hierarchical flatten structure, i.e. if the sibling
|
||||||
|
// level is lesser than this one then group is ended, if the sibling level
|
||||||
|
// is greater than this one then the group is split by some child elements
|
||||||
|
// (group will be continued).
|
||||||
|
int32_t siblingLevel = nsAccUtils::GetARIAOrDefaultLevel(sibling);
|
||||||
|
if (siblingLevel < level) {
|
||||||
|
mParent = sibling;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Skip subset.
|
||||||
|
if (siblingLevel > level)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// If the previous item in the group has calculated group information then
|
||||||
|
// build group information for this item based on found one.
|
||||||
|
if (sibling->mBits.groupInfo) {
|
||||||
|
mPosInSet += sibling->mBits.groupInfo->mPosInSet;
|
||||||
|
mParent = sibling->mBits.groupInfo->mParent;
|
||||||
|
mSetSize = sibling->mBits.groupInfo->mSetSize;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
mPosInSet++;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Compute set size.
|
||||||
|
mSetSize = mPosInSet;
|
||||||
|
|
||||||
|
for (uint32_t idx = indexInParent + 1; idx < siblingCount; idx++) {
|
||||||
|
Accessible* sibling = parent->GetChildAt(idx);
|
||||||
|
|
||||||
|
roles::Role siblingRole = sibling->Role();
|
||||||
|
|
||||||
|
// If the sibling is separator then the group is ended.
|
||||||
|
if (siblingRole == roles::SEPARATOR)
|
||||||
|
break;
|
||||||
|
|
||||||
|
// If sibling is visible and has the same base role
|
||||||
|
if (BaseRole(siblingRole) != mRole || sibling->State() & states::INVISIBLE)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// and check if it's hierarchical flatten structure.
|
||||||
|
int32_t siblingLevel = nsAccUtils::GetARIAOrDefaultLevel(sibling);
|
||||||
|
if (siblingLevel < level)
|
||||||
|
break;
|
||||||
|
|
||||||
|
// Skip subset.
|
||||||
|
if (siblingLevel > level)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// If the next item in the group has calculated group information then
|
||||||
|
// build group information for this item based on found one.
|
||||||
|
if (sibling->mBits.groupInfo) {
|
||||||
|
mParent = sibling->mBits.groupInfo->mParent;
|
||||||
|
mSetSize = sibling->mBits.groupInfo->mSetSize;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
mSetSize++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mParent)
|
||||||
|
return;
|
||||||
|
|
||||||
|
roles::Role parentRole = parent->Role();
|
||||||
|
if (ShouldReportRelations(mRole, parentRole))
|
||||||
|
mParent = parent;
|
||||||
|
|
||||||
|
// ARIA tree and list can be arranged by using ARIA groups to organize levels.
|
||||||
|
if (parentRole != roles::GROUPING)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// Way #1 for ARIA tree (not ARIA treegrid): previous sibling of a group is a
|
||||||
|
// parent. In other words the parent of the tree item will be a group and
|
||||||
|
// the previous tree item of the group is a conceptual parent of the tree
|
||||||
|
// item.
|
||||||
|
if (mRole == roles::OUTLINEITEM) {
|
||||||
|
Accessible* parentPrevSibling = parent->PrevSibling();
|
||||||
|
if (parentPrevSibling && parentPrevSibling->Role() == mRole) {
|
||||||
|
mParent = parentPrevSibling;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Way #2 for ARIA list and tree: group is a child of an item. In other words
|
||||||
|
// the parent of the item will be a group and containing item of the group is
|
||||||
|
// a conceptual parent of the item.
|
||||||
|
if (mRole == roles::LISTITEM || mRole == roles::OUTLINEITEM) {
|
||||||
|
Accessible* grandParent = parent->Parent();
|
||||||
|
if (grandParent && grandParent->Role() == mRole)
|
||||||
|
mParent = grandParent;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Accessible*
|
||||||
|
AccGroupInfo::FirstItemOf(Accessible* aContainer)
|
||||||
|
{
|
||||||
|
// ARIA tree can be arranged by ARIA groups case #1 (previous sibling of a
|
||||||
|
// group is a parent) or by aria-level.
|
||||||
|
a11y::role containerRole = aContainer->Role();
|
||||||
|
Accessible* item = aContainer->NextSibling();
|
||||||
|
if (item) {
|
||||||
|
if (containerRole == roles::OUTLINEITEM && item->Role() == roles::GROUPING)
|
||||||
|
item = item->FirstChild();
|
||||||
|
|
||||||
|
if (item) {
|
||||||
|
AccGroupInfo* itemGroupInfo = item->GetGroupInfo();
|
||||||
|
if (itemGroupInfo && itemGroupInfo->ConceptualParent() == aContainer)
|
||||||
|
return item;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ARIA list and tree can be arranged by ARIA groups case #2 (group is
|
||||||
|
// a child of an item).
|
||||||
|
item = aContainer->LastChild();
|
||||||
|
if (!item)
|
||||||
|
return nullptr;
|
||||||
|
|
||||||
|
if (item->Role() == roles::GROUPING &&
|
||||||
|
(containerRole == roles::LISTITEM || containerRole == roles::OUTLINEITEM)) {
|
||||||
|
item = item->FirstChild();
|
||||||
|
if (item) {
|
||||||
|
AccGroupInfo* itemGroupInfo = item->GetGroupInfo();
|
||||||
|
if (itemGroupInfo && itemGroupInfo->ConceptualParent() == aContainer)
|
||||||
|
return item;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Otherwise, it can be a direct child if the container is a list or tree.
|
||||||
|
item = aContainer->FirstChild();
|
||||||
|
if (ShouldReportRelations(item->Role(), containerRole))
|
||||||
|
return item;
|
||||||
|
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
Accessible*
|
||||||
|
AccGroupInfo::NextItemTo(Accessible* aItem)
|
||||||
|
{
|
||||||
|
AccGroupInfo* groupInfo = aItem->GetGroupInfo();
|
||||||
|
if (!groupInfo)
|
||||||
|
return nullptr;
|
||||||
|
|
||||||
|
// If the item in middle of the group then search next item in siblings.
|
||||||
|
if (groupInfo->PosInSet() >= groupInfo->SetSize())
|
||||||
|
return nullptr;
|
||||||
|
|
||||||
|
Accessible* parent = aItem->Parent();
|
||||||
|
uint32_t childCount = parent->ChildCount();
|
||||||
|
for (uint32_t idx = aItem->IndexInParent() + 1; idx < childCount; idx++) {
|
||||||
|
Accessible* nextItem = parent->GetChildAt(idx);
|
||||||
|
AccGroupInfo* nextGroupInfo = nextItem->GetGroupInfo();
|
||||||
|
if (nextGroupInfo &&
|
||||||
|
nextGroupInfo->ConceptualParent() == groupInfo->ConceptualParent()) {
|
||||||
|
return nextItem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
NS_NOTREACHED("Item in the middle of the group but there's no next item!");
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
AccGroupInfo::ShouldReportRelations(role aRole, role aParentRole)
|
||||||
|
{
|
||||||
|
// We only want to report hierarchy-based node relations for items in tree or
|
||||||
|
// list form. ARIA level/owns relations are always reported.
|
||||||
|
if (aParentRole == roles::OUTLINE && aRole == roles::OUTLINEITEM)
|
||||||
|
return true;
|
||||||
|
if (aParentRole == roles::TREE_TABLE && aRole == roles::ROW)
|
||||||
|
return true;
|
||||||
|
if (aParentRole == roles::LIST && aRole == roles::LISTITEM)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
114
accessible/base/AccGroupInfo.h
Normal file
114
accessible/base/AccGroupInfo.h
Normal file
|
|
@ -0,0 +1,114 @@
|
||||||
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
|
#ifndef AccGroupInfo_h_
|
||||||
|
#define AccGroupInfo_h_
|
||||||
|
|
||||||
|
#include "Accessible-inl.h"
|
||||||
|
|
||||||
|
namespace mozilla {
|
||||||
|
namespace a11y {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calculate and store group information.
|
||||||
|
*/
|
||||||
|
class AccGroupInfo
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
~AccGroupInfo() { MOZ_COUNT_DTOR(AccGroupInfo); }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return 1-based position in the group.
|
||||||
|
*/
|
||||||
|
uint32_t PosInSet() const { return mPosInSet; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return a number of items in the group.
|
||||||
|
*/
|
||||||
|
uint32_t SetSize() const { return mSetSize; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return a direct or logical parent of the accessible that this group info is
|
||||||
|
* created for.
|
||||||
|
*/
|
||||||
|
Accessible* ConceptualParent() const { return mParent; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update group information.
|
||||||
|
*/
|
||||||
|
void Update();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create group info.
|
||||||
|
*/
|
||||||
|
static AccGroupInfo* CreateGroupInfo(Accessible* aAccessible)
|
||||||
|
{
|
||||||
|
mozilla::a11y::role role = aAccessible->Role();
|
||||||
|
if (role != mozilla::a11y::roles::ROW &&
|
||||||
|
role != mozilla::a11y::roles::OUTLINEITEM &&
|
||||||
|
role != mozilla::a11y::roles::OPTION &&
|
||||||
|
role != mozilla::a11y::roles::LISTITEM &&
|
||||||
|
role != mozilla::a11y::roles::MENUITEM &&
|
||||||
|
role != mozilla::a11y::roles::COMBOBOX_OPTION &&
|
||||||
|
role != mozilla::a11y::roles::RICH_OPTION &&
|
||||||
|
role != mozilla::a11y::roles::CHECK_RICH_OPTION &&
|
||||||
|
role != mozilla::a11y::roles::PARENT_MENUITEM &&
|
||||||
|
role != mozilla::a11y::roles::CHECK_MENU_ITEM &&
|
||||||
|
role != mozilla::a11y::roles::RADIO_MENU_ITEM &&
|
||||||
|
role != mozilla::a11y::roles::RADIOBUTTON &&
|
||||||
|
role != mozilla::a11y::roles::PAGETAB)
|
||||||
|
return nullptr;
|
||||||
|
|
||||||
|
AccGroupInfo* info = new AccGroupInfo(aAccessible, BaseRole(role));
|
||||||
|
return info;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return a first item for the given container.
|
||||||
|
*/
|
||||||
|
static Accessible* FirstItemOf(Accessible* aContainer);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return next item of the same group to the given item.
|
||||||
|
*/
|
||||||
|
static Accessible* NextItemTo(Accessible* aItem);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
AccGroupInfo(Accessible* aItem, a11y::role aRole);
|
||||||
|
|
||||||
|
private:
|
||||||
|
AccGroupInfo() = delete;
|
||||||
|
AccGroupInfo(const AccGroupInfo&) = delete;
|
||||||
|
AccGroupInfo& operator =(const AccGroupInfo&) = delete;
|
||||||
|
|
||||||
|
static mozilla::a11y::role BaseRole(mozilla::a11y::role aRole)
|
||||||
|
{
|
||||||
|
if (aRole == mozilla::a11y::roles::CHECK_MENU_ITEM ||
|
||||||
|
aRole == mozilla::a11y::roles::PARENT_MENUITEM ||
|
||||||
|
aRole == mozilla::a11y::roles::RADIO_MENU_ITEM)
|
||||||
|
return mozilla::a11y::roles::MENUITEM;
|
||||||
|
|
||||||
|
if (aRole == mozilla::a11y::roles::CHECK_RICH_OPTION)
|
||||||
|
return mozilla::a11y::roles::RICH_OPTION;
|
||||||
|
|
||||||
|
return aRole;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return true if the given parent and child roles should have their node
|
||||||
|
* relations reported.
|
||||||
|
*/
|
||||||
|
static bool ShouldReportRelations(a11y::role aRole, a11y::role aParentRole);
|
||||||
|
|
||||||
|
uint32_t mPosInSet;
|
||||||
|
uint32_t mSetSize;
|
||||||
|
Accessible* mParent;
|
||||||
|
Accessible* mItem;
|
||||||
|
a11y::role mRole;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace mozilla
|
||||||
|
} // namespace a11y
|
||||||
|
|
||||||
|
#endif
|
||||||
414
accessible/base/AccIterator.cpp
Normal file
414
accessible/base/AccIterator.cpp
Normal file
|
|
@ -0,0 +1,414 @@
|
||||||
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
|
#include "AccIterator.h"
|
||||||
|
|
||||||
|
#include "AccGroupInfo.h"
|
||||||
|
#ifdef MOZ_XUL
|
||||||
|
#include "XULTreeAccessible.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "mozilla/dom/HTMLLabelElement.h"
|
||||||
|
|
||||||
|
using namespace mozilla;
|
||||||
|
using namespace mozilla::a11y;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// AccIterator
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
AccIterator::AccIterator(Accessible* aAccessible,
|
||||||
|
filters::FilterFuncPtr aFilterFunc) :
|
||||||
|
mFilterFunc(aFilterFunc)
|
||||||
|
{
|
||||||
|
mState = new IteratorState(aAccessible);
|
||||||
|
}
|
||||||
|
|
||||||
|
AccIterator::~AccIterator()
|
||||||
|
{
|
||||||
|
while (mState) {
|
||||||
|
IteratorState *tmp = mState;
|
||||||
|
mState = tmp->mParentState;
|
||||||
|
delete tmp;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Accessible*
|
||||||
|
AccIterator::Next()
|
||||||
|
{
|
||||||
|
while (mState) {
|
||||||
|
Accessible* child = mState->mParent->GetChildAt(mState->mIndex++);
|
||||||
|
if (!child) {
|
||||||
|
IteratorState* tmp = mState;
|
||||||
|
mState = mState->mParentState;
|
||||||
|
delete tmp;
|
||||||
|
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t result = mFilterFunc(child);
|
||||||
|
if (result & filters::eMatch)
|
||||||
|
return child;
|
||||||
|
|
||||||
|
if (!(result & filters::eSkipSubtree)) {
|
||||||
|
IteratorState* childState = new IteratorState(child, mState);
|
||||||
|
mState = childState;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// nsAccIterator::IteratorState
|
||||||
|
|
||||||
|
AccIterator::IteratorState::IteratorState(Accessible* aParent,
|
||||||
|
IteratorState *mParentState) :
|
||||||
|
mParent(aParent), mIndex(0), mParentState(mParentState)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// RelatedAccIterator
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
RelatedAccIterator::
|
||||||
|
RelatedAccIterator(DocAccessible* aDocument, nsIContent* aDependentContent,
|
||||||
|
nsIAtom* aRelAttr) :
|
||||||
|
mDocument(aDocument), mRelAttr(aRelAttr), mProviders(nullptr),
|
||||||
|
mBindingParent(nullptr), mIndex(0)
|
||||||
|
{
|
||||||
|
mBindingParent = aDependentContent->GetBindingParent();
|
||||||
|
nsIAtom* IDAttr = mBindingParent ?
|
||||||
|
nsGkAtoms::anonid : nsGkAtoms::id;
|
||||||
|
|
||||||
|
nsAutoString id;
|
||||||
|
if (aDependentContent->GetAttr(kNameSpaceID_None, IDAttr, id))
|
||||||
|
mProviders = mDocument->mDependentIDsHash.Get(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
Accessible*
|
||||||
|
RelatedAccIterator::Next()
|
||||||
|
{
|
||||||
|
if (!mProviders)
|
||||||
|
return nullptr;
|
||||||
|
|
||||||
|
while (mIndex < mProviders->Length()) {
|
||||||
|
DocAccessible::AttrRelProvider* provider = (*mProviders)[mIndex++];
|
||||||
|
|
||||||
|
// Return related accessible for the given attribute and if the provider
|
||||||
|
// content is in the same binding in the case of XBL usage.
|
||||||
|
if (provider->mRelAttr == mRelAttr) {
|
||||||
|
nsIContent* bindingParent = provider->mContent->GetBindingParent();
|
||||||
|
bool inScope = mBindingParent == bindingParent ||
|
||||||
|
mBindingParent == provider->mContent;
|
||||||
|
|
||||||
|
if (inScope) {
|
||||||
|
Accessible* related = mDocument->GetAccessible(provider->mContent);
|
||||||
|
if (related)
|
||||||
|
return related;
|
||||||
|
|
||||||
|
// If the document content is pointed by relation then return the document
|
||||||
|
// itself.
|
||||||
|
if (provider->mContent == mDocument->GetContent())
|
||||||
|
return mDocument;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// HTMLLabelIterator
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
HTMLLabelIterator::
|
||||||
|
HTMLLabelIterator(DocAccessible* aDocument, const Accessible* aAccessible,
|
||||||
|
LabelFilter aFilter) :
|
||||||
|
mRelIter(aDocument, aAccessible->GetContent(), nsGkAtoms::_for),
|
||||||
|
mAcc(aAccessible), mLabelFilter(aFilter)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
HTMLLabelIterator::IsLabel(Accessible* aLabel)
|
||||||
|
{
|
||||||
|
dom::HTMLLabelElement* labelEl =
|
||||||
|
dom::HTMLLabelElement::FromContent(aLabel->GetContent());
|
||||||
|
return labelEl && labelEl->GetControl() == mAcc->GetContent();
|
||||||
|
}
|
||||||
|
|
||||||
|
Accessible*
|
||||||
|
HTMLLabelIterator::Next()
|
||||||
|
{
|
||||||
|
// Get either <label for="[id]"> element which explicitly points to given
|
||||||
|
// element, or <label> ancestor which implicitly point to it.
|
||||||
|
Accessible* label = nullptr;
|
||||||
|
while ((label = mRelIter.Next())) {
|
||||||
|
if (IsLabel(label)) {
|
||||||
|
return label;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ignore ancestor label on not widget accessible.
|
||||||
|
if (mLabelFilter == eSkipAncestorLabel || !mAcc->IsWidget())
|
||||||
|
return nullptr;
|
||||||
|
|
||||||
|
// Go up tree to get a name of ancestor label if there is one (an ancestor
|
||||||
|
// <label> implicitly points to us). Don't go up farther than form or
|
||||||
|
// document.
|
||||||
|
Accessible* walkUp = mAcc->Parent();
|
||||||
|
while (walkUp && !walkUp->IsDoc()) {
|
||||||
|
nsIContent* walkUpEl = walkUp->GetContent();
|
||||||
|
if (IsLabel(walkUp) &&
|
||||||
|
!walkUpEl->HasAttr(kNameSpaceID_None, nsGkAtoms::_for)) {
|
||||||
|
mLabelFilter = eSkipAncestorLabel; // prevent infinite loop
|
||||||
|
return walkUp;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (walkUpEl->IsHTMLElement(nsGkAtoms::form))
|
||||||
|
break;
|
||||||
|
|
||||||
|
walkUp = walkUp->Parent();
|
||||||
|
}
|
||||||
|
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// HTMLOutputIterator
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
HTMLOutputIterator::
|
||||||
|
HTMLOutputIterator(DocAccessible* aDocument, nsIContent* aElement) :
|
||||||
|
mRelIter(aDocument, aElement, nsGkAtoms::_for)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
Accessible*
|
||||||
|
HTMLOutputIterator::Next()
|
||||||
|
{
|
||||||
|
Accessible* output = nullptr;
|
||||||
|
while ((output = mRelIter.Next())) {
|
||||||
|
if (output->GetContent()->IsHTMLElement(nsGkAtoms::output))
|
||||||
|
return output;
|
||||||
|
}
|
||||||
|
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// XULLabelIterator
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
XULLabelIterator::
|
||||||
|
XULLabelIterator(DocAccessible* aDocument, nsIContent* aElement) :
|
||||||
|
mRelIter(aDocument, aElement, nsGkAtoms::control)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
Accessible*
|
||||||
|
XULLabelIterator::Next()
|
||||||
|
{
|
||||||
|
Accessible* label = nullptr;
|
||||||
|
while ((label = mRelIter.Next())) {
|
||||||
|
if (label->GetContent()->IsXULElement(nsGkAtoms::label))
|
||||||
|
return label;
|
||||||
|
}
|
||||||
|
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// XULDescriptionIterator
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
XULDescriptionIterator::
|
||||||
|
XULDescriptionIterator(DocAccessible* aDocument, nsIContent* aElement) :
|
||||||
|
mRelIter(aDocument, aElement, nsGkAtoms::control)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
Accessible*
|
||||||
|
XULDescriptionIterator::Next()
|
||||||
|
{
|
||||||
|
Accessible* descr = nullptr;
|
||||||
|
while ((descr = mRelIter.Next())) {
|
||||||
|
if (descr->GetContent()->IsXULElement(nsGkAtoms::description))
|
||||||
|
return descr;
|
||||||
|
}
|
||||||
|
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// IDRefsIterator
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
IDRefsIterator::
|
||||||
|
IDRefsIterator(DocAccessible* aDoc, nsIContent* aContent,
|
||||||
|
nsIAtom* aIDRefsAttr) :
|
||||||
|
mContent(aContent), mDoc(aDoc), mCurrIdx(0)
|
||||||
|
{
|
||||||
|
if (mContent->IsInUncomposedDoc())
|
||||||
|
mContent->GetAttr(kNameSpaceID_None, aIDRefsAttr, mIDs);
|
||||||
|
}
|
||||||
|
|
||||||
|
const nsDependentSubstring
|
||||||
|
IDRefsIterator::NextID()
|
||||||
|
{
|
||||||
|
for (; mCurrIdx < mIDs.Length(); mCurrIdx++) {
|
||||||
|
if (!NS_IsAsciiWhitespace(mIDs[mCurrIdx]))
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mCurrIdx >= mIDs.Length())
|
||||||
|
return nsDependentSubstring();
|
||||||
|
|
||||||
|
nsAString::index_type idStartIdx = mCurrIdx;
|
||||||
|
while (++mCurrIdx < mIDs.Length()) {
|
||||||
|
if (NS_IsAsciiWhitespace(mIDs[mCurrIdx]))
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return Substring(mIDs, idStartIdx, mCurrIdx++ - idStartIdx);
|
||||||
|
}
|
||||||
|
|
||||||
|
nsIContent*
|
||||||
|
IDRefsIterator::NextElem()
|
||||||
|
{
|
||||||
|
while (true) {
|
||||||
|
const nsDependentSubstring id = NextID();
|
||||||
|
if (id.IsEmpty())
|
||||||
|
break;
|
||||||
|
|
||||||
|
nsIContent* refContent = GetElem(id);
|
||||||
|
if (refContent)
|
||||||
|
return refContent;
|
||||||
|
}
|
||||||
|
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
nsIContent*
|
||||||
|
IDRefsIterator::GetElem(const nsDependentSubstring& aID)
|
||||||
|
{
|
||||||
|
// Get elements in DOM tree by ID attribute if this is an explicit content.
|
||||||
|
// In case of bound element check its anonymous subtree.
|
||||||
|
if (!mContent->IsInAnonymousSubtree()) {
|
||||||
|
dom::Element* refElm = mContent->OwnerDoc()->GetElementById(aID);
|
||||||
|
if (refElm || !mContent->GetXBLBinding())
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
Accessible*
|
||||||
|
IDRefsIterator::Next()
|
||||||
|
{
|
||||||
|
nsIContent* nextEl = nullptr;
|
||||||
|
while ((nextEl = NextElem())) {
|
||||||
|
Accessible* acc = mDoc->GetAccessible(nextEl);
|
||||||
|
if (acc) {
|
||||||
|
return acc;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// SingleAccIterator
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
Accessible*
|
||||||
|
SingleAccIterator::Next()
|
||||||
|
{
|
||||||
|
RefPtr<Accessible> nextAcc;
|
||||||
|
mAcc.swap(nextAcc);
|
||||||
|
if (!nextAcc || nextAcc->IsDefunct()) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
return nextAcc;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// ItemIterator
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
Accessible*
|
||||||
|
ItemIterator::Next()
|
||||||
|
{
|
||||||
|
if (mContainer) {
|
||||||
|
mAnchor = AccGroupInfo::FirstItemOf(mContainer);
|
||||||
|
mContainer = nullptr;
|
||||||
|
return mAnchor;
|
||||||
|
}
|
||||||
|
|
||||||
|
return mAnchor ? (mAnchor = AccGroupInfo::NextItemTo(mAnchor)) : nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// XULTreeItemIterator
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
XULTreeItemIterator::XULTreeItemIterator(XULTreeAccessible* aXULTree,
|
||||||
|
nsITreeView* aTreeView,
|
||||||
|
int32_t aRowIdx) :
|
||||||
|
mXULTree(aXULTree), mTreeView(aTreeView), mRowCount(-1),
|
||||||
|
mContainerLevel(-1), mCurrRowIdx(aRowIdx + 1)
|
||||||
|
{
|
||||||
|
mTreeView->GetRowCount(&mRowCount);
|
||||||
|
if (aRowIdx != -1)
|
||||||
|
mTreeView->GetLevel(aRowIdx, &mContainerLevel);
|
||||||
|
}
|
||||||
|
|
||||||
|
Accessible*
|
||||||
|
XULTreeItemIterator::Next()
|
||||||
|
{
|
||||||
|
while (mCurrRowIdx < mRowCount) {
|
||||||
|
int32_t level = 0;
|
||||||
|
mTreeView->GetLevel(mCurrRowIdx, &level);
|
||||||
|
|
||||||
|
if (level == mContainerLevel + 1)
|
||||||
|
return mXULTree->GetTreeItemAccessible(mCurrRowIdx++);
|
||||||
|
|
||||||
|
if (level <= mContainerLevel) { // got level up
|
||||||
|
mCurrRowIdx = mRowCount;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
mCurrRowIdx++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
325
accessible/base/AccIterator.h
Normal file
325
accessible/base/AccIterator.h
Normal file
|
|
@ -0,0 +1,325 @@
|
||||||
|
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||||
|
/* vim: set ts=2 et sw=2 tw=80: */
|
||||||
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
|
#ifndef mozilla_a11y_AccIterator_h__
|
||||||
|
#define mozilla_a11y_AccIterator_h__
|
||||||
|
|
||||||
|
#include "DocAccessible.h"
|
||||||
|
#include "Filters.h"
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
class nsITreeView;
|
||||||
|
|
||||||
|
namespace mozilla {
|
||||||
|
namespace a11y {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* AccIterable is a basic interface for iterators over accessibles.
|
||||||
|
*/
|
||||||
|
class AccIterable
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
virtual ~AccIterable() { }
|
||||||
|
virtual Accessible* Next() = 0;
|
||||||
|
|
||||||
|
private:
|
||||||
|
friend class Relation;
|
||||||
|
std::unique_ptr<AccIterable> mNextIter;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Allows to iterate through accessible children or subtree complying with
|
||||||
|
* filter function.
|
||||||
|
*/
|
||||||
|
class AccIterator : public AccIterable
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
AccIterator(Accessible* aRoot, filters::FilterFuncPtr aFilterFunc);
|
||||||
|
virtual ~AccIterator();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return next accessible complying with filter function. Return the first
|
||||||
|
* accessible for the first time.
|
||||||
|
*/
|
||||||
|
virtual Accessible* Next() override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
AccIterator();
|
||||||
|
AccIterator(const AccIterator&);
|
||||||
|
AccIterator& operator =(const AccIterator&);
|
||||||
|
|
||||||
|
struct IteratorState
|
||||||
|
{
|
||||||
|
explicit IteratorState(Accessible* aParent, IteratorState* mParentState = nullptr);
|
||||||
|
|
||||||
|
Accessible* mParent;
|
||||||
|
int32_t mIndex;
|
||||||
|
IteratorState* mParentState;
|
||||||
|
};
|
||||||
|
|
||||||
|
filters::FilterFuncPtr mFilterFunc;
|
||||||
|
IteratorState* mState;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Allows to traverse through related accessibles that are pointing to the given
|
||||||
|
* dependent accessible by relation attribute.
|
||||||
|
*/
|
||||||
|
class RelatedAccIterator : public AccIterable
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
/**
|
||||||
|
* Constructor.
|
||||||
|
*
|
||||||
|
* @param aDocument [in] the document accessible the related
|
||||||
|
* & accessibles belong to.
|
||||||
|
* @param aDependentContent [in] the content of dependent accessible that
|
||||||
|
* relations were requested for
|
||||||
|
* @param aRelAttr [in] relation attribute that relations are
|
||||||
|
* pointed by
|
||||||
|
*/
|
||||||
|
RelatedAccIterator(DocAccessible* aDocument, nsIContent* aDependentContent,
|
||||||
|
nsIAtom* aRelAttr);
|
||||||
|
|
||||||
|
virtual ~RelatedAccIterator() { }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return next related accessible for the given dependent accessible.
|
||||||
|
*/
|
||||||
|
virtual Accessible* Next() override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
RelatedAccIterator();
|
||||||
|
RelatedAccIterator(const RelatedAccIterator&);
|
||||||
|
RelatedAccIterator& operator = (const RelatedAccIterator&);
|
||||||
|
|
||||||
|
DocAccessible* mDocument;
|
||||||
|
nsIAtom* mRelAttr;
|
||||||
|
DocAccessible::AttrRelProviderArray* mProviders;
|
||||||
|
nsIContent* mBindingParent;
|
||||||
|
uint32_t mIndex;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Used to iterate through HTML labels associated with the given accessible.
|
||||||
|
*/
|
||||||
|
class HTMLLabelIterator : public AccIterable
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
enum LabelFilter {
|
||||||
|
eAllLabels,
|
||||||
|
eSkipAncestorLabel
|
||||||
|
};
|
||||||
|
|
||||||
|
HTMLLabelIterator(DocAccessible* aDocument, const Accessible* aAccessible,
|
||||||
|
LabelFilter aFilter = eAllLabels);
|
||||||
|
|
||||||
|
virtual ~HTMLLabelIterator() { }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return next label accessible associated with the given element.
|
||||||
|
*/
|
||||||
|
virtual Accessible* Next() override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
HTMLLabelIterator();
|
||||||
|
HTMLLabelIterator(const HTMLLabelIterator&);
|
||||||
|
HTMLLabelIterator& operator = (const HTMLLabelIterator&);
|
||||||
|
|
||||||
|
bool IsLabel(Accessible* aLabel);
|
||||||
|
|
||||||
|
RelatedAccIterator mRelIter;
|
||||||
|
// XXX: replace it on weak reference (bug 678429), it's safe to use raw
|
||||||
|
// pointer now because iterators life cycle is short.
|
||||||
|
const Accessible* mAcc;
|
||||||
|
LabelFilter mLabelFilter;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Used to iterate through HTML outputs associated with the given element.
|
||||||
|
*/
|
||||||
|
class HTMLOutputIterator : public AccIterable
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
HTMLOutputIterator(DocAccessible* aDocument, nsIContent* aElement);
|
||||||
|
virtual ~HTMLOutputIterator() { }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return next output accessible associated with the given element.
|
||||||
|
*/
|
||||||
|
virtual Accessible* Next() override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
HTMLOutputIterator();
|
||||||
|
HTMLOutputIterator(const HTMLOutputIterator&);
|
||||||
|
HTMLOutputIterator& operator = (const HTMLOutputIterator&);
|
||||||
|
|
||||||
|
RelatedAccIterator mRelIter;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Used to iterate through XUL labels associated with the given element.
|
||||||
|
*/
|
||||||
|
class XULLabelIterator : public AccIterable
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
XULLabelIterator(DocAccessible* aDocument, nsIContent* aElement);
|
||||||
|
virtual ~XULLabelIterator() { }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return next label accessible associated with the given element.
|
||||||
|
*/
|
||||||
|
virtual Accessible* Next() override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
XULLabelIterator();
|
||||||
|
XULLabelIterator(const XULLabelIterator&);
|
||||||
|
XULLabelIterator& operator = (const XULLabelIterator&);
|
||||||
|
|
||||||
|
RelatedAccIterator mRelIter;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Used to iterate through XUL descriptions associated with the given element.
|
||||||
|
*/
|
||||||
|
class XULDescriptionIterator : public AccIterable
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
XULDescriptionIterator(DocAccessible* aDocument, nsIContent* aElement);
|
||||||
|
virtual ~XULDescriptionIterator() { }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return next description accessible associated with the given element.
|
||||||
|
*/
|
||||||
|
virtual Accessible* Next() override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
XULDescriptionIterator();
|
||||||
|
XULDescriptionIterator(const XULDescriptionIterator&);
|
||||||
|
XULDescriptionIterator& operator = (const XULDescriptionIterator&);
|
||||||
|
|
||||||
|
RelatedAccIterator mRelIter;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Used to iterate through IDs, elements or accessibles pointed by IDRefs
|
||||||
|
* attribute. Note, any method used to iterate through IDs, elements, or
|
||||||
|
* accessibles moves iterator to next position.
|
||||||
|
*/
|
||||||
|
class IDRefsIterator : public AccIterable
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
IDRefsIterator(DocAccessible* aDoc, nsIContent* aContent,
|
||||||
|
nsIAtom* aIDRefsAttr);
|
||||||
|
virtual ~IDRefsIterator() { }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return next ID.
|
||||||
|
*/
|
||||||
|
const nsDependentSubstring NextID();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return next element.
|
||||||
|
*/
|
||||||
|
nsIContent* NextElem();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the element with the given ID.
|
||||||
|
*/
|
||||||
|
nsIContent* GetElem(const nsDependentSubstring& aID);
|
||||||
|
|
||||||
|
// AccIterable
|
||||||
|
virtual Accessible* Next() override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
IDRefsIterator();
|
||||||
|
IDRefsIterator(const IDRefsIterator&);
|
||||||
|
IDRefsIterator operator = (const IDRefsIterator&);
|
||||||
|
|
||||||
|
nsString mIDs;
|
||||||
|
nsIContent* mContent;
|
||||||
|
DocAccessible* mDoc;
|
||||||
|
nsAString::index_type mCurrIdx;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Iterator that points to a single accessible returning it on the first call
|
||||||
|
* to Next().
|
||||||
|
*/
|
||||||
|
class SingleAccIterator : public AccIterable
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
explicit SingleAccIterator(Accessible* aTarget): mAcc(aTarget) { }
|
||||||
|
virtual ~SingleAccIterator() { }
|
||||||
|
|
||||||
|
virtual Accessible* Next() override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
SingleAccIterator();
|
||||||
|
SingleAccIterator(const SingleAccIterator&);
|
||||||
|
SingleAccIterator& operator = (const SingleAccIterator&);
|
||||||
|
|
||||||
|
RefPtr<Accessible> mAcc;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Used to iterate items of the given item container.
|
||||||
|
*/
|
||||||
|
class ItemIterator : public AccIterable
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
explicit ItemIterator(Accessible* aItemContainer) :
|
||||||
|
mContainer(aItemContainer), mAnchor(nullptr) { }
|
||||||
|
virtual ~ItemIterator() { }
|
||||||
|
|
||||||
|
virtual Accessible* Next() override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
ItemIterator() = delete;
|
||||||
|
ItemIterator(const ItemIterator&) = delete;
|
||||||
|
ItemIterator& operator = (const ItemIterator&) = delete;
|
||||||
|
|
||||||
|
Accessible* mContainer;
|
||||||
|
Accessible* mAnchor;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Used to iterate through XUL tree items of the same level.
|
||||||
|
*/
|
||||||
|
class XULTreeItemIterator : public AccIterable
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
XULTreeItemIterator(XULTreeAccessible* aXULTree, nsITreeView* aTreeView,
|
||||||
|
int32_t aRowIdx);
|
||||||
|
virtual ~XULTreeItemIterator() { }
|
||||||
|
|
||||||
|
virtual Accessible* Next() override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
XULTreeItemIterator() = delete;
|
||||||
|
XULTreeItemIterator(const XULTreeItemIterator&) = delete;
|
||||||
|
XULTreeItemIterator& operator = (const XULTreeItemIterator&) = delete;
|
||||||
|
|
||||||
|
XULTreeAccessible* mXULTree;
|
||||||
|
nsITreeView* mTreeView;
|
||||||
|
int32_t mRowCount;
|
||||||
|
int32_t mContainerLevel;
|
||||||
|
int32_t mCurrRowIdx;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace a11y
|
||||||
|
} // namespace mozilla
|
||||||
|
|
||||||
|
#endif
|
||||||
94
accessible/base/AccTypes.h
Normal file
94
accessible/base/AccTypes.h
Normal file
|
|
@ -0,0 +1,94 @@
|
||||||
|
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||||
|
/* vim: set ts=2 et sw=2 tw=80: */
|
||||||
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||||
|
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
|
#ifndef mozilla_a11y_AccTypes_h
|
||||||
|
#define mozilla_a11y_AccTypes_h
|
||||||
|
|
||||||
|
namespace mozilla {
|
||||||
|
namespace a11y {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Accessible object types. Each accessible class can have own type.
|
||||||
|
*/
|
||||||
|
enum AccType {
|
||||||
|
/**
|
||||||
|
* This set of types is used for accessible creation, keep them together in
|
||||||
|
* alphabetical order since they are used in switch statement.
|
||||||
|
*/
|
||||||
|
eNoType,
|
||||||
|
eHTMLBRType,
|
||||||
|
eHTMLButtonType,
|
||||||
|
eHTMLCanvasType,
|
||||||
|
eHTMLCaptionType,
|
||||||
|
eHTMLCheckboxType,
|
||||||
|
eHTMLComboboxType,
|
||||||
|
eHTMLFileInputType,
|
||||||
|
eHTMLGroupboxType,
|
||||||
|
eHTMLHRType,
|
||||||
|
eHTMLImageMapType,
|
||||||
|
eHTMLLiType,
|
||||||
|
eHTMLSelectListType,
|
||||||
|
eHTMLMediaType,
|
||||||
|
eHTMLRadioButtonType,
|
||||||
|
eHTMLRangeType,
|
||||||
|
eHTMLSpinnerType,
|
||||||
|
eHTMLTableType,
|
||||||
|
eHTMLTableCellType,
|
||||||
|
eHTMLTableRowType,
|
||||||
|
eHTMLTextFieldType,
|
||||||
|
eHyperTextType,
|
||||||
|
eImageType,
|
||||||
|
eOuterDocType,
|
||||||
|
ePluginType,
|
||||||
|
eTextLeafType,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Other accessible types.
|
||||||
|
*/
|
||||||
|
eApplicationType,
|
||||||
|
eHTMLOptGroupType,
|
||||||
|
eImageMapType,
|
||||||
|
eMenuPopupType,
|
||||||
|
eProxyType,
|
||||||
|
eProgressType,
|
||||||
|
eRootType,
|
||||||
|
eXULLabelType,
|
||||||
|
eXULListItemType,
|
||||||
|
eXULTabpanelsType,
|
||||||
|
eXULTreeType,
|
||||||
|
|
||||||
|
eLastAccType = eXULTreeType
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generic accessible type, different accessible classes can share the same
|
||||||
|
* type, the same accessible class can have several types.
|
||||||
|
*/
|
||||||
|
enum AccGenericType {
|
||||||
|
eAlert = 1 << 0,
|
||||||
|
eAutoComplete = 1 << 1,
|
||||||
|
eAutoCompletePopup = 1 << 2,
|
||||||
|
eButton = 1 << 3,
|
||||||
|
eCombobox = 1 << 4,
|
||||||
|
eDocument = 1 << 5,
|
||||||
|
eHyperText = 1 << 6,
|
||||||
|
eLandmark = 1 << 7,
|
||||||
|
eList = 1 << 8,
|
||||||
|
eListControl = 1 << 9,
|
||||||
|
eMenuButton = 1 << 10,
|
||||||
|
eSelect = 1 << 11,
|
||||||
|
eTable = 1 << 12,
|
||||||
|
eTableCell = 1 << 13,
|
||||||
|
eTableRow = 1 << 14,
|
||||||
|
eText = 1 << 15,
|
||||||
|
|
||||||
|
eLastAccGenericType = eText
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace a11y
|
||||||
|
} // namespace mozilla
|
||||||
|
|
||||||
|
#endif // mozilla_a11y_AccTypes_h
|
||||||
27
accessible/base/AccessibleOrProxy.cpp
Normal file
27
accessible/base/AccessibleOrProxy.cpp
Normal file
|
|
@ -0,0 +1,27 @@
|
||||||
|
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||||
|
/* vim: set ts=2 et sw=2 tw=80: */
|
||||||
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
|
#include "AccessibleOrProxy.h"
|
||||||
|
|
||||||
|
AccessibleOrProxy
|
||||||
|
AccessibleOrProxy::Parent() const
|
||||||
|
{
|
||||||
|
if (IsAccessible()) {
|
||||||
|
return AsAccessible()->Parent();
|
||||||
|
}
|
||||||
|
|
||||||
|
ProxyAccessible* proxy = AsProxy();
|
||||||
|
if (!proxy) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ProxyAccessible* parent = proxy->Parent()) {
|
||||||
|
return parent;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Otherwise this should be the proxy for the tab's top level document.
|
||||||
|
return proxy->OuterDocOfRemoteBrowser();
|
||||||
|
}
|
||||||
123
accessible/base/AccessibleOrProxy.h
Normal file
123
accessible/base/AccessibleOrProxy.h
Normal file
|
|
@ -0,0 +1,123 @@
|
||||||
|
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||||
|
/* vim: set ts=2 et sw=2 tw=80: */
|
||||||
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
|
#ifndef mozilla_a11y_AccessibleOrProxy_h
|
||||||
|
#define mozilla_a11y_AccessibleOrProxy_h
|
||||||
|
|
||||||
|
#include "mozilla/a11y/Accessible.h"
|
||||||
|
#include "mozilla/a11y/ProxyAccessible.h"
|
||||||
|
#include "mozilla/a11y/Role.h"
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
namespace mozilla {
|
||||||
|
namespace a11y {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This class stores an Accessible* or a ProxyAccessible* in a safe manner
|
||||||
|
* with size sizeof(void*).
|
||||||
|
*/
|
||||||
|
class AccessibleOrProxy
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
MOZ_IMPLICIT AccessibleOrProxy(Accessible* aAcc) :
|
||||||
|
mBits(reinterpret_cast<uintptr_t>(aAcc)) {}
|
||||||
|
MOZ_IMPLICIT AccessibleOrProxy(ProxyAccessible* aProxy) :
|
||||||
|
mBits(aProxy ? (reinterpret_cast<uintptr_t>(aProxy) | IS_PROXY) : 0) {}
|
||||||
|
MOZ_IMPLICIT AccessibleOrProxy(decltype(nullptr)) : mBits(0) {}
|
||||||
|
|
||||||
|
bool IsProxy() const { return mBits & IS_PROXY; }
|
||||||
|
ProxyAccessible* AsProxy() const
|
||||||
|
{
|
||||||
|
if (IsProxy()) {
|
||||||
|
return reinterpret_cast<ProxyAccessible*>(mBits & ~IS_PROXY);
|
||||||
|
}
|
||||||
|
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool IsAccessible() const { return !IsProxy(); }
|
||||||
|
Accessible* AsAccessible() const
|
||||||
|
{
|
||||||
|
if (IsAccessible()) {
|
||||||
|
return reinterpret_cast<Accessible*>(mBits);
|
||||||
|
}
|
||||||
|
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool IsNull() const { return mBits == 0; }
|
||||||
|
|
||||||
|
uint32_t ChildCount() const
|
||||||
|
{
|
||||||
|
if (IsProxy()) {
|
||||||
|
return AsProxy()->ChildrenCount();
|
||||||
|
}
|
||||||
|
|
||||||
|
return AsAccessible()->ChildCount();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the child object either an accessible or a proxied accessible at
|
||||||
|
* the given index.
|
||||||
|
*/
|
||||||
|
AccessibleOrProxy ChildAt(uint32_t aIdx)
|
||||||
|
{
|
||||||
|
if (IsProxy()) {
|
||||||
|
return AsProxy()->ChildAt(aIdx);
|
||||||
|
}
|
||||||
|
|
||||||
|
return AsAccessible()->GetChildAt(aIdx);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the first child object.
|
||||||
|
*/
|
||||||
|
AccessibleOrProxy FirstChild()
|
||||||
|
{
|
||||||
|
if (IsProxy()) {
|
||||||
|
return AsProxy()->FirstChild();
|
||||||
|
}
|
||||||
|
|
||||||
|
return AsAccessible()->FirstChild();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the first child object.
|
||||||
|
*/
|
||||||
|
AccessibleOrProxy LastChild()
|
||||||
|
{
|
||||||
|
if (IsProxy()) {
|
||||||
|
return AsProxy()->LastChild();
|
||||||
|
}
|
||||||
|
|
||||||
|
return AsAccessible()->LastChild();
|
||||||
|
}
|
||||||
|
|
||||||
|
role Role() const
|
||||||
|
{
|
||||||
|
if (IsProxy()) {
|
||||||
|
return AsProxy()->Role();
|
||||||
|
}
|
||||||
|
|
||||||
|
return AsAccessible()->Role();
|
||||||
|
}
|
||||||
|
|
||||||
|
AccessibleOrProxy Parent() const;
|
||||||
|
|
||||||
|
// XXX these are implementation details that ideally would not be exposed.
|
||||||
|
uintptr_t Bits() const { return mBits; }
|
||||||
|
void SetBits(uintptr_t aBits) { mBits = aBits; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
uintptr_t mBits;
|
||||||
|
static const uintptr_t IS_PROXY = 0x1;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
26
accessible/base/Asserts.cpp
Normal file
26
accessible/base/Asserts.cpp
Normal file
|
|
@ -0,0 +1,26 @@
|
||||||
|
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||||
|
/* vim: set ts=2 et sw=2 tw=80: */
|
||||||
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||||
|
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
|
#include "nsIAccessibleRelation.h"
|
||||||
|
#include "nsIAccessibleRole.h"
|
||||||
|
#include "RelationType.h"
|
||||||
|
#include "Role.h"
|
||||||
|
|
||||||
|
using namespace mozilla::a11y;
|
||||||
|
|
||||||
|
#define ROLE(geckoRole, stringRole, atkRole, macRole, msaaRole, ia2Role, nameRule) \
|
||||||
|
static_assert(static_cast<uint32_t>(roles::geckoRole) \
|
||||||
|
== static_cast<uint32_t>(nsIAccessibleRole::ROLE_ ## geckoRole), \
|
||||||
|
"internal and xpcom roles differ!");
|
||||||
|
#include "RoleMap.h"
|
||||||
|
#undef ROLE
|
||||||
|
|
||||||
|
#define RELATIONTYPE(geckoType, stringType, atkType, msaaType, ia2Type) \
|
||||||
|
static_assert(static_cast<uint32_t>(RelationType::geckoType) \
|
||||||
|
== static_cast<uint32_t>(nsIAccessibleRelation::RELATION_ ## geckoType), \
|
||||||
|
"internal and xpcom relations differ!");
|
||||||
|
#include "RelationTypeMap.h"
|
||||||
|
#undef RELATIONTYPE
|
||||||
594
accessible/base/DocManager.cpp
Normal file
594
accessible/base/DocManager.cpp
Normal file
|
|
@ -0,0 +1,594 @@
|
||||||
|
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||||
|
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||||
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
|
#include "DocManager.h"
|
||||||
|
|
||||||
|
#include "ApplicationAccessible.h"
|
||||||
|
#include "ARIAMap.h"
|
||||||
|
#include "DocAccessible-inl.h"
|
||||||
|
#include "DocAccessibleChild.h"
|
||||||
|
#include "DocAccessibleParent.h"
|
||||||
|
#include "nsAccessibilityService.h"
|
||||||
|
#include "Platform.h"
|
||||||
|
#include "RootAccessibleWrap.h"
|
||||||
|
#include "xpcAccessibleDocument.h"
|
||||||
|
|
||||||
|
#ifdef A11Y_LOG
|
||||||
|
#include "Logging.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "mozilla/EventListenerManager.h"
|
||||||
|
#include "mozilla/dom/Event.h" // for nsIDOMEvent::InternalDOMEvent()
|
||||||
|
#include "nsCURILoader.h"
|
||||||
|
#include "nsDocShellLoadTypes.h"
|
||||||
|
#include "nsIChannel.h"
|
||||||
|
#include "nsIDOMDocument.h"
|
||||||
|
#include "nsIInterfaceRequestorUtils.h"
|
||||||
|
#include "nsIWebNavigation.h"
|
||||||
|
#include "nsServiceManagerUtils.h"
|
||||||
|
#include "nsIWebProgress.h"
|
||||||
|
#include "nsCoreUtils.h"
|
||||||
|
#include "nsXULAppAPI.h"
|
||||||
|
#include "mozilla/dom/TabChild.h"
|
||||||
|
|
||||||
|
using namespace mozilla;
|
||||||
|
using namespace mozilla::a11y;
|
||||||
|
using namespace mozilla::dom;
|
||||||
|
|
||||||
|
StaticAutoPtr<nsTArray<DocAccessibleParent*>> DocManager::sRemoteDocuments;
|
||||||
|
nsRefPtrHashtable<nsPtrHashKey<const DocAccessibleParent>, xpcAccessibleDocument>*
|
||||||
|
DocManager::sRemoteXPCDocumentCache = nullptr;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// DocManager
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
DocManager::DocManager()
|
||||||
|
: mDocAccessibleCache(2), mXPCDocumentCache(0)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// DocManager public
|
||||||
|
|
||||||
|
DocAccessible*
|
||||||
|
DocManager::GetDocAccessible(nsIDocument* aDocument)
|
||||||
|
{
|
||||||
|
if (!aDocument)
|
||||||
|
return nullptr;
|
||||||
|
|
||||||
|
DocAccessible* docAcc = GetExistingDocAccessible(aDocument);
|
||||||
|
if (docAcc)
|
||||||
|
return docAcc;
|
||||||
|
|
||||||
|
return CreateDocOrRootAccessible(aDocument);
|
||||||
|
}
|
||||||
|
|
||||||
|
Accessible*
|
||||||
|
DocManager::FindAccessibleInCache(nsINode* aNode) const
|
||||||
|
{
|
||||||
|
for (auto iter = mDocAccessibleCache.ConstIter(); !iter.Done(); iter.Next()) {
|
||||||
|
DocAccessible* docAccessible = iter.UserData();
|
||||||
|
NS_ASSERTION(docAccessible,
|
||||||
|
"No doc accessible for the object in doc accessible cache!");
|
||||||
|
|
||||||
|
if (docAccessible) {
|
||||||
|
Accessible* accessible = docAccessible->GetAccessible(aNode);
|
||||||
|
if (accessible) {
|
||||||
|
return accessible;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
DocManager::NotifyOfDocumentShutdown(DocAccessible* aDocument,
|
||||||
|
nsIDocument* aDOMDocument)
|
||||||
|
{
|
||||||
|
// We need to remove listeners in both cases, when document is being shutdown
|
||||||
|
// or when accessibility service is being shut down as well.
|
||||||
|
RemoveListeners(aDOMDocument);
|
||||||
|
|
||||||
|
// Document will already be removed when accessibility service is shutting
|
||||||
|
// down so we do not need to remove it twice.
|
||||||
|
if (nsAccessibilityService::IsShutdown()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
xpcAccessibleDocument* xpcDoc = mXPCDocumentCache.GetWeak(aDocument);
|
||||||
|
if (xpcDoc) {
|
||||||
|
xpcDoc->Shutdown();
|
||||||
|
mXPCDocumentCache.Remove(aDocument);
|
||||||
|
}
|
||||||
|
|
||||||
|
mDocAccessibleCache.Remove(aDOMDocument);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
DocManager::NotifyOfRemoteDocShutdown(DocAccessibleParent* aDoc)
|
||||||
|
{
|
||||||
|
xpcAccessibleDocument* doc = GetCachedXPCDocument(aDoc);
|
||||||
|
if (doc) {
|
||||||
|
doc->Shutdown();
|
||||||
|
sRemoteXPCDocumentCache->Remove(aDoc);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
xpcAccessibleDocument*
|
||||||
|
DocManager::GetXPCDocument(DocAccessible* aDocument)
|
||||||
|
{
|
||||||
|
if (!aDocument)
|
||||||
|
return nullptr;
|
||||||
|
|
||||||
|
xpcAccessibleDocument* xpcDoc = mXPCDocumentCache.GetWeak(aDocument);
|
||||||
|
if (!xpcDoc) {
|
||||||
|
xpcDoc = new xpcAccessibleDocument(aDocument);
|
||||||
|
mXPCDocumentCache.Put(aDocument, xpcDoc);
|
||||||
|
}
|
||||||
|
return xpcDoc;
|
||||||
|
}
|
||||||
|
|
||||||
|
xpcAccessibleDocument*
|
||||||
|
DocManager::GetXPCDocument(DocAccessibleParent* aDoc)
|
||||||
|
{
|
||||||
|
xpcAccessibleDocument* doc = GetCachedXPCDocument(aDoc);
|
||||||
|
if (doc) {
|
||||||
|
return doc;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!sRemoteXPCDocumentCache) {
|
||||||
|
sRemoteXPCDocumentCache =
|
||||||
|
new nsRefPtrHashtable<nsPtrHashKey<const DocAccessibleParent>, xpcAccessibleDocument>;
|
||||||
|
}
|
||||||
|
|
||||||
|
doc =
|
||||||
|
new xpcAccessibleDocument(aDoc, Interfaces::DOCUMENT | Interfaces::HYPERTEXT);
|
||||||
|
sRemoteXPCDocumentCache->Put(aDoc, doc);
|
||||||
|
|
||||||
|
return doc;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef DEBUG
|
||||||
|
bool
|
||||||
|
DocManager::IsProcessingRefreshDriverNotification() const
|
||||||
|
{
|
||||||
|
for (auto iter = mDocAccessibleCache.ConstIter(); !iter.Done(); iter.Next()) {
|
||||||
|
DocAccessible* docAccessible = iter.UserData();
|
||||||
|
NS_ASSERTION(docAccessible,
|
||||||
|
"No doc accessible for the object in doc accessible cache!");
|
||||||
|
|
||||||
|
if (docAccessible && docAccessible->mNotificationController &&
|
||||||
|
docAccessible->mNotificationController->IsUpdating()) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// DocManager protected
|
||||||
|
|
||||||
|
bool
|
||||||
|
DocManager::Init()
|
||||||
|
{
|
||||||
|
nsCOMPtr<nsIWebProgress> progress =
|
||||||
|
do_GetService(NS_DOCUMENTLOADER_SERVICE_CONTRACTID);
|
||||||
|
|
||||||
|
if (!progress)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
progress->AddProgressListener(static_cast<nsIWebProgressListener*>(this),
|
||||||
|
nsIWebProgress::NOTIFY_STATE_DOCUMENT);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
DocManager::Shutdown()
|
||||||
|
{
|
||||||
|
nsCOMPtr<nsIWebProgress> progress =
|
||||||
|
do_GetService(NS_DOCUMENTLOADER_SERVICE_CONTRACTID);
|
||||||
|
|
||||||
|
if (progress)
|
||||||
|
progress->RemoveProgressListener(static_cast<nsIWebProgressListener*>(this));
|
||||||
|
|
||||||
|
ClearDocCache();
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// nsISupports
|
||||||
|
|
||||||
|
NS_IMPL_ISUPPORTS(DocManager,
|
||||||
|
nsIWebProgressListener,
|
||||||
|
nsIDOMEventListener,
|
||||||
|
nsISupportsWeakReference)
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// nsIWebProgressListener
|
||||||
|
|
||||||
|
NS_IMETHODIMP
|
||||||
|
DocManager::OnStateChange(nsIWebProgress* aWebProgress,
|
||||||
|
nsIRequest* aRequest, uint32_t aStateFlags,
|
||||||
|
nsresult aStatus)
|
||||||
|
{
|
||||||
|
NS_ASSERTION(aStateFlags & STATE_IS_DOCUMENT, "Other notifications excluded");
|
||||||
|
|
||||||
|
if (nsAccessibilityService::IsShutdown() || !aWebProgress ||
|
||||||
|
(aStateFlags & (STATE_START | STATE_STOP)) == 0)
|
||||||
|
return NS_OK;
|
||||||
|
|
||||||
|
nsCOMPtr<mozIDOMWindowProxy> DOMWindow;
|
||||||
|
aWebProgress->GetDOMWindow(getter_AddRefs(DOMWindow));
|
||||||
|
NS_ENSURE_STATE(DOMWindow);
|
||||||
|
|
||||||
|
nsPIDOMWindowOuter* piWindow = nsPIDOMWindowOuter::From(DOMWindow);
|
||||||
|
MOZ_ASSERT(piWindow);
|
||||||
|
|
||||||
|
nsCOMPtr<nsIDocument> document = piWindow->GetDoc();
|
||||||
|
NS_ENSURE_STATE(document);
|
||||||
|
|
||||||
|
// Document was loaded.
|
||||||
|
if (aStateFlags & STATE_STOP) {
|
||||||
|
#ifdef A11Y_LOG
|
||||||
|
if (logging::IsEnabled(logging::eDocLoad))
|
||||||
|
logging::DocLoad("document loaded", aWebProgress, aRequest, aStateFlags);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Figure out an event type to notify the document has been loaded.
|
||||||
|
uint32_t eventType = nsIAccessibleEvent::EVENT_DOCUMENT_LOAD_STOPPED;
|
||||||
|
|
||||||
|
// Some XUL documents get start state and then stop state with failure
|
||||||
|
// status when everything is ok. Fire document load complete event in this
|
||||||
|
// case.
|
||||||
|
if (NS_SUCCEEDED(aStatus) || !nsCoreUtils::IsContentDocument(document))
|
||||||
|
eventType = nsIAccessibleEvent::EVENT_DOCUMENT_LOAD_COMPLETE;
|
||||||
|
|
||||||
|
// If end consumer has been retargeted for loaded content then do not fire
|
||||||
|
// any event because it means no new document has been loaded, for example,
|
||||||
|
// it happens when user clicks on file link.
|
||||||
|
if (aRequest) {
|
||||||
|
uint32_t loadFlags = 0;
|
||||||
|
aRequest->GetLoadFlags(&loadFlags);
|
||||||
|
if (loadFlags & nsIChannel::LOAD_RETARGETED_DOCUMENT_URI)
|
||||||
|
eventType = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
HandleDOMDocumentLoad(document, eventType);
|
||||||
|
return NS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Document loading was started.
|
||||||
|
#ifdef A11Y_LOG
|
||||||
|
if (logging::IsEnabled(logging::eDocLoad))
|
||||||
|
logging::DocLoad("start document loading", aWebProgress, aRequest, aStateFlags);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
DocAccessible* docAcc = GetExistingDocAccessible(document);
|
||||||
|
if (!docAcc)
|
||||||
|
return NS_OK;
|
||||||
|
|
||||||
|
nsCOMPtr<nsIWebNavigation> webNav(do_GetInterface(DOMWindow));
|
||||||
|
nsCOMPtr<nsIDocShell> docShell(do_QueryInterface(webNav));
|
||||||
|
NS_ENSURE_STATE(docShell);
|
||||||
|
|
||||||
|
bool isReloading = false;
|
||||||
|
uint32_t loadType;
|
||||||
|
docShell->GetLoadType(&loadType);
|
||||||
|
if (loadType == LOAD_RELOAD_NORMAL ||
|
||||||
|
loadType == LOAD_RELOAD_BYPASS_CACHE ||
|
||||||
|
loadType == LOAD_RELOAD_BYPASS_PROXY ||
|
||||||
|
loadType == LOAD_RELOAD_BYPASS_PROXY_AND_CACHE ||
|
||||||
|
loadType == LOAD_RELOAD_ALLOW_MIXED_CONTENT) {
|
||||||
|
isReloading = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
docAcc->NotifyOfLoading(isReloading);
|
||||||
|
return NS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
NS_IMETHODIMP
|
||||||
|
DocManager::OnProgressChange(nsIWebProgress* aWebProgress,
|
||||||
|
nsIRequest* aRequest,
|
||||||
|
int32_t aCurSelfProgress,
|
||||||
|
int32_t aMaxSelfProgress,
|
||||||
|
int32_t aCurTotalProgress,
|
||||||
|
int32_t aMaxTotalProgress)
|
||||||
|
{
|
||||||
|
NS_NOTREACHED("notification excluded in AddProgressListener(...)");
|
||||||
|
return NS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
NS_IMETHODIMP
|
||||||
|
DocManager::OnLocationChange(nsIWebProgress* aWebProgress,
|
||||||
|
nsIRequest* aRequest, nsIURI* aLocation,
|
||||||
|
uint32_t aFlags)
|
||||||
|
{
|
||||||
|
NS_NOTREACHED("notification excluded in AddProgressListener(...)");
|
||||||
|
return NS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
NS_IMETHODIMP
|
||||||
|
DocManager::OnStatusChange(nsIWebProgress* aWebProgress,
|
||||||
|
nsIRequest* aRequest, nsresult aStatus,
|
||||||
|
const char16_t* aMessage)
|
||||||
|
{
|
||||||
|
NS_NOTREACHED("notification excluded in AddProgressListener(...)");
|
||||||
|
return NS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
NS_IMETHODIMP
|
||||||
|
DocManager::OnSecurityChange(nsIWebProgress* aWebProgress,
|
||||||
|
nsIRequest* aRequest,
|
||||||
|
uint32_t aState)
|
||||||
|
{
|
||||||
|
NS_NOTREACHED("notification excluded in AddProgressListener(...)");
|
||||||
|
return NS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// nsIDOMEventListener
|
||||||
|
|
||||||
|
NS_IMETHODIMP
|
||||||
|
DocManager::HandleEvent(nsIDOMEvent* aEvent)
|
||||||
|
{
|
||||||
|
nsAutoString type;
|
||||||
|
aEvent->GetType(type);
|
||||||
|
|
||||||
|
nsCOMPtr<nsIDocument> document =
|
||||||
|
do_QueryInterface(aEvent->InternalDOMEvent()->GetTarget());
|
||||||
|
NS_ASSERTION(document, "pagehide or DOMContentLoaded for non document!");
|
||||||
|
if (!document)
|
||||||
|
return NS_OK;
|
||||||
|
|
||||||
|
if (type.EqualsLiteral("pagehide")) {
|
||||||
|
// 'pagehide' event is registered on every DOM document we create an
|
||||||
|
// accessible for, process the event for the target. This document
|
||||||
|
// accessible and all its sub document accessible are shutdown as result of
|
||||||
|
// processing.
|
||||||
|
|
||||||
|
#ifdef A11Y_LOG
|
||||||
|
if (logging::IsEnabled(logging::eDocDestroy))
|
||||||
|
logging::DocDestroy("received 'pagehide' event", document);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Shutdown this one and sub document accessibles.
|
||||||
|
|
||||||
|
// We're allowed to not remove listeners when accessible document is
|
||||||
|
// shutdown since we don't keep strong reference on chrome event target and
|
||||||
|
// listeners are removed automatically when chrome event target goes away.
|
||||||
|
DocAccessible* docAccessible = GetExistingDocAccessible(document);
|
||||||
|
if (docAccessible)
|
||||||
|
docAccessible->Shutdown();
|
||||||
|
|
||||||
|
return NS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
// XXX: handle error pages loading separately since they get neither
|
||||||
|
// webprogress notifications nor 'pageshow' event.
|
||||||
|
if (type.EqualsLiteral("DOMContentLoaded") &&
|
||||||
|
nsCoreUtils::IsErrorPage(document)) {
|
||||||
|
#ifdef A11Y_LOG
|
||||||
|
if (logging::IsEnabled(logging::eDocLoad))
|
||||||
|
logging::DocLoad("handled 'DOMContentLoaded' event", document);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
HandleDOMDocumentLoad(document,
|
||||||
|
nsIAccessibleEvent::EVENT_DOCUMENT_LOAD_COMPLETE);
|
||||||
|
}
|
||||||
|
|
||||||
|
return NS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// DocManager private
|
||||||
|
|
||||||
|
void
|
||||||
|
DocManager::HandleDOMDocumentLoad(nsIDocument* aDocument,
|
||||||
|
uint32_t aLoadEventType)
|
||||||
|
{
|
||||||
|
// Document accessible can be created before we were notified the DOM document
|
||||||
|
// was loaded completely. However if it's not created yet then create it.
|
||||||
|
DocAccessible* docAcc = GetExistingDocAccessible(aDocument);
|
||||||
|
if (!docAcc) {
|
||||||
|
docAcc = CreateDocOrRootAccessible(aDocument);
|
||||||
|
if (!docAcc)
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
docAcc->NotifyOfLoad(aLoadEventType);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
DocManager::AddListeners(nsIDocument* aDocument,
|
||||||
|
bool aAddDOMContentLoadedListener)
|
||||||
|
{
|
||||||
|
nsPIDOMWindowOuter* window = aDocument->GetWindow();
|
||||||
|
EventTarget* target = window->GetChromeEventHandler();
|
||||||
|
EventListenerManager* elm = target->GetOrCreateListenerManager();
|
||||||
|
elm->AddEventListenerByType(this, NS_LITERAL_STRING("pagehide"),
|
||||||
|
TrustedEventsAtCapture());
|
||||||
|
|
||||||
|
#ifdef A11Y_LOG
|
||||||
|
if (logging::IsEnabled(logging::eDocCreate))
|
||||||
|
logging::Text("added 'pagehide' listener");
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (aAddDOMContentLoadedListener) {
|
||||||
|
elm->AddEventListenerByType(this, NS_LITERAL_STRING("DOMContentLoaded"),
|
||||||
|
TrustedEventsAtCapture());
|
||||||
|
#ifdef A11Y_LOG
|
||||||
|
if (logging::IsEnabled(logging::eDocCreate))
|
||||||
|
logging::Text("added 'DOMContentLoaded' listener");
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
DocManager::RemoveListeners(nsIDocument* aDocument)
|
||||||
|
{
|
||||||
|
nsPIDOMWindowOuter* window = aDocument->GetWindow();
|
||||||
|
if (!window)
|
||||||
|
return;
|
||||||
|
|
||||||
|
EventTarget* target = window->GetChromeEventHandler();
|
||||||
|
if (!target)
|
||||||
|
return;
|
||||||
|
|
||||||
|
EventListenerManager* elm = target->GetOrCreateListenerManager();
|
||||||
|
elm->RemoveEventListenerByType(this, NS_LITERAL_STRING("pagehide"),
|
||||||
|
TrustedEventsAtCapture());
|
||||||
|
|
||||||
|
elm->RemoveEventListenerByType(this, NS_LITERAL_STRING("DOMContentLoaded"),
|
||||||
|
TrustedEventsAtCapture());
|
||||||
|
}
|
||||||
|
|
||||||
|
DocAccessible*
|
||||||
|
DocManager::CreateDocOrRootAccessible(nsIDocument* aDocument)
|
||||||
|
{
|
||||||
|
// Ignore hiding, resource documents and documents without docshell.
|
||||||
|
if (!aDocument->IsVisibleConsideringAncestors() ||
|
||||||
|
aDocument->IsResourceDoc() || !aDocument->IsActive())
|
||||||
|
return nullptr;
|
||||||
|
|
||||||
|
// Ignore documents without presshell and not having root frame.
|
||||||
|
nsIPresShell* presShell = aDocument->GetShell();
|
||||||
|
if (!presShell || presShell->IsDestroying())
|
||||||
|
return nullptr;
|
||||||
|
|
||||||
|
bool isRootDoc = nsCoreUtils::IsRootDocument(aDocument);
|
||||||
|
|
||||||
|
DocAccessible* parentDocAcc = nullptr;
|
||||||
|
if (!isRootDoc) {
|
||||||
|
// XXXaaronl: ideally we would traverse the presshell chain. Since there's
|
||||||
|
// no easy way to do that, we cheat and use the document hierarchy.
|
||||||
|
parentDocAcc = GetDocAccessible(aDocument->GetParentDocument());
|
||||||
|
NS_ASSERTION(parentDocAcc,
|
||||||
|
"Can't create an accessible for the document!");
|
||||||
|
if (!parentDocAcc)
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
// We only create root accessibles for the true root, otherwise create a
|
||||||
|
// doc accessible.
|
||||||
|
RefPtr<DocAccessible> docAcc = isRootDoc ?
|
||||||
|
new RootAccessibleWrap(aDocument, presShell) :
|
||||||
|
new DocAccessibleWrap(aDocument, presShell);
|
||||||
|
|
||||||
|
// Cache the document accessible into document cache.
|
||||||
|
mDocAccessibleCache.Put(aDocument, docAcc);
|
||||||
|
|
||||||
|
// Initialize the document accessible.
|
||||||
|
docAcc->Init();
|
||||||
|
|
||||||
|
// Bind the document to the tree.
|
||||||
|
if (isRootDoc) {
|
||||||
|
if (!ApplicationAcc()->AppendChild(docAcc)) {
|
||||||
|
docAcc->Shutdown();
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fire reorder event to notify new accessible document has been attached to
|
||||||
|
// the tree. The reorder event is delivered after the document tree is
|
||||||
|
// constructed because event processing and tree construction are done by
|
||||||
|
// the same document.
|
||||||
|
// Note: don't use AccReorderEvent to avoid coalsecense and special reorder
|
||||||
|
// events processing.
|
||||||
|
docAcc->FireDelayedEvent(nsIAccessibleEvent::EVENT_REORDER,
|
||||||
|
ApplicationAcc());
|
||||||
|
|
||||||
|
if (IPCAccessibilityActive()) {
|
||||||
|
nsIDocShell* docShell = aDocument->GetDocShell();
|
||||||
|
if (docShell) {
|
||||||
|
nsCOMPtr<nsITabChild> tabChild = docShell->GetTabChild();
|
||||||
|
|
||||||
|
// XXX We may need to handle the case that we don't have a tab child
|
||||||
|
// differently. It may be that this will cause us to fail to notify
|
||||||
|
// the parent process about important accessible documents.
|
||||||
|
if (tabChild) {
|
||||||
|
DocAccessibleChild* ipcDoc = new DocAccessibleChild(docAcc);
|
||||||
|
docAcc->SetIPCDoc(ipcDoc);
|
||||||
|
|
||||||
|
#if defined(XP_WIN)
|
||||||
|
IAccessibleHolder holder(CreateHolderFromAccessible(docAcc));
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static_cast<TabChild*>(tabChild.get())->
|
||||||
|
SendPDocAccessibleConstructor(ipcDoc, nullptr, 0,
|
||||||
|
#if defined(XP_WIN)
|
||||||
|
AccessibleWrap::GetChildIDFor(docAcc),
|
||||||
|
holder
|
||||||
|
#else
|
||||||
|
0, 0
|
||||||
|
#endif
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
parentDocAcc->BindChildDocument(docAcc);
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef A11Y_LOG
|
||||||
|
if (logging::IsEnabled(logging::eDocCreate)) {
|
||||||
|
logging::DocCreate("document creation finished", aDocument);
|
||||||
|
logging::Stack();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
AddListeners(aDocument, isRootDoc);
|
||||||
|
return docAcc;
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// DocManager static
|
||||||
|
|
||||||
|
void
|
||||||
|
DocManager::ClearDocCache()
|
||||||
|
{
|
||||||
|
while (mDocAccessibleCache.Count() > 0) {
|
||||||
|
auto iter = mDocAccessibleCache.Iter();
|
||||||
|
MOZ_ASSERT(!iter.Done());
|
||||||
|
DocAccessible* docAcc = iter.UserData();
|
||||||
|
NS_ASSERTION(docAcc,
|
||||||
|
"No doc accessible for the object in doc accessible cache!");
|
||||||
|
if (docAcc) {
|
||||||
|
docAcc->Shutdown();
|
||||||
|
}
|
||||||
|
|
||||||
|
iter.Remove();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ensure that all xpcom accessible documents are shut down as well.
|
||||||
|
while (mXPCDocumentCache.Count() > 0) {
|
||||||
|
auto iter = mXPCDocumentCache.Iter();
|
||||||
|
MOZ_ASSERT(!iter.Done());
|
||||||
|
xpcAccessibleDocument* xpcDoc = iter.UserData();
|
||||||
|
NS_ASSERTION(xpcDoc, "No xpc doc for the object in xpc doc cache!");
|
||||||
|
|
||||||
|
if (xpcDoc) {
|
||||||
|
xpcDoc->Shutdown();
|
||||||
|
}
|
||||||
|
|
||||||
|
iter.Remove();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
DocManager::RemoteDocAdded(DocAccessibleParent* aDoc)
|
||||||
|
{
|
||||||
|
if (!sRemoteDocuments) {
|
||||||
|
sRemoteDocuments = new nsTArray<DocAccessibleParent*>;
|
||||||
|
ClearOnShutdown(&sRemoteDocuments);
|
||||||
|
}
|
||||||
|
|
||||||
|
MOZ_ASSERT(!sRemoteDocuments->Contains(aDoc),
|
||||||
|
"How did we already have the doc!");
|
||||||
|
sRemoteDocuments->AppendElement(aDoc);
|
||||||
|
ProxyCreated(aDoc, Interfaces::DOCUMENT | Interfaces::HYPERTEXT);
|
||||||
|
}
|
||||||
189
accessible/base/DocManager.h
Normal file
189
accessible/base/DocManager.h
Normal file
|
|
@ -0,0 +1,189 @@
|
||||||
|
/* 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_a11_DocManager_h_
|
||||||
|
#define mozilla_a11_DocManager_h_
|
||||||
|
|
||||||
|
#include "mozilla/ClearOnShutdown.h"
|
||||||
|
#include "nsIDocument.h"
|
||||||
|
#include "nsIDOMEventListener.h"
|
||||||
|
#include "nsRefPtrHashtable.h"
|
||||||
|
#include "nsIWebProgressListener.h"
|
||||||
|
#include "nsWeakReference.h"
|
||||||
|
#include "nsIPresShell.h"
|
||||||
|
#include "mozilla/StaticPtr.h"
|
||||||
|
|
||||||
|
namespace mozilla {
|
||||||
|
namespace a11y {
|
||||||
|
|
||||||
|
class Accessible;
|
||||||
|
class DocAccessible;
|
||||||
|
class xpcAccessibleDocument;
|
||||||
|
class DocAccessibleParent;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Manage the document accessible life cycle.
|
||||||
|
*/
|
||||||
|
class DocManager : public nsIWebProgressListener,
|
||||||
|
public nsIDOMEventListener,
|
||||||
|
public nsSupportsWeakReference
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
NS_DECL_THREADSAFE_ISUPPORTS
|
||||||
|
NS_DECL_NSIWEBPROGRESSLISTENER
|
||||||
|
NS_DECL_NSIDOMEVENTLISTENER
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return document accessible for the given DOM node.
|
||||||
|
*/
|
||||||
|
DocAccessible* GetDocAccessible(nsIDocument* aDocument);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return document accessible for the given presshell.
|
||||||
|
*/
|
||||||
|
DocAccessible* GetDocAccessible(const nsIPresShell* aPresShell)
|
||||||
|
{
|
||||||
|
if (!aPresShell)
|
||||||
|
return nullptr;
|
||||||
|
|
||||||
|
DocAccessible* doc = aPresShell->GetDocAccessible();
|
||||||
|
if (doc)
|
||||||
|
return doc;
|
||||||
|
|
||||||
|
return GetDocAccessible(aPresShell->GetDocument());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Search through all document accessibles for an accessible with the given
|
||||||
|
* unique id.
|
||||||
|
*/
|
||||||
|
Accessible* FindAccessibleInCache(nsINode* aNode) const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called by document accessible when it gets shutdown.
|
||||||
|
*/
|
||||||
|
void NotifyOfDocumentShutdown(DocAccessible* aDocument,
|
||||||
|
nsIDocument* aDOMDocument);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return XPCOM accessible document.
|
||||||
|
*/
|
||||||
|
xpcAccessibleDocument* GetXPCDocument(DocAccessible* aDocument);
|
||||||
|
xpcAccessibleDocument* GetCachedXPCDocument(DocAccessible* aDocument) const
|
||||||
|
{ return mXPCDocumentCache.GetWeak(aDocument); }
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Notification that a top level document in a content process has gone away.
|
||||||
|
*/
|
||||||
|
static void RemoteDocShutdown(DocAccessibleParent* aDoc)
|
||||||
|
{
|
||||||
|
DebugOnly<bool> result = sRemoteDocuments->RemoveElement(aDoc);
|
||||||
|
MOZ_ASSERT(result, "Why didn't we find the document!");
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Notify of a new top level document in a content process.
|
||||||
|
*/
|
||||||
|
static void RemoteDocAdded(DocAccessibleParent* aDoc);
|
||||||
|
|
||||||
|
static const nsTArray<DocAccessibleParent*>* TopLevelRemoteDocs()
|
||||||
|
{ return sRemoteDocuments; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove the xpc document for a remote document if there is one.
|
||||||
|
*/
|
||||||
|
static void NotifyOfRemoteDocShutdown(DocAccessibleParent* adoc);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get a XPC document for a remote document.
|
||||||
|
*/
|
||||||
|
static xpcAccessibleDocument* GetXPCDocument(DocAccessibleParent* aDoc);
|
||||||
|
static xpcAccessibleDocument* GetCachedXPCDocument(const DocAccessibleParent* aDoc)
|
||||||
|
{
|
||||||
|
return sRemoteXPCDocumentCache ? sRemoteXPCDocumentCache->GetWeak(aDoc)
|
||||||
|
: nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef DEBUG
|
||||||
|
bool IsProcessingRefreshDriverNotification() const;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
protected:
|
||||||
|
DocManager();
|
||||||
|
virtual ~DocManager() { }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialize the manager.
|
||||||
|
*/
|
||||||
|
bool Init();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Shutdown the manager.
|
||||||
|
*/
|
||||||
|
void Shutdown();
|
||||||
|
|
||||||
|
private:
|
||||||
|
DocManager(const DocManager&);
|
||||||
|
DocManager& operator =(const DocManager&);
|
||||||
|
|
||||||
|
private:
|
||||||
|
/**
|
||||||
|
* Create an accessible document if it was't created and fire accessibility
|
||||||
|
* events if needed.
|
||||||
|
*
|
||||||
|
* @param aDocument [in] loaded DOM document
|
||||||
|
* @param aLoadEventType [in] specifies the event type to fire load event,
|
||||||
|
* if 0 then no event is fired
|
||||||
|
*/
|
||||||
|
void HandleDOMDocumentLoad(nsIDocument* aDocument,
|
||||||
|
uint32_t aLoadEventType);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add/remove 'pagehide' and 'DOMContentLoaded' event listeners.
|
||||||
|
*/
|
||||||
|
void AddListeners(nsIDocument *aDocument, bool aAddPageShowListener);
|
||||||
|
void RemoveListeners(nsIDocument* aDocument);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create document or root accessible.
|
||||||
|
*/
|
||||||
|
DocAccessible* CreateDocOrRootAccessible(nsIDocument* aDocument);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Clear the cache and shutdown the document accessibles.
|
||||||
|
*/
|
||||||
|
void ClearDocCache();
|
||||||
|
|
||||||
|
typedef nsRefPtrHashtable<nsPtrHashKey<const nsIDocument>, DocAccessible>
|
||||||
|
DocAccessibleHashtable;
|
||||||
|
DocAccessibleHashtable mDocAccessibleCache;
|
||||||
|
|
||||||
|
typedef nsRefPtrHashtable<nsPtrHashKey<const DocAccessible>, xpcAccessibleDocument>
|
||||||
|
XPCDocumentHashtable;
|
||||||
|
XPCDocumentHashtable mXPCDocumentCache;
|
||||||
|
static nsRefPtrHashtable<nsPtrHashKey<const DocAccessibleParent>, xpcAccessibleDocument>*
|
||||||
|
sRemoteXPCDocumentCache;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The list of remote top level documents.
|
||||||
|
*/
|
||||||
|
static StaticAutoPtr<nsTArray<DocAccessibleParent*>> sRemoteDocuments;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the existing document accessible for the document if any.
|
||||||
|
* Note this returns the doc accessible for the primary pres shell if there is
|
||||||
|
* more than one.
|
||||||
|
*/
|
||||||
|
inline DocAccessible*
|
||||||
|
GetExistingDocAccessible(const nsIDocument* aDocument)
|
||||||
|
{
|
||||||
|
nsIPresShell* ps = aDocument->GetShell();
|
||||||
|
return ps ? ps->GetDocAccessible() : nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace a11y
|
||||||
|
} // namespace mozilla
|
||||||
|
|
||||||
|
#endif // mozilla_a11_DocManager_h_
|
||||||
81
accessible/base/EmbeddedObjCollector.cpp
Normal file
81
accessible/base/EmbeddedObjCollector.cpp
Normal file
|
|
@ -0,0 +1,81 @@
|
||||||
|
/* 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 "EmbeddedObjCollector.h"
|
||||||
|
|
||||||
|
#include "Accessible.h"
|
||||||
|
|
||||||
|
using namespace mozilla::a11y;
|
||||||
|
|
||||||
|
uint32_t
|
||||||
|
EmbeddedObjCollector::Count()
|
||||||
|
{
|
||||||
|
EnsureNGetIndex(nullptr);
|
||||||
|
return mObjects.Length();
|
||||||
|
}
|
||||||
|
|
||||||
|
Accessible*
|
||||||
|
EmbeddedObjCollector::GetAccessibleAt(uint32_t aIndex)
|
||||||
|
{
|
||||||
|
Accessible* accessible = mObjects.SafeElementAt(aIndex, nullptr);
|
||||||
|
if (accessible)
|
||||||
|
return accessible;
|
||||||
|
|
||||||
|
return EnsureNGetObject(aIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
Accessible*
|
||||||
|
EmbeddedObjCollector::EnsureNGetObject(uint32_t aIndex)
|
||||||
|
{
|
||||||
|
uint32_t childCount = mRoot->ChildCount();
|
||||||
|
while (mRootChildIdx < childCount) {
|
||||||
|
Accessible* child = mRoot->GetChildAt(mRootChildIdx++);
|
||||||
|
if (child->IsText())
|
||||||
|
continue;
|
||||||
|
|
||||||
|
AppendObject(child);
|
||||||
|
if (mObjects.Length() - 1 == aIndex)
|
||||||
|
return mObjects[aIndex];
|
||||||
|
}
|
||||||
|
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
int32_t
|
||||||
|
EmbeddedObjCollector::EnsureNGetIndex(Accessible* aAccessible)
|
||||||
|
{
|
||||||
|
uint32_t childCount = mRoot->ChildCount();
|
||||||
|
while (mRootChildIdx < childCount) {
|
||||||
|
Accessible* child = mRoot->GetChildAt(mRootChildIdx++);
|
||||||
|
if (child->IsText())
|
||||||
|
continue;
|
||||||
|
|
||||||
|
AppendObject(child);
|
||||||
|
if (child == aAccessible)
|
||||||
|
return mObjects.Length() - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int32_t
|
||||||
|
EmbeddedObjCollector::GetIndexAt(Accessible* aAccessible)
|
||||||
|
{
|
||||||
|
if (aAccessible->mParent != mRoot)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
MOZ_ASSERT(!aAccessible->IsProxy());
|
||||||
|
if (aAccessible->mInt.mIndexOfEmbeddedChild != -1)
|
||||||
|
return aAccessible->mInt.mIndexOfEmbeddedChild;
|
||||||
|
|
||||||
|
return !aAccessible->IsText() ? EnsureNGetIndex(aAccessible) : -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
EmbeddedObjCollector::AppendObject(Accessible* aAccessible)
|
||||||
|
{
|
||||||
|
MOZ_ASSERT(!aAccessible->IsProxy());
|
||||||
|
aAccessible->mInt.mIndexOfEmbeddedChild = mObjects.Length();
|
||||||
|
mObjects.AppendElement(aAccessible);
|
||||||
|
}
|
||||||
69
accessible/base/EmbeddedObjCollector.h
Normal file
69
accessible/base/EmbeddedObjCollector.h
Normal file
|
|
@ -0,0 +1,69 @@
|
||||||
|
/* 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_EmbeddedObjCollector_h__
|
||||||
|
#define mozilla_a11y_EmbeddedObjCollector_h__
|
||||||
|
|
||||||
|
#include "nsTArray.h"
|
||||||
|
|
||||||
|
namespace mozilla {
|
||||||
|
namespace a11y {
|
||||||
|
|
||||||
|
class Accessible;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Collect embedded objects. Provide quick access to accessible by index and
|
||||||
|
* vice versa.
|
||||||
|
*/
|
||||||
|
class EmbeddedObjCollector final
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
~EmbeddedObjCollector() { }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return index of the given accessible within the collection.
|
||||||
|
*/
|
||||||
|
int32_t GetIndexAt(Accessible* aAccessible);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return accessible count within the collection.
|
||||||
|
*/
|
||||||
|
uint32_t Count();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return an accessible from the collection at the given index.
|
||||||
|
*/
|
||||||
|
Accessible* GetAccessibleAt(uint32_t aIndex);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
/**
|
||||||
|
* Ensure accessible at the given index is stored and return it.
|
||||||
|
*/
|
||||||
|
Accessible* EnsureNGetObject(uint32_t aIndex);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Ensure index for the given accessible is stored and return it.
|
||||||
|
*/
|
||||||
|
int32_t EnsureNGetIndex(Accessible* aAccessible);
|
||||||
|
|
||||||
|
// Make sure it's used by Accessible class only.
|
||||||
|
explicit EmbeddedObjCollector(Accessible* aRoot) :
|
||||||
|
mRoot(aRoot), mRootChildIdx(0) {}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Append the object to collection.
|
||||||
|
*/
|
||||||
|
void AppendObject(Accessible* aAccessible);
|
||||||
|
|
||||||
|
friend class Accessible;
|
||||||
|
|
||||||
|
Accessible* mRoot;
|
||||||
|
uint32_t mRootChildIdx;
|
||||||
|
nsTArray<Accessible*> mObjects;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace a11y
|
||||||
|
} // namespace mozilla
|
||||||
|
|
||||||
|
#endif
|
||||||
344
accessible/base/EventQueue.cpp
Normal file
344
accessible/base/EventQueue.cpp
Normal file
|
|
@ -0,0 +1,344 @@
|
||||||
|
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||||
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
|
#include "EventQueue.h"
|
||||||
|
|
||||||
|
#include "Accessible-inl.h"
|
||||||
|
#include "nsEventShell.h"
|
||||||
|
#include "DocAccessible.h"
|
||||||
|
#include "DocAccessibleChild.h"
|
||||||
|
#include "nsAccessibilityService.h"
|
||||||
|
#include "nsTextEquivUtils.h"
|
||||||
|
#ifdef A11Y_LOG
|
||||||
|
#include "Logging.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
using namespace mozilla;
|
||||||
|
using namespace mozilla::a11y;
|
||||||
|
|
||||||
|
// Defines the number of selection add/remove events in the queue when they
|
||||||
|
// aren't packed into single selection within event.
|
||||||
|
const unsigned int kSelChangeCountToPack = 5;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// EventQueue
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
bool
|
||||||
|
EventQueue::PushEvent(AccEvent* aEvent)
|
||||||
|
{
|
||||||
|
NS_ASSERTION((aEvent->mAccessible && aEvent->mAccessible->IsApplication()) ||
|
||||||
|
aEvent->Document() == mDocument,
|
||||||
|
"Queued event belongs to another document!");
|
||||||
|
|
||||||
|
if (!mEvents.AppendElement(aEvent))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// Filter events.
|
||||||
|
CoalesceEvents();
|
||||||
|
|
||||||
|
if (aEvent->mEventRule != AccEvent::eDoNotEmit &&
|
||||||
|
(aEvent->mEventType == nsIAccessibleEvent::EVENT_NAME_CHANGE ||
|
||||||
|
aEvent->mEventType == nsIAccessibleEvent::EVENT_TEXT_REMOVED ||
|
||||||
|
aEvent->mEventType == nsIAccessibleEvent::EVENT_TEXT_INSERTED)) {
|
||||||
|
PushNameChange(aEvent->mAccessible);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
EventQueue::PushNameChange(Accessible* aTarget)
|
||||||
|
{
|
||||||
|
// Fire name change event on parent given that this event hasn't been
|
||||||
|
// coalesced, the parent's name was calculated from its subtree, and the
|
||||||
|
// subtree was changed.
|
||||||
|
if (aTarget->HasNameDependentParent()) {
|
||||||
|
// Only continue traversing up the tree if it's possible that the parent
|
||||||
|
// accessible's name can depend on this accessible's name.
|
||||||
|
Accessible* parent = aTarget->Parent();
|
||||||
|
while (parent &&
|
||||||
|
nsTextEquivUtils::HasNameRule(parent, eNameFromSubtreeIfReqRule)) {
|
||||||
|
// Test possible name dependent parent.
|
||||||
|
if (nsTextEquivUtils::HasNameRule(parent, eNameFromSubtreeRule)) {
|
||||||
|
nsAutoString name;
|
||||||
|
ENameValueFlag nameFlag = parent->Name(name);
|
||||||
|
// If name is obtained from subtree, fire name change event.
|
||||||
|
if (nameFlag == eNameFromSubtree) {
|
||||||
|
RefPtr<AccEvent> nameChangeEvent =
|
||||||
|
new AccEvent(nsIAccessibleEvent::EVENT_NAME_CHANGE, parent);
|
||||||
|
return PushEvent(nameChangeEvent);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
parent = parent->Parent();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// EventQueue: private
|
||||||
|
|
||||||
|
void
|
||||||
|
EventQueue::CoalesceEvents()
|
||||||
|
{
|
||||||
|
NS_ASSERTION(mEvents.Length(), "There should be at least one pending event!");
|
||||||
|
uint32_t tail = mEvents.Length() - 1;
|
||||||
|
AccEvent* tailEvent = mEvents[tail];
|
||||||
|
|
||||||
|
switch(tailEvent->mEventRule) {
|
||||||
|
case AccEvent::eCoalesceReorder:
|
||||||
|
{
|
||||||
|
DebugOnly<Accessible*> target = tailEvent->mAccessible.get();
|
||||||
|
MOZ_ASSERT(target->IsApplication() ||
|
||||||
|
target->IsOuterDoc() ||
|
||||||
|
target->IsXULTree(),
|
||||||
|
"Only app or outerdoc accessible reorder events are in the queue");
|
||||||
|
MOZ_ASSERT(tailEvent->GetEventType() == nsIAccessibleEvent::EVENT_REORDER, "only reorder events should be queued");
|
||||||
|
break; // case eCoalesceReorder
|
||||||
|
}
|
||||||
|
|
||||||
|
case AccEvent::eCoalesceOfSameType:
|
||||||
|
{
|
||||||
|
// Coalesce old events by newer event.
|
||||||
|
for (uint32_t index = tail - 1; index < tail; index--) {
|
||||||
|
AccEvent* accEvent = mEvents[index];
|
||||||
|
if (accEvent->mEventType == tailEvent->mEventType &&
|
||||||
|
accEvent->mEventRule == tailEvent->mEventRule) {
|
||||||
|
accEvent->mEventRule = AccEvent::eDoNotEmit;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} break; // case eCoalesceOfSameType
|
||||||
|
|
||||||
|
case AccEvent::eCoalesceSelectionChange:
|
||||||
|
{
|
||||||
|
AccSelChangeEvent* tailSelChangeEvent = downcast_accEvent(tailEvent);
|
||||||
|
for (uint32_t index = tail - 1; index < tail; index--) {
|
||||||
|
AccEvent* thisEvent = mEvents[index];
|
||||||
|
if (thisEvent->mEventRule == tailEvent->mEventRule) {
|
||||||
|
AccSelChangeEvent* thisSelChangeEvent =
|
||||||
|
downcast_accEvent(thisEvent);
|
||||||
|
|
||||||
|
// Coalesce selection change events within same control.
|
||||||
|
if (tailSelChangeEvent->mWidget == thisSelChangeEvent->mWidget) {
|
||||||
|
CoalesceSelChangeEvents(tailSelChangeEvent, thisSelChangeEvent, index);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} break; // eCoalesceSelectionChange
|
||||||
|
|
||||||
|
case AccEvent::eCoalesceStateChange:
|
||||||
|
{
|
||||||
|
// If state change event is duped then ignore previous event. If state
|
||||||
|
// change event is opposite to previous event then no event is emitted
|
||||||
|
// (accessible state wasn't changed).
|
||||||
|
for (uint32_t index = tail - 1; index < tail; index--) {
|
||||||
|
AccEvent* thisEvent = mEvents[index];
|
||||||
|
if (thisEvent->mEventRule != AccEvent::eDoNotEmit &&
|
||||||
|
thisEvent->mEventType == tailEvent->mEventType &&
|
||||||
|
thisEvent->mAccessible == tailEvent->mAccessible) {
|
||||||
|
AccStateChangeEvent* thisSCEvent = downcast_accEvent(thisEvent);
|
||||||
|
AccStateChangeEvent* tailSCEvent = downcast_accEvent(tailEvent);
|
||||||
|
if (thisSCEvent->mState == tailSCEvent->mState) {
|
||||||
|
thisEvent->mEventRule = AccEvent::eDoNotEmit;
|
||||||
|
if (thisSCEvent->mIsEnabled != tailSCEvent->mIsEnabled)
|
||||||
|
tailEvent->mEventRule = AccEvent::eDoNotEmit;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break; // eCoalesceStateChange
|
||||||
|
}
|
||||||
|
|
||||||
|
case AccEvent::eCoalesceTextSelChange:
|
||||||
|
{
|
||||||
|
// Coalesce older event by newer event for the same selection or target.
|
||||||
|
// Events for same selection may have different targets and vice versa one
|
||||||
|
// target may be pointed by different selections (for latter see
|
||||||
|
// bug 927159).
|
||||||
|
for (uint32_t index = tail - 1; index < tail; index--) {
|
||||||
|
AccEvent* thisEvent = mEvents[index];
|
||||||
|
if (thisEvent->mEventRule != AccEvent::eDoNotEmit &&
|
||||||
|
thisEvent->mEventType == tailEvent->mEventType) {
|
||||||
|
AccTextSelChangeEvent* thisTSCEvent = downcast_accEvent(thisEvent);
|
||||||
|
AccTextSelChangeEvent* tailTSCEvent = downcast_accEvent(tailEvent);
|
||||||
|
if (thisTSCEvent->mSel == tailTSCEvent->mSel ||
|
||||||
|
thisEvent->mAccessible == tailEvent->mAccessible)
|
||||||
|
thisEvent->mEventRule = AccEvent::eDoNotEmit;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
} break; // eCoalesceTextSelChange
|
||||||
|
|
||||||
|
case AccEvent::eRemoveDupes:
|
||||||
|
{
|
||||||
|
// Check for repeat events, coalesce newly appended event by more older
|
||||||
|
// event.
|
||||||
|
for (uint32_t index = tail - 1; index < tail; index--) {
|
||||||
|
AccEvent* accEvent = mEvents[index];
|
||||||
|
if (accEvent->mEventType == tailEvent->mEventType &&
|
||||||
|
accEvent->mEventRule == tailEvent->mEventRule &&
|
||||||
|
accEvent->mAccessible == tailEvent->mAccessible) {
|
||||||
|
tailEvent->mEventRule = AccEvent::eDoNotEmit;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} break; // case eRemoveDupes
|
||||||
|
|
||||||
|
default:
|
||||||
|
break; // case eAllowDupes, eDoNotEmit
|
||||||
|
} // switch
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
EventQueue::CoalesceSelChangeEvents(AccSelChangeEvent* aTailEvent,
|
||||||
|
AccSelChangeEvent* aThisEvent,
|
||||||
|
uint32_t aThisIndex)
|
||||||
|
{
|
||||||
|
aTailEvent->mPreceedingCount = aThisEvent->mPreceedingCount + 1;
|
||||||
|
|
||||||
|
// Pack all preceding events into single selection within event
|
||||||
|
// when we receive too much selection add/remove events.
|
||||||
|
if (aTailEvent->mPreceedingCount >= kSelChangeCountToPack) {
|
||||||
|
aTailEvent->mEventType = nsIAccessibleEvent::EVENT_SELECTION_WITHIN;
|
||||||
|
aTailEvent->mAccessible = aTailEvent->mWidget;
|
||||||
|
aThisEvent->mEventRule = AccEvent::eDoNotEmit;
|
||||||
|
|
||||||
|
// Do not emit any preceding selection events for same widget if they
|
||||||
|
// weren't coalesced yet.
|
||||||
|
if (aThisEvent->mEventType != nsIAccessibleEvent::EVENT_SELECTION_WITHIN) {
|
||||||
|
for (uint32_t jdx = aThisIndex - 1; jdx < aThisIndex; jdx--) {
|
||||||
|
AccEvent* prevEvent = mEvents[jdx];
|
||||||
|
if (prevEvent->mEventRule == aTailEvent->mEventRule) {
|
||||||
|
AccSelChangeEvent* prevSelChangeEvent =
|
||||||
|
downcast_accEvent(prevEvent);
|
||||||
|
if (prevSelChangeEvent->mWidget == aTailEvent->mWidget)
|
||||||
|
prevSelChangeEvent->mEventRule = AccEvent::eDoNotEmit;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Pack sequential selection remove and selection add events into
|
||||||
|
// single selection change event.
|
||||||
|
if (aTailEvent->mPreceedingCount == 1 &&
|
||||||
|
aTailEvent->mItem != aThisEvent->mItem) {
|
||||||
|
if (aTailEvent->mSelChangeType == AccSelChangeEvent::eSelectionAdd &&
|
||||||
|
aThisEvent->mSelChangeType == AccSelChangeEvent::eSelectionRemove) {
|
||||||
|
aThisEvent->mEventRule = AccEvent::eDoNotEmit;
|
||||||
|
aTailEvent->mEventType = nsIAccessibleEvent::EVENT_SELECTION;
|
||||||
|
aTailEvent->mPackedEvent = aThisEvent;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (aThisEvent->mSelChangeType == AccSelChangeEvent::eSelectionAdd &&
|
||||||
|
aTailEvent->mSelChangeType == AccSelChangeEvent::eSelectionRemove) {
|
||||||
|
aTailEvent->mEventRule = AccEvent::eDoNotEmit;
|
||||||
|
aThisEvent->mEventType = nsIAccessibleEvent::EVENT_SELECTION;
|
||||||
|
aThisEvent->mPackedEvent = aTailEvent;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Unpack the packed selection change event because we've got one
|
||||||
|
// more selection add/remove.
|
||||||
|
if (aThisEvent->mEventType == nsIAccessibleEvent::EVENT_SELECTION) {
|
||||||
|
if (aThisEvent->mPackedEvent) {
|
||||||
|
aThisEvent->mPackedEvent->mEventType =
|
||||||
|
aThisEvent->mPackedEvent->mSelChangeType == AccSelChangeEvent::eSelectionAdd ?
|
||||||
|
nsIAccessibleEvent::EVENT_SELECTION_ADD :
|
||||||
|
nsIAccessibleEvent::EVENT_SELECTION_REMOVE;
|
||||||
|
|
||||||
|
aThisEvent->mPackedEvent->mEventRule =
|
||||||
|
AccEvent::eCoalesceSelectionChange;
|
||||||
|
|
||||||
|
aThisEvent->mPackedEvent = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
aThisEvent->mEventType =
|
||||||
|
aThisEvent->mSelChangeType == AccSelChangeEvent::eSelectionAdd ?
|
||||||
|
nsIAccessibleEvent::EVENT_SELECTION_ADD :
|
||||||
|
nsIAccessibleEvent::EVENT_SELECTION_REMOVE;
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Convert into selection add since control has single selection but other
|
||||||
|
// selection events for this control are queued.
|
||||||
|
if (aTailEvent->mEventType == nsIAccessibleEvent::EVENT_SELECTION)
|
||||||
|
aTailEvent->mEventType = nsIAccessibleEvent::EVENT_SELECTION_ADD;
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// EventQueue: event queue
|
||||||
|
|
||||||
|
void
|
||||||
|
EventQueue::ProcessEventQueue()
|
||||||
|
{
|
||||||
|
// Process only currently queued events.
|
||||||
|
nsTArray<RefPtr<AccEvent> > events;
|
||||||
|
events.SwapElements(mEvents);
|
||||||
|
|
||||||
|
uint32_t eventCount = events.Length();
|
||||||
|
#ifdef A11Y_LOG
|
||||||
|
if (eventCount > 0 && logging::IsEnabled(logging::eEvents)) {
|
||||||
|
logging::MsgBegin("EVENTS", "events processing");
|
||||||
|
logging::Address("document", mDocument);
|
||||||
|
logging::MsgEnd();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
for (uint32_t idx = 0; idx < eventCount; idx++) {
|
||||||
|
AccEvent* event = events[idx];
|
||||||
|
if (event->mEventRule != AccEvent::eDoNotEmit) {
|
||||||
|
Accessible* target = event->GetAccessible();
|
||||||
|
if (!target || target->IsDefunct())
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// Dispatch the focus event if target is still focused.
|
||||||
|
if (event->mEventType == nsIAccessibleEvent::EVENT_FOCUS) {
|
||||||
|
FocusMgr()->ProcessFocusEvent(event);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Dispatch caret moved and text selection change events.
|
||||||
|
if (event->mEventType == nsIAccessibleEvent::EVENT_TEXT_SELECTION_CHANGED) {
|
||||||
|
SelectionMgr()->ProcessTextSelChangeEvent(event);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fire selected state change events in support to selection events.
|
||||||
|
if (event->mEventType == nsIAccessibleEvent::EVENT_SELECTION_ADD) {
|
||||||
|
nsEventShell::FireEvent(event->mAccessible, states::SELECTED,
|
||||||
|
true, event->mIsFromUserInput);
|
||||||
|
|
||||||
|
} else if (event->mEventType == nsIAccessibleEvent::EVENT_SELECTION_REMOVE) {
|
||||||
|
nsEventShell::FireEvent(event->mAccessible, states::SELECTED,
|
||||||
|
false, event->mIsFromUserInput);
|
||||||
|
|
||||||
|
} else if (event->mEventType == nsIAccessibleEvent::EVENT_SELECTION) {
|
||||||
|
AccSelChangeEvent* selChangeEvent = downcast_accEvent(event);
|
||||||
|
nsEventShell::FireEvent(event->mAccessible, states::SELECTED,
|
||||||
|
(selChangeEvent->mSelChangeType == AccSelChangeEvent::eSelectionAdd),
|
||||||
|
event->mIsFromUserInput);
|
||||||
|
|
||||||
|
if (selChangeEvent->mPackedEvent) {
|
||||||
|
nsEventShell::FireEvent(selChangeEvent->mPackedEvent->mAccessible,
|
||||||
|
states::SELECTED,
|
||||||
|
(selChangeEvent->mPackedEvent->mSelChangeType == AccSelChangeEvent::eSelectionAdd),
|
||||||
|
selChangeEvent->mPackedEvent->mIsFromUserInput);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
nsEventShell::FireEvent(event);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!mDocument)
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
77
accessible/base/EventQueue.h
Normal file
77
accessible/base/EventQueue.h
Normal file
|
|
@ -0,0 +1,77 @@
|
||||||
|
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||||
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
|
#ifndef mozilla_a11y_EventQueue_h_
|
||||||
|
#define mozilla_a11y_EventQueue_h_
|
||||||
|
|
||||||
|
#include "AccEvent.h"
|
||||||
|
|
||||||
|
namespace mozilla {
|
||||||
|
namespace a11y {
|
||||||
|
|
||||||
|
class DocAccessible;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Used to organize and coalesce pending events.
|
||||||
|
*/
|
||||||
|
class EventQueue
|
||||||
|
{
|
||||||
|
protected:
|
||||||
|
explicit EventQueue(DocAccessible* aDocument) : mDocument(aDocument) { }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Put an accessible event into the queue to process it later.
|
||||||
|
*/
|
||||||
|
bool PushEvent(AccEvent* aEvent);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Puts a name change event into the queue, if needed.
|
||||||
|
*/
|
||||||
|
bool PushNameChange(Accessible* aTarget);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Process events from the queue and fires events.
|
||||||
|
*/
|
||||||
|
void ProcessEventQueue();
|
||||||
|
|
||||||
|
private:
|
||||||
|
EventQueue(const EventQueue&) = delete;
|
||||||
|
EventQueue& operator = (const EventQueue&) = delete;
|
||||||
|
|
||||||
|
// Event queue processing
|
||||||
|
/**
|
||||||
|
* Coalesce redundant events from the queue.
|
||||||
|
*/
|
||||||
|
void CoalesceEvents();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Coalesce events from the same subtree.
|
||||||
|
*/
|
||||||
|
void CoalesceReorderEvents(AccEvent* aTailEvent);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Coalesce two selection change events within the same select control.
|
||||||
|
*/
|
||||||
|
void CoalesceSelChangeEvents(AccSelChangeEvent* aTailEvent,
|
||||||
|
AccSelChangeEvent* aThisEvent,
|
||||||
|
uint32_t aThisIndex);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
/**
|
||||||
|
* The document accessible reference owning this queue.
|
||||||
|
*/
|
||||||
|
DocAccessible* mDocument;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Pending events array. Don't make this an AutoTArray; we use
|
||||||
|
* SwapElements() on it.
|
||||||
|
*/
|
||||||
|
nsTArray<RefPtr<AccEvent>> mEvents;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace a11y
|
||||||
|
} // namespace mozilla
|
||||||
|
|
||||||
|
#endif // mozilla_a11y_EventQueue_h_
|
||||||
618
accessible/base/EventTree.cpp
Normal file
618
accessible/base/EventTree.cpp
Normal file
|
|
@ -0,0 +1,618 @@
|
||||||
|
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||||
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
|
#include "EventTree.h"
|
||||||
|
|
||||||
|
#include "Accessible-inl.h"
|
||||||
|
#include "nsEventShell.h"
|
||||||
|
#include "DocAccessible.h"
|
||||||
|
#ifdef A11Y_LOG
|
||||||
|
#include "Logging.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "mozilla/UniquePtr.h"
|
||||||
|
|
||||||
|
using namespace mozilla;
|
||||||
|
using namespace mozilla::a11y;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// TreeMutation class
|
||||||
|
|
||||||
|
EventTree* const TreeMutation::kNoEventTree = reinterpret_cast<EventTree*>(-1);
|
||||||
|
|
||||||
|
TreeMutation::TreeMutation(Accessible* aParent, bool aNoEvents) :
|
||||||
|
mParent(aParent), mStartIdx(UINT32_MAX),
|
||||||
|
mStateFlagsCopy(mParent->mStateFlags),
|
||||||
|
mQueueEvents(!aNoEvents)
|
||||||
|
{
|
||||||
|
#ifdef DEBUG
|
||||||
|
mIsDone = false;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef A11Y_LOG
|
||||||
|
if (mQueueEvents && logging::IsEnabled(logging::eEventTree)) {
|
||||||
|
logging::MsgBegin("EVENTS_TREE", "reordering tree before");
|
||||||
|
logging::AccessibleInfo("reordering for", mParent);
|
||||||
|
Controller()->RootEventTree().Log();
|
||||||
|
logging::MsgEnd();
|
||||||
|
|
||||||
|
if (logging::IsEnabled(logging::eVerbose)) {
|
||||||
|
logging::Tree("EVENTS_TREE", "Container tree", mParent->Document(),
|
||||||
|
PrefixLog, static_cast<void*>(this));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
mParent->mStateFlags |= Accessible::eKidsMutating;
|
||||||
|
}
|
||||||
|
|
||||||
|
TreeMutation::~TreeMutation()
|
||||||
|
{
|
||||||
|
MOZ_ASSERT(mIsDone, "Done() must be called explicitly");
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
TreeMutation::AfterInsertion(Accessible* aChild)
|
||||||
|
{
|
||||||
|
MOZ_ASSERT(aChild->Parent() == mParent);
|
||||||
|
|
||||||
|
if (static_cast<uint32_t>(aChild->mIndexInParent) < mStartIdx) {
|
||||||
|
mStartIdx = aChild->mIndexInParent + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!mQueueEvents) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
RefPtr<AccShowEvent> ev = new AccShowEvent(aChild);
|
||||||
|
DebugOnly<bool> added = Controller()->QueueMutationEvent(ev);
|
||||||
|
MOZ_ASSERT(added);
|
||||||
|
aChild->SetShowEventTarget(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
TreeMutation::BeforeRemoval(Accessible* aChild, bool aNoShutdown)
|
||||||
|
{
|
||||||
|
MOZ_ASSERT(aChild->Parent() == mParent);
|
||||||
|
|
||||||
|
if (static_cast<uint32_t>(aChild->mIndexInParent) < mStartIdx) {
|
||||||
|
mStartIdx = aChild->mIndexInParent;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!mQueueEvents) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
RefPtr<AccHideEvent> ev = new AccHideEvent(aChild, !aNoShutdown);
|
||||||
|
if (Controller()->QueueMutationEvent(ev)) {
|
||||||
|
aChild->SetHideEventTarget(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
TreeMutation::Done()
|
||||||
|
{
|
||||||
|
MOZ_ASSERT(mParent->mStateFlags & Accessible::eKidsMutating);
|
||||||
|
mParent->mStateFlags &= ~Accessible::eKidsMutating;
|
||||||
|
|
||||||
|
uint32_t length = mParent->mChildren.Length();
|
||||||
|
#ifdef DEBUG
|
||||||
|
for (uint32_t idx = 0; idx < mStartIdx && idx < length; idx++) {
|
||||||
|
MOZ_ASSERT(mParent->mChildren[idx]->mIndexInParent == static_cast<int32_t>(idx),
|
||||||
|
"Wrong index detected");
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
for (uint32_t idx = mStartIdx; idx < length; idx++) {
|
||||||
|
mParent->mChildren[idx]->mInt.mIndexOfEmbeddedChild = -1;
|
||||||
|
mParent->mChildren[idx]->mStateFlags |= Accessible::eGroupInfoDirty;
|
||||||
|
}
|
||||||
|
|
||||||
|
mParent->mEmbeddedObjCollector = nullptr;
|
||||||
|
mParent->mStateFlags |= mStateFlagsCopy & Accessible::eKidsMutating;
|
||||||
|
|
||||||
|
#ifdef DEBUG
|
||||||
|
mIsDone = true;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef A11Y_LOG
|
||||||
|
if (mQueueEvents && logging::IsEnabled(logging::eEventTree)) {
|
||||||
|
logging::MsgBegin("EVENTS_TREE", "reordering tree after");
|
||||||
|
logging::AccessibleInfo("reordering for", mParent);
|
||||||
|
Controller()->RootEventTree().Log();
|
||||||
|
logging::MsgEnd();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef A11Y_LOG
|
||||||
|
const char*
|
||||||
|
TreeMutation::PrefixLog(void* aData, Accessible* aAcc)
|
||||||
|
{
|
||||||
|
TreeMutation* thisObj = reinterpret_cast<TreeMutation*>(aData);
|
||||||
|
if (thisObj->mParent == aAcc) {
|
||||||
|
return "_X_";
|
||||||
|
}
|
||||||
|
const EventTree& ret = thisObj->Controller()->RootEventTree();
|
||||||
|
if (ret.Find(aAcc)) {
|
||||||
|
return "_с_";
|
||||||
|
}
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// EventTree
|
||||||
|
|
||||||
|
void
|
||||||
|
EventTree::Shown(Accessible* aChild)
|
||||||
|
{
|
||||||
|
RefPtr<AccShowEvent> ev = new AccShowEvent(aChild);
|
||||||
|
Controller(aChild)->WithdrawPrecedingEvents(&ev->mPrecedingEvents);
|
||||||
|
Mutated(ev);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
EventTree::Hidden(Accessible* aChild, bool aNeedsShutdown)
|
||||||
|
{
|
||||||
|
RefPtr<AccHideEvent> ev = new AccHideEvent(aChild, aNeedsShutdown);
|
||||||
|
if (!aNeedsShutdown) {
|
||||||
|
Controller(aChild)->StorePrecedingEvent(ev);
|
||||||
|
}
|
||||||
|
Mutated(ev);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
EventTree::Process(const RefPtr<DocAccessible>& aDeathGrip)
|
||||||
|
{
|
||||||
|
while (mFirst) {
|
||||||
|
// Skip a node and its subtree if its container is not in the document.
|
||||||
|
if (mFirst->mContainer->IsInDocument()) {
|
||||||
|
mFirst->Process(aDeathGrip);
|
||||||
|
if (aDeathGrip->IsDefunct()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
mFirst = Move(mFirst->mNext);
|
||||||
|
}
|
||||||
|
|
||||||
|
MOZ_ASSERT(mContainer || mDependentEvents.IsEmpty(),
|
||||||
|
"No container, no events");
|
||||||
|
MOZ_ASSERT(!mContainer || !mContainer->IsDefunct(),
|
||||||
|
"Processing events for defunct container");
|
||||||
|
MOZ_ASSERT(!mFireReorder || mContainer, "No target for reorder event");
|
||||||
|
|
||||||
|
// Fire mutation events.
|
||||||
|
uint32_t eventsCount = mDependentEvents.Length();
|
||||||
|
for (uint32_t jdx = 0; jdx < eventsCount; jdx++) {
|
||||||
|
AccMutationEvent* mtEvent = mDependentEvents[jdx];
|
||||||
|
MOZ_ASSERT(mtEvent->Document(), "No document for event target");
|
||||||
|
|
||||||
|
// Fire all hide events that has to be fired before this show event.
|
||||||
|
if (mtEvent->IsShow()) {
|
||||||
|
AccShowEvent* showEv = downcast_accEvent(mtEvent);
|
||||||
|
for (uint32_t i = 0; i < showEv->mPrecedingEvents.Length(); i++) {
|
||||||
|
nsEventShell::FireEvent(showEv->mPrecedingEvents[i]);
|
||||||
|
if (aDeathGrip->IsDefunct()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
nsEventShell::FireEvent(mtEvent);
|
||||||
|
if (aDeathGrip->IsDefunct()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mtEvent->mTextChangeEvent) {
|
||||||
|
nsEventShell::FireEvent(mtEvent->mTextChangeEvent);
|
||||||
|
if (aDeathGrip->IsDefunct()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mtEvent->IsHide()) {
|
||||||
|
// Fire menupopup end event before a hide event if a menu goes away.
|
||||||
|
|
||||||
|
// XXX: We don't look into children of hidden subtree to find hiding
|
||||||
|
// menupopup (as we did prior bug 570275) because we don't do that when
|
||||||
|
// menu is showing (and that's impossible until bug 606924 is fixed).
|
||||||
|
// Nevertheless we should do this at least because layout coalesces
|
||||||
|
// the changes before our processing and we may miss some menupopup
|
||||||
|
// events. Now we just want to be consistent in content insertion/removal
|
||||||
|
// handling.
|
||||||
|
if (mtEvent->mAccessible->ARIARole() == roles::MENUPOPUP) {
|
||||||
|
nsEventShell::FireEvent(nsIAccessibleEvent::EVENT_MENUPOPUP_END,
|
||||||
|
mtEvent->mAccessible);
|
||||||
|
if (aDeathGrip->IsDefunct()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
AccHideEvent* hideEvent = downcast_accEvent(mtEvent);
|
||||||
|
if (hideEvent->NeedsShutdown()) {
|
||||||
|
aDeathGrip->ShutdownChildrenInSubtree(mtEvent->mAccessible);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fire reorder event at last.
|
||||||
|
if (mFireReorder) {
|
||||||
|
nsEventShell::FireEvent(nsIAccessibleEvent::EVENT_REORDER, mContainer);
|
||||||
|
mContainer->Document()->MaybeNotifyOfValueChange(mContainer);
|
||||||
|
}
|
||||||
|
|
||||||
|
mDependentEvents.Clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
EventTree*
|
||||||
|
EventTree::FindOrInsert(Accessible* aContainer)
|
||||||
|
{
|
||||||
|
if (!mFirst) {
|
||||||
|
mFirst.reset(new EventTree(aContainer, mDependentEvents.IsEmpty()));
|
||||||
|
return mFirst.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
EventTree* prevNode = nullptr;
|
||||||
|
EventTree* node = mFirst.get();
|
||||||
|
do {
|
||||||
|
MOZ_ASSERT(!node->mContainer->IsApplication(),
|
||||||
|
"No event for application accessible is expected here");
|
||||||
|
MOZ_ASSERT(!node->mContainer->IsDefunct(), "An event target has to be alive");
|
||||||
|
|
||||||
|
// Case of same target.
|
||||||
|
if (node->mContainer == aContainer) {
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if the given container is contained by a current node
|
||||||
|
Accessible* top = mContainer ? mContainer : aContainer->Document();
|
||||||
|
Accessible* parent = aContainer;
|
||||||
|
while (parent) {
|
||||||
|
// Reached a top, no match for a current event.
|
||||||
|
if (parent == top) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// We got a match.
|
||||||
|
if (parent->Parent() == node->mContainer) {
|
||||||
|
// Reject the node if it's contained by a show/hide event target
|
||||||
|
uint32_t evCount = node->mDependentEvents.Length();
|
||||||
|
for (uint32_t idx = 0; idx < evCount; idx++) {
|
||||||
|
AccMutationEvent* ev = node->mDependentEvents[idx];
|
||||||
|
if (ev->GetAccessible() == parent) {
|
||||||
|
#ifdef A11Y_LOG
|
||||||
|
if (logging::IsEnabled(logging::eEventTree)) {
|
||||||
|
logging::MsgBegin("EVENTS_TREE",
|
||||||
|
"Rejecting node contained by show/hide");
|
||||||
|
logging::AccessibleInfo("Node", aContainer);
|
||||||
|
logging::MsgEnd();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
// If the node is rejected, then check if it has related hide event
|
||||||
|
// on stack, and if so, then connect it to the parent show event.
|
||||||
|
if (ev->IsShow()) {
|
||||||
|
AccShowEvent* showEv = downcast_accEvent(ev);
|
||||||
|
Controller(aContainer)->
|
||||||
|
WithdrawPrecedingEvents(&showEv->mPrecedingEvents);
|
||||||
|
}
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return node->FindOrInsert(aContainer);
|
||||||
|
}
|
||||||
|
|
||||||
|
parent = parent->Parent();
|
||||||
|
MOZ_ASSERT(parent, "Wrong tree");
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the given container contains a current node
|
||||||
|
// then
|
||||||
|
// if show or hide of the given node contains a grand parent of the current node
|
||||||
|
// then ignore the current node and its show and hide events
|
||||||
|
// otherwise ignore the current node, but not its show and hide events
|
||||||
|
Accessible* curParent = node->mContainer;
|
||||||
|
while (curParent && !curParent->IsDoc()) {
|
||||||
|
if (curParent->Parent() != aContainer) {
|
||||||
|
curParent = curParent->Parent();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Insert the tail node into the hierarchy between the current node and
|
||||||
|
// its parent.
|
||||||
|
node->mFireReorder = false;
|
||||||
|
UniquePtr<EventTree>& nodeOwnerRef = prevNode ? prevNode->mNext : mFirst;
|
||||||
|
UniquePtr<EventTree> newNode(new EventTree(aContainer, mDependentEvents.IsEmpty()));
|
||||||
|
newNode->mFirst = Move(nodeOwnerRef);
|
||||||
|
nodeOwnerRef = Move(newNode);
|
||||||
|
nodeOwnerRef->mNext = Move(node->mNext);
|
||||||
|
|
||||||
|
// Check if a next node is contained by the given node too, and move them
|
||||||
|
// under the given node if so.
|
||||||
|
prevNode = nodeOwnerRef.get();
|
||||||
|
node = nodeOwnerRef->mNext.get();
|
||||||
|
UniquePtr<EventTree>* nodeRef = &nodeOwnerRef->mNext;
|
||||||
|
EventTree* insNode = nodeOwnerRef->mFirst.get();
|
||||||
|
while (node) {
|
||||||
|
Accessible* curParent = node->mContainer;
|
||||||
|
while (curParent && !curParent->IsDoc()) {
|
||||||
|
if (curParent->Parent() != aContainer) {
|
||||||
|
curParent = curParent->Parent();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
MOZ_ASSERT(!insNode->mNext);
|
||||||
|
|
||||||
|
node->mFireReorder = false;
|
||||||
|
insNode->mNext = Move(*nodeRef);
|
||||||
|
insNode = insNode->mNext.get();
|
||||||
|
|
||||||
|
prevNode->mNext = Move(node->mNext);
|
||||||
|
node = prevNode;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
prevNode = node;
|
||||||
|
nodeRef = &node->mNext;
|
||||||
|
node = node->mNext.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
return nodeOwnerRef.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
prevNode = node;
|
||||||
|
} while ((node = node->mNext.get()));
|
||||||
|
|
||||||
|
MOZ_ASSERT(prevNode, "Nowhere to insert");
|
||||||
|
MOZ_ASSERT(!prevNode->mNext, "Taken by another node");
|
||||||
|
|
||||||
|
// If 'this' node contains the given container accessible, then
|
||||||
|
// do not emit a reorder event for the container
|
||||||
|
// if a dependent show event target contains the given container then do not
|
||||||
|
// emit show / hide events (see Process() method)
|
||||||
|
|
||||||
|
prevNode->mNext.reset(new EventTree(aContainer, mDependentEvents.IsEmpty()));
|
||||||
|
return prevNode->mNext.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
EventTree::Clear()
|
||||||
|
{
|
||||||
|
mFirst = nullptr;
|
||||||
|
mNext = nullptr;
|
||||||
|
mContainer = nullptr;
|
||||||
|
|
||||||
|
uint32_t eventsCount = mDependentEvents.Length();
|
||||||
|
for (uint32_t jdx = 0; jdx < eventsCount; jdx++) {
|
||||||
|
mDependentEvents[jdx]->mEventType = AccEvent::eDoNotEmit;
|
||||||
|
AccHideEvent* ev = downcast_accEvent(mDependentEvents[jdx]);
|
||||||
|
if (ev && ev->NeedsShutdown()) {
|
||||||
|
ev->Document()->ShutdownChildrenInSubtree(ev->mAccessible);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
mDependentEvents.Clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
const EventTree*
|
||||||
|
EventTree::Find(const Accessible* aContainer) const
|
||||||
|
{
|
||||||
|
const EventTree* et = this;
|
||||||
|
while (et) {
|
||||||
|
if (et->mContainer == aContainer) {
|
||||||
|
return et;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (et->mFirst) {
|
||||||
|
et = et->mFirst.get();
|
||||||
|
const EventTree* cet = et->Find(aContainer);
|
||||||
|
if (cet) {
|
||||||
|
return cet;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
et = et->mNext.get();
|
||||||
|
const EventTree* cet = et->Find(aContainer);
|
||||||
|
if (cet) {
|
||||||
|
return cet;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef A11Y_LOG
|
||||||
|
void
|
||||||
|
EventTree::Log(uint32_t aLevel) const
|
||||||
|
{
|
||||||
|
if (aLevel == UINT32_MAX) {
|
||||||
|
if (mFirst) {
|
||||||
|
mFirst->Log(0);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (uint32_t i = 0; i < aLevel; i++) {
|
||||||
|
printf(" ");
|
||||||
|
}
|
||||||
|
logging::AccessibleInfo("container", mContainer);
|
||||||
|
|
||||||
|
for (uint32_t i = 0; i < mDependentEvents.Length(); i++) {
|
||||||
|
AccMutationEvent* ev = mDependentEvents[i];
|
||||||
|
if (ev->IsShow()) {
|
||||||
|
for (uint32_t i = 0; i < aLevel + 1; i++) {
|
||||||
|
printf(" ");
|
||||||
|
}
|
||||||
|
logging::AccessibleInfo("shown", ev->mAccessible);
|
||||||
|
|
||||||
|
AccShowEvent* showEv = downcast_accEvent(ev);
|
||||||
|
for (uint32_t i = 0; i < showEv->mPrecedingEvents.Length(); i++) {
|
||||||
|
for (uint32_t j = 0; j < aLevel + 1; j++) {
|
||||||
|
printf(" ");
|
||||||
|
}
|
||||||
|
logging::AccessibleInfo("preceding",
|
||||||
|
showEv->mPrecedingEvents[i]->mAccessible);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
for (uint32_t i = 0; i < aLevel + 1; i++) {
|
||||||
|
printf(" ");
|
||||||
|
}
|
||||||
|
logging::AccessibleInfo("hidden", ev->mAccessible);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mFirst) {
|
||||||
|
mFirst->Log(aLevel + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mNext) {
|
||||||
|
mNext->Log(aLevel);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
void
|
||||||
|
EventTree::Mutated(AccMutationEvent* aEv)
|
||||||
|
{
|
||||||
|
// If shown or hidden node is a root of previously mutated subtree, then
|
||||||
|
// discard those subtree mutations as we are no longer interested in them.
|
||||||
|
UniquePtr<EventTree>* node = &mFirst;
|
||||||
|
while (*node) {
|
||||||
|
Accessible* cntr = (*node)->mContainer;
|
||||||
|
while (cntr != mContainer) {
|
||||||
|
if (cntr == aEv->mAccessible) {
|
||||||
|
#ifdef A11Y_LOG
|
||||||
|
if (logging::IsEnabled(logging::eEventTree)) {
|
||||||
|
logging::MsgBegin("EVENTS_TREE", "Trim subtree");
|
||||||
|
logging::AccessibleInfo("Show/hide container", aEv->mAccessible);
|
||||||
|
logging::AccessibleInfo("Trimmed subtree root", (*node)->mContainer);
|
||||||
|
logging::MsgEnd();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// If the new hide is part of a move and it contains existing child
|
||||||
|
// shows, then move preceding events from the child shows to the buffer,
|
||||||
|
// so the ongoing show event will pick them up.
|
||||||
|
if (aEv->IsHide()) {
|
||||||
|
AccHideEvent* hideEv = downcast_accEvent(aEv);
|
||||||
|
if (!hideEv->mNeedsShutdown) {
|
||||||
|
for (uint32_t i = 0; i < (*node)->mDependentEvents.Length(); i++) {
|
||||||
|
AccMutationEvent* childEv = (*node)->mDependentEvents[i];
|
||||||
|
if (childEv->IsShow()) {
|
||||||
|
AccShowEvent* childShowEv = downcast_accEvent(childEv);
|
||||||
|
if (childShowEv->mPrecedingEvents.Length() > 0) {
|
||||||
|
Controller(mContainer)->StorePrecedingEvents(
|
||||||
|
mozilla::Move(childShowEv->mPrecedingEvents));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// If the new show contains existing child shows, then move preceding
|
||||||
|
// events from the child shows to the new show.
|
||||||
|
else if (aEv->IsShow()) {
|
||||||
|
AccShowEvent* showEv = downcast_accEvent(aEv);
|
||||||
|
for (uint32_t i = 0; (*node)->mDependentEvents.Length(); i++) {
|
||||||
|
AccMutationEvent* childEv = (*node)->mDependentEvents[i];
|
||||||
|
if (childEv->IsShow()) {
|
||||||
|
AccShowEvent* showChildEv = downcast_accEvent(childEv);
|
||||||
|
if (showChildEv->mPrecedingEvents.Length() > 0) {
|
||||||
|
#ifdef A11Y_LOG
|
||||||
|
if (logging::IsEnabled(logging::eEventTree)) {
|
||||||
|
logging::MsgBegin("EVENTS_TREE", "Adopt preceding events");
|
||||||
|
logging::AccessibleInfo("Parent", aEv->mAccessible);
|
||||||
|
for (uint32_t j = 0; j < showChildEv->mPrecedingEvents.Length(); j++) {
|
||||||
|
logging::AccessibleInfo("Adoptee",
|
||||||
|
showChildEv->mPrecedingEvents[i]->mAccessible);
|
||||||
|
}
|
||||||
|
logging::MsgEnd();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
showEv->mPrecedingEvents.AppendElements(showChildEv->mPrecedingEvents);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
*node = Move((*node)->mNext);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
cntr = cntr->Parent();
|
||||||
|
}
|
||||||
|
if (cntr == aEv->mAccessible) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
node = &(*node)->mNext;
|
||||||
|
}
|
||||||
|
|
||||||
|
AccMutationEvent* prevEvent = mDependentEvents.SafeLastElement(nullptr);
|
||||||
|
mDependentEvents.AppendElement(aEv);
|
||||||
|
|
||||||
|
// Coalesce text change events from this hide/show event and the previous one.
|
||||||
|
if (prevEvent && aEv->mEventType == prevEvent->mEventType) {
|
||||||
|
if (aEv->IsHide()) {
|
||||||
|
// XXX: we need a way to ignore SplitNode and JoinNode() when they do not
|
||||||
|
// affect the text within the hypertext.
|
||||||
|
AccTextChangeEvent* prevTextEvent = prevEvent->mTextChangeEvent;
|
||||||
|
if (prevTextEvent) {
|
||||||
|
AccHideEvent* hideEvent = downcast_accEvent(aEv);
|
||||||
|
AccHideEvent* prevHideEvent = downcast_accEvent(prevEvent);
|
||||||
|
|
||||||
|
if (prevHideEvent->mNextSibling == hideEvent->mAccessible) {
|
||||||
|
hideEvent->mAccessible->AppendTextTo(prevTextEvent->mModifiedText);
|
||||||
|
}
|
||||||
|
else if (prevHideEvent->mPrevSibling == hideEvent->mAccessible) {
|
||||||
|
uint32_t oldLen = prevTextEvent->GetLength();
|
||||||
|
hideEvent->mAccessible->AppendTextTo(prevTextEvent->mModifiedText);
|
||||||
|
prevTextEvent->mStart -= prevTextEvent->GetLength() - oldLen;
|
||||||
|
}
|
||||||
|
|
||||||
|
hideEvent->mTextChangeEvent.swap(prevEvent->mTextChangeEvent);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
AccTextChangeEvent* prevTextEvent = prevEvent->mTextChangeEvent;
|
||||||
|
if (prevTextEvent) {
|
||||||
|
if (aEv->mAccessible->IndexInParent() ==
|
||||||
|
prevEvent->mAccessible->IndexInParent() + 1) {
|
||||||
|
// If tail target was inserted after this target, i.e. tail target is next
|
||||||
|
// sibling of this target.
|
||||||
|
aEv->mAccessible->AppendTextTo(prevTextEvent->mModifiedText);
|
||||||
|
}
|
||||||
|
else if (aEv->mAccessible->IndexInParent() ==
|
||||||
|
prevEvent->mAccessible->IndexInParent() - 1) {
|
||||||
|
// If tail target was inserted before this target, i.e. tail target is
|
||||||
|
// previous sibling of this target.
|
||||||
|
nsAutoString startText;
|
||||||
|
aEv->mAccessible->AppendTextTo(startText);
|
||||||
|
prevTextEvent->mModifiedText = startText + prevTextEvent->mModifiedText;
|
||||||
|
prevTextEvent->mStart -= startText.Length();
|
||||||
|
}
|
||||||
|
|
||||||
|
aEv->mTextChangeEvent.swap(prevEvent->mTextChangeEvent);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create a text change event caused by this hide/show event. When a node is
|
||||||
|
// hidden/removed or shown/appended, the text in an ancestor hyper text will
|
||||||
|
// lose or get new characters.
|
||||||
|
if (aEv->mTextChangeEvent || !mContainer->IsHyperText()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
nsAutoString text;
|
||||||
|
aEv->mAccessible->AppendTextTo(text);
|
||||||
|
if (text.IsEmpty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
int32_t offset = mContainer->AsHyperText()->GetChildOffset(aEv->mAccessible);
|
||||||
|
aEv->mTextChangeEvent =
|
||||||
|
new AccTextChangeEvent(mContainer, offset, text, aEv->IsShow(),
|
||||||
|
aEv->mIsFromUserInput ? eFromUserInput : eNoUserInput);
|
||||||
|
}
|
||||||
121
accessible/base/EventTree.h
Normal file
121
accessible/base/EventTree.h
Normal file
|
|
@ -0,0 +1,121 @@
|
||||||
|
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||||
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
|
#ifndef mozilla_a11y_EventTree_h_
|
||||||
|
#define mozilla_a11y_EventTree_h_
|
||||||
|
|
||||||
|
#include "AccEvent.h"
|
||||||
|
#include "Accessible.h"
|
||||||
|
|
||||||
|
#include "mozilla/RefPtr.h"
|
||||||
|
#include "mozilla/UniquePtr.h"
|
||||||
|
|
||||||
|
namespace mozilla {
|
||||||
|
namespace a11y {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This class makes sure required tasks are done before and after tree
|
||||||
|
* mutations. Currently this only includes group info invalidation. You must
|
||||||
|
* have an object of this class on the stack when calling methods that mutate
|
||||||
|
* the accessible tree.
|
||||||
|
*/
|
||||||
|
class TreeMutation final
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
static const bool kNoEvents = true;
|
||||||
|
static const bool kNoShutdown = true;
|
||||||
|
|
||||||
|
explicit TreeMutation(Accessible* aParent, bool aNoEvents = false);
|
||||||
|
~TreeMutation();
|
||||||
|
|
||||||
|
void AfterInsertion(Accessible* aChild);
|
||||||
|
void BeforeRemoval(Accessible* aChild, bool aNoShutdown = false);
|
||||||
|
void Done();
|
||||||
|
|
||||||
|
private:
|
||||||
|
NotificationController* Controller() const
|
||||||
|
{ return mParent->Document()->Controller(); }
|
||||||
|
|
||||||
|
static EventTree* const kNoEventTree;
|
||||||
|
|
||||||
|
#ifdef A11Y_LOG
|
||||||
|
static const char* PrefixLog(void* aData, Accessible*);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
Accessible* mParent;
|
||||||
|
uint32_t mStartIdx;
|
||||||
|
uint32_t mStateFlagsCopy;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* True if mutation events should be queued.
|
||||||
|
*/
|
||||||
|
bool mQueueEvents;
|
||||||
|
|
||||||
|
#ifdef DEBUG
|
||||||
|
bool mIsDone;
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A mutation events coalescence structure.
|
||||||
|
*/
|
||||||
|
class EventTree final {
|
||||||
|
public:
|
||||||
|
EventTree() :
|
||||||
|
mFirst(nullptr), mNext(nullptr), mContainer(nullptr), mFireReorder(false) { }
|
||||||
|
explicit EventTree(Accessible* aContainer, bool aFireReorder) :
|
||||||
|
mFirst(nullptr), mNext(nullptr), mContainer(aContainer),
|
||||||
|
mFireReorder(aFireReorder) { }
|
||||||
|
~EventTree() { Clear(); }
|
||||||
|
|
||||||
|
void Shown(Accessible* aTarget);
|
||||||
|
void Hidden(Accessible*, bool);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return an event tree node for the given accessible.
|
||||||
|
*/
|
||||||
|
const EventTree* Find(const Accessible* aContainer) const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add a mutation event to this event tree.
|
||||||
|
*/
|
||||||
|
void Mutated(AccMutationEvent* aEv);
|
||||||
|
|
||||||
|
#ifdef A11Y_LOG
|
||||||
|
void Log(uint32_t aLevel = UINT32_MAX) const;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
private:
|
||||||
|
/**
|
||||||
|
* Processes the event queue and fires events.
|
||||||
|
*/
|
||||||
|
void Process(const RefPtr<DocAccessible>& aDeathGrip);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return an event subtree for the given accessible.
|
||||||
|
*/
|
||||||
|
EventTree* FindOrInsert(Accessible* aContainer);
|
||||||
|
|
||||||
|
void Clear();
|
||||||
|
|
||||||
|
UniquePtr<EventTree> mFirst;
|
||||||
|
UniquePtr<EventTree> mNext;
|
||||||
|
|
||||||
|
Accessible* mContainer;
|
||||||
|
nsTArray<RefPtr<AccMutationEvent>> mDependentEvents;
|
||||||
|
bool mFireReorder;
|
||||||
|
|
||||||
|
static NotificationController* Controller(Accessible* aAcc)
|
||||||
|
{ return aAcc->Document()->Controller(); }
|
||||||
|
|
||||||
|
friend class NotificationController;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
} // namespace a11y
|
||||||
|
} // namespace mozilla
|
||||||
|
|
||||||
|
#endif // mozilla_a11y_EventQueue_h_
|
||||||
51
accessible/base/Filters.cpp
Normal file
51
accessible/base/Filters.cpp
Normal file
|
|
@ -0,0 +1,51 @@
|
||||||
|
/* 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 "Filters.h"
|
||||||
|
|
||||||
|
#include "Accessible-inl.h"
|
||||||
|
#include "nsAccUtils.h"
|
||||||
|
#include "Role.h"
|
||||||
|
#include "States.h"
|
||||||
|
|
||||||
|
using namespace mozilla::a11y;
|
||||||
|
using namespace mozilla::a11y::filters;
|
||||||
|
|
||||||
|
uint32_t
|
||||||
|
filters::GetSelected(Accessible* aAccessible)
|
||||||
|
{
|
||||||
|
if (aAccessible->State() & states::SELECTED)
|
||||||
|
return eMatch | eSkipSubtree;
|
||||||
|
|
||||||
|
return eSkip;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t
|
||||||
|
filters::GetSelectable(Accessible* aAccessible)
|
||||||
|
{
|
||||||
|
if (aAccessible->InteractiveState() & states::SELECTABLE)
|
||||||
|
return eMatch | eSkipSubtree;
|
||||||
|
|
||||||
|
return eSkip;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t
|
||||||
|
filters::GetRow(Accessible* aAccessible)
|
||||||
|
{
|
||||||
|
a11y::role role = aAccessible->Role();
|
||||||
|
if (role == roles::ROW)
|
||||||
|
return eMatch | eSkipSubtree;
|
||||||
|
|
||||||
|
// Look for rows inside rowgroup.
|
||||||
|
if (role == roles::GROUPING)
|
||||||
|
return eSkip;
|
||||||
|
|
||||||
|
return eSkipSubtree;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t
|
||||||
|
filters::GetCell(Accessible* aAccessible)
|
||||||
|
{
|
||||||
|
return aAccessible->IsTableCell() ? eMatch : eSkipSubtree;
|
||||||
|
}
|
||||||
50
accessible/base/Filters.h
Normal file
50
accessible/base/Filters.h
Normal file
|
|
@ -0,0 +1,50 @@
|
||||||
|
/* 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_Filters_h__
|
||||||
|
#define mozilla_a11y_Filters_h__
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Predefined filters used for nsAccIterator and nsAccCollector.
|
||||||
|
*/
|
||||||
|
namespace mozilla {
|
||||||
|
namespace a11y {
|
||||||
|
|
||||||
|
class Accessible;
|
||||||
|
|
||||||
|
namespace filters {
|
||||||
|
|
||||||
|
enum EResult {
|
||||||
|
eSkip = 0,
|
||||||
|
eMatch = 1,
|
||||||
|
eSkipSubtree = 2
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return true if the traversed accessible complies with filter.
|
||||||
|
*/
|
||||||
|
typedef uint32_t (*FilterFuncPtr) (Accessible*);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Matches selected/selectable accessibles in subtree.
|
||||||
|
*/
|
||||||
|
uint32_t GetSelected(Accessible* aAccessible);
|
||||||
|
uint32_t GetSelectable(Accessible* aAccessible);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Matches row accessibles in subtree.
|
||||||
|
*/
|
||||||
|
uint32_t GetRow(Accessible* aAccessible);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Matches cell accessibles in children.
|
||||||
|
*/
|
||||||
|
uint32_t GetCell(Accessible* aAccessible);
|
||||||
|
} // namespace filters
|
||||||
|
} // namespace a11y
|
||||||
|
} // namespace mozilla
|
||||||
|
|
||||||
|
#endif
|
||||||
404
accessible/base/FocusManager.cpp
Normal file
404
accessible/base/FocusManager.cpp
Normal file
|
|
@ -0,0 +1,404 @@
|
||||||
|
/* 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 "FocusManager.h"
|
||||||
|
|
||||||
|
#include "Accessible-inl.h"
|
||||||
|
#include "AccIterator.h"
|
||||||
|
#include "DocAccessible-inl.h"
|
||||||
|
#include "nsAccessibilityService.h"
|
||||||
|
#include "nsAccUtils.h"
|
||||||
|
#include "nsEventShell.h"
|
||||||
|
#include "Role.h"
|
||||||
|
|
||||||
|
#include "nsFocusManager.h"
|
||||||
|
#include "mozilla/EventStateManager.h"
|
||||||
|
#include "mozilla/dom/Element.h"
|
||||||
|
|
||||||
|
namespace mozilla {
|
||||||
|
namespace a11y {
|
||||||
|
|
||||||
|
FocusManager::FocusManager()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
FocusManager::~FocusManager()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
Accessible*
|
||||||
|
FocusManager::FocusedAccessible() const
|
||||||
|
{
|
||||||
|
if (mActiveItem)
|
||||||
|
return mActiveItem;
|
||||||
|
|
||||||
|
nsINode* focusedNode = FocusedDOMNode();
|
||||||
|
if (focusedNode) {
|
||||||
|
DocAccessible* doc =
|
||||||
|
GetAccService()->GetDocAccessible(focusedNode->OwnerDoc());
|
||||||
|
return doc ? doc->GetAccessibleEvenIfNotInMapOrContainer(focusedNode) : nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
FocusManager::IsFocused(const Accessible* aAccessible) const
|
||||||
|
{
|
||||||
|
if (mActiveItem)
|
||||||
|
return mActiveItem == aAccessible;
|
||||||
|
|
||||||
|
nsINode* focusedNode = FocusedDOMNode();
|
||||||
|
if (focusedNode) {
|
||||||
|
// XXX: Before getting an accessible for node having a DOM focus make sure
|
||||||
|
// they belong to the same document because it can trigger unwanted document
|
||||||
|
// accessible creation for temporary about:blank document. Without this
|
||||||
|
// peculiarity we would end up with plain implementation based on
|
||||||
|
// FocusedAccessible() method call. Make sure this issue is fixed in
|
||||||
|
// bug 638465.
|
||||||
|
if (focusedNode->OwnerDoc() == aAccessible->GetNode()->OwnerDoc()) {
|
||||||
|
DocAccessible* doc =
|
||||||
|
GetAccService()->GetDocAccessible(focusedNode->OwnerDoc());
|
||||||
|
return aAccessible ==
|
||||||
|
(doc ? doc->GetAccessibleEvenIfNotInMapOrContainer(focusedNode) : nullptr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
FocusManager::IsFocusWithin(const Accessible* aContainer) const
|
||||||
|
{
|
||||||
|
Accessible* child = FocusedAccessible();
|
||||||
|
while (child) {
|
||||||
|
if (child == aContainer)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
child = child->Parent();
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
FocusManager::FocusDisposition
|
||||||
|
FocusManager::IsInOrContainsFocus(const Accessible* aAccessible) const
|
||||||
|
{
|
||||||
|
Accessible* focus = FocusedAccessible();
|
||||||
|
if (!focus)
|
||||||
|
return eNone;
|
||||||
|
|
||||||
|
// If focused.
|
||||||
|
if (focus == aAccessible)
|
||||||
|
return eFocused;
|
||||||
|
|
||||||
|
// If contains the focus.
|
||||||
|
Accessible* child = focus->Parent();
|
||||||
|
while (child) {
|
||||||
|
if (child == aAccessible)
|
||||||
|
return eContainsFocus;
|
||||||
|
|
||||||
|
child = child->Parent();
|
||||||
|
}
|
||||||
|
|
||||||
|
// If contained by focus.
|
||||||
|
child = aAccessible->Parent();
|
||||||
|
while (child) {
|
||||||
|
if (child == focus)
|
||||||
|
return eContainedByFocus;
|
||||||
|
|
||||||
|
child = child->Parent();
|
||||||
|
}
|
||||||
|
|
||||||
|
return eNone;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
FocusManager::NotifyOfDOMFocus(nsISupports* aTarget)
|
||||||
|
{
|
||||||
|
#ifdef A11Y_LOG
|
||||||
|
if (logging::IsEnabled(logging::eFocus))
|
||||||
|
logging::FocusNotificationTarget("DOM focus", "Target", aTarget);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
mActiveItem = nullptr;
|
||||||
|
|
||||||
|
nsCOMPtr<nsINode> targetNode(do_QueryInterface(aTarget));
|
||||||
|
if (targetNode) {
|
||||||
|
DocAccessible* document =
|
||||||
|
GetAccService()->GetDocAccessible(targetNode->OwnerDoc());
|
||||||
|
if (document) {
|
||||||
|
// Set selection listener for focused element.
|
||||||
|
if (targetNode->IsElement())
|
||||||
|
SelectionMgr()->SetControlSelectionListener(targetNode->AsElement());
|
||||||
|
|
||||||
|
document->HandleNotification<FocusManager, nsINode>
|
||||||
|
(this, &FocusManager::ProcessDOMFocus, targetNode);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
FocusManager::NotifyOfDOMBlur(nsISupports* aTarget)
|
||||||
|
{
|
||||||
|
#ifdef A11Y_LOG
|
||||||
|
if (logging::IsEnabled(logging::eFocus))
|
||||||
|
logging::FocusNotificationTarget("DOM blur", "Target", aTarget);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
mActiveItem = nullptr;
|
||||||
|
|
||||||
|
// If DOM document stays focused then fire accessible focus event to process
|
||||||
|
// the case when no element within this DOM document will be focused.
|
||||||
|
nsCOMPtr<nsINode> targetNode(do_QueryInterface(aTarget));
|
||||||
|
if (targetNode && targetNode->OwnerDoc() == FocusedDOMDocument()) {
|
||||||
|
nsIDocument* DOMDoc = targetNode->OwnerDoc();
|
||||||
|
DocAccessible* document =
|
||||||
|
GetAccService()->GetDocAccessible(DOMDoc);
|
||||||
|
if (document) {
|
||||||
|
// Clear selection listener for previously focused element.
|
||||||
|
if (targetNode->IsElement())
|
||||||
|
SelectionMgr()->ClearControlSelectionListener();
|
||||||
|
|
||||||
|
document->HandleNotification<FocusManager, nsINode>
|
||||||
|
(this, &FocusManager::ProcessDOMFocus, DOMDoc);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
FocusManager::ActiveItemChanged(Accessible* aItem, bool aCheckIfActive)
|
||||||
|
{
|
||||||
|
#ifdef A11Y_LOG
|
||||||
|
if (logging::IsEnabled(logging::eFocus))
|
||||||
|
logging::FocusNotificationTarget("active item changed", "Item", aItem);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Nothing changed, happens for XUL trees and HTML selects.
|
||||||
|
if (aItem && aItem == mActiveItem)
|
||||||
|
return;
|
||||||
|
|
||||||
|
mActiveItem = nullptr;
|
||||||
|
|
||||||
|
if (aItem && aCheckIfActive) {
|
||||||
|
Accessible* widget = aItem->ContainerWidget();
|
||||||
|
#ifdef A11Y_LOG
|
||||||
|
if (logging::IsEnabled(logging::eFocus))
|
||||||
|
logging::ActiveWidget(widget);
|
||||||
|
#endif
|
||||||
|
if (!widget || !widget->IsActiveWidget() || !widget->AreItemsOperable())
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
mActiveItem = aItem;
|
||||||
|
|
||||||
|
// If active item is changed then fire accessible focus event on it, otherwise
|
||||||
|
// if there's no an active item then fire focus event to accessible having
|
||||||
|
// DOM focus.
|
||||||
|
Accessible* target = FocusedAccessible();
|
||||||
|
if (target)
|
||||||
|
DispatchFocusEvent(target->Document(), target);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
FocusManager::ForceFocusEvent()
|
||||||
|
{
|
||||||
|
nsINode* focusedNode = FocusedDOMNode();
|
||||||
|
if (focusedNode) {
|
||||||
|
DocAccessible* document =
|
||||||
|
GetAccService()->GetDocAccessible(focusedNode->OwnerDoc());
|
||||||
|
if (document) {
|
||||||
|
document->HandleNotification<FocusManager, nsINode>
|
||||||
|
(this, &FocusManager::ProcessDOMFocus, focusedNode);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
FocusManager::DispatchFocusEvent(DocAccessible* aDocument,
|
||||||
|
Accessible* aTarget)
|
||||||
|
{
|
||||||
|
NS_PRECONDITION(aDocument, "No document for focused accessible!");
|
||||||
|
if (aDocument) {
|
||||||
|
RefPtr<AccEvent> event =
|
||||||
|
new AccEvent(nsIAccessibleEvent::EVENT_FOCUS, aTarget,
|
||||||
|
eAutoDetect, AccEvent::eCoalesceOfSameType);
|
||||||
|
aDocument->FireDelayedEvent(event);
|
||||||
|
|
||||||
|
#ifdef A11Y_LOG
|
||||||
|
if (logging::IsEnabled(logging::eFocus))
|
||||||
|
logging::FocusDispatched(aTarget);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
FocusManager::ProcessDOMFocus(nsINode* aTarget)
|
||||||
|
{
|
||||||
|
#ifdef A11Y_LOG
|
||||||
|
if (logging::IsEnabled(logging::eFocus))
|
||||||
|
logging::FocusNotificationTarget("process DOM focus", "Target", aTarget);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
DocAccessible* document =
|
||||||
|
GetAccService()->GetDocAccessible(aTarget->OwnerDoc());
|
||||||
|
if (!document)
|
||||||
|
return;
|
||||||
|
|
||||||
|
Accessible* target = document->GetAccessibleEvenIfNotInMapOrContainer(aTarget);
|
||||||
|
if (target) {
|
||||||
|
// Check if still focused. Otherwise we can end up with storing the active
|
||||||
|
// item for control that isn't focused anymore.
|
||||||
|
nsINode* focusedNode = FocusedDOMNode();
|
||||||
|
if (!focusedNode)
|
||||||
|
return;
|
||||||
|
|
||||||
|
Accessible* DOMFocus =
|
||||||
|
document->GetAccessibleEvenIfNotInMapOrContainer(focusedNode);
|
||||||
|
if (target != DOMFocus)
|
||||||
|
return;
|
||||||
|
|
||||||
|
Accessible* activeItem = target->CurrentItem();
|
||||||
|
if (activeItem) {
|
||||||
|
mActiveItem = activeItem;
|
||||||
|
target = activeItem;
|
||||||
|
}
|
||||||
|
|
||||||
|
DispatchFocusEvent(document, target);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
FocusManager::ProcessFocusEvent(AccEvent* aEvent)
|
||||||
|
{
|
||||||
|
NS_PRECONDITION(aEvent->GetEventType() == nsIAccessibleEvent::EVENT_FOCUS,
|
||||||
|
"Focus event is expected!");
|
||||||
|
|
||||||
|
// Emit focus event if event target is the active item. Otherwise then check
|
||||||
|
// if it's still focused and then update active item and emit focus event.
|
||||||
|
Accessible* target = aEvent->GetAccessible();
|
||||||
|
if (target != mActiveItem) {
|
||||||
|
|
||||||
|
// Check if still focused. Otherwise we can end up with storing the active
|
||||||
|
// item for control that isn't focused anymore.
|
||||||
|
DocAccessible* document = aEvent->Document();
|
||||||
|
nsINode* focusedNode = FocusedDOMNode();
|
||||||
|
if (!focusedNode)
|
||||||
|
return;
|
||||||
|
|
||||||
|
Accessible* DOMFocus =
|
||||||
|
document->GetAccessibleEvenIfNotInMapOrContainer(focusedNode);
|
||||||
|
if (target != DOMFocus)
|
||||||
|
return;
|
||||||
|
|
||||||
|
Accessible* activeItem = target->CurrentItem();
|
||||||
|
if (activeItem) {
|
||||||
|
mActiveItem = activeItem;
|
||||||
|
target = activeItem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fire menu start/end events for ARIA menus.
|
||||||
|
if (target->IsARIARole(nsGkAtoms::menuitem)) {
|
||||||
|
// The focus was moved into menu.
|
||||||
|
Accessible* ARIAMenubar = nullptr;
|
||||||
|
for (Accessible* parent = target->Parent(); parent; parent = parent->Parent()) {
|
||||||
|
if (parent->IsARIARole(nsGkAtoms::menubar)) {
|
||||||
|
ARIAMenubar = parent;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Go up in the parent chain of the menu hierarchy.
|
||||||
|
if (!parent->IsARIARole(nsGkAtoms::menuitem) &&
|
||||||
|
!parent->IsARIARole(nsGkAtoms::menu)) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ARIAMenubar != mActiveARIAMenubar) {
|
||||||
|
// Leaving ARIA menu. Fire menu_end event on current menubar.
|
||||||
|
if (mActiveARIAMenubar) {
|
||||||
|
RefPtr<AccEvent> menuEndEvent =
|
||||||
|
new AccEvent(nsIAccessibleEvent::EVENT_MENU_END, mActiveARIAMenubar,
|
||||||
|
aEvent->FromUserInput());
|
||||||
|
nsEventShell::FireEvent(menuEndEvent);
|
||||||
|
}
|
||||||
|
|
||||||
|
mActiveARIAMenubar = ARIAMenubar;
|
||||||
|
|
||||||
|
// Entering ARIA menu. Fire menu_start event.
|
||||||
|
if (mActiveARIAMenubar) {
|
||||||
|
RefPtr<AccEvent> menuStartEvent =
|
||||||
|
new AccEvent(nsIAccessibleEvent::EVENT_MENU_START,
|
||||||
|
mActiveARIAMenubar, aEvent->FromUserInput());
|
||||||
|
nsEventShell::FireEvent(menuStartEvent);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (mActiveARIAMenubar) {
|
||||||
|
// Focus left a menu. Fire menu_end event.
|
||||||
|
RefPtr<AccEvent> menuEndEvent =
|
||||||
|
new AccEvent(nsIAccessibleEvent::EVENT_MENU_END, mActiveARIAMenubar,
|
||||||
|
aEvent->FromUserInput());
|
||||||
|
nsEventShell::FireEvent(menuEndEvent);
|
||||||
|
|
||||||
|
mActiveARIAMenubar = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef A11Y_LOG
|
||||||
|
if (logging::IsEnabled(logging::eFocus))
|
||||||
|
logging::FocusNotificationTarget("fire focus event", "Target", target);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Reset cached caret value. The cache will be updated upon processing the
|
||||||
|
// next caret move event. This ensures that we will return the correct caret
|
||||||
|
// offset before the caret move event is handled.
|
||||||
|
SelectionMgr()->ResetCaretOffset();
|
||||||
|
|
||||||
|
RefPtr<AccEvent> focusEvent =
|
||||||
|
new AccEvent(nsIAccessibleEvent::EVENT_FOCUS, target, aEvent->FromUserInput());
|
||||||
|
nsEventShell::FireEvent(focusEvent);
|
||||||
|
|
||||||
|
// Fire scrolling_start event when the document receives the focus if it has
|
||||||
|
// an anchor jump. If an accessible within the document receive the focus
|
||||||
|
// then null out the anchor jump because it no longer applies.
|
||||||
|
DocAccessible* targetDocument = target->Document();
|
||||||
|
Accessible* anchorJump = targetDocument->AnchorJump();
|
||||||
|
if (anchorJump) {
|
||||||
|
if (target == targetDocument) {
|
||||||
|
// XXX: bug 625699, note in some cases the node could go away before we
|
||||||
|
// we receive focus event, for example if the node is removed from DOM.
|
||||||
|
nsEventShell::FireEvent(nsIAccessibleEvent::EVENT_SCROLLING_START,
|
||||||
|
anchorJump, aEvent->FromUserInput());
|
||||||
|
}
|
||||||
|
targetDocument->SetAnchorJump(nullptr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
nsINode*
|
||||||
|
FocusManager::FocusedDOMNode() const
|
||||||
|
{
|
||||||
|
nsFocusManager* DOMFocusManager = nsFocusManager::GetFocusManager();
|
||||||
|
nsIContent* focusedElm = DOMFocusManager->GetFocusedContent();
|
||||||
|
|
||||||
|
// No focus on remote target elements like xul:browser having DOM focus and
|
||||||
|
// residing in chrome process because it means an element in content process
|
||||||
|
// keeps the focus.
|
||||||
|
if (focusedElm) {
|
||||||
|
if (EventStateManager::IsRemoteTarget(focusedElm)) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
return focusedElm;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Otherwise the focus can be on DOM document.
|
||||||
|
nsPIDOMWindowOuter* focusedWnd = DOMFocusManager->GetFocusedWindow();
|
||||||
|
return focusedWnd ? focusedWnd->GetExtantDoc() : nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
nsIDocument*
|
||||||
|
FocusManager::FocusedDOMDocument() const
|
||||||
|
{
|
||||||
|
nsINode* focusedNode = FocusedDOMNode();
|
||||||
|
return focusedNode ? focusedNode->OwnerDoc() : nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace a11y
|
||||||
|
} // namespace mozilla
|
||||||
132
accessible/base/FocusManager.h
Normal file
132
accessible/base/FocusManager.h
Normal file
|
|
@ -0,0 +1,132 @@
|
||||||
|
/* 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_FocusManager_h_
|
||||||
|
#define mozilla_a11y_FocusManager_h_
|
||||||
|
|
||||||
|
class nsINode;
|
||||||
|
class nsIDocument;
|
||||||
|
class nsISupports;
|
||||||
|
|
||||||
|
namespace mozilla {
|
||||||
|
namespace a11y {
|
||||||
|
|
||||||
|
class AccEvent;
|
||||||
|
class Accessible;
|
||||||
|
class DocAccessible;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Manage the accessible focus. Used to fire and process accessible events.
|
||||||
|
*/
|
||||||
|
class FocusManager
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
virtual ~FocusManager();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return a focused accessible.
|
||||||
|
*/
|
||||||
|
Accessible* FocusedAccessible() const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return true if given accessible is focused.
|
||||||
|
*/
|
||||||
|
bool IsFocused(const Accessible* aAccessible) const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return true if the given accessible is an active item, i.e. an item that
|
||||||
|
* is current within the active widget.
|
||||||
|
*/
|
||||||
|
inline bool IsActiveItem(const Accessible* aAccessible)
|
||||||
|
{ return aAccessible == mActiveItem; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return true if given DOM node has DOM focus.
|
||||||
|
*/
|
||||||
|
inline bool HasDOMFocus(const nsINode* aNode) const
|
||||||
|
{ return aNode == FocusedDOMNode(); }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return true if focused accessible is within the given container.
|
||||||
|
*/
|
||||||
|
bool IsFocusWithin(const Accessible* aContainer) const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return whether the given accessible is focused or contains the focus or
|
||||||
|
* contained by focused accessible.
|
||||||
|
*/
|
||||||
|
enum FocusDisposition {
|
||||||
|
eNone,
|
||||||
|
eFocused,
|
||||||
|
eContainsFocus,
|
||||||
|
eContainedByFocus
|
||||||
|
};
|
||||||
|
FocusDisposition IsInOrContainsFocus(const Accessible* aAccessible) const;
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Focus notifications and processing (don't use until you know what you do).
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called when DOM focus event is fired.
|
||||||
|
*/
|
||||||
|
void NotifyOfDOMFocus(nsISupports* aTarget);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called when DOM blur event is fired.
|
||||||
|
*/
|
||||||
|
void NotifyOfDOMBlur(nsISupports* aTarget);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called when active item is changed. Note: must be called when accessible
|
||||||
|
* tree is up to date.
|
||||||
|
*/
|
||||||
|
void ActiveItemChanged(Accessible* aItem, bool aCheckIfActive = true);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Dispatch delayed focus event for the current focus accessible.
|
||||||
|
*/
|
||||||
|
void ForceFocusEvent();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Dispatch delayed focus event for the given target.
|
||||||
|
*/
|
||||||
|
void DispatchFocusEvent(DocAccessible* aDocument, Accessible* aTarget);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Process DOM focus notification.
|
||||||
|
*/
|
||||||
|
void ProcessDOMFocus(nsINode* aTarget);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Process the delayed accessible event.
|
||||||
|
* do.
|
||||||
|
*/
|
||||||
|
void ProcessFocusEvent(AccEvent* aEvent);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
FocusManager();
|
||||||
|
|
||||||
|
private:
|
||||||
|
FocusManager(const FocusManager&);
|
||||||
|
FocusManager& operator =(const FocusManager&);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return DOM node having DOM focus.
|
||||||
|
*/
|
||||||
|
nsINode* FocusedDOMNode() const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return DOM document having DOM focus.
|
||||||
|
*/
|
||||||
|
nsIDocument* FocusedDOMDocument() const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
RefPtr<Accessible> mActiveItem;
|
||||||
|
RefPtr<Accessible> mActiveARIAMenubar;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace a11y
|
||||||
|
} // namespace mozilla
|
||||||
|
|
||||||
|
#endif
|
||||||
1039
accessible/base/Logging.cpp
Normal file
1039
accessible/base/Logging.cpp
Normal file
File diff suppressed because it is too large
Load diff
225
accessible/base/Logging.h
Normal file
225
accessible/base/Logging.h
Normal file
|
|
@ -0,0 +1,225 @@
|
||||||
|
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||||
|
/* vim: set ts=2 et sw=2 tw=80: */
|
||||||
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||||
|
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
|
#ifndef mozilla_a11y_logs_h__
|
||||||
|
#define mozilla_a11y_logs_h__
|
||||||
|
|
||||||
|
#include "nscore.h"
|
||||||
|
#include "nsStringFwd.h"
|
||||||
|
|
||||||
|
class nsIDocument;
|
||||||
|
class nsINode;
|
||||||
|
class nsIRequest;
|
||||||
|
class nsISelection;
|
||||||
|
class nsISupports;
|
||||||
|
class nsIWebProgress;
|
||||||
|
|
||||||
|
namespace mozilla {
|
||||||
|
namespace a11y {
|
||||||
|
|
||||||
|
class AccEvent;
|
||||||
|
class Accessible;
|
||||||
|
class DocAccessible;
|
||||||
|
class OuterDocAccessible;
|
||||||
|
|
||||||
|
namespace logging {
|
||||||
|
|
||||||
|
enum EModules {
|
||||||
|
eDocLoad = 1 << 0,
|
||||||
|
eDocCreate = 1 << 1,
|
||||||
|
eDocDestroy = 1 << 2,
|
||||||
|
eDocLifeCycle = eDocLoad | eDocCreate | eDocDestroy,
|
||||||
|
|
||||||
|
eEvents = 1 << 3,
|
||||||
|
eEventTree = 1 << 4,
|
||||||
|
ePlatforms = 1 << 5,
|
||||||
|
eText = 1 << 6,
|
||||||
|
eTree = 1 << 7,
|
||||||
|
|
||||||
|
eDOMEvents = 1 << 8,
|
||||||
|
eFocus = 1 << 9,
|
||||||
|
eSelection = 1 << 10,
|
||||||
|
eNotifications = eDOMEvents | eSelection | eFocus,
|
||||||
|
|
||||||
|
// extras
|
||||||
|
eStack = 1 << 11,
|
||||||
|
eVerbose = 1 << 12
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return true if any of the given modules is logged.
|
||||||
|
*/
|
||||||
|
bool IsEnabled(uint32_t aModules);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return true if all of the given modules are logged.
|
||||||
|
*/
|
||||||
|
bool IsEnabledAll(uint32_t aModules);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return true if the given module is logged.
|
||||||
|
*/
|
||||||
|
bool IsEnabled(const nsAString& aModules);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Log the document loading progress.
|
||||||
|
*/
|
||||||
|
void DocLoad(const char* aMsg, nsIWebProgress* aWebProgress,
|
||||||
|
nsIRequest* aRequest, uint32_t aStateFlags);
|
||||||
|
void DocLoad(const char* aMsg, nsIDocument* aDocumentNode);
|
||||||
|
void DocCompleteLoad(DocAccessible* aDocument, bool aIsLoadEventTarget);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Log that document load event was fired.
|
||||||
|
*/
|
||||||
|
void DocLoadEventFired(AccEvent* aEvent);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Log that document laod event was handled.
|
||||||
|
*/
|
||||||
|
void DocLoadEventHandled(AccEvent* aEvent);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Log the document was created.
|
||||||
|
*/
|
||||||
|
void DocCreate(const char* aMsg, nsIDocument* aDocumentNode,
|
||||||
|
DocAccessible* aDocument = nullptr);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Log the document was destroyed.
|
||||||
|
*/
|
||||||
|
void DocDestroy(const char* aMsg, nsIDocument* aDocumentNode,
|
||||||
|
DocAccessible* aDocument = nullptr);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Log the outer document was destroyed.
|
||||||
|
*/
|
||||||
|
void OuterDocDestroy(OuterDocAccessible* OuterDoc);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Log the focus notification target.
|
||||||
|
*/
|
||||||
|
void FocusNotificationTarget(const char* aMsg, const char* aTargetDescr,
|
||||||
|
Accessible* aTarget);
|
||||||
|
void FocusNotificationTarget(const char* aMsg, const char* aTargetDescr,
|
||||||
|
nsINode* aTargetNode);
|
||||||
|
void FocusNotificationTarget(const char* aMsg, const char* aTargetDescr,
|
||||||
|
nsISupports* aTargetThing);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Log a cause of active item descendant change (submessage).
|
||||||
|
*/
|
||||||
|
void ActiveItemChangeCausedBy(const char* aMsg, Accessible* aTarget);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Log the active widget (submessage).
|
||||||
|
*/
|
||||||
|
void ActiveWidget(Accessible* aWidget);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Log the focus event was dispatched (submessage).
|
||||||
|
*/
|
||||||
|
void FocusDispatched(Accessible* aTarget);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Log the selection change.
|
||||||
|
*/
|
||||||
|
void SelChange(nsISelection* aSelection, DocAccessible* aDocument,
|
||||||
|
int16_t aReason);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Log the given accessible elements info.
|
||||||
|
*/
|
||||||
|
void TreeInfo(const char* aMsg, uint32_t aExtraFlags, ...);
|
||||||
|
void TreeInfo(const char* aMsg, uint32_t aExtraFlags,
|
||||||
|
const char* aMsg1, Accessible* aAcc,
|
||||||
|
const char* aMsg2, nsINode* aNode);
|
||||||
|
void TreeInfo(const char* aMsg, uint32_t aExtraFlags, Accessible* aParent);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Log the accessible/DOM tree.
|
||||||
|
*/
|
||||||
|
typedef const char* (*GetTreePrefix)(void* aData, Accessible*);
|
||||||
|
void Tree(const char* aTitle, const char* aMsgText, Accessible* aRoot,
|
||||||
|
GetTreePrefix aPrefixFunc = nullptr, void* aGetTreePrefixData = nullptr);
|
||||||
|
void DOMTree(const char* aTitle, const char* aMsgText, DocAccessible* aDoc);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Log the message ('title: text' format) on new line. Print the start and end
|
||||||
|
* boundaries of the message body designated by '{' and '}' (2 spaces indent for
|
||||||
|
* body).
|
||||||
|
*/
|
||||||
|
void MsgBegin(const char* aTitle, const char* aMsgText, ...);
|
||||||
|
void MsgEnd();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Print start and end boundaries of the message body designated by '{' and '}'
|
||||||
|
* (2 spaces indent for body).
|
||||||
|
*/
|
||||||
|
void SubMsgBegin();
|
||||||
|
void SubMsgEnd();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Log the entry into message body (4 spaces indent).
|
||||||
|
*/
|
||||||
|
void MsgEntry(const char* aEntryText, ...);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Log the text, two spaces offset is used.
|
||||||
|
*/
|
||||||
|
void Text(const char* aText);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Log the accessible object address as message entry (4 spaces indent).
|
||||||
|
*/
|
||||||
|
void Address(const char* aDescr, Accessible* aAcc);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Log the DOM node info as message entry.
|
||||||
|
*/
|
||||||
|
void Node(const char* aDescr, nsINode* aNode);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Log the document accessible info as message entry.
|
||||||
|
*/
|
||||||
|
void Document(DocAccessible* aDocument);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Log the accessible and its DOM node as a message entry.
|
||||||
|
*/
|
||||||
|
void AccessibleInfo(const char* aDescr, Accessible* aAccessible);
|
||||||
|
void AccessibleNNode(const char* aDescr, Accessible* aAccessible);
|
||||||
|
void AccessibleNNode(const char* aDescr, nsINode* aNode);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Log the DOM event.
|
||||||
|
*/
|
||||||
|
void DOMEvent(const char* aDescr, nsINode* aOrigTarget,
|
||||||
|
const nsAString& aEventType);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Log the call stack, two spaces offset is used.
|
||||||
|
*/
|
||||||
|
void Stack();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Enable logging of the specified modules, all other modules aren't logged.
|
||||||
|
*/
|
||||||
|
void Enable(const nsAFlatCString& aModules);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Enable logging of modules specified by A11YLOG environment variable,
|
||||||
|
* all other modules aren't logged.
|
||||||
|
*/
|
||||||
|
void CheckEnv();
|
||||||
|
|
||||||
|
} // namespace logging
|
||||||
|
|
||||||
|
} // namespace a11y
|
||||||
|
} // namespace mozilla
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
340
accessible/base/MarkupMap.h
Normal file
340
accessible/base/MarkupMap.h
Normal file
|
|
@ -0,0 +1,340 @@
|
||||||
|
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||||
|
/* vim:expandtab:shiftwidth=2:tabstop=2:
|
||||||
|
*/
|
||||||
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
|
MARKUPMAP(a,
|
||||||
|
New_HTMLLink,
|
||||||
|
roles::LINK)
|
||||||
|
|
||||||
|
MARKUPMAP(abbr,
|
||||||
|
New_HyperText,
|
||||||
|
0)
|
||||||
|
|
||||||
|
MARKUPMAP(acronym,
|
||||||
|
New_HyperText,
|
||||||
|
0)
|
||||||
|
|
||||||
|
MARKUPMAP(article,
|
||||||
|
New_HyperText,
|
||||||
|
roles::DOCUMENT,
|
||||||
|
Attr(xmlroles, article))
|
||||||
|
|
||||||
|
MARKUPMAP(aside,
|
||||||
|
New_HyperText,
|
||||||
|
roles::NOTE)
|
||||||
|
|
||||||
|
MARKUPMAP(blockquote,
|
||||||
|
New_HyperText,
|
||||||
|
roles::SECTION)
|
||||||
|
|
||||||
|
MARKUPMAP(dd,
|
||||||
|
New_HTMLDefinition,
|
||||||
|
roles::DEFINITION)
|
||||||
|
|
||||||
|
MARKUPMAP(details,
|
||||||
|
New_HyperText,
|
||||||
|
roles::DETAILS)
|
||||||
|
|
||||||
|
MARKUPMAP(div,
|
||||||
|
nullptr,
|
||||||
|
roles::SECTION)
|
||||||
|
|
||||||
|
MARKUPMAP(dl,
|
||||||
|
New_HTMLList,
|
||||||
|
roles::DEFINITION_LIST)
|
||||||
|
|
||||||
|
MARKUPMAP(dt,
|
||||||
|
New_HTMLListitem,
|
||||||
|
roles::TERM)
|
||||||
|
|
||||||
|
MARKUPMAP(figcaption,
|
||||||
|
New_HTMLFigcaption,
|
||||||
|
roles::CAPTION)
|
||||||
|
|
||||||
|
MARKUPMAP(figure,
|
||||||
|
New_HTMLFigure,
|
||||||
|
roles::FIGURE,
|
||||||
|
Attr(xmlroles, figure))
|
||||||
|
|
||||||
|
MARKUPMAP(form,
|
||||||
|
New_HyperText,
|
||||||
|
roles::FORM)
|
||||||
|
|
||||||
|
MARKUPMAP(footer,
|
||||||
|
New_HyperText,
|
||||||
|
roles::FOOTER)
|
||||||
|
|
||||||
|
MARKUPMAP(header,
|
||||||
|
New_HyperText,
|
||||||
|
roles::HEADER)
|
||||||
|
|
||||||
|
MARKUPMAP(h1,
|
||||||
|
New_HyperText,
|
||||||
|
roles::HEADING)
|
||||||
|
|
||||||
|
MARKUPMAP(h2,
|
||||||
|
New_HyperText,
|
||||||
|
roles::HEADING)
|
||||||
|
|
||||||
|
MARKUPMAP(h3,
|
||||||
|
New_HyperText,
|
||||||
|
roles::HEADING)
|
||||||
|
|
||||||
|
MARKUPMAP(h4,
|
||||||
|
New_HyperText,
|
||||||
|
roles::HEADING)
|
||||||
|
|
||||||
|
MARKUPMAP(h5,
|
||||||
|
New_HyperText,
|
||||||
|
roles::HEADING)
|
||||||
|
|
||||||
|
MARKUPMAP(h6,
|
||||||
|
New_HyperText,
|
||||||
|
roles::HEADING)
|
||||||
|
|
||||||
|
MARKUPMAP(label,
|
||||||
|
New_HTMLLabel,
|
||||||
|
roles::LABEL)
|
||||||
|
|
||||||
|
MARKUPMAP(legend,
|
||||||
|
New_HTMLLegend,
|
||||||
|
roles::LABEL)
|
||||||
|
|
||||||
|
MARKUPMAP(li,
|
||||||
|
New_HTMLListitem,
|
||||||
|
0)
|
||||||
|
|
||||||
|
MARKUPMAP(map,
|
||||||
|
nullptr,
|
||||||
|
roles::TEXT_CONTAINER)
|
||||||
|
|
||||||
|
MARKUPMAP(math,
|
||||||
|
New_HyperText,
|
||||||
|
roles::MATHML_MATH)
|
||||||
|
|
||||||
|
MARKUPMAP(mi_,
|
||||||
|
New_HyperText,
|
||||||
|
roles::MATHML_IDENTIFIER)
|
||||||
|
|
||||||
|
MARKUPMAP(mn_,
|
||||||
|
New_HyperText,
|
||||||
|
roles::MATHML_NUMBER)
|
||||||
|
|
||||||
|
MARKUPMAP(mo_,
|
||||||
|
New_HyperText,
|
||||||
|
roles::MATHML_OPERATOR,
|
||||||
|
AttrFromDOM(accent_, accent_),
|
||||||
|
AttrFromDOM(fence_, fence_),
|
||||||
|
AttrFromDOM(separator_, separator_),
|
||||||
|
AttrFromDOM(largeop_, largeop_))
|
||||||
|
|
||||||
|
MARKUPMAP(mtext_,
|
||||||
|
New_HyperText,
|
||||||
|
roles::MATHML_TEXT)
|
||||||
|
|
||||||
|
MARKUPMAP(ms_,
|
||||||
|
New_HyperText,
|
||||||
|
roles::MATHML_STRING_LITERAL)
|
||||||
|
|
||||||
|
MARKUPMAP(mglyph_,
|
||||||
|
New_HyperText,
|
||||||
|
roles::MATHML_GLYPH)
|
||||||
|
|
||||||
|
MARKUPMAP(mrow_,
|
||||||
|
New_HyperText,
|
||||||
|
roles::MATHML_ROW)
|
||||||
|
|
||||||
|
MARKUPMAP(mfrac_,
|
||||||
|
New_HyperText,
|
||||||
|
roles::MATHML_FRACTION,
|
||||||
|
AttrFromDOM(bevelled_, bevelled_),
|
||||||
|
AttrFromDOM(linethickness_, linethickness_))
|
||||||
|
|
||||||
|
MARKUPMAP(msqrt_,
|
||||||
|
New_HyperText,
|
||||||
|
roles::MATHML_SQUARE_ROOT)
|
||||||
|
|
||||||
|
MARKUPMAP(mroot_,
|
||||||
|
New_HyperText,
|
||||||
|
roles::MATHML_ROOT)
|
||||||
|
|
||||||
|
MARKUPMAP(mfenced_,
|
||||||
|
New_HyperText,
|
||||||
|
roles::MATHML_FENCED,
|
||||||
|
AttrFromDOM(close, close),
|
||||||
|
AttrFromDOM(open, open),
|
||||||
|
AttrFromDOM(separators_, separators_))
|
||||||
|
|
||||||
|
MARKUPMAP(menclose_,
|
||||||
|
New_HyperText,
|
||||||
|
roles::MATHML_ENCLOSED,
|
||||||
|
AttrFromDOM(notation_, notation_))
|
||||||
|
|
||||||
|
MARKUPMAP(mstyle_,
|
||||||
|
New_HyperText,
|
||||||
|
roles::MATHML_STYLE)
|
||||||
|
|
||||||
|
MARKUPMAP(msub_,
|
||||||
|
New_HyperText,
|
||||||
|
roles::MATHML_SUB)
|
||||||
|
|
||||||
|
MARKUPMAP(msup_,
|
||||||
|
New_HyperText,
|
||||||
|
roles::MATHML_SUP)
|
||||||
|
|
||||||
|
MARKUPMAP(msubsup_,
|
||||||
|
New_HyperText,
|
||||||
|
roles::MATHML_SUB_SUP)
|
||||||
|
|
||||||
|
MARKUPMAP(munder_,
|
||||||
|
New_HyperText,
|
||||||
|
roles::MATHML_UNDER,
|
||||||
|
AttrFromDOM(accentunder_, accentunder_),
|
||||||
|
AttrFromDOM(align, align))
|
||||||
|
|
||||||
|
MARKUPMAP(mover_,
|
||||||
|
New_HyperText,
|
||||||
|
roles::MATHML_OVER,
|
||||||
|
AttrFromDOM(accent_, accent_),
|
||||||
|
AttrFromDOM(align, align))
|
||||||
|
|
||||||
|
MARKUPMAP(munderover_,
|
||||||
|
New_HyperText,
|
||||||
|
roles::MATHML_UNDER_OVER,
|
||||||
|
AttrFromDOM(accent_, accent_),
|
||||||
|
AttrFromDOM(accentunder_, accentunder_),
|
||||||
|
AttrFromDOM(align, align))
|
||||||
|
|
||||||
|
MARKUPMAP(mmultiscripts_,
|
||||||
|
New_HyperText,
|
||||||
|
roles::MATHML_MULTISCRIPTS)
|
||||||
|
|
||||||
|
MARKUPMAP(mtable_,
|
||||||
|
New_HTMLTableAccessible,
|
||||||
|
roles::MATHML_TABLE,
|
||||||
|
AttrFromDOM(align, align),
|
||||||
|
AttrFromDOM(columnlines_, columnlines_),
|
||||||
|
AttrFromDOM(rowlines_, rowlines_))
|
||||||
|
|
||||||
|
MARKUPMAP(mlabeledtr_,
|
||||||
|
New_HTMLTableRowAccessible,
|
||||||
|
roles::MATHML_LABELED_ROW)
|
||||||
|
|
||||||
|
MARKUPMAP(mtr_,
|
||||||
|
New_HTMLTableRowAccessible,
|
||||||
|
roles::MATHML_TABLE_ROW)
|
||||||
|
|
||||||
|
MARKUPMAP(mtd_,
|
||||||
|
New_HTMLTableCellAccessible,
|
||||||
|
roles::MATHML_CELL)
|
||||||
|
|
||||||
|
MARKUPMAP(maction_,
|
||||||
|
New_HyperText,
|
||||||
|
roles::MATHML_ACTION,
|
||||||
|
AttrFromDOM(actiontype_, actiontype_),
|
||||||
|
AttrFromDOM(selection_, selection_))
|
||||||
|
|
||||||
|
MARKUPMAP(merror_,
|
||||||
|
New_HyperText,
|
||||||
|
roles::MATHML_ERROR)
|
||||||
|
|
||||||
|
MARKUPMAP(mstack_,
|
||||||
|
New_HyperText,
|
||||||
|
roles::MATHML_STACK,
|
||||||
|
AttrFromDOM(align, align),
|
||||||
|
AttrFromDOM(position, position))
|
||||||
|
|
||||||
|
MARKUPMAP(mlongdiv_,
|
||||||
|
New_HyperText,
|
||||||
|
roles::MATHML_LONG_DIVISION,
|
||||||
|
AttrFromDOM(longdivstyle_, longdivstyle_))
|
||||||
|
|
||||||
|
MARKUPMAP(msgroup_,
|
||||||
|
New_HyperText,
|
||||||
|
roles::MATHML_STACK_GROUP,
|
||||||
|
AttrFromDOM(position, position),
|
||||||
|
AttrFromDOM(shift_, shift_))
|
||||||
|
|
||||||
|
MARKUPMAP(msrow_,
|
||||||
|
New_HyperText,
|
||||||
|
roles::MATHML_STACK_ROW,
|
||||||
|
AttrFromDOM(position, position))
|
||||||
|
|
||||||
|
MARKUPMAP(mscarries_,
|
||||||
|
New_HyperText,
|
||||||
|
roles::MATHML_STACK_CARRIES,
|
||||||
|
AttrFromDOM(location_, location_),
|
||||||
|
AttrFromDOM(position, position))
|
||||||
|
|
||||||
|
MARKUPMAP(mscarry_,
|
||||||
|
New_HyperText,
|
||||||
|
roles::MATHML_STACK_CARRY,
|
||||||
|
AttrFromDOM(crossout_, crossout_))
|
||||||
|
|
||||||
|
MARKUPMAP(msline_,
|
||||||
|
New_HyperText,
|
||||||
|
roles::MATHML_STACK_LINE,
|
||||||
|
AttrFromDOM(position, position))
|
||||||
|
|
||||||
|
MARKUPMAP(nav,
|
||||||
|
New_HyperText,
|
||||||
|
roles::SECTION)
|
||||||
|
|
||||||
|
MARKUPMAP(ol,
|
||||||
|
New_HTMLList,
|
||||||
|
roles::LIST)
|
||||||
|
|
||||||
|
MARKUPMAP(option,
|
||||||
|
New_HTMLOption,
|
||||||
|
0)
|
||||||
|
|
||||||
|
MARKUPMAP(optgroup,
|
||||||
|
New_HTMLOptgroup,
|
||||||
|
0)
|
||||||
|
|
||||||
|
MARKUPMAP(output,
|
||||||
|
New_HTMLOutput,
|
||||||
|
roles::SECTION,
|
||||||
|
Attr(live, polite))
|
||||||
|
|
||||||
|
MARKUPMAP(p,
|
||||||
|
nullptr,
|
||||||
|
roles::PARAGRAPH)
|
||||||
|
|
||||||
|
MARKUPMAP(progress,
|
||||||
|
New_HTMLProgress,
|
||||||
|
0)
|
||||||
|
|
||||||
|
MARKUPMAP(q,
|
||||||
|
New_HyperText,
|
||||||
|
0)
|
||||||
|
|
||||||
|
MARKUPMAP(section,
|
||||||
|
New_HyperText,
|
||||||
|
roles::SECTION,
|
||||||
|
Attr(xmlroles, region))
|
||||||
|
|
||||||
|
MARKUPMAP(summary,
|
||||||
|
New_HTMLSummary,
|
||||||
|
roles::SUMMARY)
|
||||||
|
|
||||||
|
MARKUPMAP(time,
|
||||||
|
New_HyperText,
|
||||||
|
0,
|
||||||
|
Attr(xmlroles, time),
|
||||||
|
AttrFromDOM(datetime, datetime))
|
||||||
|
|
||||||
|
MARKUPMAP(td,
|
||||||
|
New_HTMLTableHeaderCellIfScope,
|
||||||
|
0)
|
||||||
|
|
||||||
|
MARKUPMAP(th,
|
||||||
|
New_HTMLTableHeaderCell,
|
||||||
|
0)
|
||||||
|
|
||||||
|
MARKUPMAP(ul,
|
||||||
|
New_HTMLList,
|
||||||
|
roles::LIST)
|
||||||
947
accessible/base/NotificationController.cpp
Normal file
947
accessible/base/NotificationController.cpp
Normal file
|
|
@ -0,0 +1,947 @@
|
||||||
|
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||||
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
|
#include "NotificationController.h"
|
||||||
|
|
||||||
|
#include "DocAccessible-inl.h"
|
||||||
|
#include "DocAccessibleChild.h"
|
||||||
|
#include "TextLeafAccessible.h"
|
||||||
|
#include "TextUpdater.h"
|
||||||
|
|
||||||
|
#include "mozilla/dom/TabChild.h"
|
||||||
|
#include "mozilla/dom/Element.h"
|
||||||
|
#include "mozilla/Telemetry.h"
|
||||||
|
|
||||||
|
using namespace mozilla;
|
||||||
|
using namespace mozilla::a11y;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// NotificationCollector
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
NotificationController::NotificationController(DocAccessible* aDocument,
|
||||||
|
nsIPresShell* aPresShell) :
|
||||||
|
EventQueue(aDocument), mObservingState(eNotObservingRefresh),
|
||||||
|
mPresShell(aPresShell), mEventGeneration(0)
|
||||||
|
{
|
||||||
|
#ifdef DEBUG
|
||||||
|
mMoveGuardOnStack = false;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Schedule initial accessible tree construction.
|
||||||
|
ScheduleProcessing();
|
||||||
|
}
|
||||||
|
|
||||||
|
NotificationController::~NotificationController()
|
||||||
|
{
|
||||||
|
NS_ASSERTION(!mDocument, "Controller wasn't shutdown properly!");
|
||||||
|
if (mDocument)
|
||||||
|
Shutdown();
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// NotificationCollector: AddRef/Release and cycle collection
|
||||||
|
|
||||||
|
NS_IMPL_CYCLE_COLLECTING_NATIVE_ADDREF(NotificationController)
|
||||||
|
NS_IMPL_CYCLE_COLLECTING_NATIVE_RELEASE(NotificationController)
|
||||||
|
|
||||||
|
NS_IMPL_CYCLE_COLLECTION_CLASS(NotificationController)
|
||||||
|
|
||||||
|
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(NotificationController)
|
||||||
|
if (tmp->mDocument)
|
||||||
|
tmp->Shutdown();
|
||||||
|
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
|
||||||
|
|
||||||
|
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(NotificationController)
|
||||||
|
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mHangingChildDocuments)
|
||||||
|
for (auto it = tmp->mContentInsertions.ConstIter(); !it.Done(); it.Next()) {
|
||||||
|
NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mContentInsertions key");
|
||||||
|
cb.NoteXPCOMChild(it.Key());
|
||||||
|
nsTArray<nsCOMPtr<nsIContent>>* list = it.UserData();
|
||||||
|
for (uint32_t i = 0; i < list->Length(); i++) {
|
||||||
|
NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb,
|
||||||
|
"mContentInsertions value item");
|
||||||
|
cb.NoteXPCOMChild(list->ElementAt(i));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mEvents)
|
||||||
|
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mRelocations)
|
||||||
|
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
|
||||||
|
|
||||||
|
NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(NotificationController, AddRef)
|
||||||
|
NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(NotificationController, Release)
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// NotificationCollector: public
|
||||||
|
|
||||||
|
void
|
||||||
|
NotificationController::Shutdown()
|
||||||
|
{
|
||||||
|
if (mObservingState != eNotObservingRefresh &&
|
||||||
|
mPresShell->RemoveRefreshObserver(this, Flush_Display)) {
|
||||||
|
mObservingState = eNotObservingRefresh;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Shutdown handling child documents.
|
||||||
|
int32_t childDocCount = mHangingChildDocuments.Length();
|
||||||
|
for (int32_t idx = childDocCount - 1; idx >= 0; idx--) {
|
||||||
|
if (!mHangingChildDocuments[idx]->IsDefunct())
|
||||||
|
mHangingChildDocuments[idx]->Shutdown();
|
||||||
|
}
|
||||||
|
|
||||||
|
mHangingChildDocuments.Clear();
|
||||||
|
|
||||||
|
mDocument = nullptr;
|
||||||
|
mPresShell = nullptr;
|
||||||
|
|
||||||
|
mTextHash.Clear();
|
||||||
|
mContentInsertions.Clear();
|
||||||
|
mNotifications.Clear();
|
||||||
|
mEvents.Clear();
|
||||||
|
mRelocations.Clear();
|
||||||
|
mEventTree.Clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
EventTree*
|
||||||
|
NotificationController::QueueMutation(Accessible* aContainer)
|
||||||
|
{
|
||||||
|
EventTree* tree = mEventTree.FindOrInsert(aContainer);
|
||||||
|
if (tree) {
|
||||||
|
ScheduleProcessing();
|
||||||
|
}
|
||||||
|
return tree;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
NotificationController::QueueMutationEvent(AccTreeMutationEvent* aEvent)
|
||||||
|
{
|
||||||
|
// We have to allow there to be a hide and then a show event for a target
|
||||||
|
// because of targets getting moved. However we need to coalesce a show and
|
||||||
|
// then a hide for a target which means we need to check for that here.
|
||||||
|
if (aEvent->GetEventType() == nsIAccessibleEvent::EVENT_HIDE &&
|
||||||
|
aEvent->GetAccessible()->ShowEventTarget()) {
|
||||||
|
AccTreeMutationEvent* showEvent = mMutationMap.GetEvent(aEvent->GetAccessible(), EventMap::ShowEvent);
|
||||||
|
DropMutationEvent(showEvent);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
AccMutationEvent* mutEvent = downcast_accEvent(aEvent);
|
||||||
|
mEventGeneration++;
|
||||||
|
mutEvent->SetEventGeneration(mEventGeneration);
|
||||||
|
|
||||||
|
if (!mFirstMutationEvent) {
|
||||||
|
mFirstMutationEvent = aEvent;
|
||||||
|
ScheduleProcessing();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mLastMutationEvent) {
|
||||||
|
NS_ASSERTION(!mLastMutationEvent->NextEvent(), "why isn't the last event the end?");
|
||||||
|
mLastMutationEvent->SetNextEvent(aEvent);
|
||||||
|
}
|
||||||
|
|
||||||
|
aEvent->SetPrevEvent(mLastMutationEvent);
|
||||||
|
mLastMutationEvent = aEvent;
|
||||||
|
mMutationMap.PutEvent(aEvent);
|
||||||
|
|
||||||
|
// Because we could be hiding the target of a show event we need to get rid
|
||||||
|
// of any such events. It may be possible to do less than coallesce all
|
||||||
|
// events, however that is easiest.
|
||||||
|
if (aEvent->GetEventType() == nsIAccessibleEvent::EVENT_HIDE) {
|
||||||
|
CoalesceMutationEvents();
|
||||||
|
|
||||||
|
// mLastMutationEvent will point to something other than aEvent if and only
|
||||||
|
// if aEvent was just coalesced away. In that case a parent accessible
|
||||||
|
// must already have the required reorder and text change events so we are
|
||||||
|
// done here.
|
||||||
|
if (mLastMutationEvent != aEvent) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// We need to fire a reorder event after all of the events targeted at shown or
|
||||||
|
// hidden children of a container. So either queue a new one, or move an
|
||||||
|
// existing one to the end of the queue if the container already has a
|
||||||
|
// reorder event.
|
||||||
|
Accessible* target = aEvent->GetAccessible();
|
||||||
|
Accessible* container = aEvent->GetAccessible()->Parent();
|
||||||
|
RefPtr<AccReorderEvent> reorder;
|
||||||
|
if (!container->ReorderEventTarget()) {
|
||||||
|
reorder = new AccReorderEvent(container);
|
||||||
|
container->SetReorderEventTarget(true);
|
||||||
|
mMutationMap.PutEvent(reorder);
|
||||||
|
|
||||||
|
// Since this is the first child of container that is changing, the name of
|
||||||
|
// container may be changing.
|
||||||
|
QueueNameChange(target);
|
||||||
|
} else {
|
||||||
|
AccReorderEvent* event = downcast_accEvent(mMutationMap.GetEvent(container, EventMap::ReorderEvent));
|
||||||
|
reorder = event;
|
||||||
|
if (mFirstMutationEvent == event) {
|
||||||
|
mFirstMutationEvent = event->NextEvent();
|
||||||
|
} else {
|
||||||
|
event->PrevEvent()->SetNextEvent(event->NextEvent());
|
||||||
|
}
|
||||||
|
|
||||||
|
event->NextEvent()->SetPrevEvent(event->PrevEvent());
|
||||||
|
event->SetNextEvent(nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
reorder->SetEventGeneration(mEventGeneration);
|
||||||
|
reorder->SetPrevEvent(mLastMutationEvent);
|
||||||
|
mLastMutationEvent->SetNextEvent(reorder);
|
||||||
|
mLastMutationEvent = reorder;
|
||||||
|
|
||||||
|
// It is not possible to have a text change event for something other than a
|
||||||
|
// hyper text accessible.
|
||||||
|
if (!container->IsHyperText()) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
MOZ_ASSERT(mutEvent);
|
||||||
|
|
||||||
|
nsString text;
|
||||||
|
aEvent->GetAccessible()->AppendTextTo(text);
|
||||||
|
if (text.IsEmpty()) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
int32_t offset = container->AsHyperText()->GetChildOffset(target);
|
||||||
|
AccTreeMutationEvent* prevEvent = aEvent->PrevEvent();
|
||||||
|
while (prevEvent && prevEvent->GetEventType() == nsIAccessibleEvent::EVENT_REORDER) {
|
||||||
|
prevEvent = prevEvent->PrevEvent();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (prevEvent && prevEvent->GetEventType() == nsIAccessibleEvent::EVENT_HIDE &&
|
||||||
|
mutEvent->IsHide()) {
|
||||||
|
AccHideEvent* prevHide = downcast_accEvent(prevEvent);
|
||||||
|
AccTextChangeEvent* prevTextChange = prevHide->mTextChangeEvent;
|
||||||
|
if (prevTextChange && prevHide->Parent() == mutEvent->Parent()) {
|
||||||
|
if (prevHide->mNextSibling == target) {
|
||||||
|
target->AppendTextTo(prevTextChange->mModifiedText);
|
||||||
|
prevHide->mTextChangeEvent.swap(mutEvent->mTextChangeEvent);
|
||||||
|
} else if (prevHide->mPrevSibling == target) {
|
||||||
|
nsString temp;
|
||||||
|
target->AppendTextTo(temp);
|
||||||
|
|
||||||
|
uint32_t extraLen = temp.Length();
|
||||||
|
temp += prevTextChange->mModifiedText;;
|
||||||
|
prevTextChange->mModifiedText = temp;
|
||||||
|
prevTextChange->mStart -= extraLen;
|
||||||
|
prevHide->mTextChangeEvent.swap(mutEvent->mTextChangeEvent);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (prevEvent && mutEvent->IsShow() &&
|
||||||
|
prevEvent->GetEventType() == nsIAccessibleEvent::EVENT_SHOW) {
|
||||||
|
AccShowEvent* prevShow = downcast_accEvent(prevEvent);
|
||||||
|
AccTextChangeEvent* prevTextChange = prevShow->mTextChangeEvent;
|
||||||
|
if (prevTextChange && prevShow->Parent() == target->Parent()) {
|
||||||
|
int32_t index = target->IndexInParent();
|
||||||
|
int32_t prevIndex = prevShow->GetAccessible()->IndexInParent();
|
||||||
|
if (prevIndex + 1 == index) {
|
||||||
|
target->AppendTextTo(prevTextChange->mModifiedText);
|
||||||
|
prevShow->mTextChangeEvent.swap(mutEvent->mTextChangeEvent);
|
||||||
|
} else if (index + 1 == prevIndex) {
|
||||||
|
nsString temp;
|
||||||
|
target->AppendTextTo(temp);
|
||||||
|
prevTextChange->mStart -= temp.Length();
|
||||||
|
temp += prevTextChange->mModifiedText;
|
||||||
|
prevTextChange->mModifiedText = temp;
|
||||||
|
prevShow->mTextChangeEvent.swap(mutEvent->mTextChangeEvent);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!mutEvent->mTextChangeEvent) {
|
||||||
|
mutEvent->mTextChangeEvent =
|
||||||
|
new AccTextChangeEvent(container, offset, text, mutEvent->IsShow(),
|
||||||
|
aEvent->mIsFromUserInput ? eFromUserInput : eNoUserInput);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
NotificationController::DropMutationEvent(AccTreeMutationEvent* aEvent)
|
||||||
|
{
|
||||||
|
// unset the event bits since the event isn't being fired any more.
|
||||||
|
if (aEvent->GetEventType() == nsIAccessibleEvent::EVENT_REORDER) {
|
||||||
|
aEvent->GetAccessible()->SetReorderEventTarget(false);
|
||||||
|
} else if (aEvent->GetEventType() == nsIAccessibleEvent::EVENT_SHOW) {
|
||||||
|
aEvent->GetAccessible()->SetShowEventTarget(false);
|
||||||
|
} else {
|
||||||
|
AccHideEvent* hideEvent = downcast_accEvent(aEvent);
|
||||||
|
MOZ_ASSERT(hideEvent);
|
||||||
|
|
||||||
|
if (hideEvent->NeedsShutdown()) {
|
||||||
|
mDocument->ShutdownChildrenInSubtree(aEvent->GetAccessible());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Do the work to splice the event out of the list.
|
||||||
|
if (mFirstMutationEvent == aEvent) {
|
||||||
|
mFirstMutationEvent = aEvent->NextEvent();
|
||||||
|
} else {
|
||||||
|
aEvent->PrevEvent()->SetNextEvent(aEvent->NextEvent());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mLastMutationEvent == aEvent) {
|
||||||
|
mLastMutationEvent = aEvent->PrevEvent();
|
||||||
|
} else {
|
||||||
|
aEvent->NextEvent()->SetPrevEvent(aEvent->PrevEvent());
|
||||||
|
}
|
||||||
|
|
||||||
|
aEvent->SetPrevEvent(nullptr);
|
||||||
|
aEvent->SetNextEvent(nullptr);
|
||||||
|
mMutationMap.RemoveEvent(aEvent);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
NotificationController::CoalesceMutationEvents()
|
||||||
|
{
|
||||||
|
AccTreeMutationEvent* event = mFirstMutationEvent;
|
||||||
|
while (event) {
|
||||||
|
AccTreeMutationEvent* nextEvent = event->NextEvent();
|
||||||
|
uint32_t eventType = event->GetEventType();
|
||||||
|
if (event->GetEventType() == nsIAccessibleEvent::EVENT_REORDER) {
|
||||||
|
Accessible* acc = event->GetAccessible();
|
||||||
|
while (acc) {
|
||||||
|
if (acc->IsDoc()) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// if a parent of the reorder event's target is being hidden that
|
||||||
|
// hide event's target must have a parent that is also a reorder event
|
||||||
|
// target. That means we don't need this reorder event.
|
||||||
|
if (acc->HideEventTarget()) {
|
||||||
|
DropMutationEvent(event);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
Accessible* parent = acc->Parent();
|
||||||
|
if (parent->ReorderEventTarget()) {
|
||||||
|
AccReorderEvent* reorder = downcast_accEvent(mMutationMap.GetEvent(parent, EventMap::ReorderEvent));
|
||||||
|
|
||||||
|
// We want to make sure that a reorder event comes after any show or
|
||||||
|
// hide events targeted at the children of its target. We keep the
|
||||||
|
// invariant that event generation goes up as you are farther in the
|
||||||
|
// queue, so we want to use the spot of the event with the higher
|
||||||
|
// generation number, and keep that generation number.
|
||||||
|
if (reorder && reorder->EventGeneration() < event->EventGeneration()) {
|
||||||
|
reorder->SetEventGeneration(event->EventGeneration());
|
||||||
|
|
||||||
|
// It may be true that reorder was before event, and we coalesced
|
||||||
|
// away all the show / hide events between them. In that case
|
||||||
|
// event is already immediately after reorder in the queue and we
|
||||||
|
// do not need to rearrange the list of events.
|
||||||
|
if (event != reorder->NextEvent()) {
|
||||||
|
// There really should be a show or hide event before the first
|
||||||
|
// reorder event.
|
||||||
|
if (reorder->PrevEvent()) {
|
||||||
|
reorder->PrevEvent()->SetNextEvent(reorder->NextEvent());
|
||||||
|
} else {
|
||||||
|
mFirstMutationEvent = reorder->NextEvent();
|
||||||
|
}
|
||||||
|
|
||||||
|
reorder->NextEvent()->SetPrevEvent(reorder->PrevEvent());
|
||||||
|
event->PrevEvent()->SetNextEvent(reorder);
|
||||||
|
reorder->SetPrevEvent(event->PrevEvent());
|
||||||
|
event->SetPrevEvent(reorder);
|
||||||
|
reorder->SetNextEvent(event);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
DropMutationEvent(event);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
acc = parent;
|
||||||
|
}
|
||||||
|
} else if (eventType == nsIAccessibleEvent::EVENT_SHOW) {
|
||||||
|
Accessible* parent = event->GetAccessible()->Parent();
|
||||||
|
while (parent) {
|
||||||
|
if (parent->IsDoc()) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// if the parent of a show event is being either shown or hidden then
|
||||||
|
// we don't need to fire a show event for a subtree of that change.
|
||||||
|
if (parent->ShowEventTarget() || parent->HideEventTarget()) {
|
||||||
|
DropMutationEvent(event);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
parent = parent->Parent();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
MOZ_ASSERT(eventType == nsIAccessibleEvent::EVENT_HIDE, "mutation event list has an invalid event");
|
||||||
|
|
||||||
|
AccHideEvent* hideEvent = downcast_accEvent(event);
|
||||||
|
Accessible* parent = hideEvent->Parent();
|
||||||
|
while (parent) {
|
||||||
|
if (parent->IsDoc()) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (parent->HideEventTarget()) {
|
||||||
|
DropMutationEvent(event);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (parent->ShowEventTarget()) {
|
||||||
|
AccShowEvent* showEvent = downcast_accEvent(mMutationMap.GetEvent(parent, EventMap::ShowEvent));
|
||||||
|
if (showEvent->EventGeneration() < hideEvent->EventGeneration()) {
|
||||||
|
DropMutationEvent(hideEvent);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
parent = parent->Parent();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
event = nextEvent;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
NotificationController::ScheduleChildDocBinding(DocAccessible* aDocument)
|
||||||
|
{
|
||||||
|
// Schedule child document binding to the tree.
|
||||||
|
mHangingChildDocuments.AppendElement(aDocument);
|
||||||
|
ScheduleProcessing();
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
NotificationController::ScheduleContentInsertion(Accessible* aContainer,
|
||||||
|
nsIContent* aStartChildNode,
|
||||||
|
nsIContent* aEndChildNode)
|
||||||
|
{
|
||||||
|
nsTArray<nsCOMPtr<nsIContent>>* list =
|
||||||
|
mContentInsertions.LookupOrAdd(aContainer);
|
||||||
|
|
||||||
|
bool needsProcessing = false;
|
||||||
|
nsIContent* node = aStartChildNode;
|
||||||
|
while (node != aEndChildNode) {
|
||||||
|
// Notification triggers for content insertion even if no content was
|
||||||
|
// actually inserted, check if the given content has a frame to discard
|
||||||
|
// this case early.
|
||||||
|
if (node->GetPrimaryFrame()) {
|
||||||
|
if (list->AppendElement(node))
|
||||||
|
needsProcessing = true;
|
||||||
|
}
|
||||||
|
node = node->GetNextSibling();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (needsProcessing) {
|
||||||
|
ScheduleProcessing();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
NotificationController::ScheduleProcessing()
|
||||||
|
{
|
||||||
|
// If notification flush isn't planed yet start notification flush
|
||||||
|
// asynchronously (after style and layout).
|
||||||
|
if (mObservingState == eNotObservingRefresh) {
|
||||||
|
if (mPresShell->AddRefreshObserver(this, Flush_Display))
|
||||||
|
mObservingState = eRefreshObserving;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// NotificationCollector: protected
|
||||||
|
|
||||||
|
bool
|
||||||
|
NotificationController::IsUpdatePending()
|
||||||
|
{
|
||||||
|
return mPresShell->IsLayoutFlushObserver() ||
|
||||||
|
mObservingState == eRefreshProcessingForUpdate ||
|
||||||
|
mContentInsertions.Count() != 0 || mNotifications.Length() != 0 ||
|
||||||
|
mTextHash.Count() != 0 ||
|
||||||
|
!mDocument->HasLoadState(DocAccessible::eTreeConstructed);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
NotificationController::ProcessMutationEvents()
|
||||||
|
{
|
||||||
|
// there is no reason to fire a hide event for a child of a show event
|
||||||
|
// target. That can happen if something is inserted into the tree and
|
||||||
|
// removed before the next refresh driver tick, but it should not be
|
||||||
|
// observable outside gecko so it should be safe to coalesce away any such
|
||||||
|
// events. This means that it should be fine to fire all of the hide events
|
||||||
|
// first, and then deal with any shown subtrees.
|
||||||
|
for (AccTreeMutationEvent* event = mFirstMutationEvent;
|
||||||
|
event; event = event->NextEvent()) {
|
||||||
|
if (event->GetEventType() != nsIAccessibleEvent::EVENT_HIDE) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
nsEventShell::FireEvent(event);
|
||||||
|
if (!mDocument) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
AccMutationEvent* mutEvent = downcast_accEvent(event);
|
||||||
|
if (mutEvent->mTextChangeEvent) {
|
||||||
|
nsEventShell::FireEvent(mutEvent->mTextChangeEvent);
|
||||||
|
if (!mDocument) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fire menupopup end event before a hide event if a menu goes away.
|
||||||
|
|
||||||
|
// XXX: We don't look into children of hidden subtree to find hiding
|
||||||
|
// menupopup (as we did prior bug 570275) because we don't do that when
|
||||||
|
// menu is showing (and that's impossible until bug 606924 is fixed).
|
||||||
|
// Nevertheless we should do this at least because layout coalesces
|
||||||
|
// the changes before our processing and we may miss some menupopup
|
||||||
|
// events. Now we just want to be consistent in content insertion/removal
|
||||||
|
// handling.
|
||||||
|
if (event->mAccessible->ARIARole() == roles::MENUPOPUP) {
|
||||||
|
nsEventShell::FireEvent(nsIAccessibleEvent::EVENT_MENUPOPUP_END,
|
||||||
|
event->mAccessible);
|
||||||
|
if (!mDocument) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
AccHideEvent* hideEvent = downcast_accEvent(event);
|
||||||
|
if (hideEvent->NeedsShutdown()) {
|
||||||
|
mDocument->ShutdownChildrenInSubtree(event->mAccessible);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Group the show events by the parent of their target.
|
||||||
|
nsDataHashtable<nsPtrHashKey<Accessible>, nsTArray<AccTreeMutationEvent*>> showEvents;
|
||||||
|
for (AccTreeMutationEvent* event = mFirstMutationEvent;
|
||||||
|
event; event = event->NextEvent()) {
|
||||||
|
if (event->GetEventType() != nsIAccessibleEvent::EVENT_SHOW) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
Accessible* parent = event->GetAccessible()->Parent();
|
||||||
|
showEvents.GetOrInsert(parent).AppendElement(event);
|
||||||
|
}
|
||||||
|
|
||||||
|
// We need to fire show events for the children of an accessible in the order
|
||||||
|
// of their indices at this point. So sort each set of events for the same
|
||||||
|
// container by the index of their target.
|
||||||
|
for (auto iter = showEvents.Iter(); !iter.Done(); iter.Next()) {
|
||||||
|
struct AccIdxComparator {
|
||||||
|
bool LessThan(const AccTreeMutationEvent* a, const AccTreeMutationEvent* b) const
|
||||||
|
{
|
||||||
|
int32_t aIdx = a->GetAccessible()->IndexInParent();
|
||||||
|
int32_t bIdx = b->GetAccessible()->IndexInParent();
|
||||||
|
MOZ_ASSERT(aIdx >= 0 && bIdx >= 0 && aIdx != bIdx);
|
||||||
|
return aIdx < bIdx;
|
||||||
|
}
|
||||||
|
bool Equals(const AccTreeMutationEvent* a, const AccTreeMutationEvent* b) const
|
||||||
|
{
|
||||||
|
DebugOnly<int32_t> aIdx = a->GetAccessible()->IndexInParent();
|
||||||
|
DebugOnly<int32_t> bIdx = b->GetAccessible()->IndexInParent();
|
||||||
|
MOZ_ASSERT(aIdx >= 0 && bIdx >= 0 && aIdx != bIdx);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
nsTArray<AccTreeMutationEvent*>& events = iter.Data();
|
||||||
|
events.Sort(AccIdxComparator());
|
||||||
|
for (AccTreeMutationEvent* event: events) {
|
||||||
|
nsEventShell::FireEvent(event);
|
||||||
|
if (!mDocument) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
AccMutationEvent* mutEvent = downcast_accEvent(event);
|
||||||
|
if (mutEvent->mTextChangeEvent) {
|
||||||
|
nsEventShell::FireEvent(mutEvent->mTextChangeEvent);
|
||||||
|
if (!mDocument) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Now we can fire the reorder events after all the show and hide events.
|
||||||
|
for (AccTreeMutationEvent* event = mFirstMutationEvent;
|
||||||
|
event; event = event->NextEvent()) {
|
||||||
|
if (event->GetEventType() != nsIAccessibleEvent::EVENT_REORDER) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
nsEventShell::FireEvent(event);
|
||||||
|
if (!mDocument) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Accessible* target = event->GetAccessible();
|
||||||
|
target->Document()->MaybeNotifyOfValueChange(target);
|
||||||
|
if (!mDocument) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// NotificationCollector: private
|
||||||
|
|
||||||
|
void
|
||||||
|
NotificationController::WillRefresh(mozilla::TimeStamp aTime)
|
||||||
|
{
|
||||||
|
PROFILER_LABEL_FUNC(js::ProfileEntry::Category::OTHER);
|
||||||
|
Telemetry::AutoTimer<Telemetry::A11Y_UPDATE_TIME> updateTimer;
|
||||||
|
|
||||||
|
// If the document accessible that notification collector was created for is
|
||||||
|
// now shut down, don't process notifications anymore.
|
||||||
|
NS_ASSERTION(mDocument,
|
||||||
|
"The document was shut down while refresh observer is attached!");
|
||||||
|
if (!mDocument)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (mObservingState == eRefreshProcessing ||
|
||||||
|
mObservingState == eRefreshProcessingForUpdate)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// Any generic notifications should be queued if we're processing content
|
||||||
|
// insertions or generic notifications.
|
||||||
|
mObservingState = eRefreshProcessingForUpdate;
|
||||||
|
|
||||||
|
// Initial accessible tree construction.
|
||||||
|
if (!mDocument->HasLoadState(DocAccessible::eTreeConstructed)) {
|
||||||
|
// If document is not bound to parent at this point then the document is not
|
||||||
|
// ready yet (process notifications later).
|
||||||
|
if (!mDocument->IsBoundToParent()) {
|
||||||
|
mObservingState = eRefreshObserving;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef A11Y_LOG
|
||||||
|
if (logging::IsEnabled(logging::eTree)) {
|
||||||
|
logging::MsgBegin("TREE", "initial tree created");
|
||||||
|
logging::Address("document", mDocument);
|
||||||
|
logging::MsgEnd();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
mDocument->DoInitialUpdate();
|
||||||
|
|
||||||
|
NS_ASSERTION(mContentInsertions.Count() == 0,
|
||||||
|
"Pending content insertions while initial accessible tree isn't created!");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Initialize scroll support if needed.
|
||||||
|
if (!(mDocument->mDocFlags & DocAccessible::eScrollInitialized))
|
||||||
|
mDocument->AddScrollListener();
|
||||||
|
|
||||||
|
// Process rendered text change notifications.
|
||||||
|
for (auto iter = mTextHash.Iter(); !iter.Done(); iter.Next()) {
|
||||||
|
nsCOMPtrHashKey<nsIContent>* entry = iter.Get();
|
||||||
|
nsIContent* textNode = entry->GetKey();
|
||||||
|
Accessible* textAcc = mDocument->GetAccessible(textNode);
|
||||||
|
|
||||||
|
// If the text node is not in tree or doesn't have frame then this case should
|
||||||
|
// have been handled already by content removal notifications.
|
||||||
|
nsINode* containerNode = textNode->GetParentNode();
|
||||||
|
if (!containerNode) {
|
||||||
|
NS_ASSERTION(!textAcc,
|
||||||
|
"Text node was removed but accessible is kept alive!");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
nsIFrame* textFrame = textNode->GetPrimaryFrame();
|
||||||
|
if (!textFrame) {
|
||||||
|
NS_ASSERTION(!textAcc,
|
||||||
|
"Text node isn't rendered but accessible is kept alive!");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
nsIContent* containerElm = containerNode->IsElement() ?
|
||||||
|
containerNode->AsElement() : nullptr;
|
||||||
|
|
||||||
|
nsIFrame::RenderedText text = textFrame->GetRenderedText(0,
|
||||||
|
UINT32_MAX, nsIFrame::TextOffsetType::OFFSETS_IN_CONTENT_TEXT,
|
||||||
|
nsIFrame::TrailingWhitespace::DONT_TRIM_TRAILING_WHITESPACE);
|
||||||
|
|
||||||
|
// Remove text accessible if rendered text is empty.
|
||||||
|
if (textAcc) {
|
||||||
|
if (text.mString.IsEmpty()) {
|
||||||
|
#ifdef A11Y_LOG
|
||||||
|
if (logging::IsEnabled(logging::eTree | logging::eText)) {
|
||||||
|
logging::MsgBegin("TREE", "text node lost its content; doc: %p", mDocument);
|
||||||
|
logging::Node("container", containerElm);
|
||||||
|
logging::Node("content", textNode);
|
||||||
|
logging::MsgEnd();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
mDocument->ContentRemoved(containerElm, textNode);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update text of the accessible and fire text change events.
|
||||||
|
#ifdef A11Y_LOG
|
||||||
|
if (logging::IsEnabled(logging::eText)) {
|
||||||
|
logging::MsgBegin("TEXT", "text may be changed; doc: %p", mDocument);
|
||||||
|
logging::Node("container", containerElm);
|
||||||
|
logging::Node("content", textNode);
|
||||||
|
logging::MsgEntry("old text '%s'",
|
||||||
|
NS_ConvertUTF16toUTF8(textAcc->AsTextLeaf()->Text()).get());
|
||||||
|
logging::MsgEntry("new text: '%s'",
|
||||||
|
NS_ConvertUTF16toUTF8(text.mString).get());
|
||||||
|
logging::MsgEnd();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
TextUpdater::Run(mDocument, textAcc->AsTextLeaf(), text.mString);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Append an accessible if rendered text is not empty.
|
||||||
|
if (!text.mString.IsEmpty()) {
|
||||||
|
#ifdef A11Y_LOG
|
||||||
|
if (logging::IsEnabled(logging::eTree | logging::eText)) {
|
||||||
|
logging::MsgBegin("TREE", "text node gains new content; doc: %p", mDocument);
|
||||||
|
logging::Node("container", containerElm);
|
||||||
|
logging::Node("content", textNode);
|
||||||
|
logging::MsgEnd();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
Accessible* container = mDocument->AccessibleOrTrueContainer(containerNode);
|
||||||
|
MOZ_ASSERT(container,
|
||||||
|
"Text node having rendered text hasn't accessible document!");
|
||||||
|
if (container) {
|
||||||
|
nsTArray<nsCOMPtr<nsIContent>>* list =
|
||||||
|
mContentInsertions.LookupOrAdd(container);
|
||||||
|
list->AppendElement(textNode);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
mTextHash.Clear();
|
||||||
|
|
||||||
|
// Process content inserted notifications to update the tree.
|
||||||
|
for (auto iter = mContentInsertions.ConstIter(); !iter.Done(); iter.Next()) {
|
||||||
|
mDocument->ProcessContentInserted(iter.Key(), iter.UserData());
|
||||||
|
if (!mDocument) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
mContentInsertions.Clear();
|
||||||
|
|
||||||
|
// Bind hanging child documents.
|
||||||
|
uint32_t hangingDocCnt = mHangingChildDocuments.Length();
|
||||||
|
nsTArray<RefPtr<DocAccessible>> newChildDocs;
|
||||||
|
for (uint32_t idx = 0; idx < hangingDocCnt; idx++) {
|
||||||
|
DocAccessible* childDoc = mHangingChildDocuments[idx];
|
||||||
|
if (childDoc->IsDefunct())
|
||||||
|
continue;
|
||||||
|
|
||||||
|
nsIContent* ownerContent = mDocument->DocumentNode()->
|
||||||
|
FindContentForSubDocument(childDoc->DocumentNode());
|
||||||
|
if (ownerContent) {
|
||||||
|
Accessible* outerDocAcc = mDocument->GetAccessible(ownerContent);
|
||||||
|
if (outerDocAcc && outerDocAcc->AppendChild(childDoc)) {
|
||||||
|
if (mDocument->AppendChildDocument(childDoc)) {
|
||||||
|
newChildDocs.AppendElement(Move(mHangingChildDocuments[idx]));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
outerDocAcc->RemoveChild(childDoc);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Failed to bind the child document, destroy it.
|
||||||
|
childDoc->Shutdown();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mHangingChildDocuments.Clear();
|
||||||
|
|
||||||
|
// If the document is ready and all its subdocuments are completely loaded
|
||||||
|
// then process the document load.
|
||||||
|
if (mDocument->HasLoadState(DocAccessible::eReady) &&
|
||||||
|
!mDocument->HasLoadState(DocAccessible::eCompletelyLoaded) &&
|
||||||
|
hangingDocCnt == 0) {
|
||||||
|
uint32_t childDocCnt = mDocument->ChildDocumentCount(), childDocIdx = 0;
|
||||||
|
for (; childDocIdx < childDocCnt; childDocIdx++) {
|
||||||
|
DocAccessible* childDoc = mDocument->GetChildDocumentAt(childDocIdx);
|
||||||
|
if (!childDoc->HasLoadState(DocAccessible::eCompletelyLoaded))
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (childDocIdx == childDocCnt) {
|
||||||
|
mDocument->ProcessLoad();
|
||||||
|
if (!mDocument)
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Process only currently queued generic notifications.
|
||||||
|
nsTArray < RefPtr<Notification> > notifications;
|
||||||
|
notifications.SwapElements(mNotifications);
|
||||||
|
|
||||||
|
uint32_t notificationCount = notifications.Length();
|
||||||
|
for (uint32_t idx = 0; idx < notificationCount; idx++) {
|
||||||
|
notifications[idx]->Process();
|
||||||
|
if (!mDocument)
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Process invalidation list of the document after all accessible tree
|
||||||
|
// modification are done.
|
||||||
|
mDocument->ProcessInvalidationList();
|
||||||
|
|
||||||
|
// We cannot rely on DOM tree to keep aria-owns relations updated. Make
|
||||||
|
// a validation to remove dead links.
|
||||||
|
mDocument->ValidateARIAOwned();
|
||||||
|
|
||||||
|
// Process relocation list.
|
||||||
|
for (uint32_t idx = 0; idx < mRelocations.Length(); idx++) {
|
||||||
|
if (mRelocations[idx]->IsInDocument()) {
|
||||||
|
mDocument->DoARIAOwnsRelocation(mRelocations[idx]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
mRelocations.Clear();
|
||||||
|
|
||||||
|
// If a generic notification occurs after this point then we may be allowed to
|
||||||
|
// process it synchronously. However we do not want to reenter if fireing
|
||||||
|
// events causes script to run.
|
||||||
|
mObservingState = eRefreshProcessing;
|
||||||
|
|
||||||
|
CoalesceMutationEvents();
|
||||||
|
ProcessMutationEvents();
|
||||||
|
mEventGeneration = 0;
|
||||||
|
|
||||||
|
// Now that we are done with them get rid of the events we fired.
|
||||||
|
RefPtr<AccTreeMutationEvent> mutEvent = Move(mFirstMutationEvent);
|
||||||
|
mLastMutationEvent = nullptr;
|
||||||
|
mFirstMutationEvent = nullptr;
|
||||||
|
while (mutEvent) {
|
||||||
|
RefPtr<AccTreeMutationEvent> nextEvent = mutEvent->NextEvent();
|
||||||
|
Accessible* target = mutEvent->GetAccessible();
|
||||||
|
|
||||||
|
// We need to be careful here, while it may seem that we can simply 0 all
|
||||||
|
// the pending event bits that is not true. Because accessibles may be
|
||||||
|
// reparented they may be the target of both a hide event and a show event
|
||||||
|
// at the same time.
|
||||||
|
if (mutEvent->GetEventType() == nsIAccessibleEvent::EVENT_SHOW) {
|
||||||
|
target->SetShowEventTarget(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mutEvent->GetEventType() == nsIAccessibleEvent::EVENT_HIDE) {
|
||||||
|
target->SetHideEventTarget(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
// However it is not possible for a reorder event target to also be the
|
||||||
|
// target of a show or hide, so we can just zero that.
|
||||||
|
target->SetReorderEventTarget(false);
|
||||||
|
|
||||||
|
mutEvent->SetPrevEvent(nullptr);
|
||||||
|
mutEvent->SetNextEvent(nullptr);
|
||||||
|
mMutationMap.RemoveEvent(mutEvent);
|
||||||
|
mutEvent = nextEvent;
|
||||||
|
}
|
||||||
|
|
||||||
|
ProcessEventQueue();
|
||||||
|
|
||||||
|
if (IPCAccessibilityActive()) {
|
||||||
|
size_t newDocCount = newChildDocs.Length();
|
||||||
|
for (size_t i = 0; i < newDocCount; i++) {
|
||||||
|
DocAccessible* childDoc = newChildDocs[i];
|
||||||
|
if (childDoc->IsDefunct()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
Accessible* parent = childDoc->Parent();
|
||||||
|
DocAccessibleChild* parentIPCDoc = mDocument->IPCDoc();
|
||||||
|
uint64_t id = reinterpret_cast<uintptr_t>(parent->UniqueID());
|
||||||
|
MOZ_ASSERT(id);
|
||||||
|
DocAccessibleChild* ipcDoc = childDoc->IPCDoc();
|
||||||
|
if (ipcDoc) {
|
||||||
|
parentIPCDoc->SendBindChildDoc(ipcDoc, id);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
ipcDoc = new DocAccessibleChild(childDoc);
|
||||||
|
childDoc->SetIPCDoc(ipcDoc);
|
||||||
|
|
||||||
|
#if defined(XP_WIN)
|
||||||
|
MOZ_ASSERT(parentIPCDoc);
|
||||||
|
parentIPCDoc->ConstructChildDocInParentProcess(ipcDoc, id,
|
||||||
|
AccessibleWrap::GetChildIDFor(childDoc));
|
||||||
|
#else
|
||||||
|
nsCOMPtr<nsITabChild> tabChild =
|
||||||
|
do_GetInterface(mDocument->DocumentNode()->GetDocShell());
|
||||||
|
if (tabChild) {
|
||||||
|
MOZ_ASSERT(parentIPCDoc);
|
||||||
|
static_cast<TabChild*>(tabChild.get())->
|
||||||
|
SendPDocAccessibleConstructor(ipcDoc, parentIPCDoc, id, 0, 0);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mObservingState = eRefreshObserving;
|
||||||
|
if (!mDocument)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// Stop further processing if there are no new notifications of any kind or
|
||||||
|
// events and document load is processed.
|
||||||
|
if (mContentInsertions.Count() == 0 && mNotifications.IsEmpty() &&
|
||||||
|
mEvents.IsEmpty() && mTextHash.Count() == 0 &&
|
||||||
|
mHangingChildDocuments.IsEmpty() &&
|
||||||
|
mDocument->HasLoadState(DocAccessible::eCompletelyLoaded) &&
|
||||||
|
mPresShell->RemoveRefreshObserver(this, Flush_Display)) {
|
||||||
|
mObservingState = eNotObservingRefresh;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
NotificationController::EventMap::PutEvent(AccTreeMutationEvent* aEvent)
|
||||||
|
{
|
||||||
|
EventType type = GetEventType(aEvent);
|
||||||
|
uint64_t addr = reinterpret_cast<uintptr_t>(aEvent->GetAccessible());
|
||||||
|
MOZ_ASSERT((addr & 0x3) == 0, "accessible is not 4 byte aligned");
|
||||||
|
addr |= type;
|
||||||
|
mTable.Put(addr, aEvent);
|
||||||
|
}
|
||||||
|
|
||||||
|
AccTreeMutationEvent*
|
||||||
|
NotificationController::EventMap::GetEvent(Accessible* aTarget, EventType aType)
|
||||||
|
{
|
||||||
|
uint64_t addr = reinterpret_cast<uintptr_t>(aTarget);
|
||||||
|
MOZ_ASSERT((addr & 0x3) == 0, "target is not 4 byte aligned");
|
||||||
|
|
||||||
|
addr |= aType;
|
||||||
|
return mTable.GetWeak(addr);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
NotificationController::EventMap::RemoveEvent(AccTreeMutationEvent* aEvent)
|
||||||
|
{
|
||||||
|
EventType type = GetEventType(aEvent);
|
||||||
|
uint64_t addr = reinterpret_cast<uintptr_t>(aEvent->GetAccessible());
|
||||||
|
MOZ_ASSERT((addr & 0x3) == 0, "accessible is not 4 byte aligned");
|
||||||
|
addr |= type;
|
||||||
|
|
||||||
|
MOZ_ASSERT(mTable.GetWeak(addr) == aEvent, "mTable has the wrong event");
|
||||||
|
mTable.Remove(addr);
|
||||||
|
}
|
||||||
|
|
||||||
|
NotificationController::EventMap::EventType
|
||||||
|
NotificationController::EventMap::GetEventType(AccTreeMutationEvent* aEvent)
|
||||||
|
{
|
||||||
|
switch(aEvent->GetEventType())
|
||||||
|
{
|
||||||
|
case nsIAccessibleEvent::EVENT_SHOW:
|
||||||
|
return ShowEvent;
|
||||||
|
case nsIAccessibleEvent::EVENT_HIDE:
|
||||||
|
return HideEvent;
|
||||||
|
case nsIAccessibleEvent::EVENT_REORDER:
|
||||||
|
return ReorderEvent;
|
||||||
|
default:
|
||||||
|
MOZ_ASSERT_UNREACHABLE("event has invalid type");
|
||||||
|
return ShowEvent;
|
||||||
|
}
|
||||||
|
}
|
||||||
439
accessible/base/NotificationController.h
Normal file
439
accessible/base/NotificationController.h
Normal file
|
|
@ -0,0 +1,439 @@
|
||||||
|
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||||
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
|
#ifndef mozilla_a11y_NotificationController_h_
|
||||||
|
#define mozilla_a11y_NotificationController_h_
|
||||||
|
|
||||||
|
#include "EventQueue.h"
|
||||||
|
#include "EventTree.h"
|
||||||
|
|
||||||
|
#include "mozilla/IndexSequence.h"
|
||||||
|
#include "mozilla/Tuple.h"
|
||||||
|
#include "nsCycleCollectionParticipant.h"
|
||||||
|
#include "nsRefreshDriver.h"
|
||||||
|
|
||||||
|
#ifdef A11Y_LOG
|
||||||
|
#include "Logging.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
namespace mozilla {
|
||||||
|
namespace a11y {
|
||||||
|
|
||||||
|
class DocAccessible;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Notification interface.
|
||||||
|
*/
|
||||||
|
class Notification
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
NS_INLINE_DECL_REFCOUNTING(mozilla::a11y::Notification)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Process notification.
|
||||||
|
*/
|
||||||
|
virtual void Process() = 0;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
Notification() { }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Protected destructor, to discourage deletion outside of Release():
|
||||||
|
*/
|
||||||
|
virtual ~Notification() { }
|
||||||
|
|
||||||
|
private:
|
||||||
|
Notification(const Notification&);
|
||||||
|
Notification& operator = (const Notification&);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Template class for generic notification.
|
||||||
|
*
|
||||||
|
* @note Instance is kept as a weak ref, the caller must guarantee it exists
|
||||||
|
* longer than the document accessible owning the notification controller
|
||||||
|
* that this notification is processed by.
|
||||||
|
*/
|
||||||
|
template<class Class, class ... Args>
|
||||||
|
class TNotification : public Notification
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
typedef void (Class::*Callback)(Args* ...);
|
||||||
|
|
||||||
|
TNotification(Class* aInstance, Callback aCallback, Args* ... aArgs) :
|
||||||
|
mInstance(aInstance), mCallback(aCallback), mArgs(aArgs...) { }
|
||||||
|
virtual ~TNotification() { mInstance = nullptr; }
|
||||||
|
|
||||||
|
virtual void Process() override
|
||||||
|
{ ProcessHelper(typename IndexSequenceFor<Args...>::Type()); }
|
||||||
|
|
||||||
|
private:
|
||||||
|
TNotification(const TNotification&);
|
||||||
|
TNotification& operator = (const TNotification&);
|
||||||
|
|
||||||
|
template <size_t... Indices>
|
||||||
|
void ProcessHelper(IndexSequence<Indices...>)
|
||||||
|
{
|
||||||
|
(mInstance->*mCallback)(Get<Indices>(mArgs)...);
|
||||||
|
}
|
||||||
|
|
||||||
|
Class* mInstance;
|
||||||
|
Callback mCallback;
|
||||||
|
Tuple<RefPtr<Args> ...> mArgs;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Used to process notifications from core for the document accessible.
|
||||||
|
*/
|
||||||
|
class NotificationController final : public EventQueue,
|
||||||
|
public nsARefreshObserver
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
NotificationController(DocAccessible* aDocument, nsIPresShell* aPresShell);
|
||||||
|
|
||||||
|
NS_IMETHOD_(MozExternalRefCountType) AddRef(void) override;
|
||||||
|
NS_IMETHOD_(MozExternalRefCountType) Release(void) override;
|
||||||
|
|
||||||
|
NS_DECL_CYCLE_COLLECTION_NATIVE_CLASS(NotificationController)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Shutdown the notification controller.
|
||||||
|
*/
|
||||||
|
void Shutdown();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add an accessible event into the queue to process it later.
|
||||||
|
*/
|
||||||
|
void QueueEvent(AccEvent* aEvent)
|
||||||
|
{
|
||||||
|
if (PushEvent(aEvent)) {
|
||||||
|
ScheduleProcessing();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates and adds a name change event into the queue for a container of
|
||||||
|
* the given accessible, if the accessible is a part of name computation of
|
||||||
|
* the container.
|
||||||
|
*/
|
||||||
|
void QueueNameChange(Accessible* aChangeTarget)
|
||||||
|
{
|
||||||
|
if (PushNameChange(aChangeTarget)) {
|
||||||
|
ScheduleProcessing();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns existing event tree for the given the accessible or creates one if
|
||||||
|
* it doesn't exists yet.
|
||||||
|
*/
|
||||||
|
EventTree* QueueMutation(Accessible* aContainer);
|
||||||
|
|
||||||
|
class MoveGuard final {
|
||||||
|
public:
|
||||||
|
explicit MoveGuard(NotificationController* aController) :
|
||||||
|
mController(aController)
|
||||||
|
{
|
||||||
|
#ifdef DEBUG
|
||||||
|
MOZ_ASSERT(!mController->mMoveGuardOnStack,
|
||||||
|
"Move guard is on stack already!");
|
||||||
|
mController->mMoveGuardOnStack = true;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
~MoveGuard() {
|
||||||
|
#ifdef DEBUG
|
||||||
|
MOZ_ASSERT(mController->mMoveGuardOnStack, "No move guard on stack!");
|
||||||
|
mController->mMoveGuardOnStack = false;
|
||||||
|
#endif
|
||||||
|
mController->mPrecedingEvents.Clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
NotificationController* mController;
|
||||||
|
};
|
||||||
|
|
||||||
|
#ifdef A11Y_LOG
|
||||||
|
const EventTree& RootEventTree() const { return mEventTree; };
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Queue a mutation event to emit if not coalesced away. Returns true if the
|
||||||
|
* event was queued and has not yet been coalesced.
|
||||||
|
*/
|
||||||
|
bool QueueMutationEvent(AccTreeMutationEvent* aEvent);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Coalesce all queued mutation events.
|
||||||
|
*/
|
||||||
|
void CoalesceMutationEvents();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Schedule binding the child document to the tree of this document.
|
||||||
|
*/
|
||||||
|
void ScheduleChildDocBinding(DocAccessible* aDocument);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Schedule the accessible tree update because of rendered text changes.
|
||||||
|
*/
|
||||||
|
inline void ScheduleTextUpdate(nsIContent* aTextNode)
|
||||||
|
{
|
||||||
|
// Make sure we are not called with a node that is not in the DOM tree or
|
||||||
|
// not visible.
|
||||||
|
MOZ_ASSERT(aTextNode->GetParentNode(), "A text node is not in DOM");
|
||||||
|
MOZ_ASSERT(aTextNode->GetPrimaryFrame(), "A text node doesn't have a frame");
|
||||||
|
MOZ_ASSERT(aTextNode->GetPrimaryFrame()->StyleVisibility()->IsVisible(),
|
||||||
|
"A text node is not visible");
|
||||||
|
|
||||||
|
mTextHash.PutEntry(aTextNode);
|
||||||
|
ScheduleProcessing();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Pend accessible tree update for content insertion.
|
||||||
|
*/
|
||||||
|
void ScheduleContentInsertion(Accessible* aContainer,
|
||||||
|
nsIContent* aStartChildNode,
|
||||||
|
nsIContent* aEndChildNode);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Pend an accessible subtree relocation.
|
||||||
|
*/
|
||||||
|
void ScheduleRelocation(Accessible* aOwner)
|
||||||
|
{
|
||||||
|
if (!mRelocations.Contains(aOwner) && mRelocations.AppendElement(aOwner)) {
|
||||||
|
ScheduleProcessing();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Start to observe refresh to make notifications and events processing after
|
||||||
|
* layout.
|
||||||
|
*/
|
||||||
|
void ScheduleProcessing();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Process the generic notification synchronously if there are no pending
|
||||||
|
* layout changes and no notifications are pending or being processed right
|
||||||
|
* now. Otherwise, queue it up to process asynchronously.
|
||||||
|
*
|
||||||
|
* @note The caller must guarantee that the given instance still exists when
|
||||||
|
* the notification is processed.
|
||||||
|
*/
|
||||||
|
template<class Class, class Arg>
|
||||||
|
inline void HandleNotification(Class* aInstance,
|
||||||
|
typename TNotification<Class, Arg>::Callback aMethod,
|
||||||
|
Arg* aArg)
|
||||||
|
{
|
||||||
|
if (!IsUpdatePending()) {
|
||||||
|
#ifdef A11Y_LOG
|
||||||
|
if (mozilla::a11y::logging::IsEnabled(mozilla::a11y::logging::eNotifications))
|
||||||
|
mozilla::a11y::logging::Text("sync notification processing");
|
||||||
|
#endif
|
||||||
|
(aInstance->*aMethod)(aArg);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
RefPtr<Notification> notification =
|
||||||
|
new TNotification<Class, Arg>(aInstance, aMethod, aArg);
|
||||||
|
if (notification && mNotifications.AppendElement(notification))
|
||||||
|
ScheduleProcessing();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Schedule the generic notification to process asynchronously.
|
||||||
|
*
|
||||||
|
* @note The caller must guarantee that the given instance still exists when
|
||||||
|
* the notification is processed.
|
||||||
|
*/
|
||||||
|
template<class Class>
|
||||||
|
inline void ScheduleNotification(Class* aInstance,
|
||||||
|
typename TNotification<Class>::Callback aMethod)
|
||||||
|
{
|
||||||
|
RefPtr<Notification> notification =
|
||||||
|
new TNotification<Class>(aInstance, aMethod);
|
||||||
|
if (notification && mNotifications.AppendElement(notification))
|
||||||
|
ScheduleProcessing();
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef DEBUG
|
||||||
|
bool IsUpdating() const
|
||||||
|
{ return mObservingState == eRefreshProcessingForUpdate; }
|
||||||
|
#endif
|
||||||
|
|
||||||
|
protected:
|
||||||
|
virtual ~NotificationController();
|
||||||
|
|
||||||
|
nsCycleCollectingAutoRefCnt mRefCnt;
|
||||||
|
NS_DECL_OWNINGTHREAD
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return true if the accessible tree state update is pending.
|
||||||
|
*/
|
||||||
|
bool IsUpdatePending();
|
||||||
|
|
||||||
|
private:
|
||||||
|
NotificationController(const NotificationController&);
|
||||||
|
NotificationController& operator = (const NotificationController&);
|
||||||
|
|
||||||
|
// nsARefreshObserver
|
||||||
|
virtual void WillRefresh(mozilla::TimeStamp aTime) override;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set and returns a hide event, paired with a show event, for the move.
|
||||||
|
*/
|
||||||
|
void WithdrawPrecedingEvents(nsTArray<RefPtr<AccHideEvent>>* aEvs)
|
||||||
|
{
|
||||||
|
if (mPrecedingEvents.Length() > 0) {
|
||||||
|
aEvs->AppendElements(mozilla::Move(mPrecedingEvents));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
void StorePrecedingEvent(AccHideEvent* aEv)
|
||||||
|
{
|
||||||
|
MOZ_ASSERT(mMoveGuardOnStack, "No move guard on stack!");
|
||||||
|
mPrecedingEvents.AppendElement(aEv);
|
||||||
|
}
|
||||||
|
void StorePrecedingEvents(nsTArray<RefPtr<AccHideEvent>>&& aEvs)
|
||||||
|
{
|
||||||
|
MOZ_ASSERT(mMoveGuardOnStack, "No move guard on stack!");
|
||||||
|
mPrecedingEvents.InsertElementsAt(0, aEvs);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
/**
|
||||||
|
* get rid of a mutation event that is no longer necessary.
|
||||||
|
*/
|
||||||
|
void DropMutationEvent(AccTreeMutationEvent* aEvent);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fire all necessary mutation events.
|
||||||
|
*/
|
||||||
|
void ProcessMutationEvents();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Indicates whether we're waiting on an event queue processing from our
|
||||||
|
* notification controller to flush events.
|
||||||
|
*/
|
||||||
|
enum eObservingState {
|
||||||
|
eNotObservingRefresh,
|
||||||
|
eRefreshObserving,
|
||||||
|
eRefreshProcessing,
|
||||||
|
eRefreshProcessingForUpdate
|
||||||
|
};
|
||||||
|
eObservingState mObservingState;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The presshell of the document accessible.
|
||||||
|
*/
|
||||||
|
nsIPresShell* mPresShell;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Child documents that needs to be bound to the tree.
|
||||||
|
*/
|
||||||
|
nsTArray<RefPtr<DocAccessible> > mHangingChildDocuments;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Pending accessible tree update notifications for content insertions.
|
||||||
|
*/
|
||||||
|
nsClassHashtable<nsRefPtrHashKey<Accessible>,
|
||||||
|
nsTArray<nsCOMPtr<nsIContent>>> mContentInsertions;
|
||||||
|
|
||||||
|
template<class T>
|
||||||
|
class nsCOMPtrHashKey : public PLDHashEntryHdr
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
typedef T* KeyType;
|
||||||
|
typedef const T* KeyTypePointer;
|
||||||
|
|
||||||
|
explicit nsCOMPtrHashKey(const T* aKey) : mKey(const_cast<T*>(aKey)) {}
|
||||||
|
explicit nsCOMPtrHashKey(const nsPtrHashKey<T> &aToCopy) : mKey(aToCopy.mKey) {}
|
||||||
|
~nsCOMPtrHashKey() { }
|
||||||
|
|
||||||
|
KeyType GetKey() const { return mKey; }
|
||||||
|
bool KeyEquals(KeyTypePointer aKey) const { return aKey == mKey; }
|
||||||
|
|
||||||
|
static KeyTypePointer KeyToPointer(KeyType aKey) { return aKey; }
|
||||||
|
static PLDHashNumber HashKey(KeyTypePointer aKey)
|
||||||
|
{ return NS_PTR_TO_INT32(aKey) >> 2; }
|
||||||
|
|
||||||
|
enum { ALLOW_MEMMOVE = true };
|
||||||
|
|
||||||
|
protected:
|
||||||
|
nsCOMPtr<T> mKey;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Pending accessible tree update notifications for rendered text changes.
|
||||||
|
*/
|
||||||
|
nsTHashtable<nsCOMPtrHashKey<nsIContent> > mTextHash;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Other notifications like DOM events. Don't make this an AutoTArray; we
|
||||||
|
* use SwapElements() on it.
|
||||||
|
*/
|
||||||
|
nsTArray<RefPtr<Notification> > mNotifications;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Holds all scheduled relocations.
|
||||||
|
*/
|
||||||
|
nsTArray<RefPtr<Accessible> > mRelocations;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Holds all mutation events.
|
||||||
|
*/
|
||||||
|
EventTree mEventTree;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A temporary collection of hide events that should be fired before related
|
||||||
|
* show event. Used by EventTree.
|
||||||
|
*/
|
||||||
|
nsTArray<RefPtr<AccHideEvent>> mPrecedingEvents;
|
||||||
|
|
||||||
|
#ifdef DEBUG
|
||||||
|
bool mMoveGuardOnStack;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
friend class MoveGuard;
|
||||||
|
friend class EventTree;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A list of all mutation events we may want to emit. Ordered from the first
|
||||||
|
* event that should be emitted to the last one to emit.
|
||||||
|
*/
|
||||||
|
RefPtr<AccTreeMutationEvent> mFirstMutationEvent;
|
||||||
|
RefPtr<AccTreeMutationEvent> mLastMutationEvent;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A class to map an accessible and event type to an event.
|
||||||
|
*/
|
||||||
|
class EventMap
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
enum EventType
|
||||||
|
{
|
||||||
|
ShowEvent = 0x0,
|
||||||
|
HideEvent = 0x1,
|
||||||
|
ReorderEvent = 0x2,
|
||||||
|
};
|
||||||
|
|
||||||
|
void PutEvent(AccTreeMutationEvent* aEvent);
|
||||||
|
AccTreeMutationEvent* GetEvent(Accessible* aTarget, EventType aType);
|
||||||
|
void RemoveEvent(AccTreeMutationEvent* aEvent);
|
||||||
|
void Clear() { mTable.Clear(); }
|
||||||
|
|
||||||
|
private:
|
||||||
|
EventType GetEventType(AccTreeMutationEvent* aEvent);
|
||||||
|
|
||||||
|
nsRefPtrHashtable<nsUint64HashKey, AccTreeMutationEvent> mTable;
|
||||||
|
};
|
||||||
|
|
||||||
|
EventMap mMutationMap;
|
||||||
|
uint32_t mEventGeneration;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace a11y
|
||||||
|
} // namespace mozilla
|
||||||
|
|
||||||
|
#endif // mozilla_a11y_NotificationController_h_
|
||||||
88
accessible/base/Platform.h
Normal file
88
accessible/base/Platform.h
Normal file
|
|
@ -0,0 +1,88 @@
|
||||||
|
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||||
|
/* vim: set ts=2 et sw=2 tw=80: */
|
||||||
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
|
#ifndef mozilla_a11y_Platform_h
|
||||||
|
#define mozilla_a11y_Platform_h
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
class nsString;
|
||||||
|
|
||||||
|
namespace mozilla {
|
||||||
|
namespace a11y {
|
||||||
|
|
||||||
|
class ProxyAccessible;
|
||||||
|
|
||||||
|
enum EPlatformDisabledState {
|
||||||
|
ePlatformIsForceEnabled = -1,
|
||||||
|
ePlatformIsEnabled = 0,
|
||||||
|
ePlatformIsDisabled = 1
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the platform disabled state.
|
||||||
|
*/
|
||||||
|
EPlatformDisabledState PlatformDisabledState();
|
||||||
|
|
||||||
|
#ifdef MOZ_ACCESSIBILITY_ATK
|
||||||
|
/**
|
||||||
|
* Perform initialization that should be done as soon as possible, in order
|
||||||
|
* to minimize startup time.
|
||||||
|
* XXX: this function and the next defined in ApplicationAccessibleWrap.cpp
|
||||||
|
*/
|
||||||
|
void PreInit();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(MOZ_ACCESSIBILITY_ATK) || defined(XP_MACOSX)
|
||||||
|
/**
|
||||||
|
* Is platform accessibility enabled.
|
||||||
|
* Only used on linux with atk and MacOS for now.
|
||||||
|
*/
|
||||||
|
bool ShouldA11yBeEnabled();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called to initialize platform specific accessibility support.
|
||||||
|
* Note this is called after internal accessibility support is initialized.
|
||||||
|
*/
|
||||||
|
void PlatformInit();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Shutdown platform accessibility.
|
||||||
|
* Note this is called before internal accessibility support is shutdown.
|
||||||
|
*/
|
||||||
|
void PlatformShutdown();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* called when a new ProxyAccessible is created, so the platform may setup a
|
||||||
|
* wrapper for it, or take other action.
|
||||||
|
*/
|
||||||
|
void ProxyCreated(ProxyAccessible* aProxy, uint32_t aInterfaces);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called just before a ProxyAccessible is destroyed so its wrapper can be
|
||||||
|
* disposed of and other action taken.
|
||||||
|
*/
|
||||||
|
void ProxyDestroyed(ProxyAccessible*);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Callied when an event is fired on a proxied accessible.
|
||||||
|
*/
|
||||||
|
void ProxyEvent(ProxyAccessible* aTarget, uint32_t aEventType);
|
||||||
|
void ProxyStateChangeEvent(ProxyAccessible* aTarget, uint64_t aState,
|
||||||
|
bool aEnabled);
|
||||||
|
void ProxyCaretMoveEvent(ProxyAccessible* aTarget, int32_t aOffset);
|
||||||
|
void ProxyTextChangeEvent(ProxyAccessible* aTarget, const nsString& aStr,
|
||||||
|
int32_t aStart, uint32_t aLen, bool aIsInsert,
|
||||||
|
bool aFromUser);
|
||||||
|
void ProxyShowHideEvent(ProxyAccessible* aTarget, ProxyAccessible* aParent,
|
||||||
|
bool aInsert, bool aFromUser);
|
||||||
|
void ProxySelectionEvent(ProxyAccessible* aTarget, ProxyAccessible* aWidget,
|
||||||
|
uint32_t aType);
|
||||||
|
} // namespace a11y
|
||||||
|
} // namespace mozilla
|
||||||
|
|
||||||
|
#endif // mozilla_a11y_Platform_h
|
||||||
108
accessible/base/Relation.h
Normal file
108
accessible/base/Relation.h
Normal file
|
|
@ -0,0 +1,108 @@
|
||||||
|
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||||
|
/* vim: set ts=2 et sw=2 tw=80: */
|
||||||
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
|
#ifndef mozilla_a11y_relation_h_
|
||||||
|
#define mozilla_a11y_relation_h_
|
||||||
|
|
||||||
|
#include "AccIterator.h"
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
namespace mozilla {
|
||||||
|
namespace a11y {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A collection of relation targets of a certain type. Targets are computed
|
||||||
|
* lazily while enumerating.
|
||||||
|
*/
|
||||||
|
class Relation
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
Relation() : mFirstIter(nullptr), mLastIter(nullptr) { }
|
||||||
|
|
||||||
|
explicit Relation(AccIterable* aIter) :
|
||||||
|
mFirstIter(aIter), mLastIter(aIter) { }
|
||||||
|
|
||||||
|
explicit Relation(Accessible* aAcc) :
|
||||||
|
mFirstIter(nullptr), mLastIter(nullptr)
|
||||||
|
{ AppendTarget(aAcc); }
|
||||||
|
|
||||||
|
Relation(DocAccessible* aDocument, nsIContent* aContent) :
|
||||||
|
mFirstIter(nullptr), mLastIter(nullptr)
|
||||||
|
{ AppendTarget(aDocument, aContent); }
|
||||||
|
|
||||||
|
Relation(Relation&& aOther) :
|
||||||
|
mFirstIter(Move(aOther.mFirstIter)), mLastIter(aOther.mLastIter)
|
||||||
|
{
|
||||||
|
aOther.mLastIter = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
Relation& operator = (Relation&& aRH)
|
||||||
|
{
|
||||||
|
mFirstIter = Move(aRH.mFirstIter);
|
||||||
|
mLastIter = aRH.mLastIter;
|
||||||
|
aRH.mLastIter = nullptr;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void AppendIter(AccIterable* aIter)
|
||||||
|
{
|
||||||
|
if (mLastIter)
|
||||||
|
mLastIter->mNextIter.reset(aIter);
|
||||||
|
else
|
||||||
|
mFirstIter.reset(aIter);
|
||||||
|
|
||||||
|
mLastIter = aIter;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Append the given accessible to the set of related accessibles.
|
||||||
|
*/
|
||||||
|
inline void AppendTarget(Accessible* aAcc)
|
||||||
|
{
|
||||||
|
if (aAcc)
|
||||||
|
AppendIter(new SingleAccIterator(aAcc));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Append the one accessible for this content node to the set of related
|
||||||
|
* accessibles.
|
||||||
|
*/
|
||||||
|
void AppendTarget(DocAccessible* aDocument, nsIContent* aContent)
|
||||||
|
{
|
||||||
|
if (aContent)
|
||||||
|
AppendTarget(aDocument->GetAccessible(aContent));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* compute and return the next related accessible.
|
||||||
|
*/
|
||||||
|
inline Accessible* Next()
|
||||||
|
{
|
||||||
|
Accessible* target = nullptr;
|
||||||
|
|
||||||
|
while (mFirstIter && !(target = mFirstIter->Next()))
|
||||||
|
mFirstIter = std::move(mFirstIter->mNextIter);
|
||||||
|
|
||||||
|
if (!mFirstIter)
|
||||||
|
mLastIter = nullptr;
|
||||||
|
|
||||||
|
return target;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
Relation& operator = (const Relation&) = delete;
|
||||||
|
Relation(const Relation&) = delete;
|
||||||
|
|
||||||
|
std::unique_ptr<AccIterable> mFirstIter;
|
||||||
|
AccIterable* mLastIter;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace a11y
|
||||||
|
} // namespace mozilla
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
163
accessible/base/RelationType.h
Normal file
163
accessible/base/RelationType.h
Normal file
|
|
@ -0,0 +1,163 @@
|
||||||
|
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||||
|
/* vim: set ts=2 et sw=2 tw=80: */
|
||||||
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
|
#ifndef mozilla_a11y_relationtype_h_
|
||||||
|
#define mozilla_a11y_relationtype_h_
|
||||||
|
|
||||||
|
namespace mozilla {
|
||||||
|
namespace a11y {
|
||||||
|
|
||||||
|
enum class RelationType {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This object is labelled by a target object.
|
||||||
|
*/
|
||||||
|
LABELLED_BY = 0x00,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This object is label for a target object.
|
||||||
|
*/
|
||||||
|
LABEL_FOR = 0x01,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This object is described by the target object.
|
||||||
|
*/
|
||||||
|
DESCRIBED_BY = 0x02,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This object is describes the target object.
|
||||||
|
*/
|
||||||
|
DESCRIPTION_FOR = 0x3,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This object is a child of a target object.
|
||||||
|
*/
|
||||||
|
NODE_CHILD_OF = 0x4,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This object is a parent of a target object. A dual relation to
|
||||||
|
* NODE_CHILD_OF.
|
||||||
|
*/
|
||||||
|
NODE_PARENT_OF = 0x5,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Some attribute of this object is affected by a target object.
|
||||||
|
*/
|
||||||
|
CONTROLLED_BY = 0x06,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This object is interactive and controls some attribute of a target object.
|
||||||
|
*/
|
||||||
|
CONTROLLER_FOR = 0x07,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Content flows from this object to a target object, i.e. has content that
|
||||||
|
* flows logically to another object in a sequential way, e.g. text flow.
|
||||||
|
*/
|
||||||
|
FLOWS_TO = 0x08,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Content flows to this object from a target object, i.e. has content that
|
||||||
|
* flows logically from another object in a sequential way, e.g. text flow.
|
||||||
|
*/
|
||||||
|
FLOWS_FROM = 0x09,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This object is a member of a group of one or more objects. When there is
|
||||||
|
* more than one object in the group each member may have one and the same
|
||||||
|
* target, e.g. a grouping object. It is also possible that each member has
|
||||||
|
* multiple additional targets, e.g. one for every other member in the group.
|
||||||
|
*/
|
||||||
|
MEMBER_OF = 0x0a,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This object is a sub window of a target object.
|
||||||
|
*/
|
||||||
|
SUBWINDOW_OF = 0x0b,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This object embeds a target object. This relation can be used on the
|
||||||
|
* OBJID_CLIENT accessible for a top level window to show where the content
|
||||||
|
* areas are.
|
||||||
|
*/
|
||||||
|
EMBEDS = 0x0c,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This object is embedded by a target object.
|
||||||
|
*/
|
||||||
|
EMBEDDED_BY = 0x0d,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This object is a transient component related to the target object. When
|
||||||
|
* this object is activated the target object doesn't lose focus.
|
||||||
|
*/
|
||||||
|
POPUP_FOR = 0x0e,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This object is a parent window of the target object.
|
||||||
|
*/
|
||||||
|
PARENT_WINDOW_OF = 0x0f,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Part of a form/dialog with a related default button. It is used for
|
||||||
|
* MSAA/XPCOM, it isn't for IA2 or ATK.
|
||||||
|
*/
|
||||||
|
DEFAULT_BUTTON = 0x10,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The target object is the containing document object.
|
||||||
|
*/
|
||||||
|
CONTAINING_DOCUMENT = 0x11,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The target object is the topmost containing document object in the tab pane.
|
||||||
|
*/
|
||||||
|
CONTAINING_TAB_PANE = 0x12,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The target object is the containing window object.
|
||||||
|
*/
|
||||||
|
CONTAINING_WINDOW = 0x13,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The target object is the containing application object.
|
||||||
|
*/
|
||||||
|
CONTAINING_APPLICATION = 0x14,
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The target object provides the detailed, extended description for this
|
||||||
|
* object. It provides more detailed information than would normally be
|
||||||
|
* provided using the DESCRIBED_BY relation. A common use for this relation is
|
||||||
|
* in digital publishing where an extended description needs to be conveyed in
|
||||||
|
* a book that requires structural markup or the embedding of other technology
|
||||||
|
* to provide illustrative content.
|
||||||
|
*/
|
||||||
|
DETAILS = 0x15,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This object provides the detailed, extended description for the target
|
||||||
|
* object. See DETAILS relation.
|
||||||
|
*/
|
||||||
|
DETAILS_FOR = 0x16,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The target object is the error message for this object.
|
||||||
|
*/
|
||||||
|
ERRORMSG = 0x17,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This object is the error message for the target object.
|
||||||
|
*/
|
||||||
|
ERRORMSG_FOR = 0x18,
|
||||||
|
|
||||||
|
LAST = ERRORMSG_FOR
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace a11y
|
||||||
|
} // namespace mozilla
|
||||||
|
|
||||||
|
#endif
|
||||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue