mirror of
https://repo.dactyloidae.xyz/Dactyloidae/UXP.git
synced 2026-10-14 11:17:31 +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