Vendor dependencies for 0.3.0 release

This commit is contained in:
2025-09-27 10:29:08 -05:00
parent 0c8d39d483
commit 82ab7f317b
26803 changed files with 16134934 additions and 0 deletions

View File

@@ -0,0 +1 @@
{"files":{"CHANGELOG.md":"6bac14566083ec15dc8fc04899c8ca8937989fb7e5d4fc36afd2a5ab8dc65406","Cargo.lock":"f73b3b1e58d199872389978bfa8e4125c949d68dd6585486cb7552065ec6940c","Cargo.toml":"daff39b8f07c5c77a7bb525d5fd48f8b53c6d62406b3afd06bbcbbd6d7f25d65","README.md":"28c871133e9adeb24b4140a520614cee08713c35e2e2688f4a2fed7d4e62b472","src/filters.rs":"74b3a6cb2ddc8a944f49cc41b4e72f0f9c5ab40ce1839694511d0188a6c894a1","src/iterators.rs":"f4871739f24cf7fa6c58e92865f102fa92fd770e73e87fb33d01b92b24eef9de","src/lib.rs":"5c9eac044ea3d69edff3b3946e22af29568cbcac53756be1a90054cacde8a61e","src/node.rs":"f41f3c1fc3bb72962e9187f96c19ace7a58da48c57bd5a95692a206f0882a66c","src/text.rs":"c26a8f8523aadda0e383987046d36a36a0fe720db6da561b1ffd4613f3cd50c1","src/tree.rs":"94a7c050d12a43576f95b55f160d83411f98b019faaec3c9a151a0b3b55f7e0e"},"package":"d0bf66a7bf0b7ea4fd7742d50b64782a88f99217cf246b3f93b4162528dde520"}

605
vendor/accesskit_consumer/CHANGELOG.md vendored Normal file
View File

@@ -0,0 +1,605 @@
# Changelog
* The following workspace dependencies were updated
* dependencies
* accesskit bumped from 0.10.0 to 0.10.1
* The following workspace dependencies were updated
* dependencies
* accesskit bumped from 0.10.1 to 0.11.0
* The following workspace dependencies were updated
* dependencies
* accesskit bumped from 0.11.0 to 0.11.1
* The following workspace dependencies were updated
* dependencies
* accesskit bumped from 0.11.1 to 0.11.2
* The following workspace dependencies were updated
* dependencies
* accesskit bumped from 0.12.2 to 0.12.3
* The following workspace dependencies were updated
* dependencies
* accesskit bumped from 0.16.2 to 0.16.3
## [0.27.0](https://github.com/AccessKit/accesskit/compare/accesskit_consumer-v0.26.0...accesskit_consumer-v0.27.0) (2025-03-06)
### ⚠ BREAKING CHANGES
* Optimize simple string getters ([#493](https://github.com/AccessKit/accesskit/issues/493))
* Drop `Tree::app_name` ([#492](https://github.com/AccessKit/accesskit/issues/492))
### Features
* Add list box support to the `consumer` and `atspi-common` crates ([d6dca15](https://github.com/AccessKit/accesskit/commit/d6dca15d5c298c797ab7a702f0186043eac33c5c))
* Android adapter ([#500](https://github.com/AccessKit/accesskit/issues/500)) ([7e65ac7](https://github.com/AccessKit/accesskit/commit/7e65ac77d7e108ac5b9f3722f488a2fdf2e3b3e0))
* Expose the `is_required` property ([#497](https://github.com/AccessKit/accesskit/issues/497)) ([46ed99b](https://github.com/AccessKit/accesskit/commit/46ed99bb958ddb32cbf1bee2fcfb7b328bcbe0ab))
### Bug Fixes
* Derive `Debug` for adapters ([#513](https://github.com/AccessKit/accesskit/issues/513)) ([753d904](https://github.com/AccessKit/accesskit/commit/753d90473cf57682568c7a17c82474c8e5d00b25))
* Optimize dynamic string building ([#491](https://github.com/AccessKit/accesskit/issues/491)) ([a86901d](https://github.com/AccessKit/accesskit/commit/a86901ddea5d5ba72ab237e98b53d6adcc6087bb))
* Optimize removal of unreachable nodes ([#486](https://github.com/AccessKit/accesskit/issues/486)) ([93d0a72](https://github.com/AccessKit/accesskit/commit/93d0a72880901479fe44ed92ef24fa71b7bb4803))
* Optimize the "short node list" helper used in panic messages ([#490](https://github.com/AccessKit/accesskit/issues/490)) ([b4a89a3](https://github.com/AccessKit/accesskit/commit/b4a89a386474b9a71f22aa36d09c2d07bca084cd))
* Remove unnecessary explicit lifetimes ([#488](https://github.com/AccessKit/accesskit/issues/488)) ([d2bcd6d](https://github.com/AccessKit/accesskit/commit/d2bcd6d3048d23df4e132bee6171eb247b2dc2c8))
### Code Refactoring
* Drop `Tree::app_name` ([#492](https://github.com/AccessKit/accesskit/issues/492)) ([089794c](https://github.com/AccessKit/accesskit/commit/089794c8f74957e91a19ae3df508e2a892f39ebc))
* Optimize simple string getters ([#493](https://github.com/AccessKit/accesskit/issues/493)) ([484fd7c](https://github.com/AccessKit/accesskit/commit/484fd7cbfb778222369d3f57d31dd998f6fa80d8))
### Dependencies
* The following workspace dependencies were updated
* dependencies
* accesskit bumped from 0.17.1 to 0.18.0
## [0.26.0](https://github.com/AccessKit/accesskit/compare/accesskit_consumer-v0.25.0...accesskit_consumer-v0.26.0) (2024-11-23)
### Features
* Make the consumer crate no-std ([#471](https://github.com/AccessKit/accesskit/issues/471)) ([f25d03a](https://github.com/AccessKit/accesskit/commit/f25d03ad81736017a29ce0f5ed1b387047534d2d))
### Bug Fixes
* Avoid reallocations when processing tree updates ([#482](https://github.com/AccessKit/accesskit/issues/482)) ([dcb17bc](https://github.com/AccessKit/accesskit/commit/dcb17bc1e69eccc2fea6af6a6b61f71c9e73a0b9))
### Dependencies
* The following workspace dependencies were updated
* dependencies
* accesskit bumped from 0.17.0 to 0.17.1
## [0.25.0](https://github.com/AccessKit/accesskit/compare/accesskit_consumer-v0.24.3...accesskit_consumer-v0.25.0) (2024-10-31)
### ⚠ BREAKING CHANGES
* Rename `name` to `label` and use `value` for label content ([#475](https://github.com/AccessKit/accesskit/issues/475))
* Rename `NodeBuilder` to `Node` and the old `Node` to `FrozenNode` ([#476](https://github.com/AccessKit/accesskit/issues/476))
* Rename `Role::InlineTextBox` to `TextRun` ([#473](https://github.com/AccessKit/accesskit/issues/473))
* Drop `DefaultActionVerb` ([#472](https://github.com/AccessKit/accesskit/issues/472))
* Make the core crate no-std ([#468](https://github.com/AccessKit/accesskit/issues/468))
### Features
* Make the core crate no-std ([#468](https://github.com/AccessKit/accesskit/issues/468)) ([2fa0d3f](https://github.com/AccessKit/accesskit/commit/2fa0d3f5b2b7ac11ef1751c133706f29e548bd6d))
### Code Refactoring
* Drop `DefaultActionVerb` ([#472](https://github.com/AccessKit/accesskit/issues/472)) ([ef3b003](https://github.com/AccessKit/accesskit/commit/ef3b0038224459094f650368412650bc3b69526b))
* Rename `name` to `label` and use `value` for label content ([#475](https://github.com/AccessKit/accesskit/issues/475)) ([e0053a5](https://github.com/AccessKit/accesskit/commit/e0053a5399929e8e0d4f07aa18de604ed8766ace))
* Rename `NodeBuilder` to `Node` and the old `Node` to `FrozenNode` ([#476](https://github.com/AccessKit/accesskit/issues/476)) ([7d8910e](https://github.com/AccessKit/accesskit/commit/7d8910e35f7bc0543724cc124941a3bd0304bcc0))
* Rename `Role::InlineTextBox` to `TextRun` ([#473](https://github.com/AccessKit/accesskit/issues/473)) ([29fa341](https://github.com/AccessKit/accesskit/commit/29fa34125a811bd3a0f9da579a9f35c9da90bf29))
### Dependencies
* The following workspace dependencies were updated
* dependencies
* accesskit bumped from 0.16.3 to 0.17.0
## [0.24.2](https://github.com/AccessKit/accesskit/compare/accesskit_consumer-v0.24.1...accesskit_consumer-v0.24.2) (2024-10-07)
### Bug Fixes
* Update minimum supported Rust version to 1.75 ([#457](https://github.com/AccessKit/accesskit/issues/457)) ([fc622fe](https://github.com/AccessKit/accesskit/commit/fc622fe7657c80a4eedad6f6cded11d2538b54d5))
### Dependencies
* The following workspace dependencies were updated
* dependencies
* accesskit bumped from 0.16.1 to 0.16.2
## [0.24.1](https://github.com/AccessKit/accesskit/compare/accesskit_consumer-v0.24.0...accesskit_consumer-v0.24.1) (2024-09-24)
### Bug Fixes
* `Node::is_focusable` always returns true if the node is focused ([#451](https://github.com/AccessKit/accesskit/issues/451)) ([d286883](https://github.com/AccessKit/accesskit/commit/d286883d88b5c1e51f6e8bbfbc2e0e5b1986d9b5))
* Extend the implicit labelled-by relation to more parent roles ([#448](https://github.com/AccessKit/accesskit/issues/448)) ([df518c7](https://github.com/AccessKit/accesskit/commit/df518c71934cb4e0071764643968e67f9908a8dd))
### Dependencies
* The following workspace dependencies were updated
* dependencies
* accesskit bumped from 0.16.0 to 0.16.1
## [0.24.0](https://github.com/AccessKit/accesskit/compare/accesskit_consumer-v0.23.0...accesskit_consumer-v0.24.0) (2024-06-29)
### ⚠ BREAKING CHANGES
* Rename the `StaticText` role to `Label` ([#434](https://github.com/AccessKit/accesskit/issues/434))
### Bug Fixes
* Correctly handle recursive filtering ([#438](https://github.com/AccessKit/accesskit/issues/438)) ([72f9b42](https://github.com/AccessKit/accesskit/commit/72f9b424a5c6e7914df8bf31eeb2fc61be35f47b))
### Code Refactoring
* Rename the `StaticText` role to `Label` ([#434](https://github.com/AccessKit/accesskit/issues/434)) ([7086bc0](https://github.com/AccessKit/accesskit/commit/7086bc0fad446d3ed4a0fd5eff641a1e75f6c599))
### Dependencies
* The following workspace dependencies were updated
* dependencies
* accesskit bumped from 0.15.0 to 0.16.0
## [0.23.0](https://github.com/AccessKit/accesskit/compare/accesskit_consumer-v0.22.0...accesskit_consumer-v0.23.0) (2024-06-09)
### Features
* Add `author_id` property ([#424](https://github.com/AccessKit/accesskit/issues/424)) ([0d1c56f](https://github.com/AccessKit/accesskit/commit/0d1c56f0bdde58715e1c69f6015df600cb7cb8c1))
### Bug Fixes
* Clamp character index when getting focus from a text selection ([#428](https://github.com/AccessKit/accesskit/issues/428)) ([38e649d](https://github.com/AccessKit/accesskit/commit/38e649de6b72c99d1e438b26b3fc1f647ac39e6c))
### Dependencies
* The following workspace dependencies were updated
* dependencies
* accesskit bumped from 0.14.0 to 0.15.0
## [0.22.0](https://github.com/AccessKit/accesskit/compare/accesskit_consumer-v0.21.0...accesskit_consumer-v0.22.0) (2024-05-27)
### Features
* Expose the `orientation` property ([#421](https://github.com/AccessKit/accesskit/issues/421)) ([590aada](https://github.com/AccessKit/accesskit/commit/590aada070dc812f9b8f171fb9e43ac984fad2a1))
## [0.21.0](https://github.com/AccessKit/accesskit/compare/accesskit_consumer-v0.20.0...accesskit_consumer-v0.21.0) (2024-05-26)
### Features
* Add basic text support on Unix ([#362](https://github.com/AccessKit/accesskit/issues/362)) ([52540f8](https://github.com/AccessKit/accesskit/commit/52540f82cf9fc148358351ed486bab3e7e91f1d6))
* Expose the `placeholder` property ([#417](https://github.com/AccessKit/accesskit/issues/417)) ([8f4a0a1](https://github.com/AccessKit/accesskit/commit/8f4a0a1c10f83fcc8580a37d8013fec2d110865b))
### Bug Fixes
* Clamp character indices when converting a text selection to a range ([#416](https://github.com/AccessKit/accesskit/issues/416)) ([5c550af](https://github.com/AccessKit/accesskit/commit/5c550af7afc81b3a32c30d31327ff95b93718545))
* Fix a logic error that sometimes caused filtered traversal to stop prematurely ([#412](https://github.com/AccessKit/accesskit/issues/412)) ([9946d38](https://github.com/AccessKit/accesskit/commit/9946d38b9d13489517713f43284cf6b96d88cb8c))
* Go back to detecting unchanged nodes when processing tree updates ([#415](https://github.com/AccessKit/accesskit/issues/415)) ([489302d](https://github.com/AccessKit/accesskit/commit/489302db7143a016605145682b989ab18583d59c))
* Update minimum version of immutable-chunkmap ([#419](https://github.com/AccessKit/accesskit/issues/419)) ([893f688](https://github.com/AccessKit/accesskit/commit/893f68845dd322da5f3ae4d39fc2b1cc01f88888))
## [0.20.0](https://github.com/AccessKit/accesskit/compare/accesskit_consumer-v0.19.1...accesskit_consumer-v0.20.0) (2024-05-13)
### ⚠ BREAKING CHANGES
* Restore full copy-on-write tree snapshots, now using `immutable-chunkmap` ([#365](https://github.com/AccessKit/accesskit/issues/365))
### Bug Fixes
* Fix the filtered sibling iterators to use the filtered parent to find the back node ([#408](https://github.com/AccessKit/accesskit/issues/408)) ([2f8155c](https://github.com/AccessKit/accesskit/commit/2f8155ca260d7e50de5de502744b420769875e83))
### Code Refactoring
* Restore full copy-on-write tree snapshots, now using `immutable-chunkmap` ([#365](https://github.com/AccessKit/accesskit/issues/365)) ([441bf5f](https://github.com/AccessKit/accesskit/commit/441bf5ff77d1785dfea228de9109aceff4773da1))
## [0.19.1](https://github.com/AccessKit/accesskit/compare/accesskit_consumer-v0.19.0...accesskit_consumer-v0.19.1) (2024-05-11)
### Bug Fixes
* Improve panic messages ([#401](https://github.com/AccessKit/accesskit/issues/401)) ([e6ce021](https://github.com/AccessKit/accesskit/commit/e6ce021b3b172f5ea7ee31496c9afaf66b1871f2))
## [0.19.0](https://github.com/AccessKit/accesskit/compare/accesskit_consumer-v0.18.0...accesskit_consumer-v0.19.0) (2024-04-30)
### ⚠ BREAKING CHANGES
* Drop `NodeClassSet` ([#389](https://github.com/AccessKit/accesskit/issues/389))
* Rename `Checked` to `Toggled`; drop `ToggleButton` role ([#388](https://github.com/AccessKit/accesskit/issues/388))
### Features
* Expose the class name property ([#385](https://github.com/AccessKit/accesskit/issues/385)) ([53dcf2a](https://github.com/AccessKit/accesskit/commit/53dcf2ae47546273590c46a9b31b708aa1409837))
* Implement the `description` property ([#382](https://github.com/AccessKit/accesskit/issues/382)) ([d49f406](https://github.com/AccessKit/accesskit/commit/d49f40660b5dc23ed074cd72a91e511b130756ae))
### Bug Fixes
* Increase minimum supported Rust version to `1.70` ([#396](https://github.com/AccessKit/accesskit/issues/396)) ([a8398b8](https://github.com/AccessKit/accesskit/commit/a8398b847aa003de91042ac45e33126fc2cae053))
### Code Refactoring
* Drop `NodeClassSet` ([#389](https://github.com/AccessKit/accesskit/issues/389)) ([1b153ed](https://github.com/AccessKit/accesskit/commit/1b153ed51f8421cdba2dc98beca2e8f5f8c781bc))
* Rename `Checked` to `Toggled`; drop `ToggleButton` role ([#388](https://github.com/AccessKit/accesskit/issues/388)) ([6bc040b](https://github.com/AccessKit/accesskit/commit/6bc040b7cf75cdbd6a019cc380d8dbce804b3c81))
### Dependencies
* The following workspace dependencies were updated
* dependencies
* accesskit bumped from 0.13.0 to 0.14.0
## [0.18.0](https://github.com/AccessKit/accesskit/compare/accesskit_consumer-v0.17.1...accesskit_consumer-v0.18.0) (2024-04-14)
### ⚠ BREAKING CHANGES
* New approach to lazy initialization ([#375](https://github.com/AccessKit/accesskit/issues/375))
### Code Refactoring
* New approach to lazy initialization ([#375](https://github.com/AccessKit/accesskit/issues/375)) ([9baebdc](https://github.com/AccessKit/accesskit/commit/9baebdceed7300389b6768815d7ae48f1ce401e4))
### Dependencies
* The following workspace dependencies were updated
* dependencies
* accesskit bumped from 0.12.3 to 0.13.0
## [0.17.0](https://github.com/AccessKit/accesskit/compare/accesskit_consumer-v0.16.1...accesskit_consumer-v0.17.0) (2024-01-03)
### Features
* Support custom role descriptions ([#316](https://github.com/AccessKit/accesskit/issues/316)) ([c8d1a56](https://github.com/AccessKit/accesskit/commit/c8d1a5638fa6c33adfa059815c04f7e043c56026))
### Dependencies
* The following workspace dependencies were updated
* dependencies
* accesskit bumped from 0.12.1 to 0.12.2
## [0.16.1](https://github.com/AccessKit/accesskit/compare/accesskit_consumer-v0.16.0...accesskit_consumer-v0.16.1) (2023-11-04)
### Bug Fixes
* Add missing semicolons when not returning anything ([#303](https://github.com/AccessKit/accesskit/issues/303)) ([38d4de1](https://github.com/AccessKit/accesskit/commit/38d4de1442247e701047d75122a9638a2ed99b1f))
### Dependencies
* The following workspace dependencies were updated
* dependencies
* accesskit bumped from 0.12.0 to 0.12.1
## [0.16.0](https://github.com/AccessKit/accesskit/compare/accesskit_consumer-v0.15.2...accesskit_consumer-v0.16.0) (2023-09-27)
### ⚠ BREAKING CHANGES
* Allow providing app_name, toolkit_name and toolkit_version in Tree, remove parameters from unix adapter constructor ([#291](https://github.com/AccessKit/accesskit/issues/291))
* Clean up roles and properties ([#289](https://github.com/AccessKit/accesskit/issues/289))
* Drop `Tree::root_scroller` ([#279](https://github.com/AccessKit/accesskit/issues/279))
* Decouple in-tree focus from host window/view focus ([#278](https://github.com/AccessKit/accesskit/issues/278))
* Switch to simple unsigned 64-bit integer for node IDs ([#276](https://github.com/AccessKit/accesskit/issues/276))
### Features
* Add role for terminals ([#282](https://github.com/AccessKit/accesskit/issues/282)) ([ddbef37](https://github.com/AccessKit/accesskit/commit/ddbef37158b57f56217317b480e40d58f83a9c24))
* Allow providing app_name, toolkit_name and toolkit_version in Tree, remove parameters from unix adapter constructor ([#291](https://github.com/AccessKit/accesskit/issues/291)) ([5313860](https://github.com/AccessKit/accesskit/commit/531386023257150f49b5e4be942f359855fb7cb6))
### Bug Fixes
* Drop `Tree::root_scroller` ([#279](https://github.com/AccessKit/accesskit/issues/279)) ([fc6c4e0](https://github.com/AccessKit/accesskit/commit/fc6c4e0091d5b257a3869a468fca144a1453cebc))
* Support text fields without a value property ([#274](https://github.com/AccessKit/accesskit/issues/274)) ([5ae557b](https://github.com/AccessKit/accesskit/commit/5ae557b40d395b4a9966a90a2d80e7d97ad50bf9))
* Use common filters across platform adapters ([#287](https://github.com/AccessKit/accesskit/issues/287)) ([09c1204](https://github.com/AccessKit/accesskit/commit/09c12045ff4ccdb22f0cf643077a27465013572d))
### Code Refactoring
* Clean up roles and properties ([#289](https://github.com/AccessKit/accesskit/issues/289)) ([4fc9c55](https://github.com/AccessKit/accesskit/commit/4fc9c55c91812472593923d93ff89d75ff305ee4))
* Decouple in-tree focus from host window/view focus ([#278](https://github.com/AccessKit/accesskit/issues/278)) ([d360d20](https://github.com/AccessKit/accesskit/commit/d360d20cf951e7643b81a5303006c9f7daa5bd56))
* Switch to simple unsigned 64-bit integer for node IDs ([#276](https://github.com/AccessKit/accesskit/issues/276)) ([3eadd48](https://github.com/AccessKit/accesskit/commit/3eadd48ec47854faa94a94ebf910ec08f514642f))
### Dependencies
* The following workspace dependencies were updated
* dependencies
* accesskit bumped from 0.11.2 to 0.12.0
## [0.15.0](https://github.com/AccessKit/accesskit/compare/accesskit_consumer-v0.14.2...accesskit_consumer-v0.15.0) (2023-03-30)
### ⚠ BREAKING CHANGES
* Force a semver-breaking version bump in downstream crates ([#234](https://github.com/AccessKit/accesskit/issues/234))
### Bug Fixes
* Force a semver-breaking version bump in downstream crates ([#234](https://github.com/AccessKit/accesskit/issues/234)) ([773389b](https://github.com/AccessKit/accesskit/commit/773389bff857fa18edf15de426e029251fc34591))
## [0.14.0](https://github.com/AccessKit/accesskit/compare/accesskit_consumer-v0.13.0...accesskit_consumer-v0.14.0) (2023-02-12)
### ⚠ BREAKING CHANGES
* Move thread synchronization into platform adapters; drop parking_lot ([#212](https://github.com/AccessKit/accesskit/issues/212))
### Code Refactoring
* Move thread synchronization into platform adapters; drop parking_lot ([#212](https://github.com/AccessKit/accesskit/issues/212)) ([5df52e5](https://github.com/AccessKit/accesskit/commit/5df52e5545faddf6a51905409013c2f5be23981e))
### Dependencies
* The following workspace dependencies were updated
* dependencies
* accesskit bumped from 0.9.0 to 0.10.0
## [0.13.0](https://github.com/AccessKit/accesskit/compare/accesskit_consumer-v0.12.1...accesskit_consumer-v0.13.0) (2023-02-05)
### ⚠ BREAKING CHANGES
* Make `Node` opaque and optimize it for size ([#205](https://github.com/AccessKit/accesskit/issues/205))
### Code Refactoring
* Make `Node` opaque and optimize it for size ([#205](https://github.com/AccessKit/accesskit/issues/205)) ([4811152](https://github.com/AccessKit/accesskit/commit/48111521439b76c1a8687418a4b20f9b705eac6d))
### Dependencies
* The following workspace dependencies were updated
* dependencies
* accesskit bumped from 0.8.1 to 0.9.0
## [0.12.1](https://github.com/AccessKit/accesskit/compare/accesskit_consumer-v0.12.0...accesskit_consumer-v0.12.1) (2023-01-06)
### Bug Fixes
* Make `Node::filtered_parent` recursive as it was meant to be ([#203](https://github.com/AccessKit/accesskit/issues/203)) ([d2faef5](https://github.com/AccessKit/accesskit/commit/d2faef5a2ad61b9e4d3f3d5c89570cdeec6fe6e6))
## [0.12.0](https://github.com/AccessKit/accesskit/compare/accesskit_consumer-v0.11.0...accesskit_consumer-v0.12.0) (2023-01-05)
### Features
* Basic Unix platform adapter ([#198](https://github.com/AccessKit/accesskit/issues/198)) ([1cea32e](https://github.com/AccessKit/accesskit/commit/1cea32e44ee743b778ac941ceff9087ae745cb37))
## [0.11.0](https://github.com/AccessKit/accesskit/compare/accesskit_consumer-v0.10.0...accesskit_consumer-v0.11.0) (2022-12-17)
### Features
* Text support on macOS ([#191](https://github.com/AccessKit/accesskit/issues/191)) ([3a35dbe](https://github.com/AccessKit/accesskit/commit/3a35dbe02122c789fe682995c5b7e022aef5cc36))
### Bug Fixes
* More reliable handling of the edge case for wrapped lines ([#192](https://github.com/AccessKit/accesskit/issues/192)) ([c626d2c](https://github.com/AccessKit/accesskit/commit/c626d2c3028085b076ada7dd31242cf3ca3c0f08))
## [0.10.0](https://github.com/AccessKit/accesskit/compare/accesskit_consumer-v0.9.1...accesskit_consumer-v0.10.0) (2022-12-04)
### Features
* Automatically get button and link labels from descendants ([#184](https://github.com/AccessKit/accesskit/issues/184)) ([ec5c38e](https://github.com/AccessKit/accesskit/commit/ec5c38ef3001a10b7a135df1438901246463f3e1))
### Dependencies
* The following workspace dependencies were updated
* dependencies
* accesskit bumped from 0.8.0 to 0.8.1
### [0.9.1](https://www.github.com/AccessKit/accesskit/compare/accesskit_consumer-v0.9.0...accesskit_consumer-v0.9.1) (2022-11-25)
### Bug Fixes
* **consumer:** Allow editable spin buttons ([#167](https://www.github.com/AccessKit/accesskit/issues/167)) ([65a7aa0](https://www.github.com/AccessKit/accesskit/commit/65a7aa0114bfc6e17189e834578e256945b84a98))
* Gracefully handle nodes that only support text ranges some of the time ([#169](https://www.github.com/AccessKit/accesskit/issues/169)) ([1f50df6](https://www.github.com/AccessKit/accesskit/commit/1f50df6820b9d23fe2e579f043f4981acf285de2))
## [0.9.0](https://www.github.com/AccessKit/accesskit/compare/accesskit_consumer-v0.8.0...accesskit_consumer-v0.9.0) (2022-11-23)
### Features
* **platforms/macos:** Basic macOS platform adapter ([#158](https://www.github.com/AccessKit/accesskit/issues/158)) ([a06725e](https://www.github.com/AccessKit/accesskit/commit/a06725e952e6041dbd366944fa793b746c9f195e))
## [0.8.0](https://www.github.com/AccessKit/accesskit/compare/accesskit_consumer-v0.7.1...accesskit_consumer-v0.8.0) (2022-11-17)
### ⚠ BREAKING CHANGES
* **consumer:** Eliminate the dependency on `im` due to licensing (#153)
### Code Refactoring
* **consumer:** Eliminate the dependency on `im` due to licensing ([#153](https://www.github.com/AccessKit/accesskit/issues/153)) ([b4c4cb5](https://www.github.com/AccessKit/accesskit/commit/b4c4cb5713d4833d8ee7979e4f4e39c7e96a3ed4))
### Dependencies
* The following workspace dependencies were updated
* dependencies
* accesskit bumped from 0.7.0 to 0.8.0
### [0.7.1](https://www.github.com/AccessKit/accesskit/compare/accesskit_consumer-v0.7.0...accesskit_consumer-v0.7.1) (2022-11-12)
### Bug Fixes
* **consumer, platforms/windows, platforms/winit:** Update to parking_lot 0.12.1 ([#146](https://www.github.com/AccessKit/accesskit/issues/146)) ([6772855](https://www.github.com/AccessKit/accesskit/commit/6772855a7b540fd728faad15d8d208b05c1bbd8a))
## [0.7.0](https://www.github.com/AccessKit/accesskit/compare/accesskit_consumer-v0.6.1...accesskit_consumer-v0.7.0) (2022-11-11)
### ⚠ BREAKING CHANGES
* Text range support (#145)
* Drop the `ignored` field and implement generic filtered tree traversal (#143)
### Features
* Text range support ([#145](https://www.github.com/AccessKit/accesskit/issues/145)) ([455e6f7](https://www.github.com/AccessKit/accesskit/commit/455e6f73bc058644d299c06eeeda9cc4cbe8844f))
### Code Refactoring
* Drop the `ignored` field and implement generic filtered tree traversal ([#143](https://www.github.com/AccessKit/accesskit/issues/143)) ([a4befe6](https://www.github.com/AccessKit/accesskit/commit/a4befe6e8a5afbe4a52dfd09eb87fdf2078d6c1d))
### Dependencies
* The following workspace dependencies were updated
* dependencies
* accesskit bumped from 0.6.1 to 0.7.0
### [0.6.1](https://www.github.com/AccessKit/accesskit/compare/accesskit_consumer-v0.6.0...accesskit_consumer-v0.6.1) (2022-10-10)
### Dependencies
* The following workspace dependencies were updated
* dependencies
* accesskit bumped from 0.6.0 to 0.6.1
## [0.6.0](https://www.github.com/AccessKit/accesskit/compare/accesskit_consumer-v0.5.1...accesskit_consumer-v0.6.0) (2022-10-09)
### ⚠ BREAKING CHANGES
* **consumer:** Optimize tree access and change handling (#134)
* Wrap `TreeUpdate` nodes in `Arc` (#135)
* **consumer:** Make `Node::data` private to the crate (#137)
* Store node ID in `TreeUpdate`, not `accesskit::Node` (#132)
### Bug Fixes
* **consumer:** Drop printing of detached nodes before panic ([#136](https://www.github.com/AccessKit/accesskit/issues/136)) ([2f20477](https://www.github.com/AccessKit/accesskit/commit/2f204772a97d4e21205609f31f3e84bc878554cd))
* Don't try to optimize tree updates with unchanged nodes ([#138](https://www.github.com/AccessKit/accesskit/issues/138)) ([7721719](https://www.github.com/AccessKit/accesskit/commit/7721719fb0ab90bf41cc30dd0469c7de90228fe9))
### Code Refactoring
* **consumer:** Make `Node::data` private to the crate ([#137](https://www.github.com/AccessKit/accesskit/issues/137)) ([adb372d](https://www.github.com/AccessKit/accesskit/commit/adb372dda78d183c7189966e3bbc2d3780070513))
* **consumer:** Optimize tree access and change handling ([#134](https://www.github.com/AccessKit/accesskit/issues/134)) ([765ab74](https://www.github.com/AccessKit/accesskit/commit/765ab74efcf10a3b3871dc901d28f3cf1ff6020c))
* Store node ID in `TreeUpdate`, not `accesskit::Node` ([#132](https://www.github.com/AccessKit/accesskit/issues/132)) ([0bb86dd](https://www.github.com/AccessKit/accesskit/commit/0bb86ddb298cb5a253a91f07be0bad8b84b2fda3))
* Wrap `TreeUpdate` nodes in `Arc` ([#135](https://www.github.com/AccessKit/accesskit/issues/135)) ([907bc18](https://www.github.com/AccessKit/accesskit/commit/907bc1820b80d95833b6c5c3acaa2a8a4e93a6c2))
### Dependencies
* The following workspace dependencies were updated
* dependencies
* accesskit bumped from 0.5.1 to 0.6.0
### [0.5.1](https://www.github.com/AccessKit/accesskit/compare/accesskit_consumer-v0.5.0...accesskit_consumer-v0.5.1) (2022-10-03)
### Dependencies
* The following workspace dependencies were updated
* dependencies
* accesskit bumped from 0.5.0 to 0.5.1
## [0.5.0](https://www.github.com/AccessKit/accesskit/compare/accesskit_consumer-v0.4.0...accesskit_consumer-v0.5.0) (2022-09-23)
### ⚠ BREAKING CHANGES
* Basic live regions (#128)
### Features
* Basic live regions ([#128](https://www.github.com/AccessKit/accesskit/issues/128)) ([03d745b](https://www.github.com/AccessKit/accesskit/commit/03d745b891147175bde2693cc10b96a2f6e31f39))
### Dependencies
* The following workspace dependencies were updated
* dependencies
* accesskit bumped from 0.4.0 to 0.5.0
## [0.4.0](https://www.github.com/AccessKit/accesskit/compare/accesskit_consumer-v0.3.0...accesskit_consumer-v0.4.0) (2022-07-22)
### ⚠ BREAKING CHANGES
* String indices are always in UTF-8 code units (#114)
* Drop unused tree IDs (#113)
* Switch to NonZeroU128 for NodeIDs (#99)
### Bug Fixes
* **consumer, platforms/windows:** Resolve new clippy warning ([#100](https://www.github.com/AccessKit/accesskit/issues/100)) ([e8cd95c](https://www.github.com/AccessKit/accesskit/commit/e8cd95c3741b39b77e4ddc8ce82efdc20f93f096))
* Migrate to 2021 edition ([#115](https://www.github.com/AccessKit/accesskit/issues/115)) ([f2333c8](https://www.github.com/AccessKit/accesskit/commit/f2333c8ce17d46aab6fc190338ab4cfcf8569f9e))
* Switch to NonZeroU128 for NodeIDs ([#99](https://www.github.com/AccessKit/accesskit/issues/99)) ([25a1a52](https://www.github.com/AccessKit/accesskit/commit/25a1a52c4562b163bfcc8c625a233c00a41aacf2))
### Code Refactoring
* Drop unused tree IDs ([#113](https://www.github.com/AccessKit/accesskit/issues/113)) ([ca60770](https://www.github.com/AccessKit/accesskit/commit/ca607702cee13c93fe538d2faec88e474261f7ab))
* String indices are always in UTF-8 code units ([#114](https://www.github.com/AccessKit/accesskit/issues/114)) ([386ca0a](https://www.github.com/AccessKit/accesskit/commit/386ca0a89c42fd201843f617b2fd6b6d1de77f59))
### Dependencies
* The following workspace dependencies were updated
* dependencies
* accesskit bumped from 0.3.0 to 0.4.0
## [0.3.0](https://www.github.com/AccessKit/accesskit/compare/accesskit_consumer-v0.2.0...accesskit_consumer-v0.3.0) (2021-12-29)
### ⚠ BREAKING CHANGES
* Drop `TreeUpdate::clear` (#96)
### Code Refactoring
* Drop `TreeUpdate::clear` ([#96](https://www.github.com/AccessKit/accesskit/issues/96)) ([38f520b](https://www.github.com/AccessKit/accesskit/commit/38f520b960c6db7b3927b369aee206ee6bc5e8aa))
### Dependencies
* The following workspace dependencies were updated
* dependencies
* accesskit bumped from 0.2.0 to 0.3.0

48
vendor/accesskit_consumer/Cargo.lock generated vendored Normal file
View File

@@ -0,0 +1,48 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 3
[[package]]
name = "accesskit"
version = "0.18.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "becf0eb5215b6ecb0a739c31c21bd83c4f326524c9b46b7e882d77559b60a529"
[[package]]
name = "accesskit_consumer"
version = "0.27.0"
dependencies = [
"accesskit",
"hashbrown",
"immutable-chunkmap",
]
[[package]]
name = "arrayvec"
version = "0.7.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8da52d66c7071e2e3fa2a1e5c6d088fec47b593032b254f5e980de8ea54454d6"
[[package]]
name = "foldhash"
version = "0.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f81ec6369c545a7d40e4589b5597581fa1c441fe1cce96dd1de43159910a36a2"
[[package]]
name = "hashbrown"
version = "0.15.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289"
dependencies = [
"foldhash",
]
[[package]]
name = "immutable-chunkmap"
version = "2.0.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "12f97096f508d54f8f8ab8957862eee2ccd628847b6217af1a335e1c44dee578"
dependencies = [
"arrayvec",
]

48
vendor/accesskit_consumer/Cargo.toml vendored Normal file
View File

@@ -0,0 +1,48 @@
# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO
#
# When uploading crates to the registry Cargo will automatically
# "normalize" Cargo.toml files for maximal compatibility
# with all versions of Cargo and also rewrite `path` dependencies
# to registry (e.g., crates.io) dependencies.
#
# If you are reading this file be aware that the original Cargo.toml
# will likely look very different (and much more reasonable).
# See Cargo.toml.orig for the original contents.
[package]
edition = "2021"
rust-version = "1.77.2"
name = "accesskit_consumer"
version = "0.27.0"
authors = ["The AccessKit contributors"]
build = false
autolib = false
autobins = false
autoexamples = false
autotests = false
autobenches = false
description = "AccessKit consumer library (internal)"
readme = "README.md"
keywords = [
"gui",
"ui",
"accessibility",
]
categories = ["gui"]
license = "MIT OR Apache-2.0"
repository = "https://github.com/AccessKit/accesskit"
[lib]
name = "accesskit_consumer"
path = "src/lib.rs"
[dependencies.accesskit]
version = "0.18.0"
[dependencies.hashbrown]
version = "0.15"
features = ["default-hasher"]
default-features = false
[dependencies.immutable-chunkmap]
version = "2.0.6"

3
vendor/accesskit_consumer/README.md vendored Normal file
View File

@@ -0,0 +1,3 @@
# AccessKit consumer library
This library is used by code that consumes AccessKit accessibility trees, such as platform adapters. It does not need to be used directly by applications integrating AccessKit.

View File

@@ -0,0 +1,45 @@
// Copyright 2023 The AccessKit Authors. All rights reserved.
// Licensed under the Apache License, Version 2.0 (found in
// the LICENSE-APACHE file) or the MIT license (found in
// the LICENSE-MIT file), at your option.
use accesskit::Role;
use crate::node::Node;
#[derive(Clone, Copy, Debug, Hash, PartialEq, Eq, PartialOrd, Ord)]
pub enum FilterResult {
Include,
ExcludeNode,
ExcludeSubtree,
}
pub fn common_filter(node: &Node) -> FilterResult {
if node.is_focused() {
return FilterResult::Include;
}
if node.is_hidden() {
return FilterResult::ExcludeSubtree;
}
if let Some(parent) = node.parent() {
if common_filter(&parent) == FilterResult::ExcludeSubtree {
return FilterResult::ExcludeSubtree;
}
}
let role = node.role();
if role == Role::GenericContainer || role == Role::TextRun {
return FilterResult::ExcludeNode;
}
FilterResult::Include
}
pub fn common_filter_with_root_exception(node: &Node) -> FilterResult {
if node.is_root() {
return FilterResult::Include;
}
common_filter(node)
}

View File

@@ -0,0 +1,832 @@
// Copyright 2021 The AccessKit Authors. All rights reserved.
// Licensed under the Apache License, Version 2.0 (found in
// the LICENSE-APACHE file) or the MIT license (found in
// the LICENSE-MIT file), at your option.
// Derived from Chromium's accessibility abstraction.
// Copyright 2018 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE.chromium file.
use core::iter::FusedIterator;
use accesskit::NodeId;
use crate::{filters::FilterResult, node::Node, tree::State as TreeState};
/// An iterator that yields following siblings of a node.
///
/// This struct is created by the [`following_siblings`](Node::following_siblings) method on [`Node`].
pub struct FollowingSiblings<'a> {
back_position: usize,
done: bool,
front_position: usize,
parent: Option<Node<'a>>,
}
impl<'a> FollowingSiblings<'a> {
pub(crate) fn new(node: Node<'a>) -> Self {
let parent_and_index = node.parent_and_index();
let (back_position, front_position, done) =
if let Some((ref parent, index)) = parent_and_index {
let back_position = parent.data().children().len() - 1;
let front_position = index + 1;
(
back_position,
front_position,
front_position > back_position,
)
} else {
(0, 0, true)
};
Self {
back_position,
done,
front_position,
parent: parent_and_index.map(|(parent, _)| parent),
}
}
}
impl Iterator for FollowingSiblings<'_> {
type Item = NodeId;
fn next(&mut self) -> Option<Self::Item> {
if self.done {
None
} else {
self.done = self.front_position == self.back_position;
let child = self
.parent
.as_ref()?
.data()
.children()
.get(self.front_position)?;
self.front_position += 1;
Some(*child)
}
}
fn size_hint(&self) -> (usize, Option<usize>) {
let len = match self.done {
true => 0,
_ => self.back_position + 1 - self.front_position,
};
(len, Some(len))
}
}
impl DoubleEndedIterator for FollowingSiblings<'_> {
fn next_back(&mut self) -> Option<Self::Item> {
if self.done {
None
} else {
self.done = self.back_position == self.front_position;
let child = self
.parent
.as_ref()?
.data()
.children()
.get(self.back_position)?;
self.back_position -= 1;
Some(*child)
}
}
}
impl ExactSizeIterator for FollowingSiblings<'_> {}
impl FusedIterator for FollowingSiblings<'_> {}
/// An iterator that yields preceding siblings of a node.
///
/// This struct is created by the [`preceding_siblings`](Node::preceding_siblings) method on [`Node`].
pub struct PrecedingSiblings<'a> {
back_position: usize,
done: bool,
front_position: usize,
parent: Option<Node<'a>>,
}
impl<'a> PrecedingSiblings<'a> {
pub(crate) fn new(node: Node<'a>) -> Self {
let parent_and_index = node.parent_and_index();
let (back_position, front_position, done) = if let Some((_, index)) = parent_and_index {
let front_position = index.saturating_sub(1);
(0, front_position, index == 0)
} else {
(0, 0, true)
};
Self {
back_position,
done,
front_position,
parent: parent_and_index.map(|(parent, _)| parent),
}
}
}
impl Iterator for PrecedingSiblings<'_> {
type Item = NodeId;
fn next(&mut self) -> Option<Self::Item> {
if self.done {
None
} else {
self.done = self.front_position == self.back_position;
let child = self
.parent
.as_ref()?
.data()
.children()
.get(self.front_position)?;
if !self.done {
self.front_position -= 1;
}
Some(*child)
}
}
fn size_hint(&self) -> (usize, Option<usize>) {
let len = match self.done {
true => 0,
_ => self.front_position + 1 - self.back_position,
};
(len, Some(len))
}
}
impl DoubleEndedIterator for PrecedingSiblings<'_> {
fn next_back(&mut self) -> Option<Self::Item> {
if self.done {
None
} else {
self.done = self.back_position == self.front_position;
let child = self
.parent
.as_ref()?
.data()
.children()
.get(self.back_position)?;
self.back_position += 1;
Some(*child)
}
}
}
impl ExactSizeIterator for PrecedingSiblings<'_> {}
impl FusedIterator for PrecedingSiblings<'_> {}
fn next_filtered_sibling<'a>(
node: Option<Node<'a>>,
filter: &impl Fn(&Node) -> FilterResult,
) -> Option<Node<'a>> {
let mut next = node;
let mut consider_children = false;
while let Some(current) = next {
if let Some(Some(child)) = consider_children.then(|| current.children().next()) {
let result = filter(&child);
next = Some(child);
if result == FilterResult::Include {
return next;
}
consider_children = result == FilterResult::ExcludeNode;
} else if let Some(sibling) = current.following_siblings().next() {
let result = filter(&sibling);
next = Some(sibling);
if result == FilterResult::Include {
return next;
}
if result == FilterResult::ExcludeNode {
consider_children = true;
}
} else {
let parent = current.parent();
next = parent;
if let Some(parent) = parent {
if filter(&parent) != FilterResult::ExcludeNode {
return None;
}
consider_children = false;
} else {
return None;
}
}
}
None
}
fn previous_filtered_sibling<'a>(
node: Option<Node<'a>>,
filter: &impl Fn(&Node) -> FilterResult,
) -> Option<Node<'a>> {
let mut previous = node;
let mut consider_children = false;
while let Some(current) = previous {
if let Some(Some(child)) = consider_children.then(|| current.children().next_back()) {
let result = filter(&child);
previous = Some(child);
if result == FilterResult::Include {
return previous;
}
consider_children = result == FilterResult::ExcludeNode;
} else if let Some(sibling) = current.preceding_siblings().next() {
let result = filter(&sibling);
previous = Some(sibling);
if result == FilterResult::Include {
return previous;
}
if result == FilterResult::ExcludeNode {
consider_children = true;
}
} else {
let parent = current.parent();
previous = parent;
if let Some(parent) = parent {
if filter(&parent) != FilterResult::ExcludeNode {
return None;
}
consider_children = false;
} else {
return None;
}
}
}
None
}
/// An iterator that yields following siblings of a node according to the
/// specified filter.
///
/// This struct is created by the [`following_filtered_siblings`](Node::following_filtered_siblings) method on [`Node`].
pub struct FollowingFilteredSiblings<'a, Filter: Fn(&Node) -> FilterResult> {
filter: Filter,
back: Option<Node<'a>>,
done: bool,
front: Option<Node<'a>>,
}
impl<'a, Filter: Fn(&Node) -> FilterResult> FollowingFilteredSiblings<'a, Filter> {
pub(crate) fn new(node: Node<'a>, filter: Filter) -> Self {
let front = next_filtered_sibling(Some(node), &filter);
let back = node
.filtered_parent(&filter)
.and_then(|parent| parent.last_filtered_child(&filter));
Self {
filter,
back,
done: back.is_none() || front.is_none(),
front,
}
}
}
impl<'a, Filter: Fn(&Node) -> FilterResult> Iterator for FollowingFilteredSiblings<'a, Filter> {
type Item = Node<'a>;
fn next(&mut self) -> Option<Self::Item> {
if self.done {
None
} else {
self.done = self.front.as_ref().unwrap().id() == self.back.as_ref().unwrap().id();
let current = self.front;
self.front = next_filtered_sibling(self.front, &self.filter);
current
}
}
}
impl<Filter: Fn(&Node) -> FilterResult> DoubleEndedIterator
for FollowingFilteredSiblings<'_, Filter>
{
fn next_back(&mut self) -> Option<Self::Item> {
if self.done {
None
} else {
self.done = self.back.as_ref().unwrap().id() == self.front.as_ref().unwrap().id();
let current = self.back;
self.back = previous_filtered_sibling(self.back, &self.filter);
current
}
}
}
impl<Filter: Fn(&Node) -> FilterResult> FusedIterator for FollowingFilteredSiblings<'_, Filter> {}
/// An iterator that yields preceding siblings of a node according to the
/// specified filter.
///
/// This struct is created by the [`preceding_filtered_siblings`](Node::preceding_filtered_siblings) method on [`Node`].
pub struct PrecedingFilteredSiblings<'a, Filter: Fn(&Node) -> FilterResult> {
filter: Filter,
back: Option<Node<'a>>,
done: bool,
front: Option<Node<'a>>,
}
impl<'a, Filter: Fn(&Node) -> FilterResult> PrecedingFilteredSiblings<'a, Filter> {
pub(crate) fn new(node: Node<'a>, filter: Filter) -> Self {
let front = previous_filtered_sibling(Some(node), &filter);
let back = node
.filtered_parent(&filter)
.and_then(|parent| parent.first_filtered_child(&filter));
Self {
filter,
back,
done: back.is_none() || front.is_none(),
front,
}
}
}
impl<'a, Filter: Fn(&Node) -> FilterResult> Iterator for PrecedingFilteredSiblings<'a, Filter> {
type Item = Node<'a>;
fn next(&mut self) -> Option<Self::Item> {
if self.done {
None
} else {
self.done = self.front.as_ref().unwrap().id() == self.back.as_ref().unwrap().id();
let current = self.front;
self.front = previous_filtered_sibling(self.front, &self.filter);
current
}
}
}
impl<Filter: Fn(&Node) -> FilterResult> DoubleEndedIterator
for PrecedingFilteredSiblings<'_, Filter>
{
fn next_back(&mut self) -> Option<Self::Item> {
if self.done {
None
} else {
self.done = self.back.as_ref().unwrap().id() == self.front.as_ref().unwrap().id();
let current = self.back;
self.back = next_filtered_sibling(self.back, &self.filter);
current
}
}
}
impl<Filter: Fn(&Node) -> FilterResult> FusedIterator for PrecedingFilteredSiblings<'_, Filter> {}
/// An iterator that yields children of a node according to the specified
/// filter.
///
/// This struct is created by the [`filtered_children`](Node::filtered_children) method on [`Node`].
pub struct FilteredChildren<'a, Filter: Fn(&Node) -> FilterResult> {
filter: Filter,
back: Option<Node<'a>>,
done: bool,
front: Option<Node<'a>>,
}
impl<'a, Filter: Fn(&Node) -> FilterResult> FilteredChildren<'a, Filter> {
pub(crate) fn new(node: Node<'a>, filter: Filter) -> Self {
let front = node.first_filtered_child(&filter);
let back = node.last_filtered_child(&filter);
Self {
filter,
back,
done: back.is_none() || front.is_none(),
front,
}
}
}
impl<'a, Filter: Fn(&Node) -> FilterResult> Iterator for FilteredChildren<'a, Filter> {
type Item = Node<'a>;
fn next(&mut self) -> Option<Self::Item> {
if self.done {
None
} else {
self.done = self.front.as_ref().unwrap().id() == self.back.as_ref().unwrap().id();
let current = self.front;
self.front = next_filtered_sibling(self.front, &self.filter);
current
}
}
}
impl<Filter: Fn(&Node) -> FilterResult> DoubleEndedIterator for FilteredChildren<'_, Filter> {
fn next_back(&mut self) -> Option<Self::Item> {
if self.done {
None
} else {
self.done = self.back.as_ref().unwrap().id() == self.front.as_ref().unwrap().id();
let current = self.back;
self.back = previous_filtered_sibling(self.back, &self.filter);
current
}
}
}
impl<Filter: Fn(&Node) -> FilterResult> FusedIterator for FilteredChildren<'_, Filter> {}
pub(crate) enum LabelledBy<'a, Filter: Fn(&Node) -> FilterResult> {
FromDescendants(FilteredChildren<'a, Filter>),
Explicit {
ids: core::slice::Iter<'a, NodeId>,
tree_state: &'a TreeState,
},
}
impl<'a, Filter: Fn(&Node) -> FilterResult> Iterator for LabelledBy<'a, Filter> {
type Item = Node<'a>;
fn next(&mut self) -> Option<Self::Item> {
match self {
Self::FromDescendants(iter) => iter.next(),
Self::Explicit { ids, tree_state } => {
ids.next().map(|id| tree_state.node_by_id(*id).unwrap())
}
}
}
fn size_hint(&self) -> (usize, Option<usize>) {
match self {
Self::FromDescendants(iter) => iter.size_hint(),
Self::Explicit { ids, .. } => ids.size_hint(),
}
}
}
impl<Filter: Fn(&Node) -> FilterResult> DoubleEndedIterator for LabelledBy<'_, Filter> {
fn next_back(&mut self) -> Option<Self::Item> {
match self {
Self::FromDescendants(iter) => iter.next_back(),
Self::Explicit { ids, tree_state } => ids
.next_back()
.map(|id| tree_state.node_by_id(*id).unwrap()),
}
}
}
impl<Filter: Fn(&Node) -> FilterResult> FusedIterator for LabelledBy<'_, Filter> {}
#[cfg(test)]
mod tests {
use crate::tests::*;
use accesskit::NodeId;
use alloc::vec::Vec;
#[test]
fn following_siblings() {
let tree = test_tree();
assert!(tree.state().root().following_siblings().next().is_none());
assert_eq!(0, tree.state().root().following_siblings().len());
assert_eq!(
[
PARAGRAPH_1_IGNORED_ID,
PARAGRAPH_2_ID,
PARAGRAPH_3_IGNORED_ID
],
tree.state()
.node_by_id(PARAGRAPH_0_ID)
.unwrap()
.following_siblings()
.map(|node| node.id())
.collect::<Vec<NodeId>>()[..]
);
assert_eq!(
3,
tree.state()
.node_by_id(PARAGRAPH_0_ID)
.unwrap()
.following_siblings()
.len()
);
assert!(tree
.state()
.node_by_id(PARAGRAPH_3_IGNORED_ID)
.unwrap()
.following_siblings()
.next()
.is_none());
assert_eq!(
0,
tree.state()
.node_by_id(PARAGRAPH_3_IGNORED_ID)
.unwrap()
.following_siblings()
.len()
);
}
#[test]
fn following_siblings_reversed() {
let tree = test_tree();
assert!(tree
.state()
.root()
.following_siblings()
.next_back()
.is_none());
assert_eq!(
[
PARAGRAPH_3_IGNORED_ID,
PARAGRAPH_2_ID,
PARAGRAPH_1_IGNORED_ID
],
tree.state()
.node_by_id(PARAGRAPH_0_ID)
.unwrap()
.following_siblings()
.rev()
.map(|node| node.id())
.collect::<Vec<NodeId>>()[..]
);
assert!(tree
.state()
.node_by_id(PARAGRAPH_3_IGNORED_ID)
.unwrap()
.following_siblings()
.next_back()
.is_none());
}
#[test]
fn preceding_siblings() {
let tree = test_tree();
assert!(tree.state().root().preceding_siblings().next().is_none());
assert_eq!(0, tree.state().root().preceding_siblings().len());
assert_eq!(
[PARAGRAPH_2_ID, PARAGRAPH_1_IGNORED_ID, PARAGRAPH_0_ID],
tree.state()
.node_by_id(PARAGRAPH_3_IGNORED_ID)
.unwrap()
.preceding_siblings()
.map(|node| node.id())
.collect::<Vec<NodeId>>()[..]
);
assert_eq!(
3,
tree.state()
.node_by_id(PARAGRAPH_3_IGNORED_ID)
.unwrap()
.preceding_siblings()
.len()
);
assert!(tree
.state()
.node_by_id(PARAGRAPH_0_ID)
.unwrap()
.preceding_siblings()
.next()
.is_none());
assert_eq!(
0,
tree.state()
.node_by_id(PARAGRAPH_0_ID)
.unwrap()
.preceding_siblings()
.len()
);
}
#[test]
fn preceding_siblings_reversed() {
let tree = test_tree();
assert!(tree
.state()
.root()
.preceding_siblings()
.next_back()
.is_none());
assert_eq!(
[PARAGRAPH_0_ID, PARAGRAPH_1_IGNORED_ID, PARAGRAPH_2_ID],
tree.state()
.node_by_id(PARAGRAPH_3_IGNORED_ID)
.unwrap()
.preceding_siblings()
.rev()
.map(|node| node.id())
.collect::<Vec<NodeId>>()[..]
);
assert!(tree
.state()
.node_by_id(PARAGRAPH_0_ID)
.unwrap()
.preceding_siblings()
.next_back()
.is_none());
}
#[test]
fn following_filtered_siblings() {
let tree = test_tree();
assert!(tree
.state()
.root()
.following_filtered_siblings(test_tree_filter)
.next()
.is_none());
assert_eq!(
[LABEL_1_1_ID, PARAGRAPH_2_ID, LABEL_3_1_0_ID, BUTTON_3_2_ID],
tree.state()
.node_by_id(PARAGRAPH_0_ID)
.unwrap()
.following_filtered_siblings(test_tree_filter)
.map(|node| node.id())
.collect::<Vec<NodeId>>()[..]
);
assert_eq!(
[BUTTON_3_2_ID],
tree.state()
.node_by_id(LABEL_3_1_0_ID)
.unwrap()
.following_filtered_siblings(test_tree_filter)
.map(|node| node.id())
.collect::<Vec<NodeId>>()[..]
);
assert!(tree
.state()
.node_by_id(PARAGRAPH_3_IGNORED_ID)
.unwrap()
.following_filtered_siblings(test_tree_filter)
.next()
.is_none());
}
#[test]
fn following_filtered_siblings_reversed() {
let tree = test_tree();
assert!(tree
.state()
.root()
.following_filtered_siblings(test_tree_filter)
.next_back()
.is_none());
assert_eq!(
[BUTTON_3_2_ID, LABEL_3_1_0_ID, PARAGRAPH_2_ID, LABEL_1_1_ID],
tree.state()
.node_by_id(PARAGRAPH_0_ID)
.unwrap()
.following_filtered_siblings(test_tree_filter)
.rev()
.map(|node| node.id())
.collect::<Vec<NodeId>>()[..]
);
assert_eq!(
[BUTTON_3_2_ID,],
tree.state()
.node_by_id(LABEL_3_1_0_ID)
.unwrap()
.following_filtered_siblings(test_tree_filter)
.rev()
.map(|node| node.id())
.collect::<Vec<NodeId>>()[..]
);
assert!(tree
.state()
.node_by_id(PARAGRAPH_3_IGNORED_ID)
.unwrap()
.following_filtered_siblings(test_tree_filter)
.next_back()
.is_none());
}
#[test]
fn preceding_filtered_siblings() {
let tree = test_tree();
assert!(tree
.state()
.root()
.preceding_filtered_siblings(test_tree_filter)
.next()
.is_none());
assert_eq!(
[PARAGRAPH_2_ID, LABEL_1_1_ID, PARAGRAPH_0_ID],
tree.state()
.node_by_id(PARAGRAPH_3_IGNORED_ID)
.unwrap()
.preceding_filtered_siblings(test_tree_filter)
.map(|node| node.id())
.collect::<Vec<NodeId>>()[..]
);
assert_eq!(
[PARAGRAPH_2_ID, LABEL_1_1_ID, PARAGRAPH_0_ID],
tree.state()
.node_by_id(LABEL_3_1_0_ID)
.unwrap()
.preceding_filtered_siblings(test_tree_filter)
.map(|node| node.id())
.collect::<Vec<NodeId>>()[..]
);
assert!(tree
.state()
.node_by_id(PARAGRAPH_0_ID)
.unwrap()
.preceding_filtered_siblings(test_tree_filter)
.next()
.is_none());
}
#[test]
fn preceding_filtered_siblings_reversed() {
let tree = test_tree();
assert!(tree
.state()
.root()
.preceding_filtered_siblings(test_tree_filter)
.next_back()
.is_none());
assert_eq!(
[PARAGRAPH_0_ID, LABEL_1_1_ID, PARAGRAPH_2_ID],
tree.state()
.node_by_id(PARAGRAPH_3_IGNORED_ID)
.unwrap()
.preceding_filtered_siblings(test_tree_filter)
.rev()
.map(|node| node.id())
.collect::<Vec<NodeId>>()[..]
);
assert_eq!(
[PARAGRAPH_0_ID, LABEL_1_1_ID, PARAGRAPH_2_ID],
tree.state()
.node_by_id(LABEL_3_1_0_ID)
.unwrap()
.preceding_filtered_siblings(test_tree_filter)
.rev()
.map(|node| node.id())
.collect::<Vec<NodeId>>()[..]
);
assert!(tree
.state()
.node_by_id(PARAGRAPH_0_ID)
.unwrap()
.preceding_filtered_siblings(test_tree_filter)
.next_back()
.is_none());
}
#[test]
fn filtered_children() {
let tree = test_tree();
assert_eq!(
[
PARAGRAPH_0_ID,
LABEL_1_1_ID,
PARAGRAPH_2_ID,
LABEL_3_1_0_ID,
BUTTON_3_2_ID
],
tree.state()
.root()
.filtered_children(test_tree_filter)
.map(|node| node.id())
.collect::<Vec<NodeId>>()[..]
);
assert!(tree
.state()
.node_by_id(PARAGRAPH_0_ID)
.unwrap()
.filtered_children(test_tree_filter)
.next()
.is_none());
assert!(tree
.state()
.node_by_id(LABEL_0_0_IGNORED_ID)
.unwrap()
.filtered_children(test_tree_filter)
.next()
.is_none());
}
#[test]
fn filtered_children_reversed() {
let tree = test_tree();
assert_eq!(
[
BUTTON_3_2_ID,
LABEL_3_1_0_ID,
PARAGRAPH_2_ID,
LABEL_1_1_ID,
PARAGRAPH_0_ID
],
tree.state()
.root()
.filtered_children(test_tree_filter)
.rev()
.map(|node| node.id())
.collect::<Vec<NodeId>>()[..]
);
assert!(tree
.state()
.node_by_id(PARAGRAPH_0_ID)
.unwrap()
.filtered_children(test_tree_filter)
.next_back()
.is_none());
assert!(tree
.state()
.node_by_id(LABEL_0_0_IGNORED_ID)
.unwrap()
.filtered_children(test_tree_filter)
.next_back()
.is_none());
}
}

204
vendor/accesskit_consumer/src/lib.rs vendored Normal file
View File

@@ -0,0 +1,204 @@
// Copyright 2021 The AccessKit Authors. All rights reserved.
// Licensed under the Apache License, Version 2.0 (found in
// the LICENSE-APACHE file) or the MIT license (found in
// the LICENSE-MIT file), at your option.
#![no_std]
extern crate alloc;
pub(crate) mod tree;
pub use tree::{ChangeHandler as TreeChangeHandler, State as TreeState, Tree};
pub(crate) mod node;
pub use node::Node;
pub(crate) mod filters;
pub use filters::{common_filter, common_filter_with_root_exception, FilterResult};
pub(crate) mod iterators;
pub(crate) mod text;
pub use text::{
AttributeValue as TextAttributeValue, Position as TextPosition, Range as TextRange,
WeakRange as WeakTextRange,
};
#[cfg(test)]
mod tests {
use accesskit::{Affine, Node, NodeId, Rect, Role, Tree, TreeUpdate, Vec2};
use alloc::vec;
use crate::FilterResult;
pub const ROOT_ID: NodeId = NodeId(0);
pub const PARAGRAPH_0_ID: NodeId = NodeId(1);
pub const LABEL_0_0_IGNORED_ID: NodeId = NodeId(2);
pub const PARAGRAPH_1_IGNORED_ID: NodeId = NodeId(3);
pub const BUTTON_1_0_HIDDEN_ID: NodeId = NodeId(4);
pub const CONTAINER_1_0_0_HIDDEN_ID: NodeId = NodeId(5);
pub const LABEL_1_1_ID: NodeId = NodeId(6);
pub const BUTTON_1_2_HIDDEN_ID: NodeId = NodeId(7);
pub const CONTAINER_1_2_0_HIDDEN_ID: NodeId = NodeId(8);
pub const PARAGRAPH_2_ID: NodeId = NodeId(9);
pub const LABEL_2_0_ID: NodeId = NodeId(10);
pub const PARAGRAPH_3_IGNORED_ID: NodeId = NodeId(11);
pub const EMPTY_CONTAINER_3_0_IGNORED_ID: NodeId = NodeId(12);
pub const LINK_3_1_IGNORED_ID: NodeId = NodeId(13);
pub const LABEL_3_1_0_ID: NodeId = NodeId(14);
pub const BUTTON_3_2_ID: NodeId = NodeId(15);
pub const EMPTY_CONTAINER_3_3_IGNORED_ID: NodeId = NodeId(16);
pub fn test_tree() -> crate::tree::Tree {
let root = {
let mut node = Node::new(Role::RootWebArea);
node.set_children(vec![
PARAGRAPH_0_ID,
PARAGRAPH_1_IGNORED_ID,
PARAGRAPH_2_ID,
PARAGRAPH_3_IGNORED_ID,
]);
node
};
let paragraph_0 = {
let mut node = Node::new(Role::Paragraph);
node.set_children(vec![LABEL_0_0_IGNORED_ID]);
node
};
let label_0_0_ignored = {
let mut node = Node::new(Role::Label);
node.set_value("label_0_0_ignored");
node
};
let paragraph_1_ignored = {
let mut node = Node::new(Role::Paragraph);
node.set_transform(Affine::translate(Vec2::new(10.0, 40.0)));
node.set_bounds(Rect {
x0: 0.0,
y0: 0.0,
x1: 800.0,
y1: 40.0,
});
node.set_children(vec![
BUTTON_1_0_HIDDEN_ID,
LABEL_1_1_ID,
BUTTON_1_2_HIDDEN_ID,
]);
node
};
let button_1_0_hidden = {
let mut node = Node::new(Role::Button);
node.set_label("button_1_0_hidden");
node.set_hidden();
node.set_children(vec![CONTAINER_1_0_0_HIDDEN_ID]);
node
};
let container_1_0_0_hidden = {
let mut node = Node::new(Role::GenericContainer);
node.set_hidden();
node
};
let label_1_1 = {
let mut node = Node::new(Role::Label);
node.set_bounds(Rect {
x0: 10.0,
y0: 10.0,
x1: 90.0,
y1: 30.0,
});
node.set_value("label_1_1");
node
};
let button_1_2_hidden = {
let mut node = Node::new(Role::Button);
node.set_label("button_1_2_hidden");
node.set_hidden();
node.set_children(vec![CONTAINER_1_2_0_HIDDEN_ID]);
node
};
let container_1_2_0_hidden = {
let mut node = Node::new(Role::GenericContainer);
node.set_hidden();
node
};
let paragraph_2 = {
let mut node = Node::new(Role::Paragraph);
node.set_children(vec![LABEL_2_0_ID]);
node
};
let label_2_0 = {
let mut node = Node::new(Role::Label);
node.set_label("label_2_0");
node
};
let paragraph_3_ignored = {
let mut node = Node::new(Role::Paragraph);
node.set_children(vec![
EMPTY_CONTAINER_3_0_IGNORED_ID,
LINK_3_1_IGNORED_ID,
BUTTON_3_2_ID,
EMPTY_CONTAINER_3_3_IGNORED_ID,
]);
node
};
let empty_container_3_0_ignored = Node::new(Role::GenericContainer);
let link_3_1_ignored = {
let mut node = Node::new(Role::Link);
node.set_children(vec![LABEL_3_1_0_ID]);
node.set_linked();
node
};
let label_3_1_0 = {
let mut node = Node::new(Role::Label);
node.set_value("label_3_1_0");
node
};
let button_3_2 = {
let mut node = Node::new(Role::Button);
node.set_label("button_3_2");
node
};
let empty_container_3_3_ignored = Node::new(Role::GenericContainer);
let initial_update = TreeUpdate {
nodes: vec![
(ROOT_ID, root),
(PARAGRAPH_0_ID, paragraph_0),
(LABEL_0_0_IGNORED_ID, label_0_0_ignored),
(PARAGRAPH_1_IGNORED_ID, paragraph_1_ignored),
(BUTTON_1_0_HIDDEN_ID, button_1_0_hidden),
(CONTAINER_1_0_0_HIDDEN_ID, container_1_0_0_hidden),
(LABEL_1_1_ID, label_1_1),
(BUTTON_1_2_HIDDEN_ID, button_1_2_hidden),
(CONTAINER_1_2_0_HIDDEN_ID, container_1_2_0_hidden),
(PARAGRAPH_2_ID, paragraph_2),
(LABEL_2_0_ID, label_2_0),
(PARAGRAPH_3_IGNORED_ID, paragraph_3_ignored),
(EMPTY_CONTAINER_3_0_IGNORED_ID, empty_container_3_0_ignored),
(LINK_3_1_IGNORED_ID, link_3_1_ignored),
(LABEL_3_1_0_ID, label_3_1_0),
(BUTTON_3_2_ID, button_3_2),
(EMPTY_CONTAINER_3_3_IGNORED_ID, empty_container_3_3_ignored),
],
tree: Some(Tree::new(ROOT_ID)),
focus: ROOT_ID,
};
crate::tree::Tree::new(initial_update, false)
}
pub fn test_tree_filter(node: &crate::Node) -> FilterResult {
let id = node.id();
if node.is_hidden() {
FilterResult::ExcludeSubtree
} else if id == LABEL_0_0_IGNORED_ID
|| id == PARAGRAPH_1_IGNORED_ID
|| id == PARAGRAPH_3_IGNORED_ID
|| id == EMPTY_CONTAINER_3_0_IGNORED_ID
|| id == LINK_3_1_IGNORED_ID
|| id == EMPTY_CONTAINER_3_3_IGNORED_ID
{
FilterResult::ExcludeNode
} else {
FilterResult::Include
}
}
}

1319
vendor/accesskit_consumer/src/node.rs vendored Normal file

File diff suppressed because it is too large Load Diff

2065
vendor/accesskit_consumer/src/text.rs vendored Normal file

File diff suppressed because it is too large Load Diff

759
vendor/accesskit_consumer/src/tree.rs vendored Normal file
View File

@@ -0,0 +1,759 @@
// Copyright 2021 The AccessKit Authors. All rights reserved.
// Licensed under the Apache License, Version 2.0 (found in
// the LICENSE-APACHE file) or the MIT license (found in
// the LICENSE-MIT file), at your option.
use accesskit::{FrozenNode as NodeData, NodeId, Tree as TreeData, TreeUpdate};
use alloc::{sync::Arc, vec};
use core::fmt;
use hashbrown::{HashMap, HashSet};
use immutable_chunkmap::map::MapM as ChunkMap;
use crate::node::{Node, NodeState, ParentAndIndex};
#[derive(Clone, Debug)]
pub struct State {
pub(crate) nodes: ChunkMap<NodeId, NodeState>,
pub(crate) data: TreeData,
pub(crate) focus: NodeId,
is_host_focused: bool,
}
#[derive(Default)]
struct InternalChanges {
added_node_ids: HashSet<NodeId>,
updated_node_ids: HashSet<NodeId>,
removed_node_ids: HashSet<NodeId>,
}
impl State {
fn validate_global(&self) {
if self.nodes.get_key(&self.data.root).is_none() {
panic!("Root id #{} is not in the node list", self.data.root.0);
}
if self.nodes.get_key(&self.focus).is_none() {
panic!("Focused id #{} is not in the node list", self.focus.0);
}
}
fn update(
&mut self,
update: TreeUpdate,
is_host_focused: bool,
mut changes: Option<&mut InternalChanges>,
) {
let mut unreachable = HashSet::new();
if let Some(tree) = update.tree {
if tree.root != self.data.root {
unreachable.insert(self.data.root);
}
self.data = tree;
}
let root = self.data.root;
let mut pending_nodes: HashMap<NodeId, _> = HashMap::new();
let mut pending_children = HashMap::new();
fn add_node(
nodes: &mut ChunkMap<NodeId, NodeState>,
changes: &mut Option<&mut InternalChanges>,
parent_and_index: Option<ParentAndIndex>,
id: NodeId,
data: NodeData,
) {
let state = NodeState {
parent_and_index,
data: Arc::new(data),
};
nodes.insert_cow(id, state);
if let Some(changes) = changes {
changes.added_node_ids.insert(id);
}
}
for (node_id, node_data) in update.nodes {
let node_data = NodeData::from(node_data);
unreachable.remove(&node_id);
let mut seen_child_ids = HashSet::with_capacity(node_data.children().len());
for (child_index, child_id) in node_data.children().iter().enumerate() {
if seen_child_ids.contains(child_id) {
panic!(
"Node #{} of TreeUpdate includes duplicate child #{};",
node_id.0, child_id.0
);
}
unreachable.remove(child_id);
let parent_and_index = ParentAndIndex(node_id, child_index);
if let Some(child_state) = self.nodes.get_mut_cow(child_id) {
if child_state.parent_and_index != Some(parent_and_index) {
child_state.parent_and_index = Some(parent_and_index);
}
} else if let Some(child_data) = pending_nodes.remove(child_id) {
add_node(
&mut self.nodes,
&mut changes,
Some(parent_and_index),
*child_id,
child_data,
);
} else {
pending_children.insert(*child_id, parent_and_index);
}
seen_child_ids.insert(*child_id);
}
if let Some(node_state) = self.nodes.get_mut_cow(&node_id) {
if node_id == root {
node_state.parent_and_index = None;
}
for child_id in node_state.data.children().iter() {
if !seen_child_ids.contains(child_id) {
unreachable.insert(*child_id);
}
}
if *node_state.data != node_data {
node_state.data = Arc::new(node_data);
if let Some(changes) = &mut changes {
changes.updated_node_ids.insert(node_id);
}
}
} else if let Some(parent_and_index) = pending_children.remove(&node_id) {
add_node(
&mut self.nodes,
&mut changes,
Some(parent_and_index),
node_id,
node_data,
);
} else if node_id == root {
add_node(&mut self.nodes, &mut changes, None, node_id, node_data);
} else {
pending_nodes.insert(node_id, node_data);
}
}
if !pending_nodes.is_empty() {
panic!("TreeUpdate includes {} nodes which are neither in the current tree nor a child of another node from the update: {}", pending_nodes.len(), ShortNodeList(&pending_nodes));
}
if !pending_children.is_empty() {
panic!("TreeUpdate's nodes include {} children ids which are neither in the current tree nor the id of another node from the update: {}", pending_children.len(), ShortNodeList(&pending_children));
}
self.focus = update.focus;
self.is_host_focused = is_host_focused;
if !unreachable.is_empty() {
fn traverse_unreachable(
nodes: &mut ChunkMap<NodeId, NodeState>,
changes: &mut Option<&mut InternalChanges>,
id: NodeId,
) {
if let Some(changes) = changes {
changes.removed_node_ids.insert(id);
}
let node = nodes.remove_cow(&id).unwrap();
for child_id in node.data.children().iter() {
traverse_unreachable(nodes, changes, *child_id);
}
}
for id in unreachable {
traverse_unreachable(&mut self.nodes, &mut changes, id);
}
}
self.validate_global();
}
fn update_host_focus_state(
&mut self,
is_host_focused: bool,
changes: Option<&mut InternalChanges>,
) {
let update = TreeUpdate {
nodes: vec![],
tree: None,
focus: self.focus,
};
self.update(update, is_host_focused, changes);
}
pub fn has_node(&self, id: NodeId) -> bool {
self.nodes.get(&id).is_some()
}
pub fn node_by_id(&self, id: NodeId) -> Option<Node<'_>> {
self.nodes.get(&id).map(|node_state| Node {
tree_state: self,
id,
state: node_state,
})
}
pub fn root_id(&self) -> NodeId {
self.data.root
}
pub fn root(&self) -> Node<'_> {
self.node_by_id(self.root_id()).unwrap()
}
pub fn is_host_focused(&self) -> bool {
self.is_host_focused
}
pub fn focus_id_in_tree(&self) -> NodeId {
self.focus
}
pub fn focus_in_tree(&self) -> Node<'_> {
self.node_by_id(self.focus_id_in_tree()).unwrap()
}
pub fn focus_id(&self) -> Option<NodeId> {
self.is_host_focused.then_some(self.focus)
}
pub fn focus(&self) -> Option<Node<'_>> {
self.focus_id().map(|id| self.node_by_id(id).unwrap())
}
pub fn toolkit_name(&self) -> Option<&str> {
self.data.toolkit_name.as_deref()
}
pub fn toolkit_version(&self) -> Option<&str> {
self.data.toolkit_version.as_deref()
}
}
pub trait ChangeHandler {
fn node_added(&mut self, node: &Node);
fn node_updated(&mut self, old_node: &Node, new_node: &Node);
fn focus_moved(&mut self, old_node: Option<&Node>, new_node: Option<&Node>);
fn node_removed(&mut self, node: &Node);
}
#[derive(Debug)]
pub struct Tree {
state: State,
}
impl Tree {
pub fn new(mut initial_state: TreeUpdate, is_host_focused: bool) -> Self {
let Some(tree) = initial_state.tree.take() else {
panic!("Tried to initialize the accessibility tree without a root tree. TreeUpdate::tree must be Some.");
};
let mut state = State {
nodes: ChunkMap::new(),
data: tree,
focus: initial_state.focus,
is_host_focused,
};
state.update(initial_state, is_host_focused, None);
Self { state }
}
pub fn update(&mut self, update: TreeUpdate) {
self.state.update(update, self.state.is_host_focused, None);
}
pub fn update_and_process_changes(
&mut self,
update: TreeUpdate,
handler: &mut impl ChangeHandler,
) {
let mut changes = InternalChanges::default();
let old_state = self.state.clone();
self.state
.update(update, self.state.is_host_focused, Some(&mut changes));
self.process_changes(old_state, changes, handler);
}
pub fn update_host_focus_state(&mut self, is_host_focused: bool) {
self.state.update_host_focus_state(is_host_focused, None);
}
pub fn update_host_focus_state_and_process_changes(
&mut self,
is_host_focused: bool,
handler: &mut impl ChangeHandler,
) {
let mut changes = InternalChanges::default();
let old_state = self.state.clone();
self.state
.update_host_focus_state(is_host_focused, Some(&mut changes));
self.process_changes(old_state, changes, handler);
}
fn process_changes(
&self,
old_state: State,
changes: InternalChanges,
handler: &mut impl ChangeHandler,
) {
for id in &changes.added_node_ids {
let node = self.state.node_by_id(*id).unwrap();
handler.node_added(&node);
}
for id in &changes.updated_node_ids {
let old_node = old_state.node_by_id(*id).unwrap();
let new_node = self.state.node_by_id(*id).unwrap();
handler.node_updated(&old_node, &new_node);
}
if old_state.focus_id() != self.state.focus_id() {
let old_node = old_state.focus();
if let Some(old_node) = &old_node {
let id = old_node.id();
if !changes.updated_node_ids.contains(&id)
&& !changes.removed_node_ids.contains(&id)
{
if let Some(old_node_new_version) = self.state.node_by_id(id) {
handler.node_updated(old_node, &old_node_new_version);
}
}
}
let new_node = self.state.focus();
if let Some(new_node) = &new_node {
let id = new_node.id();
if !changes.added_node_ids.contains(&id) && !changes.updated_node_ids.contains(&id)
{
if let Some(new_node_old_version) = old_state.node_by_id(id) {
handler.node_updated(&new_node_old_version, new_node);
}
}
}
handler.focus_moved(old_node.as_ref(), new_node.as_ref());
}
for id in &changes.removed_node_ids {
let node = old_state.node_by_id(*id).unwrap();
handler.node_removed(&node);
}
}
pub fn state(&self) -> &State {
&self.state
}
}
struct ShortNodeList<'a, T>(&'a HashMap<NodeId, T>);
impl<T> fmt::Display for ShortNodeList<'_, T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "[")?;
let mut iter = self.0.iter();
for i in 0..10 {
let Some((id, _)) = iter.next() else {
break;
};
if i != 0 {
write!(f, ", ")?;
}
write!(f, "#{}", id.0)?;
}
if iter.next().is_some() {
write!(f, " ...")?;
}
write!(f, "]")
}
}
#[cfg(test)]
mod tests {
use accesskit::{Node, NodeId, Role, Tree, TreeUpdate};
use alloc::vec;
#[test]
fn init_tree_with_root_node() {
let update = TreeUpdate {
nodes: vec![(NodeId(0), Node::new(Role::Window))],
tree: Some(Tree::new(NodeId(0))),
focus: NodeId(0),
};
let tree = super::Tree::new(update, false);
assert_eq!(NodeId(0), tree.state().root().id());
assert_eq!(Role::Window, tree.state().root().role());
assert!(tree.state().root().parent().is_none());
}
#[test]
fn root_node_has_children() {
let update = TreeUpdate {
nodes: vec![
(NodeId(0), {
let mut node = Node::new(Role::Window);
node.set_children(vec![NodeId(1), NodeId(2)]);
node
}),
(NodeId(1), Node::new(Role::Button)),
(NodeId(2), Node::new(Role::Button)),
],
tree: Some(Tree::new(NodeId(0))),
focus: NodeId(0),
};
let tree = super::Tree::new(update, false);
let state = tree.state();
assert_eq!(
NodeId(0),
state.node_by_id(NodeId(1)).unwrap().parent().unwrap().id()
);
assert_eq!(
NodeId(0),
state.node_by_id(NodeId(2)).unwrap().parent().unwrap().id()
);
assert_eq!(2, state.root().children().count());
}
#[test]
fn add_child_to_root_node() {
let root_node = Node::new(Role::Window);
let first_update = TreeUpdate {
nodes: vec![(NodeId(0), root_node.clone())],
tree: Some(Tree::new(NodeId(0))),
focus: NodeId(0),
};
let mut tree = super::Tree::new(first_update, false);
assert_eq!(0, tree.state().root().children().count());
let second_update = TreeUpdate {
nodes: vec![
(NodeId(0), {
let mut node = root_node;
node.push_child(NodeId(1));
node
}),
(NodeId(1), Node::new(Role::RootWebArea)),
],
tree: None,
focus: NodeId(0),
};
struct Handler {
got_new_child_node: bool,
got_updated_root_node: bool,
}
fn unexpected_change() {
panic!("expected only new child node and updated root node");
}
impl super::ChangeHandler for Handler {
fn node_added(&mut self, node: &crate::Node) {
if node.id() == NodeId(1) {
self.got_new_child_node = true;
return;
}
unexpected_change();
}
fn node_updated(&mut self, old_node: &crate::Node, new_node: &crate::Node) {
if new_node.id() == NodeId(0)
&& old_node.data().children().is_empty()
&& new_node.data().children() == [NodeId(1)]
{
self.got_updated_root_node = true;
return;
}
unexpected_change();
}
fn focus_moved(
&mut self,
_old_node: Option<&crate::Node>,
_new_node: Option<&crate::Node>,
) {
unexpected_change();
}
fn node_removed(&mut self, _node: &crate::Node) {
unexpected_change();
}
}
let mut handler = Handler {
got_new_child_node: false,
got_updated_root_node: false,
};
tree.update_and_process_changes(second_update, &mut handler);
assert!(handler.got_new_child_node);
assert!(handler.got_updated_root_node);
let state = tree.state();
assert_eq!(1, state.root().children().count());
assert_eq!(NodeId(1), state.root().children().next().unwrap().id());
assert_eq!(
NodeId(0),
state.node_by_id(NodeId(1)).unwrap().parent().unwrap().id()
);
}
#[test]
fn remove_child_from_root_node() {
let root_node = Node::new(Role::Window);
let first_update = TreeUpdate {
nodes: vec![
(NodeId(0), {
let mut node = root_node.clone();
node.push_child(NodeId(1));
node
}),
(NodeId(1), Node::new(Role::RootWebArea)),
],
tree: Some(Tree::new(NodeId(0))),
focus: NodeId(0),
};
let mut tree = super::Tree::new(first_update, false);
assert_eq!(1, tree.state().root().children().count());
let second_update = TreeUpdate {
nodes: vec![(NodeId(0), root_node)],
tree: None,
focus: NodeId(0),
};
struct Handler {
got_updated_root_node: bool,
got_removed_child_node: bool,
}
fn unexpected_change() {
panic!("expected only removed child node and updated root node");
}
impl super::ChangeHandler for Handler {
fn node_added(&mut self, _node: &crate::Node) {
unexpected_change();
}
fn node_updated(&mut self, old_node: &crate::Node, new_node: &crate::Node) {
if new_node.id() == NodeId(0)
&& old_node.data().children() == [NodeId(1)]
&& new_node.data().children().is_empty()
{
self.got_updated_root_node = true;
return;
}
unexpected_change();
}
fn focus_moved(
&mut self,
_old_node: Option<&crate::Node>,
_new_node: Option<&crate::Node>,
) {
unexpected_change();
}
fn node_removed(&mut self, node: &crate::Node) {
if node.id() == NodeId(1) {
self.got_removed_child_node = true;
return;
}
unexpected_change();
}
}
let mut handler = Handler {
got_updated_root_node: false,
got_removed_child_node: false,
};
tree.update_and_process_changes(second_update, &mut handler);
assert!(handler.got_updated_root_node);
assert!(handler.got_removed_child_node);
assert_eq!(0, tree.state().root().children().count());
assert!(tree.state().node_by_id(NodeId(1)).is_none());
}
#[test]
fn move_focus_between_siblings() {
let first_update = TreeUpdate {
nodes: vec![
(NodeId(0), {
let mut node = Node::new(Role::Window);
node.set_children(vec![NodeId(1), NodeId(2)]);
node
}),
(NodeId(1), Node::new(Role::Button)),
(NodeId(2), Node::new(Role::Button)),
],
tree: Some(Tree::new(NodeId(0))),
focus: NodeId(1),
};
let mut tree = super::Tree::new(first_update, true);
assert!(tree.state().node_by_id(NodeId(1)).unwrap().is_focused());
let second_update = TreeUpdate {
nodes: vec![],
tree: None,
focus: NodeId(2),
};
struct Handler {
got_old_focus_node_update: bool,
got_new_focus_node_update: bool,
got_focus_change: bool,
}
fn unexpected_change() {
panic!("expected only focus change");
}
impl super::ChangeHandler for Handler {
fn node_added(&mut self, _node: &crate::Node) {
unexpected_change();
}
fn node_updated(&mut self, old_node: &crate::Node, new_node: &crate::Node) {
if old_node.id() == NodeId(1)
&& new_node.id() == NodeId(1)
&& old_node.is_focused()
&& !new_node.is_focused()
{
self.got_old_focus_node_update = true;
return;
}
if old_node.id() == NodeId(2)
&& new_node.id() == NodeId(2)
&& !old_node.is_focused()
&& new_node.is_focused()
{
self.got_new_focus_node_update = true;
return;
}
unexpected_change();
}
fn focus_moved(
&mut self,
old_node: Option<&crate::Node>,
new_node: Option<&crate::Node>,
) {
if let (Some(old_node), Some(new_node)) = (old_node, new_node) {
if old_node.id() == NodeId(1) && new_node.id() == NodeId(2) {
self.got_focus_change = true;
return;
}
}
unexpected_change();
}
fn node_removed(&mut self, _node: &crate::Node) {
unexpected_change();
}
}
let mut handler = Handler {
got_old_focus_node_update: false,
got_new_focus_node_update: false,
got_focus_change: false,
};
tree.update_and_process_changes(second_update, &mut handler);
assert!(handler.got_old_focus_node_update);
assert!(handler.got_new_focus_node_update);
assert!(handler.got_focus_change);
assert!(tree.state().node_by_id(NodeId(2)).unwrap().is_focused());
assert!(!tree.state().node_by_id(NodeId(1)).unwrap().is_focused());
}
#[test]
fn update_node() {
let child_node = Node::new(Role::Button);
let first_update = TreeUpdate {
nodes: vec![
(NodeId(0), {
let mut node = Node::new(Role::Window);
node.set_children(vec![NodeId(1)]);
node
}),
(NodeId(1), {
let mut node = child_node.clone();
node.set_label("foo");
node
}),
],
tree: Some(Tree::new(NodeId(0))),
focus: NodeId(0),
};
let mut tree = super::Tree::new(first_update, false);
assert_eq!(
Some("foo".into()),
tree.state().node_by_id(NodeId(1)).unwrap().label()
);
let second_update = TreeUpdate {
nodes: vec![(NodeId(1), {
let mut node = child_node;
node.set_label("bar");
node
})],
tree: None,
focus: NodeId(0),
};
struct Handler {
got_updated_child_node: bool,
}
fn unexpected_change() {
panic!("expected only updated child node");
}
impl super::ChangeHandler for Handler {
fn node_added(&mut self, _node: &crate::Node) {
unexpected_change();
}
fn node_updated(&mut self, old_node: &crate::Node, new_node: &crate::Node) {
if new_node.id() == NodeId(1)
&& old_node.label() == Some("foo".into())
&& new_node.label() == Some("bar".into())
{
self.got_updated_child_node = true;
return;
}
unexpected_change();
}
fn focus_moved(
&mut self,
_old_node: Option<&crate::Node>,
_new_node: Option<&crate::Node>,
) {
unexpected_change();
}
fn node_removed(&mut self, _node: &crate::Node) {
unexpected_change();
}
}
let mut handler = Handler {
got_updated_child_node: false,
};
tree.update_and_process_changes(second_update, &mut handler);
assert!(handler.got_updated_child_node);
assert_eq!(
Some("bar".into()),
tree.state().node_by_id(NodeId(1)).unwrap().label()
);
}
// Verify that if an update consists entirely of node data and tree data
// that's the same as before, no changes are reported. This is useful
// for a provider that constructs a fresh tree every time, such as
// an immediate-mode GUI.
#[test]
fn no_change_update() {
let update = TreeUpdate {
nodes: vec![
(NodeId(0), {
let mut node = Node::new(Role::Window);
node.set_children(vec![NodeId(1)]);
node
}),
(NodeId(1), {
let mut node = Node::new(Role::Button);
node.set_label("foo");
node
}),
],
tree: Some(Tree::new(NodeId(0))),
focus: NodeId(0),
};
let mut tree = super::Tree::new(update.clone(), false);
struct Handler;
fn unexpected_change() {
panic!("expected no changes");
}
impl super::ChangeHandler for Handler {
fn node_added(&mut self, _node: &crate::Node) {
unexpected_change();
}
fn node_updated(&mut self, _old_node: &crate::Node, _new_node: &crate::Node) {
unexpected_change();
}
fn focus_moved(
&mut self,
_old_node: Option<&crate::Node>,
_new_node: Option<&crate::Node>,
) {
unexpected_change();
}
fn node_removed(&mut self, _node: &crate::Node) {
unexpected_change();
}
}
let mut handler = Handler {};
tree.update_and_process_changes(update, &mut handler);
}
}