Previously, UIA requested certain cache domains just by firing events, even if no client cared about those events.
This happened because unlike MSAA/IA2 win events, many UIA events include information about the thing that is changing; e.g. a name change event includes the new name.
In addition, live region events are based on other events (name change, text inserted, text removed) and thus need to query whether the element is a live region, which requires additional domains.
this caused our caching granularity tests to break, since those deliberately request only specific domains.
Firing core events caused us to fire UIA events (even if a UIA client didn't actually query us), which in turn caused us to request domains the test doesn't expect.
Less critical (but still important), this meant that these domains would always have been enabled as soon as an event is fired.
That's not great, since it somewhat defeats the point of caching granularity.
As mentioned in the previous patch, checking UiaClientsAreListening() is not sufficient to mitigate this in most cases.
The ideal solution is perhaps to avoid firing those events in the first place.
However, that would require checking for specific domains in the UIA code, which seems fragile if we change what domains are required for existing core methods, add new core methods, etc.
Also, we should probably really be avoiding these events at the core level, rather than requiring OS specific code to filter these out.
Instead, as a more straightforward solution, this patch adds a CacheDomainActivationBlocker RAII class to prevent requesting of new domains.
This is used specifically when firing UIA events.
The events we fire won't contain all the data they should, but that's okay because no client likely cares yet.
We still use explicit client queries (plus a list of known clients) as a signal to request new domains, after which the events will contain information from all the domains that are now active.
This approach could also easily be used on other platforms where needed.
Differential Revision: https://phabricator.services.mozilla.com/D245373
In bug 1951067, I pruned all 0 width whitespace text nodes from the accessibility tree.
However, it turns out that whitespace text nodes at the end of wrapped lines can also be 0 width.
These have semantic importance, since otherwise, words in separate inline nodes can be merged together without a space.
To fix this, explicitly check that the node is before a hard line break, not a soft (wrapped) line break.
Differential Revision: https://phabricator.services.mozilla.com/D242290
When DocAccessibles shut down, they shut down their child documents.
However, shutting down a document can result in shutting down the accessibility service if XPCOM is the only consumer and there are no more cached XPCOM documents.
If this is triggered by a child document, the service will shut down while the parent document is still shutting down, resulting in reentry and a crash.
In bug 1690456, code was added to prevent shutting down the service for a document with a parent.
However, this doesn't address "hanging child documents"; i.e. documents which currently have no parent because their OuterDocAccessible is being destroyed/recreated.
Rather than trying to avoid this specific case and given that we've hit reentry problems here twice before now (bug 1330765 and bug 1690456), I've taken a completely different approach.
Whenever shutdown of the service is triggered by a document shutdown, we now shut down the service asynchronously by dispatching a runnable.
This ensures that the service can't be shut down while shutting down a document.
We do this for both local and remote documents, since although we've never seen this for remote documents, I think this is safer.
In addition:
1. DocAccessible::Shutdown now has a diagnostic assert to hopefully detect such reentry should it occur again in future, making it much easier to debug.
2. Functions related to this have been refactored slightly for readability and consistency.
Differential Revision: https://phabricator.services.mozilla.com/D238143
MOZ_RUNINIT => initialized at runtime
MOZ_CONSTINIT => initialized at compile time
MOZ_GLOBINIT => initialized either at runtime or compile time, depending on template parameter, macro parameter etc
This annotation is only understood by our clang-tidy plugin. It has no
effect on regular compilation.
Differential Revision: https://phabricator.services.mozilla.com/D223341
The target might be an element for which we don't create an Accessible; e.g. a <b> element.
Previously, we wouldn't fire an event in NotifyOfAnchorJumpTo and would instead defer the event until the next document focus.
However, the document might already have focus, in which case we won't fire this event when the user expects it (if ever).
Instead, use GetAccessibleOrContainer, which is also consistent with the deferred anchor jump code in FocusManager.
This means we will fire the event on the correct container Accessible immediately.
Differential Revision: https://phabricator.services.mozilla.com/D226437
The target might be an element for which we don't create an Accessible; e.g. a <b> element.
Previously, we wouldn't fire an event in NotifyOfAnchorJumpTo and would instead defer the event until the next document focus.
However, the document might already have focus, in which case we won't fire this event when the user expects it (if ever).
Instead, use GetAccessibleOrContainer, which is also consistent with the deferred anchor jump code in FocusManager.
This means we will fire the event on the correct container Accessible immediately.
Differential Revision: https://phabricator.services.mozilla.com/D226437
This revision adds a pref, read only on startup, that enables all cache domains.
By default, cache domains are only enabled as-needed. This pref is uesful for
test environments, such as fuzzing.
Differential Revision: https://phabricator.services.mozilla.com/D224187
This revision adds the capability of querying and sending information about
individual cache domains. It introduces the concept of active cache domains to
the accessibility service: cache domains that we think clients need. Conversely,
cache domains that clients don't need are inactive, and we avoid doing any work
to push information about those domains. This revision adds an IPC mechanism for
setting cache domains. It adds a way for content process documents to enable,
gather, and send to the parent process information from all of their accessibles
that's newly needed. It adds a way to instantiate new accessibility services
with a predetermined set of cache domains. It adds a mechanism for local accs to
use in BundleFieldsForCache, but doesn't implement it yet (see next revision).
Differential Revision: https://phabricator.services.mozilla.com/D220036
This revision is a step towards ensuring we get the right domains for known
accessibility instantiators. We want to anticipate the needs of known clients
and make sure we have all the cache domains ready, especially for heavy-use
clients like screen readers. The domains we'll need are a bit of a work in
progress, but can be updated easily. For now, err on the side of caution. This
revision also implements better client detection on macOS, so we can handle
multiple clients.
Differential Revision: https://phabricator.services.mozilla.com/D220035
CSS alt text makes most sense for an image.
However, even when the content property specifies text, you can still specify alt text!
To support this, this patch does two things:
1. Uses the alt text for the TextLeafAccessible instead of the primary text.
2. Tweaks nsTextEquivUtils to use the alt text when gathering text from a subtree.
As with the last patch, changing the CSS content replaces the pseudo-element, which in turn replaces the Accessible with a new one, so we don't need any additional code to handle updates.
Differential Revision: https://phabricator.services.mozilla.com/D210017
Previously, a11y did get notified about CSS images, but we chose not to create Accessibles for them.
This patch allows us to create an ImageAccessible for a CSS image if it has alt text.
Since there is now an Accessible, the previous patch will then mean that Accessible::Name will return the CSS alt text.
Changing the CSS content replaces the pseudo-element, which in turn replaces the Accessible with a new one, so we don't need any additional code to handle updates.
Differential Revision: https://phabricator.services.mozilla.com/D210016
This doesn't change behavior on its own, but it's likely we want to make
the tab focusability more complicated in bug 1895184, and this will make
changes to this area less painful.
Differential Revision: https://phabricator.services.mozilla.com/D209525
Since SVG elements aren't in a markup map, Gecko doesn't check for them when
searching markup maps while determining whether to create an accessible in
display:contents contexts. This revision addresses the problem by factoring out
the SVG creation code and using it in two places - newly in the dislay:contents
code. This revision also removes expected failures from relevant web platform
tests.
Differential Revision: https://phabricator.services.mozilla.com/D207943
This revision implements the ARIA rowgroup role in Gecko. Previously, Gecko was
using roles::GROUPING for multiple types of groups and disambiguating them
in various places. This revision unwinds that while maintaining present
functionality.
Differential Revision: https://phabricator.services.mozilla.com/D205671
This revision implements the ARIA rowgroup role in Gecko. Previously, Gecko was
using roles::GROUPING for multiple types of groups and disambiguating them
in various places. This revision unwinds that while maintaining present
functionality.
Differential Revision: https://phabricator.services.mozilla.com/D205671
This changes comes with several different refactorings all rolled into one,
unfotunately I couldn't find a way to pull them apart:
- First of all annotations now can either recorded (that is, we copy the value
and have the crash reporting code own the copy) or registered. Several
annotations are changed to use this functionality so that we don't need to
update them as their value change.
- The code in the exception handler is modified to read the annotations from
the mozannotation_client crate. This has the unfortunate side-effect that
we need three different bits of code to serialize them: one for annotations
read from a child process, one for reading annotations from the main process
outside of the exception handler and one for reading annotations from the
main process within the exception handler. As we move to fully
out-of-process crash reporting the last two methods will go away.
- The mozannotation_client crate now doesn't record annotation types anymore.
I realized as I was working on this that storing types at runtime has two
issues: the first one is that buggy code might change the type of an
annotation (that is record it under two different types at two different
moments), the second issue is that types might become corrupt during a
crash, so better enforce them at annotation-writing time. The end result is
that the mozannotation_* crates now only store byte buffers, track the
format the data is stored in (null-terminated string, fixed size buffer,
etc...) but not the type of data each annotation is supposed to contain.
- Which brings us to the next change: concrete types for annotations are now
enforced when they're written out. If an annotation doesn't match the
expected type it's skipped. Storing an annotation with the wrong type will
also trigger an assertion in debug builds.
Differential Revision: https://phabricator.services.mozilla.com/D195248
Accessibility needs to keep track of changes to explicitly set attr-elements.
Since the popovertarget content attribute is "" for any explicitly set attr-element, we won't always get attribute change notifications for the content attribute when .popoverTargetElement is set.
For example, if e1's popovertarget content attribute is absent and you set e1.popoverTargetElement to e2, the popovertarget content attribute will be "".
If you later set e1.popoverTargetElement to e3, there won't be a notification for the content attribute change, since it remains "".
Even if there were, it might occur before the element has changed, which means we can't detect any relevant state changes there; e.g. mPrevStateBits.
To deal with this, we now have DOM notify accessibility before and after the explicitly set attr-element is changed.
Within DocAccessible, this is treated like any other attribute change, but the notification methods get called consistently and at the appropriate time.
Differential Revision: https://phabricator.services.mozilla.com/D201662
A popover can have multiple invoker buttons.
Previously, we only fired a state change event on the button which was invoked.
This meant that the cached expanded/collapsed state of any other invokers was stale.
To facilitate this:
1. Add popovertarget to DocAccessible's kRelationAttrs so that we track reverse relationships. This will also later be used for exposing relations.
2. When an Accessible is shown or hidden, if it is a popover, use RelatedAccIterator to get all the invokers and fire appropriate state change events on each of them.
3. This also means we can get rid of nsAccessibilityService::PopovertargetMaybeChanged, since this explicit notification from DOM is no longer useful.
4. Add popovertarget to LocalAccessible::AttributeChangesState so that we fire an event for the expandable/expanded/collapsed state change if appropriate when that attribute is changed.
Differential Revision: https://phabricator.services.mozilla.com/D199842
We don't normally create an Accessible for <foreignObject>.
However, if there's an ARIA role or similar, we forceably create one.
Previously, if we ever did this for an SVG element, we would use an AccessibleWrap, which doesn't support HyperText.
This is normally correct because most SVG elements can't contain text.
However, a <foreignObject> can most definitely contain text, so we must use HyperTextAccessible.
This fixes assertions and text attributes.
Differential Revision: https://phabricator.services.mozilla.com/D195387
This is now just an alias for HyperTextAccessible on all platforms.
This was done with the following bash script:
```
cd accessible
find -name HyperTextAccessibleWrap.h -delete
sed -i 's/#include "HyperTextAccessibleWrap.h"/#include "HyperTextAccessible.h"/;/"HyperTextAccessibleWrap.h",/d;s/HyperTextAccessibleWrap/HyperTextAccessible/g' `git grep -l HyperTextAccessibleWrap`
```
Differential Revision: https://phabricator.services.mozilla.com/D184796
This was done with the following Python script:
```
import re
cacheConsts = open("accessible/base/CacheConstants.h", "rt").read()
aliases = {
alias: atom
for atom, alias in
re.findall(
r'static constexpr nsStaticAtom\*\s+(.*?)\s+=\s+(nsGkAtoms::.*?);',
cacheConsts
)
}
RE_ATOM = re.compile(r'(fields->SetAttribute|(?:mCachedFields|aFields)->(?:GetAttribute|GetAttributeRefPtr|GetMutableAttribute|HasAttribute|Remove|SetAttribute)(?:<.+>)?)(\(\s*)(nsGkAtoms::[a-zA-Z_]+)')
def repl(m):
# Group 3 is the atom.
alias = aliases.get(m.group(3))
if not alias:
# No alias for this atom. Return input unaltered.
return m.group(0)
alias = "CacheKey::" + alias
# Groups 1 and 2 should be returned unaltered. Group 3 (the atom) is replaced
# with the alias.
return m.group(1) + m.group(2) + alias
for fn in (
# Found with: git grep -l 'ields->'
"accessible/base/CachedTableAccessible.cpp",
"accessible/base/nsAccessibilityService.cpp",
"accessible/base/TextLeafRange.cpp",
"accessible/generic/LocalAccessible.cpp",
"accessible/ipc/DocAccessibleParent.cpp",
"accessible/ipc/RemoteAccessible.cpp",
"accessible/ipc/RemoteAccessible.h",
"accessible/windows/sdn/sdnAccessible.cpp",
):
input = open(fn, "rt").read()
output = RE_ATOM.sub(repl, input)
open(fn, "wt").write(output)
```
Differential Revision: https://phabricator.services.mozilla.com/D184791
Role.h will soon be generated, but it is generated within the obj dir, so local includes won't work.
Our C++ style guide says we should prefer exported includes wherever possible anyway.
This was done with this shell command inside the accessible/ directory:
```
sed -i 's,#include "Role.h",#include "mozilla/a11y/Role.h",' `git grep -l '#include "Role.h"'`
```
Differential Revision: https://phabricator.services.mozilla.com/D183940
Per the HTML-AAM spec, a and area elements without href attributes should have
generic roles. This revision implements this preference by creating hypertext
accessibles when said elements lack href attributes (or click listeners). A
byproduct of this change is recognizing that a elements have no intrinsic role
mapping; they could be generics or links. This revision handles situations
where href or click listeners might appear or dissapear, and recreates the
accessibles when necessary. Since image map areas are handled by their
containing image maps, this revision specializes HTMLAreaAccessible::NativeRole
to account for the discrepancy that we can't account for in the markup map.
This revision also changes the relevant WPT test expectations, updates existing
tests that this change affects, and adds tests to verify that changing href
and click listeners dynamically changes the role appropriately.
Differential Revision: https://phabricator.services.mozilla.com/D183550
This revision removes unnecessary include directives from cpp files in the
accessible/base directory. These suggestions came from the Include What You Use
tool.
Differential Revision: https://phabricator.services.mozilla.com/D182288