The new detection code introduced in bug 1838123 doesn't work on Windows 10.
This patch:
1. Splits the Windows 11 code into its own function.
2. Refactors the system handle enumeration code into its own function which can be called with a lambda, since it is needed for both Windows 11 and Windows 10.
3. Adds code to detect clients on Windows 10 based on the old detection code before bug 1838123, with some noteworthy changes:
- Hooking the UIA window message doesn't work; our hook runs too late. It also doesn't work well for blocking; some clients will very likely poke us more than the maximum attempts in the old code (5 times).
- Instead, we run this code as part of LazyInstantiator::ShouldInstantiate, just as we do for all other client detection.
- This means we use the same UIA detection caching strategy; i.e. reset on foreground changes.
- It also means we reuse the same instantiator setting and block listing code in LazyInstantiator.
Differential Revision: https://phabricator.services.mozilla.com/D185627
The new detection code introduced in bug 1838123 doesn't work on Windows 10.
This patch:
1. Splits the Windows 11 code into its own function.
2. Refactors the system handle enumeration code into its own function which can be called with a lambda, since it is needed for both Windows 11 and Windows 10.
3. Adds code to detect clients on Windows 10 based on the old detection code before bug 1838123, with some noteworthy changes:
- Hooking the UIA window message doesn't work; our hook runs too late. It also doesn't work well for blocking; some clients will very likely poke us more than the maximum attempts in the old code (5 times).
- Instead, we run this code as part of LazyInstantiator::ShouldInstantiate, just as we do for all other client detection.
- This means we use the same UIA detection caching strategy; i.e. reset on foreground changes.
- It also means we reuse the same instantiator setting and block listing code in LazyInstantiator.
Differential Revision: https://phabricator.services.mozilla.com/D185627
Eventually, the bulk of this functionality should be moved to TextLeafRange.
In the meantime, let's get rid of the platform specific ugliness here.
Differential Revision: https://phabricator.services.mozilla.com/D185263
This is consistent with other browsers and thus more web compatible.
In particular, it makes infinite scroll work correctly on YouTube (e.g. when scrolling with screen readers), which didn't work previously.
Differential Revision: https://phabricator.services.mozilla.com/D185516
Eventually, the bulk of this functionality should be moved to TextLeafRange.
In the meantime, let's get rid of the platform specific ugliness here.
Differential Revision: https://phabricator.services.mozilla.com/D185263
Implemented the new <search> HTML element.
All WPT tests for it now pass (except one for iso-8859-8, not done generally).
A11y role uses just landmark as recommended instead of a new search role (for now).
Co-authored-by: Henri Sivonen <hsivonen@mozilla.com>
Differential Revision: https://phabricator.services.mozilla.com/D176967
This revision removes test_link.html since it has been failing mysteriously in
CI. It's unclear why this is happening, and no amount of logging or local
testing has revealed the issue. This revision migrates the tests to the browser
tests, lumping it in with similar tests in browser_caching_actions.js.
Differential Revision: https://phabricator.services.mozilla.com/D185482
Implemented the new <search> HTML element.
All WPT tests for it now pass (except one for iso-8859-8, not done generally).
A11y role uses just landmark as recommended instead of a new search role (for now).
Co-authored-by: Henri Sivonen <hsivonen@mozilla.com>
Differential Revision: https://phabricator.services.mozilla.com/D176967
Implemented the new <search> HTML element.
All WPT tests for it now pass (except one for iso-8859-8, not done generally).
A11y role uses just landmark as recommended instead of a new search role (for now).
Co-authored-by: Henri Sivonen <hsivonen@mozilla.com>
Differential Revision: https://phabricator.services.mozilla.com/D176967
New word segmenter that is compatible with UAX#29 returns different results
against the old word segmenter. Adding both results.
Differential Revision: https://phabricator.services.mozilla.com/D185272
In each case, I'm putting the declaration at the start of the script block with
the main test logic, to be sure that it gets run ASAP and enables the full log before the failure happens (hopefully).
Once we've gotten what we need from the logs (or determined them to be not
useful), we can remove these requestCompleteLog() statements.
Differential Revision: https://phabricator.services.mozilla.com/D185391
get_selections is largely based on the old IAccessible2_3::get_selectionRanges method.
However, this makes use of HyperTextAccessibleBase::CroppedSelectionRanges, which didn't exist before.
It has also been updated to return IAccessibleText pointers as required by the new interface.
setSelections is entirely new, but relies on existing mechanisms to convert offsets and to add and remove selections.
Differential Revision: https://phabricator.services.mozilla.com/D185135
IAccessibleTextSelectionContainer::setSelections passes us IAccessibleText COM pointers to identify the target Accessibles.
We need to safely get a Gecko Accessible from such a COM pointer.
The client could hand us anything, so it's not safe to just static_cast without being certain that it's one of our Accessibles.
Instead, we use an internal IID to validate that it's an MsaaAccessible and return the correct pointer, after which we can easily get the Accessible.
Differential Revision: https://phabricator.services.mozilla.com/D185134
get_selections is largely based on the old IAccessible2_3::get_selectionRanges method.
However, this makes use of HyperTextAccessibleBase::CroppedSelectionRanges, which didn't exist before.
It has also been updated to return IAccessibleText pointers as required by the new interface.
setSelections is entirely new, but relies on existing mechanisms to convert offsets and to add and remove selections.
Differential Revision: https://phabricator.services.mozilla.com/D185135
IAccessibleTextSelectionContainer::setSelections passes us IAccessibleText COM pointers to identify the target Accessibles.
We need to safely get a Gecko Accessible from such a COM pointer.
The client could hand us anything, so it's not safe to just static_cast without being certain that it's one of our Accessibles.
Instead, we use an internal IID to validate that it's an MsaaAccessible and return the correct pointer, after which we can easily get the Accessible.
Differential Revision: https://phabricator.services.mozilla.com/D185134
The methods have already been updated to used unified cross-platform methods.
All that was preventing these from working was the IsLocal restriction in QueryInterface.
Differential Revision: https://phabricator.services.mozilla.com/D185253
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
We previously cached aria-placeholder, but not HTML placeholder.
These both map to the placeholder object attribute exposed by Accessible::Attributes, but they are retrieved differently internally.
This also fixes LocalAccessible::Attributes to always prefer HTML placeholder over aria-placeholder as per the ARIA spec.
Previously, the attribute we preferred was somewhat indeterminate (from the user's perspective) due to the ordering of hash maps.
Differential Revision: https://phabricator.services.mozilla.com/D184795
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
In the content process, we simply split into multiple calls when the number of Accessibles exceeds our maximum.
The maximum is calculated to allow for every Accessible to consume 2 KB in the IPDL message.
Currently, this means we split every 131072 Accessibles.
Of course, we could still exceed this IPDL message size if one or more Accessibles consumed a lot more than this; e.g. many labels longer than 2 KB.
However, this seems unlikely in the real world.
If this turns out to be a problem, we'll need to count the actual size of the serialized data for each Accessible.
For example, we could use AccAttributes::SizeOfExcludingThis, though that isn't exactly the serialized size.
I worry though that such data structure traversal could get expensive at scale.
In the parent process, we defer attaching the root of the new subtree to its parent until the final call.
This is achieved by saving the root during the first call and using that to attach and fire events in the final call.
Differential Revision: https://phabricator.services.mozilla.com/D184367
When we serialize a subtree, we put it into a flat list.
Previously, we included the child count for each Accessible so that we knew how many Accessibels to consume as children when de-serializing.
We also de-serialized recursively.
This made it very difficult to split serialization across IPDL calls, since we would always end up splitting in the middle of some Accessible's children.
Instead, we now no longer include the child count, but we do include the parent id and the index of the child in that parent.
This means that each Accessible can be de-serialized independently and iteratively, making it possible to split wherever we need to.
RemoteAccessible creation has also been separated from attachment of the child to its parent, since we will need this when splitting.
Differential Revision: https://phabricator.services.mozilla.com/D184366
Some member functions are defined in LocalAssessible-inl.h as inline functions, but where declared in LocalAccessible.h without inline specifiers. When compiling files, such as AccIterator.cpp, that include the LocalAccessible.h declarations but not the LocalAccessible-inl.h definitions, the compiler doesn't know that those member functions are not defined out-of-line. The linker expects to find those out-of-line definitions, but can't because they are defined inline.
Solution:
1. Include LocalAccessible-inl.h where needed.
2. Mark LocalAccessible.h's member function declarations as inline if they are defined inline in LocalAccessible-inl.h. This allows the compiler to warn when a file fails to include the LocalAccessible-inl.h definitions. Example warning:
obj-aarch64-apple-darwin22.5.0/dist/include/mozilla/a11y/LocalAccessible.h:174:30: error: inline function 'mozilla::a11y::LocalAccessible::ARIARole' is not defined [-Werror,-Wundefined-inline]
inline mozilla::a11y::role ARIARole();
^
accessible/generic/DocAccessible-inl.h:127:32: note: used here
roles::Role role = aChild->ARIARole();
instead of linker errors (in non-unified builds) like:
ld64.lld: error: undefined symbol: mozilla::a11y::LocalAccessible::IsDefunct() const
>>> referenced by AccIterator.cpp:288 (/Users/chris/Code/mozilla/firefox/accessible/base/AccIterator.cpp:288)
>>> ../../../accessible/base/AccIterator.o:(symbol mozilla::a11y::SingleAccIterator::Next()+0x48)
Differential Revision: https://phabricator.services.mozilla.com/D184603
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
In some edge cases (such as in accessible/tests/crashtests/1472024-1.html), there can be an outer HTML table which contains an inner table according to layout, but the inner table isn't included in the a11y tree.
The inner table has no semantic value, so including it wouldn't be appropriate.
However, HTMLTableAccessible::Col/RowExtent previously retrieved the table using the a11y tree, which meant we used the layout frame for the outer table instead of the inner table.
This resulted in assertions.
To fix this, always ask the cell's layout frame for the correct table frame, rather than walking the a11y tree.
As a bonus, this simplifies and trims the code somewhat.
Differential Revision: https://phabricator.services.mozilla.com/D184066