4 Commits

Author SHA1 Message Date
47dc685ffb Rediff patches
Add 0003-Use-mini-as-release-profile.patch: <REASON>
Add 0001-Alter-blake3-to-emit-Built-Using-info.patch: <REASON>
Add 0002-Use-pure-Rust-implementation-of-Blake3-parts.patch: <REASON>
2025-09-28 12:58:43 -05:00
736f7ab260 Add missing build-depends 2025-09-28 12:55:15 -05:00
2d5830d3bc Begin package for Debian Trixie 2025-09-28 12:46:23 -05:00
82ab7f317b Vendor dependencies for 0.3.0 release 2025-09-27 20:53:56 -05:00
26813 changed files with 16135149 additions and 0 deletions

View File

@@ -1,2 +1,8 @@
[target.wasm32-unknown-unknown]
runner = "wasm-server-runner"
[source.crates-io]
replace-with = "vendored-sources"
[source.vendored-sources]
directory = "vendor"

5
debian/changelog vendored Normal file
View File

@@ -0,0 +1,5 @@
another-boids-in-rust (0.3.0-1) UNRELEASED; urgency=medium
* TODO: Regenerate the changelog from Git history
-- Robert Garrett <robertgarrett404@gmail.com> Sat, 27 Sep 2025 10:33:04 -0500

24
debian/control vendored Normal file
View File

@@ -0,0 +1,24 @@
Source: another-boids-in-rust
Maintainer: Robert Garrett <robertgarrett404@gmail.com>
Section: misc
Priority: optional
Standards-Version: 4.6.2
Build-Depends:
debhelper-compat (= 13),
dh-cargo,
pkg-config,
libasound2-dev,
libudev-dev,
Homepage: https://git.gelvin.dev/robert/boids
Vcs-Git: https://git.gelvin.dev/robert/boids
Vcs-Browser: https://git.gelvin.dev/robert/boids
Rules-Requires-Root: no
Package: another-boids-in-rust
Architecture: any
Depends:
${misc:Depends},
${shlibs:Depends},
Description: Another Boids implementation in Rust.
Boids is a flocking algorithm. This one is built in Rust using the Bevy game
engine.

26
debian/copyright vendored Normal file
View File

@@ -0,0 +1,26 @@
Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
Upstream-Name: boids
Upstream-Contact: Robert Garrett <robertgarrett404@gmail.com>
Source: https://git.gelvin.dev/robert/boids
Files: *
Copyright: 2025 Robert Garrett <robertgarrett404@gmail.com>
License: GPL-3+
License: GPL-3+
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
.
It is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
License for more details.
.
You should have received a copy of the GNU General Public License
along with it. If not, see <http://www.gnu.org/licenses/>.
.
On Debian systems, the full text of the GNU General Public License version 3
can be found in the file /usr/share/common-licenses/GPL-3.

6
debian/gbp.conf vendored Normal file
View File

@@ -0,0 +1,6 @@
[DEFAULT]
compression = xz
compression-level = 9
upstream-tag = v%(version)s
debian-branch = deb/trixie

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,28 @@
From: Robert Garrett <robertgarrett404@gmail.com>
Date: Fri, 26 Sep 2025 11:02:04 -0500
Subject: Use pure Rust implementation of Blake3 parts
I can't figure out how to get Debian's build system to tell the blake3
crate what CPU features are available. It's possible the answer is that
I'm not supposed to, or that I simply do not.
Rather than figure it out, I'll just avoid the question by not using
C, C++, or assembly through the conditional compilation systems.
---
Cargo.toml | 3 +++
1 file changed, 3 insertions(+)
diff --git a/Cargo.toml b/Cargo.toml
index fe0a0c2..60dd621 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -6,6 +6,9 @@ edition = "2024"
[dependencies]
bevy = "0.16.0"
+# Use pure-Rust impl. to dodge problems with CPU feature set availability.
+blake3 = { version = "1.8.2", features = ["pure"] }
+
# Grand-dependency pins
# ab_glyph = "0.2.16"
# fnv = "1.0.6"

View File

@@ -0,0 +1,25 @@
From: Robert Garrett <robertgarrett404@gmail.com>
Date: Sat, 27 Sep 2025 22:01:16 -0500
Subject: Use "mini" as "release" profile
---
Cargo.toml | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)
diff --git a/Cargo.toml b/Cargo.toml
index 60dd621..c7bcf17 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -36,8 +36,11 @@ opt-level = 1
opt-level = 3
[profile.release]
-# codegen-units = 1
lto = "fat"
+opt-level = "z"
+codegen-units = 1
+strip = "symbols"
+panic = "abort"
[profile.mini]
inherits = "release"

3
debian/patches/series vendored Normal file
View File

@@ -0,0 +1,3 @@
0001-Alter-blake3-to-emit-Built-Using-info.patch
0002-Use-pure-Rust-implementation-of-Blake3-parts.patch
0003-Use-mini-as-release-profile.patch

27
debian/rules vendored Executable file
View File

@@ -0,0 +1,27 @@
#!/usr/bin/make -f
export DEB_BUILD_MAINT_OPTIONS = hardening=+all
DPKG_EXPORT_BUILDFLAGS = 1
include /usr/share/dpkg/default.mk
include /usr/share/rustc/architecture.mk
export DEB_HOST_RUST_TYPE
export PATH:=/usr/share/cargo/bin:$(PATH)
export CARGO=/usr/share/cargo/bin/cargo
export CARGO_HOME=$(CURDIR)/debian/cargo_home
export CARGO_REGISTRY=$(CURDIR)/debian/cargo_registry
export DEB_CARGO_CRATE=$(DEB_SOURCE)_$(DEB_VERSION_UPSTREAM)
%:
dh $@ --buildsystem=cargo
execute_after_dh_auto_clean:
$(CARGO) clean
rm -rf $(CARGO_HOME)
rm -rf $(CARGO_REGISTRY)
rm -f debian/cargo-checksum.json
execute_before_dh_auto_configure:
$(CARGO) prepare-debian $(CARGO_REGISTRY) --link-from-system
rm -f Cargo.lock
touch debian/cargo-checksum.json

1
debian/source/format vendored Normal file
View File

@@ -0,0 +1 @@
3.0 (quilt)

1
vendor/accesskit/.cargo-checksum.json vendored Normal file
View File

@@ -0,0 +1 @@
{"files":{"CHANGELOG.md":"0610bcadd91949bcc2dbd8cad91b64e70ac51232e22b14d82e3d5bc06c0ae4fe","Cargo.lock":"33801abd7926c32c171e6859bdb01d452c1370564b206d7b4061b2fefafc2c5b","Cargo.toml":"824ab03b2dd1596e36441bcdc067845f2643aa11488cb3582e8bf9160c7c6f71","README.md":"b2bb57a4bb7554d7ec0ce918ba31460d4add9f8a81ac502bc96d7b078297c3a1","src/geometry.rs":"2f2c37da6a856f1463c593bd2c01d07f237951556c3f72594cb05a2561afa7ed","src/lib.rs":"ac9f010278a4b8520093ef535cb738714c8521910b421fdefaeb4a9b67d2b186"},"package":"becf0eb5215b6ecb0a739c31c21bd83c4f326524c9b46b7e882d77559b60a529"}

372
vendor/accesskit/CHANGELOG.md vendored Normal file
View File

@@ -0,0 +1,372 @@
# Changelog
## [0.18.0](https://github.com/AccessKit/accesskit/compare/accesskit-v0.17.1...accesskit-v0.18.0) (2025-03-06)
### ⚠ BREAKING CHANGES
* Drop `Tree::app_name` ([#492](https://github.com/AccessKit/accesskit/issues/492))
### Features
* Android adapter ([#500](https://github.com/AccessKit/accesskit/issues/500)) ([7e65ac7](https://github.com/AccessKit/accesskit/commit/7e65ac77d7e108ac5b9f3722f488a2fdf2e3b3e0))
### Bug Fixes
* Update pyo3 to 0.23 ([#512](https://github.com/AccessKit/accesskit/issues/512)) ([93d3a27](https://github.com/AccessKit/accesskit/commit/93d3a27ac4af60eef4a1faf26392a6f7ff69cf81))
### Code Refactoring
* Drop `Tree::app_name` ([#492](https://github.com/AccessKit/accesskit/issues/492)) ([089794c](https://github.com/AccessKit/accesskit/commit/089794c8f74957e91a19ae3df508e2a892f39ebc))
## [0.17.1](https://github.com/AccessKit/accesskit/compare/accesskit-v0.17.0...accesskit-v0.17.1) (2024-11-23)
### Bug Fixes
* Fix some broken links in the documentation ([#484](https://github.com/AccessKit/accesskit/issues/484)) ([0a51225](https://github.com/AccessKit/accesskit/commit/0a5122561c6f6aca5cf802464220056d763040f8))
## [0.17.0](https://github.com/AccessKit/accesskit/compare/accesskit-v0.16.3...accesskit-v0.17.0) (2024-10-31)
### ⚠ BREAKING CHANGES
* Drop the `is_hovered` property ([#479](https://github.com/AccessKit/accesskit/issues/479))
* 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))
### Bug Fixes
* Drop the `is_hovered` property ([#479](https://github.com/AccessKit/accesskit/issues/479)) ([95dfdb6](https://github.com/AccessKit/accesskit/commit/95dfdb6c88f7d705f6a7283cb8524168a9f542b2))
### 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))
## [0.16.3](https://github.com/AccessKit/accesskit/compare/accesskit-v0.16.2...accesskit-v0.16.3) (2024-10-08)
### Bug Fixes
* Eliminate duplicate definitions ([#461](https://github.com/AccessKit/accesskit/issues/461)) ([59826d4](https://github.com/AccessKit/accesskit/commit/59826d4500ddfe880181f7087f9fe83ff2209fc4))
## [0.16.2](https://github.com/AccessKit/accesskit/compare/accesskit-v0.16.1...accesskit-v0.16.2) (2024-10-07)
### Bug Fixes
* Don't use a macro to generate Action debug helper function ([#459](https://github.com/AccessKit/accesskit/issues/459)) ([ed1fb73](https://github.com/AccessKit/accesskit/commit/ed1fb7370780c9dd15028cdfd13e2065642bf490))
* Update minimum supported Rust version to 1.75 ([#457](https://github.com/AccessKit/accesskit/issues/457)) ([fc622fe](https://github.com/AccessKit/accesskit/commit/fc622fe7657c80a4eedad6f6cded11d2538b54d5))
## [0.16.1](https://github.com/AccessKit/accesskit/compare/accesskit-v0.16.0...accesskit-v0.16.1) (2024-09-24)
### Bug Fixes
* Improve debug representation of `Node` and `NodeBuilder` ([#452](https://github.com/AccessKit/accesskit/issues/452)) ([119aa1d](https://github.com/AccessKit/accesskit/commit/119aa1dca8fe734112ecbd59568c876b336ccb6c))
## [0.16.0](https://github.com/AccessKit/accesskit/compare/accesskit-v0.15.0...accesskit-v0.16.0) (2024-06-29)
### ⚠ BREAKING CHANGES
* Optimize serialization and make it compatible with more data formats ([#437](https://github.com/AccessKit/accesskit/issues/437))
* Rename the `StaticText` role to `Label` ([#434](https://github.com/AccessKit/accesskit/issues/434))
### Code Refactoring
* Optimize serialization and make it compatible with more data formats ([#437](https://github.com/AccessKit/accesskit/issues/437)) ([5a80d3a](https://github.com/AccessKit/accesskit/commit/5a80d3ae46cfe85780d4900f4fa9f4feaba52053))
* Rename the `StaticText` role to `Label` ([#434](https://github.com/AccessKit/accesskit/issues/434)) ([7086bc0](https://github.com/AccessKit/accesskit/commit/7086bc0fad446d3ed4a0fd5eff641a1e75f6c599))
## [0.15.0](https://github.com/AccessKit/accesskit/compare/accesskit-v0.14.0...accesskit-v0.15.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
* Add explicit cargo features for `enumn` and `pyo3` ([#425](https://github.com/AccessKit/accesskit/issues/425)) ([71ad45b](https://github.com/AccessKit/accesskit/commit/71ad45be1651409ee6918cf835b656e6b5e0fe2d))
## [0.14.0](https://github.com/AccessKit/accesskit/compare/accesskit-v0.13.0...accesskit-v0.14.0) (2024-04-30)
### ⚠ BREAKING CHANGES
* Clean up table roles and properties ([#393](https://github.com/AccessKit/accesskit/issues/393))
* Drop `SortDirection::Unsorted` ([#391](https://github.com/AccessKit/accesskit/issues/391))
* Rename `hierarchical_level` to `level` ([#390](https://github.com/AccessKit/accesskit/issues/390))
* 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
* Add the `owns` relation ([#392](https://github.com/AccessKit/accesskit/issues/392)) ([fd668dd](https://github.com/AccessKit/accesskit/commit/fd668ddc4b64cb05ab3600972b3d3823a037f2d5))
### 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
* Clean up table roles and properties ([#393](https://github.com/AccessKit/accesskit/issues/393)) ([e34dad9](https://github.com/AccessKit/accesskit/commit/e34dad94448a5321ece9def3f2e054aa5f62dd79))
* Drop `NodeClassSet` ([#389](https://github.com/AccessKit/accesskit/issues/389)) ([1b153ed](https://github.com/AccessKit/accesskit/commit/1b153ed51f8421cdba2dc98beca2e8f5f8c781bc))
* Drop `SortDirection::Unsorted` ([#391](https://github.com/AccessKit/accesskit/issues/391)) ([b86f484](https://github.com/AccessKit/accesskit/commit/b86f484b7e6645e63362896b744a71ec758f810d))
* Rename `Checked` to `Toggled`; drop `ToggleButton` role ([#388](https://github.com/AccessKit/accesskit/issues/388)) ([6bc040b](https://github.com/AccessKit/accesskit/commit/6bc040b7cf75cdbd6a019cc380d8dbce804b3c81))
* Rename `hierarchical_level` to `level` ([#390](https://github.com/AccessKit/accesskit/issues/390)) ([2d61e01](https://github.com/AccessKit/accesskit/commit/2d61e01fffff1265b348c141715f6f9b6fe4081b))
## [0.13.0](https://github.com/AccessKit/accesskit/compare/accesskit-v0.12.3...accesskit-v0.13.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))
## [0.12.3](https://github.com/AccessKit/accesskit/compare/accesskit-v0.12.2...accesskit-v0.12.3) (2024-03-07)
### Bug Fixes
* Derive `PartialOrd` and `Ord` on `NodeId` ([#363](https://github.com/AccessKit/accesskit/issues/363)) ([ce3bba1](https://github.com/AccessKit/accesskit/commit/ce3bba1e043d650c406d8814b4f33e9104199c8b))
* Make `NodeClassSet::new` const ([#368](https://github.com/AccessKit/accesskit/issues/368)) ([11d2968](https://github.com/AccessKit/accesskit/commit/11d2968464d50c3e3f55e9a872d0d454c19e7e51))
## [0.12.2](https://github.com/AccessKit/accesskit/compare/accesskit-v0.12.1...accesskit-v0.12.2) (2024-01-03)
### Bug Fixes
* Bump pyo3; add `rename_all` attribute to enums ([#330](https://github.com/AccessKit/accesskit/issues/330)) ([5a4c6f3](https://github.com/AccessKit/accesskit/commit/5a4c6f399837d67b066451a8fb4d43d03c8acb8b))
* Document the `role_description` node property ([#331](https://github.com/AccessKit/accesskit/issues/331)) ([936fa2c](https://github.com/AccessKit/accesskit/commit/936fa2c23190c5d7cd4eb880612295785a009721))
## [0.12.1](https://github.com/AccessKit/accesskit/compare/accesskit-v0.12.0...accesskit-v0.12.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))
## [0.12.0](https://github.com/AccessKit/accesskit/compare/accesskit-v0.11.2...accesskit-v0.12.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))
* Make `ActionHandler::do_action` take `&mut self` ([#296](https://github.com/AccessKit/accesskit/issues/296))
* Clean up roles and properties ([#289](https://github.com/AccessKit/accesskit/issues/289))
* Drop next/previous focus properties ([#288](https://github.com/AccessKit/accesskit/issues/288))
* 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))
* Drop next/previous focus properties ([#288](https://github.com/AccessKit/accesskit/issues/288)) ([d35c7c1](https://github.com/AccessKit/accesskit/commit/d35c7c149a650dfedf1b031c0668adad585659fa))
* Support the pyo3 crate in all public enums ([#270](https://github.com/AccessKit/accesskit/issues/270)) ([9b12d0c](https://github.com/AccessKit/accesskit/commit/9b12d0c3d828d4c847510b611d891872c4666984))
### 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))
* Make `ActionHandler::do_action` take `&mut self` ([#296](https://github.com/AccessKit/accesskit/issues/296)) ([4fc7846](https://github.com/AccessKit/accesskit/commit/4fc7846d732d61fb45c023060ebab96801a0053e))
* 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))
## [0.11.2](https://github.com/AccessKit/accesskit/compare/accesskit-v0.11.1...accesskit-v0.11.2) (2023-08-08)
### Bug Fixes
* Support the enumn crate in all public enums ([#264](https://github.com/AccessKit/accesskit/issues/264)) ([b9b3cd1](https://github.com/AccessKit/accesskit/commit/b9b3cd18fccdd6526fb4f58c13eb91599452a3d6))
## [0.11.1](https://github.com/AccessKit/accesskit/compare/accesskit-v0.11.0...accesskit-v0.11.1) (2023-07-30)
### Bug Fixes
* Fix broken intra-doc-link. ([#262](https://github.com/AccessKit/accesskit/issues/262)) ([63c1715](https://github.com/AccessKit/accesskit/commit/63c17152d1eb8ae6ff19c2bc4a6756372bc490c2))
## [0.11.0](https://github.com/AccessKit/accesskit/compare/accesskit-v0.10.1...accesskit-v0.11.0) (2023-03-29)
### Features
* Add C bindings ([#230](https://github.com/AccessKit/accesskit/issues/230)) ([7f7f4c7](https://github.com/AccessKit/accesskit/commit/7f7f4c755890ab8210a5a8bf8e237ba6a51dd205))
## [0.10.1](https://github.com/AccessKit/accesskit/compare/accesskit-v0.10.0...accesskit-v0.10.1) (2023-02-20)
### Bug Fixes
* Set appropriate representations on all public types that will be exposed via FFI ([54e82f6](https://github.com/AccessKit/accesskit/commit/54e82f673f5c7b46d9077fe5f946305800862bf0))
## [0.10.0](https://github.com/AccessKit/accesskit/compare/accesskit-v0.9.0...accesskit-v0.10.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))
## [0.9.0](https://github.com/AccessKit/accesskit/compare/accesskit-v0.8.1...accesskit-v0.9.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))
## [0.8.1](https://github.com/AccessKit/accesskit/compare/accesskit-v0.8.0...accesskit-v0.8.1) (2022-12-04)
### Documentation
* Fix outdated documentation for `TreeUpdate` ([#182](https://github.com/AccessKit/accesskit/issues/182)) ([dd658c7](https://github.com/AccessKit/accesskit/commit/dd658c70df55b2234a0346220362b0b9a40bb41d))
## [0.8.0](https://www.github.com/AccessKit/accesskit/compare/accesskit-v0.7.0...accesskit-v0.8.0) (2022-11-17)
### ⚠ BREAKING CHANGES
* Be opinionated about coordinates after all (#151)
### Code Refactoring
* Be opinionated about coordinates after all ([#151](https://www.github.com/AccessKit/accesskit/issues/151)) ([91a29a1](https://www.github.com/AccessKit/accesskit/commit/91a29a1bf99bca39e9a00a744025533924e45190))
## [0.7.0](https://www.github.com/AccessKit/accesskit/compare/accesskit-v0.6.1...accesskit-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))
### [0.6.1](https://www.github.com/AccessKit/accesskit/compare/accesskit-v0.6.0...accesskit-v0.6.1) (2022-10-10)
### Bug Fixes
* **common:** Restore compatibility with Rust 1.61 ([#139](https://www.github.com/AccessKit/accesskit/issues/139)) ([d8c6b16](https://www.github.com/AccessKit/accesskit/commit/d8c6b166c83796bfd6d748df60136029a9ec81d2))
## [0.6.0](https://www.github.com/AccessKit/accesskit/compare/accesskit-v0.5.1...accesskit-v0.6.0) (2022-10-09)
### ⚠ BREAKING CHANGES
* Wrap `TreeUpdate` nodes in `Arc` (#135)
* Store node ID in `TreeUpdate`, not `accesskit::Node` (#132)
### Bug Fixes
* 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
* 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))
### [0.5.1](https://www.github.com/AccessKit/accesskit/compare/accesskit-v0.5.0...accesskit-v0.5.1) (2022-10-03)
### Bug Fixes
* **common:** Write a README specifically for the accesskit crate ([#130](https://www.github.com/AccessKit/accesskit/issues/130)) ([0c2f5cf](https://www.github.com/AccessKit/accesskit/commit/0c2f5cf71bdacf3142bff77defea36eeb2b4e1e9)), closes [#129](https://www.github.com/AccessKit/accesskit/issues/129)
## [0.5.0](https://www.github.com/AccessKit/accesskit/compare/accesskit-v0.4.0...accesskit-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))
### Bug Fixes
* **common:** Enable the serde feature when the schemars feature is turned on ([#122](https://www.github.com/AccessKit/accesskit/issues/122)) ([126b6e1](https://www.github.com/AccessKit/accesskit/commit/126b6e13294bee2b4c905a78147b49d763a61d05))
* **common:** Skip `ActionRequest::data` if it is `None` during serialization ([#123](https://www.github.com/AccessKit/accesskit/issues/123)) ([2d88ea8](https://www.github.com/AccessKit/accesskit/commit/2d88ea8518c99692beacfb955ef0bd4f388a4908))
## [0.4.0](https://www.github.com/AccessKit/accesskit/compare/accesskit-v0.3.0...accesskit-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)
### Features
* **common:** Conversion from `NonZeroU64` to `NodeId` ([#112](https://www.github.com/AccessKit/accesskit/issues/112)) ([b7adfb9](https://www.github.com/AccessKit/accesskit/commit/b7adfb906cb09107be71a148b5199ba87df2a6b3))
### Bug Fixes
* **common:** Various documentation fixes and improvements ([#111](https://www.github.com/AccessKit/accesskit/issues/111)) ([4d27234](https://www.github.com/AccessKit/accesskit/commit/4d27234195e96de65bf55869877405cb5e45f6fc))
* 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))
## [0.3.0](https://www.github.com/AccessKit/accesskit/compare/accesskit-v0.2.0...accesskit-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))

269
vendor/accesskit/Cargo.lock generated vendored Normal file
View File

@@ -0,0 +1,269 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 3
[[package]]
name = "accesskit"
version = "0.18.0"
dependencies = [
"enumn",
"pyo3",
"schemars",
"serde",
]
[[package]]
name = "autocfg"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
[[package]]
name = "cfg-if"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
[[package]]
name = "dyn-clone"
version = "1.0.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "68b0cf012f1230e43cd00ebb729c6bb58707ecfa8ad08b52ef3a4ccd2697fc30"
[[package]]
name = "enumn"
version = "0.1.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2f9ed6b3789237c8a0c1c505af1c7eb2c560df6186f01b098c3a1064ea532f38"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "heck"
version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea"
[[package]]
name = "indoc"
version = "2.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1e186cfbae8084e513daff4240b4797e342f988cecda4fb6c939150f96315fd8"
[[package]]
name = "itoa"
version = "1.0.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "453ad9f582a441959e5f0d088b02ce04cfe8d51a8eaf077f12ac6d3e94164ca6"
[[package]]
name = "libc"
version = "0.2.169"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b5aba8db14291edd000dfcc4d620c7ebfb122c613afb886ca8803fa4e128a20a"
[[package]]
name = "memoffset"
version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5a634b1c61a95585bd15607c6ab0c4e5b226e695ff2800ba0cdccddf208c406c"
dependencies = [
"autocfg",
]
[[package]]
name = "once_cell"
version = "1.19.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92"
[[package]]
name = "portable-atomic"
version = "1.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cc9c68a3f6da06753e9335d63e27f6b9754dd1920d941135b7ea8224f141adb2"
[[package]]
name = "proc-macro2"
version = "1.0.87"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b3e4daa0dcf6feba26f985457cdf104d4b4256fc5a09547140f3631bb076b19a"
dependencies = [
"unicode-ident",
]
[[package]]
name = "pyo3"
version = "0.23.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "57fe09249128b3173d092de9523eaa75136bf7ba85e0d69eca241c7939c933cc"
dependencies = [
"cfg-if",
"indoc",
"libc",
"memoffset",
"once_cell",
"portable-atomic",
"pyo3-build-config",
"pyo3-ffi",
"pyo3-macros",
"unindent",
]
[[package]]
name = "pyo3-build-config"
version = "0.23.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1cd3927b5a78757a0d71aa9dff669f903b1eb64b54142a9bd9f757f8fde65fd7"
dependencies = [
"once_cell",
"target-lexicon",
]
[[package]]
name = "pyo3-ffi"
version = "0.23.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dab6bb2102bd8f991e7749f130a70d05dd557613e39ed2deeee8e9ca0c4d548d"
dependencies = [
"libc",
"pyo3-build-config",
]
[[package]]
name = "pyo3-macros"
version = "0.23.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "91871864b353fd5ffcb3f91f2f703a22a9797c91b9ab497b1acac7b07ae509c7"
dependencies = [
"proc-macro2",
"pyo3-macros-backend",
"quote",
"syn",
]
[[package]]
name = "pyo3-macros-backend"
version = "0.23.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "43abc3b80bc20f3facd86cd3c60beed58c3e2aa26213f3cda368de39c60a27e4"
dependencies = [
"heck",
"proc-macro2",
"pyo3-build-config",
"quote",
"syn",
]
[[package]]
name = "quote"
version = "1.0.37"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af"
dependencies = [
"proc-macro2",
]
[[package]]
name = "ryu"
version = "1.0.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f91339c0467de62360649f8d3e185ca8de4224ff281f66000de5eb2a77a79041"
[[package]]
name = "schemars"
version = "0.8.21"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "09c024468a378b7e36765cd36702b7a90cc3cba11654f6685c8f233408e89e92"
dependencies = [
"dyn-clone",
"schemars_derive",
"serde",
"serde_json",
]
[[package]]
name = "schemars_derive"
version = "0.8.21"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b1eee588578aff73f856ab961cd2f79e36bc45d7ded33a7562adba4667aecc0e"
dependencies = [
"proc-macro2",
"quote",
"serde_derive_internals",
"syn",
]
[[package]]
name = "serde"
version = "1.0.210"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c8e3592472072e6e22e0a54d5904d9febf8508f65fb8552499a1abc7d1078c3a"
dependencies = [
"serde_derive",
]
[[package]]
name = "serde_derive"
version = "1.0.210"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "243902eda00fad750862fc144cea25caca5e20d615af0a81bee94ca738f1df1f"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "serde_derive_internals"
version = "0.29.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "18d26a20a969b9e3fdf2fc2d9f21eda6c40e2de84c9408bb5d3b05d499aae711"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "serde_json"
version = "1.0.94"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1c533a59c9d8a93a09c6ab31f0fd5e5f4dd1b8fc9434804029839884765d04ea"
dependencies = [
"itoa",
"ryu",
"serde",
]
[[package]]
name = "syn"
version = "2.0.79"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "89132cd0bf050864e1d38dc3bbc07a0eb8e7530af26344d3d2bbbef83499f590"
dependencies = [
"proc-macro2",
"quote",
"unicode-ident",
]
[[package]]
name = "target-lexicon"
version = "0.12.16"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "61c41af27dd6d1e27b1b16b489db798443478cef1f06a660c96db617ba5de3b1"
[[package]]
name = "unicode-ident"
version = "1.0.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e5464a87b239f13a63a501f2701565754bae92d243d4bb7eb12f6d57d2269bf4"
[[package]]
name = "unindent"
version = "0.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c7de7d73e1754487cb58364ee906a499937a0dfabd86bcb980fa99ec8c8fa2ce"

76
vendor/accesskit/Cargo.toml vendored Normal file
View File

@@ -0,0 +1,76 @@
# 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"
version = "0.18.0"
authors = ["The AccessKit contributors"]
build = false
autolib = false
autobins = false
autoexamples = false
autotests = false
autobenches = false
description = "UI accessibility infrastructure across platforms"
readme = "README.md"
keywords = [
"gui",
"ui",
"accessibility",
]
categories = ["gui"]
license = "MIT OR Apache-2.0"
repository = "https://github.com/AccessKit/accesskit"
[package.metadata.docs.rs]
features = [
"schemars",
"serde",
]
[lib]
name = "accesskit"
path = "src/lib.rs"
[dependencies.enumn]
version = "0.1.6"
optional = true
[dependencies.pyo3]
version = "0.23"
optional = true
[dependencies.schemars]
version = "0.8.7"
optional = true
[dependencies.serde]
version = "1.0"
features = [
"alloc",
"derive",
]
optional = true
default-features = false
[features]
enumn = ["dep:enumn"]
pyo3 = ["dep:pyo3"]
schemars = [
"dep:schemars",
"serde",
]
serde = [
"dep:serde",
"enumn",
]

13
vendor/accesskit/README.md vendored Normal file
View File

@@ -0,0 +1,13 @@
# AccessKit
This is the shared cross-platform crate for [AccessKit](https://accesskit.dev/). It defines the data structures that represent an accessibility tree, and the trait for handling action requests from assistive technologies.
To use AccessKit in your application or toolkit, you will also need a platform adapter. The following platform adapters are currently available:
* [accesskit_windows](https://crates.io/crates/accesskit_windows): exposes an AccessKit tree on Windows using the UI Automation API
* [accesskit_macos](https://crates.io/crates/accesskit_macos): exposes an AccessKit tree on MacOS through the Cocoa `NSAccessibility` protocol
* [accesskit_unix](https://crates.io/crates/accesskit_unix): exposes an AccessKit tree on Linux and Unix systems through the AT-SPI protocol
* [accesskit_android](https://crates.io/crates/accesskit_android): exposes an AccessKit tree on Android through the Java-based Android accessibility API
* [accesskit_winit](https://crates.io/crates/accesskit_winit): wraps other platform adapters for use with the [winit](https://crates.io/crates/winit) windowing library
Some platform adapters include simple examples.

866
vendor/accesskit/src/geometry.rs vendored Normal file
View File

@@ -0,0 +1,866 @@
// 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.
// Derived from kurbo.
// Copyright 2018 The kurbo Authors.
// 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 core::{
fmt,
ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Sub, SubAssign},
};
/// A 2D affine transform. Derived from [kurbo](https://github.com/linebender/kurbo).
#[derive(Clone, Copy, Debug, PartialEq)]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[repr(C)]
pub struct Affine([f64; 6]);
impl Affine {
/// The identity transform.
pub const IDENTITY: Affine = Affine::scale(1.0);
/// A transform that is flipped on the y-axis. Useful for converting between
/// y-up and y-down spaces.
pub const FLIP_Y: Affine = Affine::new([1.0, 0., 0., -1.0, 0., 0.]);
/// A transform that is flipped on the x-axis.
pub const FLIP_X: Affine = Affine::new([-1.0, 0., 0., 1.0, 0., 0.]);
/// Construct an affine transform from coefficients.
///
/// If the coefficients are `(a, b, c, d, e, f)`, then the resulting
/// transformation represents this augmented matrix:
///
/// ```text
/// | a c e |
/// | b d f |
/// | 0 0 1 |
/// ```
///
/// Note that this convention is transposed from PostScript and
/// Direct2D, but is consistent with the
/// [Wikipedia](https://en.wikipedia.org/wiki/Affine_transformation)
/// formulation of affine transformation as augmented matrix. The
/// idea is that `(A * B) * v == A * (B * v)`, where `*` is the
/// [`Mul`](core::ops::Mul) trait.
#[inline]
pub const fn new(c: [f64; 6]) -> Affine {
Affine(c)
}
/// An affine transform representing uniform scaling.
#[inline]
pub const fn scale(s: f64) -> Affine {
Affine([s, 0.0, 0.0, s, 0.0, 0.0])
}
/// An affine transform representing non-uniform scaling
/// with different scale values for x and y
#[inline]
pub const fn scale_non_uniform(s_x: f64, s_y: f64) -> Affine {
Affine([s_x, 0.0, 0.0, s_y, 0.0, 0.0])
}
/// An affine transform representing translation.
#[inline]
pub fn translate<V: Into<Vec2>>(p: V) -> Affine {
let p = p.into();
Affine([1.0, 0.0, 0.0, 1.0, p.x, p.y])
}
/// Creates an affine transformation that takes the unit square to the given rectangle.
///
/// Useful when you want to draw into the unit square but have your output fill any rectangle.
/// In this case push the `Affine` onto the transform stack.
pub fn map_unit_square(rect: Rect) -> Affine {
Affine([rect.width(), 0., 0., rect.height(), rect.x0, rect.y0])
}
/// Get the coefficients of the transform.
#[inline]
pub fn as_coeffs(self) -> [f64; 6] {
self.0
}
/// Compute the determinant of this transform.
pub fn determinant(self) -> f64 {
self.0[0] * self.0[3] - self.0[1] * self.0[2]
}
/// Compute the inverse transform.
///
/// Produces NaN values when the determinant is zero.
pub fn inverse(self) -> Affine {
let inv_det = self.determinant().recip();
Affine([
inv_det * self.0[3],
-inv_det * self.0[1],
-inv_det * self.0[2],
inv_det * self.0[0],
inv_det * (self.0[2] * self.0[5] - self.0[3] * self.0[4]),
inv_det * (self.0[1] * self.0[4] - self.0[0] * self.0[5]),
])
}
/// Compute the bounding box of a transformed rectangle.
///
/// Returns the minimal `Rect` that encloses the given `Rect` after affine transformation.
/// If the transform is axis-aligned, then this bounding box is "tight", in other words the
/// returned `Rect` is the transformed rectangle.
///
/// The returned rectangle always has non-negative width and height.
pub fn transform_rect_bbox(self, rect: Rect) -> Rect {
let p00 = self * Point::new(rect.x0, rect.y0);
let p01 = self * Point::new(rect.x0, rect.y1);
let p10 = self * Point::new(rect.x1, rect.y0);
let p11 = self * Point::new(rect.x1, rect.y1);
Rect::from_points(p00, p01).union(Rect::from_points(p10, p11))
}
/// Is this map finite?
#[inline]
pub fn is_finite(&self) -> bool {
self.0[0].is_finite()
&& self.0[1].is_finite()
&& self.0[2].is_finite()
&& self.0[3].is_finite()
&& self.0[4].is_finite()
&& self.0[5].is_finite()
}
/// Is this map NaN?
#[inline]
pub fn is_nan(&self) -> bool {
self.0[0].is_nan()
|| self.0[1].is_nan()
|| self.0[2].is_nan()
|| self.0[3].is_nan()
|| self.0[4].is_nan()
|| self.0[5].is_nan()
}
}
impl Default for Affine {
#[inline]
fn default() -> Affine {
Affine::IDENTITY
}
}
impl Mul<Point> for Affine {
type Output = Point;
#[inline]
fn mul(self, other: Point) -> Point {
Point::new(
self.0[0] * other.x + self.0[2] * other.y + self.0[4],
self.0[1] * other.x + self.0[3] * other.y + self.0[5],
)
}
}
impl Mul for Affine {
type Output = Affine;
#[inline]
fn mul(self, other: Affine) -> Affine {
Affine([
self.0[0] * other.0[0] + self.0[2] * other.0[1],
self.0[1] * other.0[0] + self.0[3] * other.0[1],
self.0[0] * other.0[2] + self.0[2] * other.0[3],
self.0[1] * other.0[2] + self.0[3] * other.0[3],
self.0[0] * other.0[4] + self.0[2] * other.0[5] + self.0[4],
self.0[1] * other.0[4] + self.0[3] * other.0[5] + self.0[5],
])
}
}
impl MulAssign for Affine {
#[inline]
fn mul_assign(&mut self, other: Affine) {
*self = self.mul(other);
}
}
impl Mul<Affine> for f64 {
type Output = Affine;
#[inline]
fn mul(self, other: Affine) -> Affine {
Affine([
self * other.0[0],
self * other.0[1],
self * other.0[2],
self * other.0[3],
self * other.0[4],
self * other.0[5],
])
}
}
/// A 2D point. Derived from [kurbo](https://github.com/linebender/kurbo).
#[derive(Clone, Copy, Default, PartialEq)]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[repr(C)]
pub struct Point {
/// The x coordinate.
pub x: f64,
/// The y coordinate.
pub y: f64,
}
impl Point {
/// The point (0, 0).
pub const ZERO: Point = Point::new(0., 0.);
/// The point at the origin; (0, 0).
pub const ORIGIN: Point = Point::new(0., 0.);
/// Create a new `Point` with the provided `x` and `y` coordinates.
#[inline]
pub const fn new(x: f64, y: f64) -> Self {
Point { x, y }
}
/// Convert this point into a `Vec2`.
#[inline]
pub const fn to_vec2(self) -> Vec2 {
Vec2::new(self.x, self.y)
}
}
impl From<(f64, f64)> for Point {
#[inline]
fn from(v: (f64, f64)) -> Point {
Point { x: v.0, y: v.1 }
}
}
impl From<Point> for (f64, f64) {
#[inline]
fn from(v: Point) -> (f64, f64) {
(v.x, v.y)
}
}
impl Add<Vec2> for Point {
type Output = Point;
#[inline]
fn add(self, other: Vec2) -> Self {
Point::new(self.x + other.x, self.y + other.y)
}
}
impl AddAssign<Vec2> for Point {
#[inline]
fn add_assign(&mut self, other: Vec2) {
*self = Point::new(self.x + other.x, self.y + other.y);
}
}
impl Sub<Vec2> for Point {
type Output = Point;
#[inline]
fn sub(self, other: Vec2) -> Self {
Point::new(self.x - other.x, self.y - other.y)
}
}
impl SubAssign<Vec2> for Point {
#[inline]
fn sub_assign(&mut self, other: Vec2) {
*self = Point::new(self.x - other.x, self.y - other.y);
}
}
impl Add<(f64, f64)> for Point {
type Output = Point;
#[inline]
fn add(self, (x, y): (f64, f64)) -> Self {
Point::new(self.x + x, self.y + y)
}
}
impl AddAssign<(f64, f64)> for Point {
#[inline]
fn add_assign(&mut self, (x, y): (f64, f64)) {
*self = Point::new(self.x + x, self.y + y);
}
}
impl Sub<(f64, f64)> for Point {
type Output = Point;
#[inline]
fn sub(self, (x, y): (f64, f64)) -> Self {
Point::new(self.x - x, self.y - y)
}
}
impl SubAssign<(f64, f64)> for Point {
#[inline]
fn sub_assign(&mut self, (x, y): (f64, f64)) {
*self = Point::new(self.x - x, self.y - y);
}
}
impl Sub<Point> for Point {
type Output = Vec2;
#[inline]
fn sub(self, other: Point) -> Vec2 {
Vec2::new(self.x - other.x, self.y - other.y)
}
}
impl fmt::Debug for Point {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "({:?}, {:?})", self.x, self.y)
}
}
/// A rectangle. Derived from [kurbo](https://github.com/linebender/kurbo).
#[derive(Clone, Copy, Default, PartialEq)]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[repr(C)]
pub struct Rect {
/// The minimum x coordinate (left edge).
pub x0: f64,
/// The minimum y coordinate (top edge in y-down spaces).
pub y0: f64,
/// The maximum x coordinate (right edge).
pub x1: f64,
/// The maximum y coordinate (bottom edge in y-down spaces).
pub y1: f64,
}
impl From<(Point, Point)> for Rect {
fn from(points: (Point, Point)) -> Rect {
Rect::from_points(points.0, points.1)
}
}
impl From<(Point, Size)> for Rect {
fn from(params: (Point, Size)) -> Rect {
Rect::from_origin_size(params.0, params.1)
}
}
impl Add<Vec2> for Rect {
type Output = Rect;
#[inline]
fn add(self, v: Vec2) -> Rect {
Rect::new(self.x0 + v.x, self.y0 + v.y, self.x1 + v.x, self.y1 + v.y)
}
}
impl Sub<Vec2> for Rect {
type Output = Rect;
#[inline]
fn sub(self, v: Vec2) -> Rect {
Rect::new(self.x0 - v.x, self.y0 - v.y, self.x1 - v.x, self.y1 - v.y)
}
}
impl fmt::Debug for Rect {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
if f.alternate() {
write!(
f,
"Rect {{ origin: {:?}, size: {:?} }}",
self.origin(),
self.size()
)
} else {
write!(
f,
"Rect {{ x0: {:?}, y0: {:?}, x1: {:?}, y1: {:?} }}",
self.x0, self.y0, self.x1, self.y1
)
}
}
}
impl Rect {
/// The empty rectangle at the origin.
pub const ZERO: Rect = Rect::new(0., 0., 0., 0.);
/// A new rectangle from minimum and maximum coordinates.
#[inline]
pub const fn new(x0: f64, y0: f64, x1: f64, y1: f64) -> Rect {
Rect { x0, y0, x1, y1 }
}
/// A new rectangle from two points.
///
/// The result will have non-negative width and height.
#[inline]
pub fn from_points(p0: impl Into<Point>, p1: impl Into<Point>) -> Rect {
let p0 = p0.into();
let p1 = p1.into();
Rect::new(p0.x, p0.y, p1.x, p1.y).abs()
}
/// A new rectangle from origin and size.
///
/// The result will have non-negative width and height.
#[inline]
pub fn from_origin_size(origin: impl Into<Point>, size: impl Into<Size>) -> Rect {
let origin = origin.into();
Rect::from_points(origin, origin + size.into().to_vec2())
}
/// Create a new `Rect` with the same size as `self` and a new origin.
#[inline]
pub fn with_origin(self, origin: impl Into<Point>) -> Rect {
Rect::from_origin_size(origin, self.size())
}
/// Create a new `Rect` with the same origin as `self` and a new size.
#[inline]
pub fn with_size(self, size: impl Into<Size>) -> Rect {
Rect::from_origin_size(self.origin(), size)
}
/// The width of the rectangle.
///
/// Note: nothing forbids negative width.
#[inline]
pub fn width(&self) -> f64 {
self.x1 - self.x0
}
/// The height of the rectangle.
///
/// Note: nothing forbids negative height.
#[inline]
pub fn height(&self) -> f64 {
self.y1 - self.y0
}
/// Returns the minimum value for the x-coordinate of the rectangle.
#[inline]
pub fn min_x(&self) -> f64 {
self.x0.min(self.x1)
}
/// Returns the maximum value for the x-coordinate of the rectangle.
#[inline]
pub fn max_x(&self) -> f64 {
self.x0.max(self.x1)
}
/// Returns the minimum value for the y-coordinate of the rectangle.
#[inline]
pub fn min_y(&self) -> f64 {
self.y0.min(self.y1)
}
/// Returns the maximum value for the y-coordinate of the rectangle.
#[inline]
pub fn max_y(&self) -> f64 {
self.y0.max(self.y1)
}
/// The origin of the rectangle.
///
/// This is the top left corner in a y-down space and with
/// non-negative width and height.
#[inline]
pub fn origin(&self) -> Point {
Point::new(self.x0, self.y0)
}
/// The size of the rectangle.
#[inline]
pub fn size(&self) -> Size {
Size::new(self.width(), self.height())
}
/// Take absolute value of width and height.
///
/// The resulting rect has the same extents as the original, but is
/// guaranteed to have non-negative width and height.
#[inline]
pub fn abs(&self) -> Rect {
let Rect { x0, y0, x1, y1 } = *self;
Rect::new(x0.min(x1), y0.min(y1), x0.max(x1), y0.max(y1))
}
/// The area of the rectangle.
#[inline]
pub fn area(&self) -> f64 {
self.width() * self.height()
}
/// Whether this rectangle has zero area.
///
/// Note: a rectangle with negative area is not considered empty.
#[inline]
pub fn is_empty(&self) -> bool {
self.area() == 0.0
}
/// Returns `true` if `point` lies within `self`.
#[inline]
pub fn contains(&self, point: Point) -> bool {
point.x >= self.x0 && point.x < self.x1 && point.y >= self.y0 && point.y < self.y1
}
/// The smallest rectangle enclosing two rectangles.
///
/// Results are valid only if width and height are non-negative.
#[inline]
pub fn union(&self, other: Rect) -> Rect {
Rect::new(
self.x0.min(other.x0),
self.y0.min(other.y0),
self.x1.max(other.x1),
self.y1.max(other.y1),
)
}
/// Compute the union with one point.
///
/// This method includes the perimeter of zero-area rectangles.
/// Thus, a succession of `union_pt` operations on a series of
/// points yields their enclosing rectangle.
///
/// Results are valid only if width and height are non-negative.
pub fn union_pt(&self, pt: Point) -> Rect {
Rect::new(
self.x0.min(pt.x),
self.y0.min(pt.y),
self.x1.max(pt.x),
self.y1.max(pt.y),
)
}
/// The intersection of two rectangles.
///
/// The result is zero-area if either input has negative width or
/// height. The result always has non-negative width and height.
#[inline]
pub fn intersect(&self, other: Rect) -> Rect {
let x0 = self.x0.max(other.x0);
let y0 = self.y0.max(other.y0);
let x1 = self.x1.min(other.x1);
let y1 = self.y1.min(other.y1);
Rect::new(x0, y0, x1.max(x0), y1.max(y0))
}
}
/// A 2D size. Derived from [kurbo](https://github.com/linebender/kurbo).
#[derive(Clone, Copy, Default, PartialEq)]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[repr(C)]
pub struct Size {
/// The width.
pub width: f64,
/// The height.
pub height: f64,
}
impl Size {
/// A size with zero width or height.
pub const ZERO: Size = Size::new(0., 0.);
/// Create a new `Size` with the provided `width` and `height`.
#[inline]
pub const fn new(width: f64, height: f64) -> Self {
Size { width, height }
}
/// Convert this size into a [`Vec2`], with `width` mapped to `x` and `height`
/// mapped to `y`.
#[inline]
pub const fn to_vec2(self) -> Vec2 {
Vec2::new(self.width, self.height)
}
}
impl fmt::Debug for Size {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{:?}W×{:?}H", self.width, self.height)
}
}
impl MulAssign<f64> for Size {
#[inline]
fn mul_assign(&mut self, other: f64) {
*self = Size {
width: self.width * other,
height: self.height * other,
};
}
}
impl Mul<Size> for f64 {
type Output = Size;
#[inline]
fn mul(self, other: Size) -> Size {
other * self
}
}
impl Mul<f64> for Size {
type Output = Size;
#[inline]
fn mul(self, other: f64) -> Size {
Size {
width: self.width * other,
height: self.height * other,
}
}
}
impl DivAssign<f64> for Size {
#[inline]
fn div_assign(&mut self, other: f64) {
*self = Size {
width: self.width / other,
height: self.height / other,
};
}
}
impl Div<f64> for Size {
type Output = Size;
#[inline]
fn div(self, other: f64) -> Size {
Size {
width: self.width / other,
height: self.height / other,
}
}
}
impl Add<Size> for Size {
type Output = Size;
#[inline]
fn add(self, other: Size) -> Size {
Size {
width: self.width + other.width,
height: self.height + other.height,
}
}
}
impl AddAssign<Size> for Size {
#[inline]
fn add_assign(&mut self, other: Size) {
*self = *self + other;
}
}
impl Sub<Size> for Size {
type Output = Size;
#[inline]
fn sub(self, other: Size) -> Size {
Size {
width: self.width - other.width,
height: self.height - other.height,
}
}
}
impl SubAssign<Size> for Size {
#[inline]
fn sub_assign(&mut self, other: Size) {
*self = *self - other;
}
}
impl From<(f64, f64)> for Size {
#[inline]
fn from(v: (f64, f64)) -> Size {
Size {
width: v.0,
height: v.1,
}
}
}
impl From<Size> for (f64, f64) {
#[inline]
fn from(v: Size) -> (f64, f64) {
(v.width, v.height)
}
}
/// A 2D vector. Derived from [kurbo](https://github.com/linebender/kurbo).
///
/// This is intended primarily for a vector in the mathematical sense,
/// but it can be interpreted as a translation, and converted to and
/// from a point (vector relative to the origin) and size.
#[derive(Clone, Copy, Default, Debug, PartialEq)]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[repr(C)]
pub struct Vec2 {
/// The x-coordinate.
pub x: f64,
/// The y-coordinate.
pub y: f64,
}
impl Vec2 {
/// The vector (0, 0).
pub const ZERO: Vec2 = Vec2::new(0., 0.);
/// Create a new vector.
#[inline]
pub const fn new(x: f64, y: f64) -> Vec2 {
Vec2 { x, y }
}
/// Convert this vector into a `Point`.
#[inline]
pub const fn to_point(self) -> Point {
Point::new(self.x, self.y)
}
/// Convert this vector into a `Size`.
#[inline]
pub const fn to_size(self) -> Size {
Size::new(self.x, self.y)
}
}
impl From<(f64, f64)> for Vec2 {
#[inline]
fn from(v: (f64, f64)) -> Vec2 {
Vec2 { x: v.0, y: v.1 }
}
}
impl From<Vec2> for (f64, f64) {
#[inline]
fn from(v: Vec2) -> (f64, f64) {
(v.x, v.y)
}
}
impl Add for Vec2 {
type Output = Vec2;
#[inline]
fn add(self, other: Vec2) -> Vec2 {
Vec2 {
x: self.x + other.x,
y: self.y + other.y,
}
}
}
impl AddAssign for Vec2 {
#[inline]
fn add_assign(&mut self, other: Vec2) {
*self = Vec2 {
x: self.x + other.x,
y: self.y + other.y,
}
}
}
impl Sub for Vec2 {
type Output = Vec2;
#[inline]
fn sub(self, other: Vec2) -> Vec2 {
Vec2 {
x: self.x - other.x,
y: self.y - other.y,
}
}
}
impl SubAssign for Vec2 {
#[inline]
fn sub_assign(&mut self, other: Vec2) {
*self = Vec2 {
x: self.x - other.x,
y: self.y - other.y,
}
}
}
impl Mul<f64> for Vec2 {
type Output = Vec2;
#[inline]
fn mul(self, other: f64) -> Vec2 {
Vec2 {
x: self.x * other,
y: self.y * other,
}
}
}
impl MulAssign<f64> for Vec2 {
#[inline]
fn mul_assign(&mut self, other: f64) {
*self = Vec2 {
x: self.x * other,
y: self.y * other,
};
}
}
impl Mul<Vec2> for f64 {
type Output = Vec2;
#[inline]
fn mul(self, other: Vec2) -> Vec2 {
other * self
}
}
impl Div<f64> for Vec2 {
type Output = Vec2;
/// Note: division by a scalar is implemented by multiplying by the reciprocal.
///
/// This is more efficient but has different roundoff behavior than division.
#[inline]
#[allow(clippy::suspicious_arithmetic_impl)]
fn div(self, other: f64) -> Vec2 {
self * other.recip()
}
}
impl DivAssign<f64> for Vec2 {
#[inline]
fn div_assign(&mut self, other: f64) {
self.mul_assign(other.recip());
}
}
impl Neg for Vec2 {
type Output = Vec2;
#[inline]
fn neg(self) -> Vec2 {
Vec2 {
x: -self.x,
y: -self.y,
}
}
}

2490
vendor/accesskit/src/lib.rs vendored Normal file

File diff suppressed because it is too large Load Diff

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);
}
}

View File

@@ -0,0 +1 @@
{"files":{"CHANGELOG.md":"9cdb91dc9517c9cfc4a61a8e95857f5b13f5604e6ad1f59d3e21e0a578333d46","Cargo.lock":"497e60103053946c4a7558f55c1dd904d1cceb94782271c82b754ec797c7c7fe","Cargo.toml":"98a79e9b88dd3c86bcfc80b930e95b1b40f3eedd05287273f94693af2fa3ceb1","README.md":"ac9a875391361e0cc0a0cae754cf5cc451d24f1c7f7b70c8f16c7601ec53bfd4","src/adapter.rs":"93556c38fe26af394d67edeb2788c9a31c995d3a8836579ac8c15248da0df41b","src/context.rs":"683964180cc0d009206bf9a2fd9a44d2f4b050f95079d6fb67f4b8fe08b87e44","src/event.rs":"0dca09cbdeaa4b3f86d5fbc6e7c079d9679228bde919ac33432c8eb40a8ee9a7","src/filters.rs":"cfe74d16da43ccfda209f11107faf78442c6830fa126cf2d48ffdcdf14c65288","src/lib.rs":"b1df68dc7181efe2f833df5367493a3d2cc06dc2993202f612c4bf18285f7972","src/node.rs":"a9baf1e5fc90a81249d00f604d565c20110e88e35492a48cd4857776e34e2b4d","src/patch.rs":"d523ebaa0105ddb2adf342838b3128263480747e1b6d55f4d62a65b4db173990","src/subclass.rs":"967a9e8aecf0045572d92c90c7ac293dfc351af49bc79fe56d6d2546ed799a21","src/util.rs":"19a695214d29f873d3dc06ed9a4e3b972531aa7d659d18fd405d3e2526f9fef3"},"package":"09e230718177753b4e4ad9e1d9f6cfc2f4921212d4c1c480b253f526babb258d"}

541
vendor/accesskit_macos/CHANGELOG.md vendored Normal file
View File

@@ -0,0 +1,541 @@
# Changelog
* The following workspace dependencies were updated
* dependencies
* accesskit_consumer bumped from 0.11.0 to 0.12.0
* The following workspace dependencies were updated
* dependencies
* accesskit_consumer bumped from 0.12.0 to 0.12.1
* The following workspace dependencies were updated
* dependencies
* accesskit bumped from 0.10.0 to 0.10.1
* accesskit_consumer bumped from 0.14.0 to 0.14.1
* The following workspace dependencies were updated
* dependencies
* accesskit bumped from 0.12.0 to 0.12.1
* accesskit_consumer bumped from 0.16.0 to 0.16.1
* The following workspace dependencies were updated
* dependencies
* accesskit bumped from 0.12.2 to 0.12.3
* accesskit_consumer bumped from 0.17.0 to 0.17.1
* The following workspace dependencies were updated
* dependencies
* accesskit_consumer bumped from 0.19.0 to 0.19.1
* The following workspace dependencies were updated
* dependencies
* accesskit bumped from 0.16.0 to 0.16.1
* accesskit_consumer bumped from 0.24.0 to 0.24.1
* The following workspace dependencies were updated
* dependencies
* accesskit bumped from 0.16.2 to 0.16.3
* accesskit_consumer bumped from 0.24.2 to 0.24.3
## [0.19.0](https://github.com/AccessKit/accesskit/compare/accesskit_macos-v0.18.1...accesskit_macos-v0.19.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
* Expose the `is_required` property ([#497](https://github.com/AccessKit/accesskit/issues/497)) ([46ed99b](https://github.com/AccessKit/accesskit/commit/46ed99bb958ddb32cbf1bee2fcfb7b328bcbe0ab))
### Bug Fixes
* Add list box support to the platform adapters ([6c622cf](https://github.com/AccessKit/accesskit/commit/6c622cff4c0c989d9a5f16b775adff9cdacf534c))
* Derive `Debug` for adapters ([#513](https://github.com/AccessKit/accesskit/issues/513)) ([753d904](https://github.com/AccessKit/accesskit/commit/753d90473cf57682568c7a17c82474c8e5d00b25))
* 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
* accesskit_consumer bumped from 0.26.0 to 0.27.0
## [0.18.1](https://github.com/AccessKit/accesskit/compare/accesskit_macos-v0.18.0...accesskit_macos-v0.18.1) (2024-11-23)
### Bug Fixes
* Add sub roles to MacOS adapter ([#480](https://github.com/AccessKit/accesskit/issues/480)) ([40ad828](https://github.com/AccessKit/accesskit/commit/40ad828a8f95c94f3079310d95c94ab7b16e0887))
* Optimize use of hash tables in platform adapters ([#485](https://github.com/AccessKit/accesskit/issues/485)) ([f4f0bfb](https://github.com/AccessKit/accesskit/commit/f4f0bfbf21b8e22e80ab07deb432f9e7e16469ab))
### Dependencies
* The following workspace dependencies were updated
* dependencies
* accesskit bumped from 0.17.0 to 0.17.1
* accesskit_consumer bumped from 0.25.0 to 0.26.0
## [0.18.0](https://github.com/AccessKit/accesskit/compare/accesskit_macos-v0.17.4...accesskit_macos-v0.18.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))
### Bug Fixes
* Implement the `isAccessibilityEnabled` property on MacOS ([#474](https://github.com/AccessKit/accesskit/issues/474)) ([61e4817](https://github.com/AccessKit/accesskit/commit/61e48174ed1dd57b7dd919ecaef908f157357ec0))
### 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
* accesskit_consumer bumped from 0.24.3 to 0.25.0
## [0.17.4](https://github.com/AccessKit/accesskit/compare/accesskit_macos-v0.17.3...accesskit_macos-v0.17.4) (2024-10-21)
### Bug Fixes
* Add properties needed by the Xcode Accessibility Inspector ([#466](https://github.com/AccessKit/accesskit/issues/466)) ([295b188](https://github.com/AccessKit/accesskit/commit/295b1881936dd097d82a10317ff14d1369f7e4bd))
## [0.17.2](https://github.com/AccessKit/accesskit/compare/accesskit_macos-v0.17.1...accesskit_macos-v0.17.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
* accesskit_consumer bumped from 0.24.1 to 0.24.2
## [0.17.0](https://github.com/AccessKit/accesskit/compare/accesskit_macos-v0.16.0...accesskit_macos-v0.17.0) (2024-06-29)
### ⚠ BREAKING CHANGES
* Rename the `StaticText` role to `Label` ([#434](https://github.com/AccessKit/accesskit/issues/434))
### 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
* accesskit_consumer bumped from 0.23.0 to 0.24.0
## [0.16.0](https://github.com/AccessKit/accesskit/compare/accesskit_macos-v0.15.0...accesskit_macos-v0.16.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))
### Dependencies
* The following workspace dependencies were updated
* dependencies
* accesskit bumped from 0.14.0 to 0.15.0
* accesskit_consumer bumped from 0.22.0 to 0.23.0
## [0.15.0](https://github.com/AccessKit/accesskit/compare/accesskit_macos-v0.14.0...accesskit_macos-v0.15.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))
### Dependencies
* The following workspace dependencies were updated
* dependencies
* accesskit_consumer bumped from 0.21.0 to 0.22.0
## [0.14.0](https://github.com/AccessKit/accesskit/compare/accesskit_macos-v0.13.2...accesskit_macos-v0.14.0) (2024-05-26)
### Features
* Expose the `placeholder` property ([#417](https://github.com/AccessKit/accesskit/issues/417)) ([8f4a0a1](https://github.com/AccessKit/accesskit/commit/8f4a0a1c10f83fcc8580a37d8013fec2d110865b))
### Dependencies
* The following workspace dependencies were updated
* dependencies
* accesskit_consumer bumped from 0.20.0 to 0.21.0
## [0.13.2](https://github.com/AccessKit/accesskit/compare/accesskit_macos-v0.13.1...accesskit_macos-v0.13.2) (2024-05-13)
### Bug Fixes
* Fix platform adapters to support copy-on-write tree snapshots again ([#411](https://github.com/AccessKit/accesskit/issues/411)) ([d3a130a](https://github.com/AccessKit/accesskit/commit/d3a130a5ec8ae1d9edf0bf85a44f35f0e365242c))
### Dependencies
* The following workspace dependencies were updated
* dependencies
* accesskit_consumer bumped from 0.19.1 to 0.20.0
## [0.13.0](https://github.com/AccessKit/accesskit/compare/accesskit_macos-v0.12.0...accesskit_macos-v0.13.0) (2024-04-30)
### ⚠ BREAKING CHANGES
* Clean up table roles and properties ([#393](https://github.com/AccessKit/accesskit/issues/393))
* 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
* 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))
* Use new objc2 crates ([#384](https://github.com/AccessKit/accesskit/issues/384)) ([b3484c0](https://github.com/AccessKit/accesskit/commit/b3484c0fb1fef3ecd41ff9592978336c20b8b4f8))
### Code Refactoring
* Clean up table roles and properties ([#393](https://github.com/AccessKit/accesskit/issues/393)) ([e34dad9](https://github.com/AccessKit/accesskit/commit/e34dad94448a5321ece9def3f2e054aa5f62dd79))
* 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
* accesskit_consumer bumped from 0.18.0 to 0.19.0
## [0.12.0](https://github.com/AccessKit/accesskit/compare/accesskit_macos-v0.11.1...accesskit_macos-v0.12.0) (2024-04-14)
### ⚠ BREAKING CHANGES
* New approach to lazy initialization ([#375](https://github.com/AccessKit/accesskit/issues/375))
### Bug Fixes
* Fix new compiler warning in Rust 1.77 ([#376](https://github.com/AccessKit/accesskit/issues/376)) ([1de7c63](https://github.com/AccessKit/accesskit/commit/1de7c63e7db12bc7eda57a191e913fef0e572f43))
### 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
* accesskit_consumer bumped from 0.17.1 to 0.18.0
## [0.11.0](https://github.com/AccessKit/accesskit/compare/accesskit_macos-v0.10.1...accesskit_macos-v0.11.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))
### Bug Fixes
* Bump objc2 to 0.5.0; bring icrate 0.1.0 ([#323](https://github.com/AccessKit/accesskit/issues/323)) ([23b3f2f](https://github.com/AccessKit/accesskit/commit/23b3f2f93b9452c80374d1da3e9abeaec60ba9bf))
### Dependencies
* The following workspace dependencies were updated
* dependencies
* accesskit bumped from 0.12.1 to 0.12.2
* accesskit_consumer bumped from 0.16.1 to 0.17.0
## [0.10.0](https://github.com/AccessKit/accesskit/compare/accesskit_macos-v0.9.0...accesskit_macos-v0.10.0) (2023-09-27)
### ⚠ BREAKING CHANGES
* Make `ActionHandler::do_action` take `&mut self` ([#296](https://github.com/AccessKit/accesskit/issues/296))
* Clean up roles and properties ([#289](https://github.com/AccessKit/accesskit/issues/289))
* 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))
### Bug Fixes
* 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))
* Make `ActionHandler::do_action` take `&mut self` ([#296](https://github.com/AccessKit/accesskit/issues/296)) ([4fc7846](https://github.com/AccessKit/accesskit/commit/4fc7846d732d61fb45c023060ebab96801a0053e))
* 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
* accesskit_consumer bumped from 0.15.2 to 0.16.0
## [0.9.0](https://github.com/AccessKit/accesskit/compare/accesskit_macos-v0.8.0...accesskit_macos-v0.9.0) (2023-08-08)
### Features
* Workaround for libraries that put the macOS keyboard focus on the window rather than the content view ([#266](https://github.com/AccessKit/accesskit/issues/266)) ([c2db1b0](https://github.com/AccessKit/accesskit/commit/c2db1b0424e905d87691f8148f28b77405f29926))
### Dependencies
* The following workspace dependencies were updated
* dependencies
* accesskit bumped from 0.11.1 to 0.11.2
* accesskit_consumer bumped from 0.15.1 to 0.15.2
## [0.8.0](https://github.com/AccessKit/accesskit/compare/accesskit_macos-v0.7.1...accesskit_macos-v0.8.0) (2023-07-30)
### Features
* Add window-based constructor to macOS subclassing adapter ([#253](https://github.com/AccessKit/accesskit/issues/253)) ([022ef04](https://github.com/AccessKit/accesskit/commit/022ef045b9f28262b738ee1ca29a4c7303061fb3))
### Dependencies
* The following workspace dependencies were updated
* dependencies
* accesskit bumped from 0.11.0 to 0.11.1
* accesskit_consumer bumped from 0.15.0 to 0.15.1
## [0.7.1](https://github.com/AccessKit/accesskit/compare/accesskit_macos-v0.7.0...accesskit_macos-v0.7.1) (2023-06-20)
### Bug Fixes
* Set proper target to build accesskit_macos documentation ([#226](https://github.com/AccessKit/accesskit/issues/226)) ([9cd6bb1](https://github.com/AccessKit/accesskit/commit/9cd6bb14d60bf85027b330a51afe912c37723902))
## [0.7.0](https://github.com/AccessKit/accesskit/compare/accesskit_macos-v0.6.3...accesskit_macos-v0.7.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))
### Dependencies
* The following workspace dependencies were updated
* dependencies
* accesskit_consumer bumped from 0.14.2 to 0.15.0
## [0.6.3](https://github.com/AccessKit/accesskit/compare/accesskit_macos-v0.6.2...accesskit_macos-v0.6.3) (2023-03-29)
### Bug Fixes
* Fix problems related to the root node ([#231](https://github.com/AccessKit/accesskit/issues/231)) ([7228494](https://github.com/AccessKit/accesskit/commit/7228494361c4f131af6a7fc2af8a98406cd9a63e))
### Dependencies
* The following workspace dependencies were updated
* dependencies
* accesskit bumped from 0.10.1 to 0.11.0
* accesskit_consumer bumped from 0.14.1 to 0.14.2
## [0.6.2](https://github.com/AccessKit/accesskit/compare/accesskit_macos-v0.6.1...accesskit_macos-v0.6.2) (2023-03-14)
### Bug Fixes
* Fix macOS leaks ([e8537fc](https://github.com/AccessKit/accesskit/commit/e8537fcbdf4a68f39c9bc51cf9fe6960903e26f2))
## [0.6.0](https://github.com/AccessKit/accesskit/compare/accesskit_macos-v0.5.0...accesskit_macos-v0.6.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
* accesskit_consumer bumped from 0.13.0 to 0.14.0
## [0.5.0](https://github.com/AccessKit/accesskit/compare/accesskit_macos-v0.4.2...accesskit_macos-v0.5.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
* accesskit_consumer bumped from 0.12.1 to 0.13.0
## [0.4.0](https://github.com/AccessKit/accesskit/compare/accesskit_macos-v0.3.0...accesskit_macos-v0.4.0) (2022-12-27)
### Features
* Live regions on macOS ([#196](https://github.com/AccessKit/accesskit/issues/196)) ([47d8d9f](https://github.com/AccessKit/accesskit/commit/47d8d9f6a567dfe909aa4065886cace07084efb7))
### Bug Fixes
* Pin objc2 dependency to 0.3.0-beta.3 ([#201](https://github.com/AccessKit/accesskit/issues/201)) ([0adfed1](https://github.com/AccessKit/accesskit/commit/0adfed1192ee255fba34ad82e8483ab9296ac2df))
## [0.3.0](https://github.com/AccessKit/accesskit/compare/accesskit_macos-v0.2.1...accesskit_macos-v0.3.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
* Don't expose the window title in our root element on macOS ([#187](https://github.com/AccessKit/accesskit/issues/187)) ([9739b74](https://github.com/AccessKit/accesskit/commit/9739b7424328da45c1c43b6db49af142a8789aa5))
* Expose which accessibility selectors are actually allowed for a particular node ([#181](https://github.com/AccessKit/accesskit/issues/181)) ([c4cbb23](https://github.com/AccessKit/accesskit/commit/c4cbb23156749d513df4e520dcb9be0a74c697d3))
* 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))
### Dependencies
* The following workspace dependencies were updated
* dependencies
* accesskit_consumer bumped from 0.10.0 to 0.11.0
## [0.2.1](https://github.com/AccessKit/accesskit/compare/accesskit_macos-v0.2.0...accesskit_macos-v0.2.1) (2022-12-04)
### Bug Fixes
* Correctly apply the DPI scale factor to coordinates ([#185](https://github.com/AccessKit/accesskit/issues/185)) ([d263938](https://github.com/AccessKit/accesskit/commit/d263938d68bb63567853a340d3466ff27e076d87))
* Expose static text as the value rather than the title on macOS ([#186](https://github.com/AccessKit/accesskit/issues/186)) ([e3720c8](https://github.com/AccessKit/accesskit/commit/e3720c8e2d7c5e8c8601c52ad620dcfcacebc570))
### Dependencies
* The following workspace dependencies were updated
* dependencies
* accesskit bumped from 0.8.0 to 0.8.1
* accesskit_consumer bumped from 0.9.1 to 0.10.0
## [0.2.0](https://github.com/AccessKit/accesskit/compare/accesskit_macos-v0.1.5...accesskit_macos-v0.2.0) (2022-11-29)
### ⚠ BREAKING CHANGES
* Move lazy initialization from the core platform adapter to the caller ([#179](https://github.com/AccessKit/accesskit/issues/179))
### Code Refactoring
* Move lazy initialization from the core platform adapter to the caller ([#179](https://github.com/AccessKit/accesskit/issues/179)) ([f35c941](https://github.com/AccessKit/accesskit/commit/f35c941f395f3162db376a69cfaaaf770d376267))
## [0.1.5](https://github.com/AccessKit/accesskit/compare/accesskit_macos-v0.1.4...accesskit_macos-v0.1.5) (2022-11-27)
### Bug Fixes
* Handle views with flipped coordinates ([#174](https://github.com/AccessKit/accesskit/issues/174)) ([d14484c](https://github.com/AccessKit/accesskit/commit/d14484cdcfdd99a497354aa3e012a0e130cc3d64))
* Make VoiceOver move through nodes in logical order ([#176](https://github.com/AccessKit/accesskit/issues/176)) ([f060be4](https://github.com/AccessKit/accesskit/commit/f060be409945296ed100cd63ecb3d2bb6bbad89e))
### [0.1.4](https://www.github.com/AccessKit/accesskit/compare/accesskit_macos-v0.1.3...accesskit_macos-v0.1.4) (2022-11-25)
### Bug Fixes
* Re-export types from objc2 ([#172](https://www.github.com/AccessKit/accesskit/issues/172)) ([1ac67ad](https://www.github.com/AccessKit/accesskit/commit/1ac67ad17587d79b5338cb71e2bc07612fc10c44))
### [0.1.3](https://www.github.com/AccessKit/accesskit/compare/accesskit_macos-v0.1.2...accesskit_macos-v0.1.3) (2022-11-25)
### Dependencies
* The following workspace dependencies were updated
* dependencies
* accesskit_consumer bumped from 0.9.0 to 0.9.1
### [0.1.2](https://www.github.com/AccessKit/accesskit/compare/accesskit_macos-v0.1.1...accesskit_macos-v0.1.2) (2022-11-24)
### Bug Fixes
* **platforms/macos:** Add the macOS crate to the release-please configuration ([#164](https://www.github.com/AccessKit/accesskit/issues/164)) ([da83f63](https://www.github.com/AccessKit/accesskit/commit/da83f63d279a10c5a7199a9145ca9eb9e27d7b56))

182
vendor/accesskit_macos/Cargo.lock generated vendored Normal file
View File

@@ -0,0 +1,182 @@
# 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"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d0bf66a7bf0b7ea4fd7742d50b64782a88f99217cf246b3f93b4162528dde520"
dependencies = [
"accesskit",
"hashbrown",
"immutable-chunkmap",
]
[[package]]
name = "accesskit_macos"
version = "0.19.0"
dependencies = [
"accesskit",
"accesskit_consumer",
"hashbrown",
"objc2",
"objc2-app-kit",
"objc2-foundation",
]
[[package]]
name = "arrayvec"
version = "0.7.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8da52d66c7071e2e3fa2a1e5c6d088fec47b593032b254f5e980de8ea54454d6"
[[package]]
name = "bitflags"
version = "2.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8f68f53c83ab957f72c32642f3868eec03eb974d1fb82e453128456482613d36"
[[package]]
name = "block2"
version = "0.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2c132eebf10f5cad5289222520a4a058514204aed6d791f1cf4fe8088b82d15f"
dependencies = [
"objc2",
]
[[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",
]
[[package]]
name = "libc"
version = "0.2.169"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b5aba8db14291edd000dfcc4d620c7ebfb122c613afb886ca8803fa4e128a20a"
[[package]]
name = "objc-sys"
version = "0.3.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cdb91bdd390c7ce1a8607f35f3ca7151b65afc0ff5ff3b34fa350f7d7c7e4310"
[[package]]
name = "objc2"
version = "0.5.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "46a785d4eeff09c14c487497c162e92766fbb3e4059a71840cecc03d9a50b804"
dependencies = [
"objc-sys",
"objc2-encode",
]
[[package]]
name = "objc2-app-kit"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e4e89ad9e3d7d297152b17d39ed92cd50ca8063a89a9fa569046d41568891eff"
dependencies = [
"bitflags",
"block2",
"libc",
"objc2",
"objc2-core-data",
"objc2-core-image",
"objc2-foundation",
"objc2-quartz-core",
]
[[package]]
name = "objc2-core-data"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "617fbf49e071c178c0b24c080767db52958f716d9eabdf0890523aeae54773ef"
dependencies = [
"bitflags",
"block2",
"objc2",
"objc2-foundation",
]
[[package]]
name = "objc2-core-image"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "55260963a527c99f1819c4f8e3b47fe04f9650694ef348ffd2227e8196d34c80"
dependencies = [
"block2",
"objc2",
"objc2-foundation",
"objc2-metal",
]
[[package]]
name = "objc2-encode"
version = "4.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ef25abbcd74fb2609453eb695bd2f860d389e457f67dc17cafc8b8cbc89d0c33"
[[package]]
name = "objc2-foundation"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0ee638a5da3799329310ad4cfa62fbf045d5f56e3ef5ba4149e7452dcf89d5a8"
dependencies = [
"bitflags",
"block2",
"libc",
"objc2",
]
[[package]]
name = "objc2-metal"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dd0cba1276f6023976a406a14ffa85e1fdd19df6b0f737b063b95f6c8c7aadd6"
dependencies = [
"bitflags",
"block2",
"objc2",
"objc2-foundation",
]
[[package]]
name = "objc2-quartz-core"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e42bee7bff906b14b167da2bac5efe6b6a07e6f7c0a21a7308d40c960242dc7a"
dependencies = [
"bitflags",
"block2",
"objc2",
"objc2-foundation",
"objc2-metal",
]

75
vendor/accesskit_macos/Cargo.toml vendored Normal file
View File

@@ -0,0 +1,75 @@
# 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_macos"
version = "0.19.0"
authors = ["The AccessKit contributors"]
build = false
autolib = false
autobins = false
autoexamples = false
autotests = false
autobenches = false
description = "AccessKit UI accessibility infrastructure: macOS adapter"
readme = "README.md"
keywords = [
"gui",
"ui",
"accessibility",
]
categories = ["gui"]
license = "MIT OR Apache-2.0"
repository = "https://github.com/AccessKit/accesskit"
[package.metadata.docs.rs]
default-target = "x86_64-apple-darwin"
[lib]
name = "accesskit_macos"
path = "src/lib.rs"
[dependencies.accesskit]
version = "0.18.0"
[dependencies.accesskit_consumer]
version = "0.27.0"
[dependencies.hashbrown]
version = "0.15"
features = ["default-hasher"]
default-features = false
[dependencies.objc2]
version = "0.5.1"
[dependencies.objc2-app-kit]
version = "0.2.0"
features = [
"NSAccessibility",
"NSAccessibilityConstants",
"NSAccessibilityElement",
"NSAccessibilityProtocols",
"NSResponder",
"NSView",
"NSWindow",
]
[dependencies.objc2-foundation]
version = "0.2.0"
features = [
"NSArray",
"NSDictionary",
"NSValue",
"NSThread",
]

7
vendor/accesskit_macos/README.md vendored Normal file
View File

@@ -0,0 +1,7 @@
# AccessKit macOS adapter
This is the macOS adapter for [AccessKit](https://accesskit.dev/). It exposes an AccessKit accessibility tree through the Cocoa `NSAccessibility` protocol.
## Known issues
- The selected state of ListBox items is not reported ([#520](https://github.com/AccessKit/accesskit/issues/520))

297
vendor/accesskit_macos/src/adapter.rs vendored Normal file
View File

@@ -0,0 +1,297 @@
// Copyright 2022 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 crate::{
context::{ActionHandlerNoMut, ActionHandlerWrapper, Context},
event::{focus_event, EventGenerator, QueuedEvents},
filters::filter,
node::can_be_focused,
util::*,
};
use accesskit::{
ActionHandler, ActionRequest, ActivationHandler, Node as NodeProvider, NodeId, Role,
Tree as TreeData, TreeUpdate,
};
use accesskit_consumer::{FilterResult, Tree};
use objc2::rc::{Id, WeakId};
use objc2_app_kit::NSView;
use objc2_foundation::{MainThreadMarker, NSArray, NSObject, NSPoint};
use std::fmt::{Debug, Formatter};
use std::{ffi::c_void, ptr::null_mut, rc::Rc};
const PLACEHOLDER_ROOT_ID: NodeId = NodeId(0);
enum State {
Inactive {
view: WeakId<NSView>,
is_view_focused: bool,
action_handler: Rc<dyn ActionHandlerNoMut>,
mtm: MainThreadMarker,
},
Placeholder {
placeholder_context: Rc<Context>,
is_view_focused: bool,
action_handler: Rc<dyn ActionHandlerNoMut>,
},
Active(Rc<Context>),
}
impl Debug for State {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
match self {
State::Inactive {
view,
is_view_focused,
action_handler: _,
mtm,
} => f
.debug_struct("Inactive")
.field("view", view)
.field("is_view_focused", is_view_focused)
.field("mtm", mtm)
.finish(),
State::Placeholder {
placeholder_context,
is_view_focused,
action_handler: _,
} => f
.debug_struct("Placeholder")
.field("placeholder_context", placeholder_context)
.field("is_view_focused", is_view_focused)
.finish(),
State::Active(context) => f.debug_struct("Active").field("context", context).finish(),
}
}
}
struct PlaceholderActionHandler;
impl ActionHandler for PlaceholderActionHandler {
fn do_action(&mut self, _request: ActionRequest) {}
}
#[derive(Debug)]
pub struct Adapter {
state: State,
}
impl Adapter {
/// Create a new macOS adapter. This function must be called on
/// the main thread.
///
/// The action handler will always be called on the main thread.
///
/// # Safety
///
/// `view` must be a valid, unreleased pointer to an `NSView`.
pub unsafe fn new(
view: *mut c_void,
is_view_focused: bool,
action_handler: impl 'static + ActionHandler,
) -> Self {
let view = unsafe { Id::retain(view as *mut NSView) }.unwrap();
let view = WeakId::from_id(&view);
let mtm = MainThreadMarker::new().unwrap();
let state = State::Inactive {
view,
is_view_focused,
action_handler: Rc::new(ActionHandlerWrapper::new(action_handler)),
mtm,
};
Self { state }
}
/// If and only if the tree has been initialized, call the provided function
/// and apply the resulting update. Note: If the caller's implementation of
/// [`ActivationHandler::request_initial_tree`] initially returned `None`,
/// the [`TreeUpdate`] returned by the provided function must contain
/// a full tree.
///
/// If a [`QueuedEvents`] instance is returned, the caller must call
/// [`QueuedEvents::raise`] on it.
pub fn update_if_active(
&mut self,
update_factory: impl FnOnce() -> TreeUpdate,
) -> Option<QueuedEvents> {
match &self.state {
State::Inactive { .. } => None,
State::Placeholder {
placeholder_context,
is_view_focused,
action_handler,
} => {
let tree = Tree::new(update_factory(), *is_view_focused);
let context = Context::new(
placeholder_context.view.clone(),
tree,
Rc::clone(action_handler),
placeholder_context.mtm,
);
let result = context
.tree
.borrow()
.state()
.focus_id()
.map(|id| QueuedEvents::new(Rc::clone(&context), vec![focus_event(id)]));
self.state = State::Active(context);
result
}
State::Active(context) => {
let mut event_generator = EventGenerator::new(context.clone());
let mut tree = context.tree.borrow_mut();
tree.update_and_process_changes(update_factory(), &mut event_generator);
Some(event_generator.into_result())
}
}
}
/// Update the tree state based on whether the window is focused.
///
/// If a [`QueuedEvents`] instance is returned, the caller must call
/// [`QueuedEvents::raise`] on it.
pub fn update_view_focus_state(&mut self, is_focused: bool) -> Option<QueuedEvents> {
match &mut self.state {
State::Inactive {
is_view_focused, ..
} => {
*is_view_focused = is_focused;
None
}
State::Placeholder {
is_view_focused, ..
} => {
*is_view_focused = is_focused;
None
}
State::Active(context) => {
let mut event_generator = EventGenerator::new(context.clone());
let mut tree = context.tree.borrow_mut();
tree.update_host_focus_state_and_process_changes(is_focused, &mut event_generator);
Some(event_generator.into_result())
}
}
}
fn get_or_init_context<H: ActivationHandler + ?Sized>(
&mut self,
activation_handler: &mut H,
) -> Rc<Context> {
match &self.state {
State::Inactive {
view,
is_view_focused,
action_handler,
mtm,
} => match activation_handler.request_initial_tree() {
Some(initial_state) => {
let tree = Tree::new(initial_state, *is_view_focused);
let context = Context::new(view.clone(), tree, Rc::clone(action_handler), *mtm);
let result = Rc::clone(&context);
self.state = State::Active(context);
result
}
None => {
let placeholder_update = TreeUpdate {
nodes: vec![(PLACEHOLDER_ROOT_ID, NodeProvider::new(Role::Window))],
tree: Some(TreeData::new(PLACEHOLDER_ROOT_ID)),
focus: PLACEHOLDER_ROOT_ID,
};
let placeholder_tree = Tree::new(placeholder_update, false);
let placeholder_context = Context::new(
view.clone(),
placeholder_tree,
Rc::new(ActionHandlerWrapper::new(PlaceholderActionHandler {})),
*mtm,
);
let result = Rc::clone(&placeholder_context);
self.state = State::Placeholder {
placeholder_context,
is_view_focused: *is_view_focused,
action_handler: Rc::clone(action_handler),
};
result
}
},
State::Placeholder {
placeholder_context,
..
} => Rc::clone(placeholder_context),
State::Active(context) => Rc::clone(context),
}
}
pub fn view_children<H: ActivationHandler + ?Sized>(
&mut self,
activation_handler: &mut H,
) -> *mut NSArray<NSObject> {
let context = self.get_or_init_context(activation_handler);
let tree = context.tree.borrow();
let state = tree.state();
let node = state.root();
let platform_nodes = if filter(&node) == FilterResult::Include {
vec![Id::into_super(Id::into_super(
context.get_or_create_platform_node(node.id()),
))]
} else {
node.filtered_children(filter)
.map(|node| {
Id::into_super(Id::into_super(
context.get_or_create_platform_node(node.id()),
))
})
.collect::<Vec<Id<NSObject>>>()
};
let array = NSArray::from_vec(platform_nodes);
Id::autorelease_return(array)
}
pub fn focus<H: ActivationHandler + ?Sized>(
&mut self,
activation_handler: &mut H,
) -> *mut NSObject {
let context = self.get_or_init_context(activation_handler);
let tree = context.tree.borrow();
let state = tree.state();
if let Some(node) = state.focus() {
if can_be_focused(&node) {
return Id::autorelease_return(context.get_or_create_platform_node(node.id()))
as *mut _;
}
}
null_mut()
}
fn weak_view(&self) -> &WeakId<NSView> {
match &self.state {
State::Inactive { view, .. } => view,
State::Placeholder {
placeholder_context,
..
} => &placeholder_context.view,
State::Active(context) => &context.view,
}
}
pub fn hit_test<H: ActivationHandler + ?Sized>(
&mut self,
point: NSPoint,
activation_handler: &mut H,
) -> *mut NSObject {
let view = match self.weak_view().load() {
Some(view) => view,
None => {
return null_mut();
}
};
let context = self.get_or_init_context(activation_handler);
let tree = context.tree.borrow();
let state = tree.state();
let root = state.root();
let point = from_ns_point(&view, &root, point);
let node = root.node_at_point(point, &filter).unwrap_or(root);
Id::autorelease_return(context.get_or_create_platform_node(node.id())) as *mut _
}
}

103
vendor/accesskit_macos/src/context.rs vendored Normal file
View File

@@ -0,0 +1,103 @@
// Copyright 2022 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 crate::node::PlatformNode;
use accesskit::{ActionHandler, ActionRequest, NodeId};
use accesskit_consumer::Tree;
use hashbrown::HashMap;
use objc2::rc::{Id, WeakId};
use objc2_app_kit::*;
use objc2_foundation::MainThreadMarker;
use std::fmt::Debug;
use std::{cell::RefCell, rc::Rc};
pub(crate) trait ActionHandlerNoMut {
fn do_action(&self, request: ActionRequest);
}
pub(crate) struct ActionHandlerWrapper<H: ActionHandler>(RefCell<H>);
impl<H: 'static + ActionHandler> ActionHandlerWrapper<H> {
pub(crate) fn new(inner: H) -> Self {
Self(RefCell::new(inner))
}
}
impl<H: ActionHandler> ActionHandlerNoMut for ActionHandlerWrapper<H> {
fn do_action(&self, request: ActionRequest) {
self.0.borrow_mut().do_action(request)
}
}
pub(crate) struct Context {
pub(crate) view: WeakId<NSView>,
pub(crate) tree: RefCell<Tree>,
pub(crate) action_handler: Rc<dyn ActionHandlerNoMut>,
platform_nodes: RefCell<HashMap<NodeId, Id<PlatformNode>>>,
pub(crate) mtm: MainThreadMarker,
}
impl Debug for Context {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("Context")
.field("view", &self.view)
.field("tree", &self.tree)
.field("action_handler", &"ActionHandler")
.field("platform_nodes", &self.platform_nodes)
.field("mtm", &self.mtm)
.finish()
}
}
impl Context {
pub(crate) fn new(
view: WeakId<NSView>,
tree: Tree,
action_handler: Rc<dyn ActionHandlerNoMut>,
mtm: MainThreadMarker,
) -> Rc<Self> {
Rc::new(Self {
view,
tree: RefCell::new(tree),
action_handler,
platform_nodes: RefCell::new(HashMap::new()),
mtm,
})
}
pub(crate) fn get_or_create_platform_node(self: &Rc<Self>, id: NodeId) -> Id<PlatformNode> {
let mut platform_nodes = self.platform_nodes.borrow_mut();
if let Some(result) = platform_nodes.get(&id) {
return result.clone();
}
let result = PlatformNode::new(Rc::downgrade(self), id);
platform_nodes.insert(id, result.clone());
result
}
pub(crate) fn remove_platform_node(&self, id: NodeId) -> Option<Id<PlatformNode>> {
let mut platform_nodes = self.platform_nodes.borrow_mut();
platform_nodes.remove(&id)
}
pub(crate) fn do_action(&self, request: ActionRequest) {
self.action_handler.do_action(request);
}
}
impl Drop for Context {
fn drop(&mut self) {
let platform_nodes = self.platform_nodes.borrow();
for platform_node in platform_nodes.values() {
unsafe {
NSAccessibilityPostNotification(
platform_node,
NSAccessibilityUIElementDestroyedNotification,
)
};
}
}
}

298
vendor/accesskit_macos/src/event.rs vendored Normal file
View File

@@ -0,0 +1,298 @@
// Copyright 2022 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::{Live, NodeId, Role};
use accesskit_consumer::{FilterResult, Node, TreeChangeHandler};
use hashbrown::HashSet;
use objc2::runtime::{AnyObject, ProtocolObject};
use objc2_app_kit::*;
use objc2_foundation::{NSMutableDictionary, NSNumber, NSString};
use std::rc::Rc;
use crate::{context::Context, filters::filter, node::NodeWrapper};
// This type is designed to be safe to create on a non-main thread
// and send to the main thread. This ability isn't yet used though.
pub(crate) enum QueuedEvent {
Generic {
node_id: NodeId,
notification: &'static NSAccessibilityNotificationName,
},
NodeDestroyed(NodeId),
Announcement {
text: String,
priority: NSAccessibilityPriorityLevel,
},
}
impl QueuedEvent {
fn live_region_announcement(node: &Node) -> Self {
Self::Announcement {
text: node.value().unwrap(),
priority: if node.live() == Live::Assertive {
NSAccessibilityPriorityLevel::NSAccessibilityPriorityHigh
} else {
NSAccessibilityPriorityLevel::NSAccessibilityPriorityMedium
},
}
}
fn raise(self, context: &Rc<Context>) {
match self {
Self::Generic {
node_id,
notification,
} => {
let platform_node = context.get_or_create_platform_node(node_id);
unsafe { NSAccessibilityPostNotification(&platform_node, notification) };
}
Self::NodeDestroyed(node_id) => {
if let Some(platform_node) = context.remove_platform_node(node_id) {
unsafe {
NSAccessibilityPostNotification(
&platform_node,
NSAccessibilityUIElementDestroyedNotification,
)
};
}
}
Self::Announcement { text, priority } => {
let view = match context.view.load() {
Some(view) => view,
None => {
return;
}
};
let window = match view.window() {
Some(window) => window,
None => {
return;
}
};
let mut user_info = NSMutableDictionary::<_, AnyObject>::new();
let text = NSString::from_str(&text);
unsafe {
user_info.setObject_forKey(
&*text,
ProtocolObject::from_ref(NSAccessibilityAnnouncementKey),
)
};
let priority = NSNumber::new_isize(priority.0);
unsafe {
user_info.setObject_forKey(
&*priority,
ProtocolObject::from_ref(NSAccessibilityPriorityKey),
)
};
unsafe {
NSAccessibilityPostNotificationWithUserInfo(
&window,
NSAccessibilityAnnouncementRequestedNotification,
Some(&**user_info),
)
};
}
}
}
}
/// Events generated by a tree update.
#[must_use = "events must be explicitly raised"]
pub struct QueuedEvents {
context: Rc<Context>,
events: Vec<QueuedEvent>,
}
impl QueuedEvents {
pub(crate) fn new(context: Rc<Context>, events: Vec<QueuedEvent>) -> Self {
Self { context, events }
}
/// Raise all queued events synchronously.
///
/// It is unknown whether accessibility methods on the view may be
/// called while events are being raised. This means that any locks
/// or runtime borrows required to access the adapter must not
/// be held while this method is called.
pub fn raise(self) {
for event in self.events {
event.raise(&self.context);
}
}
}
pub(crate) fn focus_event(node_id: NodeId) -> QueuedEvent {
QueuedEvent::Generic {
node_id,
notification: unsafe { NSAccessibilityFocusedUIElementChangedNotification },
}
}
pub(crate) struct EventGenerator {
context: Rc<Context>,
events: Vec<QueuedEvent>,
text_changed: HashSet<NodeId>,
selected_rows_changed: HashSet<NodeId>,
}
impl EventGenerator {
pub(crate) fn new(context: Rc<Context>) -> Self {
Self {
context,
events: Vec::new(),
text_changed: HashSet::new(),
selected_rows_changed: HashSet::new(),
}
}
pub(crate) fn into_result(self) -> QueuedEvents {
QueuedEvents::new(self.context, self.events)
}
fn insert_text_change_if_needed_parent(&mut self, node: Node) {
if !node.supports_text_ranges() {
return;
}
let id = node.id();
if self.text_changed.contains(&id) {
return;
}
// Text change events must come before selection change
// events. It doesn't matter if text change events come
// before other events.
self.events.insert(
0,
QueuedEvent::Generic {
node_id: id,
notification: unsafe { NSAccessibilityValueChangedNotification },
},
);
self.text_changed.insert(id);
}
fn insert_text_change_if_needed(&mut self, node: &Node) {
if node.role() != Role::TextRun {
return;
}
if let Some(node) = node.filtered_parent(&filter) {
self.insert_text_change_if_needed_parent(node);
}
}
fn enqueue_selected_rows_change_if_needed_parent(&mut self, node: Node) {
if !node.is_container_with_selectable_children() {
return;
}
let id = node.id();
if self.selected_rows_changed.contains(&id) {
return;
}
self.events.push(QueuedEvent::Generic {
node_id: id,
notification: unsafe { NSAccessibilitySelectedRowsChangedNotification },
});
self.selected_rows_changed.insert(id);
}
fn enqueue_selected_rows_change_if_needed(&mut self, node: &Node) {
if !node.is_item_like() {
return;
}
if let Some(node) = node.selection_container(&filter) {
self.enqueue_selected_rows_change_if_needed_parent(node);
}
}
}
impl TreeChangeHandler for EventGenerator {
fn node_added(&mut self, node: &Node) {
self.insert_text_change_if_needed(node);
if filter(node) != FilterResult::Include {
return;
}
if let Some(true) = node.is_selected() {
self.enqueue_selected_rows_change_if_needed(node);
}
if node.value().is_some() && node.live() != Live::Off {
self.events
.push(QueuedEvent::live_region_announcement(node));
}
}
fn node_updated(&mut self, old_node: &Node, new_node: &Node) {
if old_node.raw_value() != new_node.raw_value() {
self.insert_text_change_if_needed(new_node);
}
let old_node_was_filtered_out = filter(old_node) != FilterResult::Include;
if filter(new_node) != FilterResult::Include {
if !old_node_was_filtered_out
&& old_node.is_item_like()
&& old_node.is_selected() == Some(true)
{
self.enqueue_selected_rows_change_if_needed(old_node);
}
return;
}
let node_id = new_node.id();
let old_wrapper = NodeWrapper(old_node);
let new_wrapper = NodeWrapper(new_node);
if old_wrapper.title() != new_wrapper.title() {
self.events.push(QueuedEvent::Generic {
node_id,
notification: unsafe { NSAccessibilityTitleChangedNotification },
});
}
if old_wrapper.value() != new_wrapper.value() {
self.events.push(QueuedEvent::Generic {
node_id,
notification: unsafe { NSAccessibilityValueChangedNotification },
});
}
if old_wrapper.supports_text_ranges()
&& new_wrapper.supports_text_ranges()
&& old_wrapper.raw_text_selection() != new_wrapper.raw_text_selection()
{
self.events.push(QueuedEvent::Generic {
node_id,
notification: unsafe { NSAccessibilitySelectedTextChangedNotification },
});
}
if new_node.value().is_some()
&& new_node.live() != Live::Off
&& (new_node.value() != old_node.value()
|| new_node.live() != old_node.live()
|| old_node_was_filtered_out)
{
self.events
.push(QueuedEvent::live_region_announcement(new_node));
}
if new_node.is_item_like()
&& (new_node.is_selected() != old_node.is_selected()
|| (old_node_was_filtered_out && new_node.is_selected() == Some(true)))
{
self.enqueue_selected_rows_change_if_needed(new_node);
}
}
fn focus_moved(&mut self, _old_node: Option<&Node>, new_node: Option<&Node>) {
if let Some(new_node) = new_node {
if filter(new_node) != FilterResult::Include {
return;
}
self.events.push(focus_event(new_node.id()));
}
}
fn node_removed(&mut self, node: &Node) {
self.insert_text_change_if_needed(node);
if let Some(true) = node.is_selected() {
self.enqueue_selected_rows_change_if_needed(node);
}
self.events.push(QueuedEvent::NodeDestroyed(node.id()));
}
}

6
vendor/accesskit_macos/src/filters.rs vendored Normal file
View File

@@ -0,0 +1,6 @@
// 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.
pub(crate) use accesskit_consumer::common_filter as filter;

25
vendor/accesskit_macos/src/lib.rs vendored Normal file
View File

@@ -0,0 +1,25 @@
// Copyright 2022 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.
#![deny(unsafe_op_in_unsafe_fn)]
mod context;
mod filters;
mod node;
mod util;
mod adapter;
pub use adapter::Adapter;
mod event;
pub use event::QueuedEvents;
mod patch;
pub use patch::add_focus_forwarder_to_window_class;
mod subclass;
pub use subclass::SubclassingAdapter;
pub use objc2_foundation::{NSArray, NSObject, NSPoint};

1015
vendor/accesskit_macos/src/node.rs vendored Normal file

File diff suppressed because it is too large Load Diff

92
vendor/accesskit_macos/src/patch.rs vendored Normal file
View File

@@ -0,0 +1,92 @@
// 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 objc2::{
encode::{Encode, EncodeArguments, EncodeReturn, Encoding},
ffi::class_addMethod,
msg_send,
runtime::{AnyClass, AnyObject, Bool, MethodImplementation, Sel},
sel, Message,
};
use objc2_app_kit::NSWindow;
use std::{ffi::CString, ptr::null_mut};
extern "C" fn focus_forwarder(this: &NSWindow, _cmd: Sel) -> *mut AnyObject {
unsafe {
this.contentView().map_or_else(null_mut, |view| {
msg_send![&*view, accessibilityFocusedUIElement]
})
}
}
/// Modifies the specified class, which must be a subclass of `NSWindow`,
/// to include an `accessibilityFocusedUIElement` method that calls
/// the corresponding method on the window's content view. This is needed
/// for windowing libraries such as SDL that place the keyboard focus
/// directly on the window rather than the content view.
///
/// # Safety
///
/// This function is declared unsafe because the caller must ensure that the
/// code for this crate is never unloaded from the application process,
/// since it's not possible to reverse this operation. It's safest
/// if this crate is statically linked into the application's main executable.
/// Also, this function assumes that the specified class is a subclass
/// of `NSWindow`.
pub unsafe fn add_focus_forwarder_to_window_class(class_name: &str) {
let class = AnyClass::get(class_name).unwrap();
unsafe {
add_method(
class as *const AnyClass as *mut AnyClass,
sel!(accessibilityFocusedUIElement),
focus_forwarder as unsafe extern "C" fn(_, _) -> _,
)
};
}
// The rest of this file is copied from objc2 with only minor adaptations,
// to allow a method to be added to an existing class.
unsafe fn add_method<T, F>(class: *mut AnyClass, sel: Sel, func: F)
where
T: Message + ?Sized,
F: MethodImplementation<Callee = T>,
{
let encs = F::Arguments::ENCODINGS;
let sel_args = count_args(sel);
assert_eq!(
sel_args,
encs.len(),
"Selector {:?} accepts {} arguments, but function accepts {}",
sel,
sel_args,
encs.len(),
);
let types = method_type_encoding(&F::Return::ENCODING_RETURN, encs);
let success = Bool::from_raw(unsafe {
class_addMethod(
class as *mut _,
sel.as_ptr(),
Some(func.__imp()),
types.as_ptr(),
)
});
assert!(success.as_bool(), "Failed to add method {:?}", sel);
}
fn count_args(sel: Sel) -> usize {
sel.name().chars().filter(|&c| c == ':').count()
}
fn method_type_encoding(ret: &Encoding, args: &[Encoding]) -> CString {
// First two arguments are always self and the selector
let mut types = format!("{}{}{}", ret, <*mut AnyObject>::ENCODING, Sel::ENCODING);
for enc in args {
use core::fmt::Write;
write!(&mut types, "{}", enc).unwrap();
}
CString::new(types).unwrap()
}

265
vendor/accesskit_macos/src/subclass.rs vendored Normal file
View File

@@ -0,0 +1,265 @@
// Copyright 2022 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::{ActionHandler, ActivationHandler, TreeUpdate};
use objc2::{
declare::ClassBuilder,
declare_class,
ffi::{
objc_getAssociatedObject, objc_setAssociatedObject, object_setClass,
OBJC_ASSOCIATION_RETAIN_NONATOMIC,
},
msg_send_id,
mutability::InteriorMutable,
rc::Id,
runtime::{AnyClass, Sel},
sel, ClassType, DeclaredClass,
};
use objc2_app_kit::{NSView, NSWindow};
use objc2_foundation::{NSArray, NSObject, NSPoint};
use std::{cell::RefCell, ffi::c_void, sync::Mutex};
use crate::{event::QueuedEvents, Adapter};
static SUBCLASSES: Mutex<Vec<(&'static AnyClass, &'static AnyClass)>> = Mutex::new(Vec::new());
static ASSOCIATED_OBJECT_KEY: u8 = 0;
fn associated_object_key() -> *const c_void {
(&ASSOCIATED_OBJECT_KEY as *const u8).cast()
}
struct AssociatedObjectState {
adapter: Adapter,
activation_handler: Box<dyn ActivationHandler>,
}
struct AssociatedObjectIvars {
state: RefCell<AssociatedObjectState>,
prev_class: &'static AnyClass,
}
declare_class!(
struct AssociatedObject;
unsafe impl ClassType for AssociatedObject {
type Super = NSObject;
type Mutability = InteriorMutable;
const NAME: &'static str = "AccessKitSubclassAssociatedObject";
}
impl DeclaredClass for AssociatedObject {
type Ivars = AssociatedObjectIvars;
}
);
impl AssociatedObject {
fn new(
adapter: Adapter,
activation_handler: impl 'static + ActivationHandler,
prev_class: &'static AnyClass,
) -> Id<Self> {
let state = RefCell::new(AssociatedObjectState {
adapter,
activation_handler: Box::new(activation_handler),
});
let this = Self::alloc().set_ivars(AssociatedObjectIvars { state, prev_class });
unsafe { msg_send_id![super(this), init] }
}
}
fn associated_object(view: &NSView) -> &AssociatedObject {
unsafe {
(objc_getAssociatedObject(view as *const NSView as *const _, associated_object_key())
as *const AssociatedObject)
.as_ref()
}
.unwrap()
}
// Some view classes, like the one in winit 0.27, assume that they are the
// lowest subclass, and call [self superclass] to get their superclass.
// Give them the answer they need.
unsafe extern "C" fn superclass(this: &NSView, _cmd: Sel) -> Option<&AnyClass> {
let associated = associated_object(this);
associated.ivars().prev_class.superclass()
}
unsafe extern "C" fn children(this: &NSView, _cmd: Sel) -> *mut NSArray<NSObject> {
let associated = associated_object(this);
let mut state = associated.ivars().state.borrow_mut();
let state_mut = &mut *state;
state_mut
.adapter
.view_children(&mut *state_mut.activation_handler)
}
unsafe extern "C" fn focus(this: &NSView, _cmd: Sel) -> *mut NSObject {
let associated = associated_object(this);
let mut state = associated.ivars().state.borrow_mut();
let state_mut = &mut *state;
state_mut.adapter.focus(&mut *state_mut.activation_handler)
}
unsafe extern "C" fn hit_test(this: &NSView, _cmd: Sel, point: NSPoint) -> *mut NSObject {
let associated = associated_object(this);
let mut state = associated.ivars().state.borrow_mut();
let state_mut = &mut *state;
state_mut
.adapter
.hit_test(point, &mut *state_mut.activation_handler)
}
/// Uses dynamic Objective-C subclassing to implement the `NSView`
/// accessibility methods when normal subclassing isn't an option.
pub struct SubclassingAdapter {
view: Id<NSView>,
associated: Id<AssociatedObject>,
}
impl SubclassingAdapter {
/// Create an adapter that dynamically subclasses the specified view.
/// This must be done before the view is shown or focused for
/// the first time.
///
/// The action handler will always be called on the main thread.
///
/// # Safety
///
/// `view` must be a valid, unreleased pointer to an `NSView`.
pub unsafe fn new(
view: *mut c_void,
activation_handler: impl 'static + ActivationHandler,
action_handler: impl 'static + ActionHandler,
) -> Self {
let view = view as *mut NSView;
let retained_view = unsafe { Id::retain(view) }.unwrap();
Self::new_internal(retained_view, activation_handler, action_handler)
}
fn new_internal(
retained_view: Id<NSView>,
activation_handler: impl 'static + ActivationHandler,
action_handler: impl 'static + ActionHandler,
) -> Self {
let view = Id::as_ptr(&retained_view) as *mut NSView;
let adapter = unsafe { Adapter::new(view as *mut c_void, false, action_handler) };
// Cast to a pointer and back to force the lifetime to 'static
// SAFETY: We know the class will live as long as the instance,
// and we only use this reference while the instance is alive.
let prev_class = unsafe { &*((*view).class() as *const AnyClass) };
let associated = AssociatedObject::new(adapter, activation_handler, prev_class);
unsafe {
objc_setAssociatedObject(
view as *mut _,
associated_object_key(),
Id::as_ptr(&associated) as *mut _,
OBJC_ASSOCIATION_RETAIN_NONATOMIC,
)
};
let mut subclasses = SUBCLASSES.lock().unwrap();
let subclass = match subclasses.iter().find(|entry| entry.0 == prev_class) {
Some(entry) => entry.1,
None => {
let name = format!("AccessKitSubclassOf{}", prev_class.name());
let mut builder = ClassBuilder::new(&name, prev_class).unwrap();
unsafe {
builder.add_method(
sel!(superclass),
superclass as unsafe extern "C" fn(_, _) -> _,
);
builder.add_method(
sel!(accessibilityChildren),
children as unsafe extern "C" fn(_, _) -> _,
);
builder.add_method(
sel!(accessibilityFocusedUIElement),
focus as unsafe extern "C" fn(_, _) -> _,
);
builder.add_method(
sel!(accessibilityHitTest:),
hit_test as unsafe extern "C" fn(_, _, _) -> _,
);
}
let class = builder.register();
subclasses.push((prev_class, class));
class
}
};
// SAFETY: Changing the view's class is only safe because
// the subclass doesn't add any instance variables;
// it uses an associated object instead.
unsafe { object_setClass(view as *mut _, (subclass as *const AnyClass).cast()) };
Self {
view: retained_view,
associated,
}
}
/// Create an adapter that dynamically subclasses the content view
/// of the specified window.
///
/// The action handler will always be called on the main thread.
///
/// # Safety
///
/// `window` must be a valid, unreleased pointer to an `NSWindow`.
///
/// # Panics
///
/// This function panics if the specified window doesn't currently have
/// a content view.
pub unsafe fn for_window(
window: *mut c_void,
activation_handler: impl 'static + ActivationHandler,
action_handler: impl 'static + ActionHandler,
) -> Self {
let window = unsafe { &*(window as *const NSWindow) };
let retained_view = window.contentView().unwrap();
Self::new_internal(retained_view, activation_handler, action_handler)
}
/// If and only if the tree has been initialized, call the provided function
/// and apply the resulting update. Note: If the caller's implementation of
/// [`ActivationHandler::request_initial_tree`] initially returned `None`,
/// the [`TreeUpdate`] returned by the provided function must contain
/// a full tree.
///
/// If a [`QueuedEvents`] instance is returned, the caller must call
/// [`QueuedEvents::raise`] on it.
pub fn update_if_active(
&mut self,
update_factory: impl FnOnce() -> TreeUpdate,
) -> Option<QueuedEvents> {
let mut state = self.associated.ivars().state.borrow_mut();
state.adapter.update_if_active(update_factory)
}
/// Update the tree state based on whether the window is focused.
///
/// If a [`QueuedEvents`] instance is returned, the caller must call
/// [`QueuedEvents::raise`] on it.
pub fn update_view_focus_state(&mut self, is_focused: bool) -> Option<QueuedEvents> {
let mut state = self.associated.ivars().state.borrow_mut();
state.adapter.update_view_focus_state(is_focused)
}
}
impl Drop for SubclassingAdapter {
fn drop(&mut self) {
let prev_class = self.associated.ivars().prev_class;
let view = Id::as_ptr(&self.view) as *mut NSView;
unsafe { object_setClass(view as *mut _, (prev_class as *const AnyClass).cast()) };
unsafe {
objc_setAssociatedObject(
view as *mut _,
associated_object_key(),
std::ptr::null_mut(),
OBJC_ASSOCIATION_RETAIN_NONATOMIC,
)
};
}
}

79
vendor/accesskit_macos/src/util.rs vendored Normal file
View File

@@ -0,0 +1,79 @@
// Copyright 2022 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::{Point, Rect};
use accesskit_consumer::{Node, TextPosition, TextRange};
use objc2_app_kit::*;
use objc2_foundation::{NSPoint, NSRange, NSRect, NSSize};
pub(crate) fn from_ns_range<'a>(node: &'a Node<'a>, ns_range: NSRange) -> Option<TextRange<'a>> {
let pos = node.text_position_from_global_utf16_index(ns_range.location)?;
let mut range = pos.to_degenerate_range();
if ns_range.length > 0 {
let end =
node.text_position_from_global_utf16_index(ns_range.location + ns_range.length)?;
range.set_end(end);
}
Some(range)
}
pub(crate) fn to_ns_range(range: &TextRange) -> NSRange {
let start = range.start().to_global_utf16_index();
let end = range.end().to_global_utf16_index();
NSRange::from(start..end)
}
pub(crate) fn to_ns_range_for_character(pos: &TextPosition) -> NSRange {
let mut range = pos.to_degenerate_range();
if !pos.is_document_end() {
range.set_end(pos.forward_to_character_end());
}
to_ns_range(&range)
}
pub(crate) fn from_ns_point(view: &NSView, node: &Node, point: NSPoint) -> Point {
let window = view.window().unwrap();
let point = window.convertPointFromScreen(point);
let point = view.convertPoint_fromView(point, None);
// AccessKit coordinates are in physical (DPI-dependent) pixels, but
// macOS provides logical (DPI-independent) coordinates here.
let factor = window.backingScaleFactor();
let point = Point::new(
point.x * factor,
if view.isFlipped() {
point.y * factor
} else {
let view_bounds = view.bounds();
(view_bounds.size.height - point.y) * factor
},
);
node.transform().inverse() * point
}
pub(crate) fn to_ns_rect(view: &NSView, rect: Rect) -> NSRect {
let window = view.window().unwrap();
// AccessKit coordinates are in physical (DPI-dependent)
// pixels, but macOS expects logical (DPI-independent)
// coordinates here.
let factor = window.backingScaleFactor();
let rect = NSRect {
origin: NSPoint {
x: rect.x0 / factor,
y: if view.isFlipped() {
rect.y0 / factor
} else {
let view_bounds = view.bounds();
view_bounds.size.height - rect.y1 / factor
},
},
size: NSSize {
width: rect.width() / factor,
height: rect.height() / factor,
},
};
let rect = view.convertRect_toView(rect, None);
let window = view.window().unwrap();
window.convertRectToScreen(rect)
}

View File

@@ -0,0 +1 @@
{"files":{"CHANGELOG.md":"0041b4977724b159f2881822289458d62fce06963c40d16cb3cc1df62789c1bd","Cargo.lock":"f22006defac528b51eac5a7c7b0b01a078a6c96fabe468dd0fd37d1ba0b8d885","Cargo.toml":"c7abed6dc05dc4c1ed37448bc36ee9804993aa6823398038c8a605a6e5e95259","README.md":"622db8e92d711b64279a91e25ae9345959c82bb4d47157dbf5c3a6a53f80f6d6","examples/hello_world.rs":"590657e2d6ad3c8d96a5a258651bcb1402346ecc13c7ebf3c95b9306f49546b8","src/adapter.rs":"88879ce53c38d60597b648aa7ba2d717eeea51591e6bb4aef15d75ddb08215e8","src/context.rs":"8a45005a8c1449e4ed234bb6f041f026f2dbc6d2935e76407637adb1c127601c","src/filters.rs":"744374b547065b153123c80028f129f5c6bb53052660205e1a2f231c3e169f64","src/lib.rs":"8a6f20ed5354c9834d88a59091c764f65aa31359f81c57386fe06e9d806e9396","src/node.rs":"6f80380f4b347ea068cebc2272772ae32d8dc2cef384676c95848867ecdc907e","src/subclass.rs":"bc103a11203177cfe64f98a3ea64e2d80e34fc2da3d24344863fa6c09d80a435","src/tests/mod.rs":"72229fa5e2d94ee7ac09719e3fc4d4cd9e6d9456cc10ef5fe628e1b804815674","src/tests/simple.rs":"9ad0c8b85921620d5ccb7e83b1d90a6c9d565925dda6d9d4fcae2afdfc17b252","src/tests/subclassed.rs":"bcf410cd35d058908fe37d9d84588bfe1eec699dffbcaf5a9db86be3861de400","src/text.rs":"da038079c4912b22333c3abcf606e4dafb6ae150d2f0e1554ff2f8e4b326c2eb","src/util.rs":"5652f87597342ddf898a967a1759d460650c25bff0015908f2f57c18db4adbfd","src/window_handle.rs":"dec1d78c81784a18c50f066e89d57d0fe02a7c9199a11e47a0833f8b9113d8c2"},"package":"65178f3df98a51e4238e584fcb255cb1a4f9111820848eeddd37663be40a625f"}

751
vendor/accesskit_windows/CHANGELOG.md vendored Normal file
View File

@@ -0,0 +1,751 @@
# Changelog
* The following workspace dependencies were updated
* dependencies
* accesskit bumped from 0.8.0 to 0.8.1
* accesskit_consumer bumped from 0.9.1 to 0.10.0
* The following workspace dependencies were updated
* dependencies
* accesskit_consumer bumped from 0.11.0 to 0.12.0
* The following workspace dependencies were updated
* dependencies
* accesskit_consumer bumped from 0.12.0 to 0.12.1
* The following workspace dependencies were updated
* dependencies
* accesskit bumped from 0.10.1 to 0.11.0
* accesskit_consumer bumped from 0.14.1 to 0.14.2
* The following workspace dependencies were updated
* dependencies
* accesskit bumped from 0.11.0 to 0.11.1
* accesskit_consumer bumped from 0.15.0 to 0.15.1
* The following workspace dependencies were updated
* dependencies
* accesskit bumped from 0.11.1 to 0.11.2
* accesskit_consumer bumped from 0.15.1 to 0.15.2
* The following workspace dependencies were updated
* dependencies
* accesskit bumped from 0.12.2 to 0.12.3
* accesskit_consumer bumped from 0.17.0 to 0.17.1
* The following workspace dependencies were updated
* dependencies
* accesskit bumped from 0.16.2 to 0.16.3
* accesskit_consumer bumped from 0.24.2 to 0.24.3
## [0.25.0](https://github.com/AccessKit/accesskit/compare/accesskit_windows-v0.24.1...accesskit_windows-v0.25.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
* Expose the `is_required` property ([#497](https://github.com/AccessKit/accesskit/issues/497)) ([46ed99b](https://github.com/AccessKit/accesskit/commit/46ed99bb958ddb32cbf1bee2fcfb7b328bcbe0ab))
### Bug Fixes
* Add list box support to the platform adapters ([6c622cf](https://github.com/AccessKit/accesskit/commit/6c622cff4c0c989d9a5f16b775adff9cdacf534c))
* Derive `Debug` for adapters ([#513](https://github.com/AccessKit/accesskit/issues/513)) ([753d904](https://github.com/AccessKit/accesskit/commit/753d90473cf57682568c7a17c82474c8e5d00b25))
* Expose password input fields on Windows ([#516](https://github.com/AccessKit/accesskit/issues/516)) ([19514da](https://github.com/AccessKit/accesskit/commit/19514dabc40bcfc01bee1b1efa77355ec5b0822b))
* Fix some clippy warnings ([#509](https://github.com/AccessKit/accesskit/issues/509)) ([579b9c1](https://github.com/AccessKit/accesskit/commit/579b9c12dd8abc44ecab41fa3c326a1d8999871d))
* Optimize dynamic string building ([#491](https://github.com/AccessKit/accesskit/issues/491)) ([a86901d](https://github.com/AccessKit/accesskit/commit/a86901ddea5d5ba72ab237e98b53d6adcc6087bb))
* 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
* accesskit_consumer bumped from 0.26.0 to 0.27.0
## [0.24.1](https://github.com/AccessKit/accesskit/compare/accesskit_windows-v0.24.0...accesskit_windows-v0.24.1) (2024-11-23)
### Bug Fixes
* Optimize use of hash tables in platform adapters ([#485](https://github.com/AccessKit/accesskit/issues/485)) ([f4f0bfb](https://github.com/AccessKit/accesskit/commit/f4f0bfbf21b8e22e80ab07deb432f9e7e16469ab))
* Tell docs.rs to only build accesskit_windows on Windows ([#483](https://github.com/AccessKit/accesskit/issues/483)) ([1fead29](https://github.com/AccessKit/accesskit/commit/1fead296ed012f83afb482021051ccc1d4946167))
### Dependencies
* The following workspace dependencies were updated
* dependencies
* accesskit bumped from 0.17.0 to 0.17.1
* accesskit_consumer bumped from 0.25.0 to 0.26.0
## [0.24.0](https://github.com/AccessKit/accesskit/compare/accesskit_windows-v0.23.2...accesskit_windows-v0.24.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
* accesskit_consumer bumped from 0.24.3 to 0.25.0
## [0.23.1](https://github.com/AccessKit/accesskit/compare/accesskit_windows-v0.23.0...accesskit_windows-v0.23.1) (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
* accesskit_consumer bumped from 0.24.1 to 0.24.2
## [0.23.0](https://github.com/AccessKit/accesskit/compare/accesskit_windows-v0.22.0...accesskit_windows-v0.23.0) (2024-09-24)
### ⚠ BREAKING CHANGES
* Update windows to 0.58 on accesskit_windows ([#453](https://github.com/AccessKit/accesskit/issues/453))
### Bug Fixes
* Update windows to 0.58 on accesskit_windows ([#453](https://github.com/AccessKit/accesskit/issues/453)) ([cda35e7](https://github.com/AccessKit/accesskit/commit/cda35e77a78f72386c2bfd88e9fd29000106f7e6))
* Use the new HWND type on accesskit_winit ([#453](https://github.com/AccessKit/accesskit/issues/453)) ([68a2462](https://github.com/AccessKit/accesskit/commit/68a24629381f0b18f6ed1ee008fe72ce9330092e))
### Dependencies
* The following workspace dependencies were updated
* dependencies
* accesskit bumped from 0.16.0 to 0.16.1
* accesskit_consumer bumped from 0.24.0 to 0.24.1
## [0.22.0](https://github.com/AccessKit/accesskit/compare/accesskit_windows-v0.21.0...accesskit_windows-v0.22.0) (2024-06-29)
### ⚠ BREAKING CHANGES
* Rename the `StaticText` role to `Label` ([#434](https://github.com/AccessKit/accesskit/issues/434))
### 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
* accesskit_consumer bumped from 0.23.0 to 0.24.0
## [0.21.0](https://github.com/AccessKit/accesskit/compare/accesskit_windows-v0.20.0...accesskit_windows-v0.21.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))
### Dependencies
* The following workspace dependencies were updated
* dependencies
* accesskit bumped from 0.14.0 to 0.15.0
* accesskit_consumer bumped from 0.22.0 to 0.23.0
## [0.20.0](https://github.com/AccessKit/accesskit/compare/accesskit_windows-v0.19.0...accesskit_windows-v0.20.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))
### Dependencies
* The following workspace dependencies were updated
* dependencies
* accesskit_consumer bumped from 0.21.0 to 0.22.0
## [0.19.0](https://github.com/AccessKit/accesskit/compare/accesskit_windows-v0.18.2...accesskit_windows-v0.19.0) (2024-05-26)
### Features
* Expose the `placeholder` property ([#417](https://github.com/AccessKit/accesskit/issues/417)) ([8f4a0a1](https://github.com/AccessKit/accesskit/commit/8f4a0a1c10f83fcc8580a37d8013fec2d110865b))
### Dependencies
* The following workspace dependencies were updated
* dependencies
* accesskit_consumer bumped from 0.20.0 to 0.21.0
## [0.18.2](https://github.com/AccessKit/accesskit/compare/accesskit_windows-v0.18.1...accesskit_windows-v0.18.2) (2024-05-13)
### Bug Fixes
* Fix platform adapters to support copy-on-write tree snapshots again ([#411](https://github.com/AccessKit/accesskit/issues/411)) ([d3a130a](https://github.com/AccessKit/accesskit/commit/d3a130a5ec8ae1d9edf0bf85a44f35f0e365242c))
### Dependencies
* The following workspace dependencies were updated
* dependencies
* accesskit_consumer bumped from 0.19.1 to 0.20.0
## [0.18.1](https://github.com/AccessKit/accesskit/compare/accesskit_windows-v0.18.0...accesskit_windows-v0.18.1) (2024-05-11)
### Bug Fixes
* Make the transition from placeholder to real tree more robust ([#405](https://github.com/AccessKit/accesskit/issues/405)) ([928e11d](https://github.com/AccessKit/accesskit/commit/928e11d00e7c60b3cafcc0ac623f6377b36f7ea7))
### Dependencies
* The following workspace dependencies were updated
* dependencies
* accesskit_consumer bumped from 0.19.0 to 0.19.1
## [0.18.0](https://github.com/AccessKit/accesskit/compare/accesskit_windows-v0.17.0...accesskit_windows-v0.18.0) (2024-04-30)
### ⚠ BREAKING CHANGES
* Update winit to 0.30 ([#397](https://github.com/AccessKit/accesskit/issues/397))
* Clean up table roles and properties ([#393](https://github.com/AccessKit/accesskit/issues/393))
* 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))
* Update winit to 0.30 ([#397](https://github.com/AccessKit/accesskit/issues/397)) ([de93be3](https://github.com/AccessKit/accesskit/commit/de93be387c03a438fbf598670207e578686e6bcf))
### Code Refactoring
* Clean up table roles and properties ([#393](https://github.com/AccessKit/accesskit/issues/393)) ([e34dad9](https://github.com/AccessKit/accesskit/commit/e34dad94448a5321ece9def3f2e054aa5f62dd79))
* 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
* accesskit_consumer bumped from 0.18.0 to 0.19.0
## [0.17.0](https://github.com/AccessKit/accesskit/compare/accesskit_windows-v0.16.4...accesskit_windows-v0.17.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
* accesskit_consumer bumped from 0.17.1 to 0.18.0
## [0.16.4](https://github.com/AccessKit/accesskit/compare/accesskit_windows-v0.16.3...accesskit_windows-v0.16.4) (2024-03-18)
### Bug Fixes
* Update `windows` to `0.54` ([#373](https://github.com/AccessKit/accesskit/issues/373)) ([50f112f](https://github.com/AccessKit/accesskit/commit/50f112f0085a03f0180f86915d2ac4e5845f6b63))
## [0.16.2](https://github.com/AccessKit/accesskit/compare/accesskit_windows-v0.16.1...accesskit_windows-v0.16.2) (2024-02-25)
### Bug Fixes
* Bump windows-rs dependency to 0.52 ([#359](https://github.com/AccessKit/accesskit/issues/359)) ([69d74f6](https://github.com/AccessKit/accesskit/commit/69d74f6947922b76d4aee683eb53d8fbdd2259f2))
## [0.16.1](https://github.com/AccessKit/accesskit/compare/accesskit_windows-v0.16.0...accesskit_windows-v0.16.1) (2024-02-24)
### Bug Fixes
* Avoid `unnecessary_literal_unwrap` clippy lint ([#346](https://github.com/AccessKit/accesskit/issues/346)) ([59a6eae](https://github.com/AccessKit/accesskit/commit/59a6eae40ba35069b90d4cc0b765d838f8477c66))
## [0.16.0](https://github.com/AccessKit/accesskit/compare/accesskit_windows-v0.15.1...accesskit_windows-v0.16.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
* accesskit_consumer bumped from 0.16.1 to 0.17.0
## [0.15.1](https://github.com/AccessKit/accesskit/compare/accesskit_windows-v0.15.0...accesskit_windows-v0.15.1) (2023-11-04)
### Bug Fixes
* Make the test focus event handler thread-safe again ([#306](https://github.com/AccessKit/accesskit/issues/306)) ([bb479c6](https://github.com/AccessKit/accesskit/commit/bb479c69bddff77a1102549a7ff6ea5c7155d90d))
* Make the Windows subclassing test more robust ([#308](https://github.com/AccessKit/accesskit/issues/308)) ([0078f79](https://github.com/AccessKit/accesskit/commit/0078f7997f11a3bb1f3c33dc7a91f427b1a60db8))
### Dependencies
* The following workspace dependencies were updated
* dependencies
* accesskit bumped from 0.12.0 to 0.12.1
* accesskit_consumer bumped from 0.16.0 to 0.16.1
## [0.15.0](https://github.com/AccessKit/accesskit/compare/accesskit_windows-v0.14.3...accesskit_windows-v0.15.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))
* Make `ActionHandler::do_action` take `&mut self` ([#296](https://github.com/AccessKit/accesskit/issues/296))
* Clean up roles and properties ([#289](https://github.com/AccessKit/accesskit/issues/289))
* 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
* 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))
* Make `ActionHandler::do_action` take `&mut self` ([#296](https://github.com/AccessKit/accesskit/issues/296)) ([4fc7846](https://github.com/AccessKit/accesskit/commit/4fc7846d732d61fb45c023060ebab96801a0053e))
* 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
* accesskit_consumer bumped from 0.15.2 to 0.16.0
## [0.14.3](https://github.com/AccessKit/accesskit/compare/accesskit_windows-v0.14.2...accesskit_windows-v0.14.3) (2023-08-08)
### Bug Fixes
* Update windows crate to v0.48 ([#257](https://github.com/AccessKit/accesskit/issues/257)) ([cc703ed](https://github.com/AccessKit/accesskit/commit/cc703ed33d535aa1803e423a53beff9354b5b0df))
## [0.14.0](https://github.com/AccessKit/accesskit/compare/accesskit_windows-v0.13.3...accesskit_windows-v0.14.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))
### Dependencies
* The following workspace dependencies were updated
* dependencies
* accesskit_consumer bumped from 0.14.2 to 0.15.0
## [0.13.2](https://github.com/AccessKit/accesskit/compare/accesskit_windows-v0.13.1...accesskit_windows-v0.13.2) (2023-02-23)
### Bug Fixes
* Fix Windows 32-bit build errors ([#223](https://github.com/AccessKit/accesskit/issues/223)) ([41f28b6](https://github.com/AccessKit/accesskit/commit/41f28b670ac457b2d067bbc4ba40aa0fc8842e4d))
## [0.13.1](https://github.com/AccessKit/accesskit/compare/accesskit_windows-v0.13.0...accesskit_windows-v0.13.1) (2023-02-20)
### Bug Fixes
* Update windows-rs to 0.44 ([#220](https://github.com/AccessKit/accesskit/issues/220)) ([a6b0a12](https://github.com/AccessKit/accesskit/commit/a6b0a124e7511e37760d769b517fd5fc9050160b))
### Dependencies
* The following workspace dependencies were updated
* dependencies
* accesskit bumped from 0.10.0 to 0.10.1
* accesskit_consumer bumped from 0.14.0 to 0.14.1
## [0.13.0](https://github.com/AccessKit/accesskit/compare/accesskit_windows-v0.12.0...accesskit_windows-v0.13.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
* accesskit_consumer bumped from 0.13.0 to 0.14.0
## [0.12.0](https://github.com/AccessKit/accesskit/compare/accesskit_windows-v0.11.0...accesskit_windows-v0.12.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
* accesskit_consumer bumped from 0.12.1 to 0.13.0
## [0.11.0](https://github.com/AccessKit/accesskit/compare/accesskit_windows-v0.10.4...accesskit_windows-v0.11.0) (2023-02-02)
### ⚠ BREAKING CHANGES
* Update winit to 0.28 ([#207](https://github.com/AccessKit/accesskit/issues/207))
### Miscellaneous Chores
* Update winit to 0.28 ([#207](https://github.com/AccessKit/accesskit/issues/207)) ([3ff0cf5](https://github.com/AccessKit/accesskit/commit/3ff0cf59f982af504499142a3804f7aeeb4defe0))
## [0.10.2](https://github.com/AccessKit/accesskit/compare/accesskit_windows-v0.10.1...accesskit_windows-v0.10.2) (2022-12-17)
### Bug Fixes
* Correct broken UIA method implementation that was incompatible with Windows 11 ATs ([#193](https://github.com/AccessKit/accesskit/issues/193)) ([3c527c7](https://github.com/AccessKit/accesskit/commit/3c527c76cb4139402d2b5550d2eb1ad12e07ebe5))
* 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))
* Provide fallback property implementations for the window root ([#194](https://github.com/AccessKit/accesskit/issues/194)) ([f3d30b9](https://github.com/AccessKit/accesskit/commit/f3d30b9ba2f66e08fb7f78c304ab8a9e83e1aeca))
### Dependencies
* The following workspace dependencies were updated
* dependencies
* accesskit_consumer bumped from 0.10.0 to 0.11.0
## [0.10.0](https://github.com/AccessKit/accesskit/compare/accesskit_windows-v0.9.3...accesskit_windows-v0.10.0) (2022-11-29)
### ⚠ BREAKING CHANGES
* Move lazy initialization from the core platform adapter to the caller ([#179](https://github.com/AccessKit/accesskit/issues/179))
### Code Refactoring
* Move lazy initialization from the core platform adapter to the caller ([#179](https://github.com/AccessKit/accesskit/issues/179)) ([f35c941](https://github.com/AccessKit/accesskit/commit/f35c941f395f3162db376a69cfaaaf770d376267))
### [0.9.3](https://www.github.com/AccessKit/accesskit/compare/accesskit_windows-v0.9.2...accesskit_windows-v0.9.3) (2022-11-25)
### Bug Fixes
* 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))
* **platforms/windows:** Change default minimum and maximum for range value pattern ([#166](https://www.github.com/AccessKit/accesskit/issues/166)) ([176ec58](https://www.github.com/AccessKit/accesskit/commit/176ec5853ca127b1e12f9a992b75478177a4acce))
### Dependencies
* The following workspace dependencies were updated
* dependencies
* accesskit_consumer bumped from 0.9.0 to 0.9.1
### [0.9.2](https://www.github.com/AccessKit/accesskit/compare/accesskit_windows-v0.9.1...accesskit_windows-v0.9.2) (2022-11-24)
### Bug Fixes
* **platforms/windows:** Re-export more types from windows-rs ([#162](https://www.github.com/AccessKit/accesskit/issues/162)) ([eed692b](https://www.github.com/AccessKit/accesskit/commit/eed692b27407e1ddd5f200464f0e2d52a272b958))
### [0.9.1](https://www.github.com/AccessKit/accesskit/compare/accesskit_windows-v0.9.0...accesskit_windows-v0.9.1) (2022-11-23)
### Bug Fixes
* **platforms/windows:** Re-export the windows-rs HWND type ([#159](https://www.github.com/AccessKit/accesskit/issues/159)) ([389187a](https://www.github.com/AccessKit/accesskit/commit/389187ac5e96895ed1763d14d315d2f8f4256460))
### Dependencies
* The following workspace dependencies were updated
* dependencies
* accesskit_consumer bumped from 0.8.0 to 0.9.0
## [0.9.0](https://www.github.com/AccessKit/accesskit/compare/accesskit_windows-v0.8.0...accesskit_windows-v0.9.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
* accesskit_consumer bumped from 0.7.1 to 0.8.0
## [0.8.0](https://www.github.com/AccessKit/accesskit/compare/accesskit_windows-v0.7.0...accesskit_windows-v0.8.0) (2022-11-12)
### ⚠ BREAKING CHANGES
* **platforms/windows:** Update to windows-rs 0.42.0 (#148)
### 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))
* **platforms/windows:** Update to windows-rs 0.42.0 ([#148](https://www.github.com/AccessKit/accesskit/issues/148)) ([70d1a89](https://www.github.com/AccessKit/accesskit/commit/70d1a89f51fd6c3a32b7192d9d7f3937db09d196))
### Dependencies
* The following workspace dependencies were updated
* dependencies
* accesskit_consumer bumped from 0.7.0 to 0.7.1
## [0.7.0](https://www.github.com/AccessKit/accesskit/compare/accesskit_windows-v0.6.1...accesskit_windows-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
* accesskit_consumer bumped from 0.6.1 to 0.7.0
### [0.6.1](https://www.github.com/AccessKit/accesskit/compare/accesskit_windows-v0.6.0...accesskit_windows-v0.6.1) (2022-10-10)
### Dependencies
* The following workspace dependencies were updated
* dependencies
* accesskit bumped from 0.6.0 to 0.6.1
* accesskit_consumer bumped from 0.6.0 to 0.6.1
## [0.6.0](https://www.github.com/AccessKit/accesskit/compare/accesskit_windows-v0.5.1...accesskit_windows-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)
### 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
* accesskit_consumer bumped from 0.5.1 to 0.6.0
### [0.5.1](https://www.github.com/AccessKit/accesskit/compare/accesskit_windows-v0.5.0...accesskit_windows-v0.5.1) (2022-10-03)
### Dependencies
* The following workspace dependencies were updated
* dependencies
* accesskit bumped from 0.5.0 to 0.5.1
* accesskit_consumer bumped from 0.5.0 to 0.5.1
## [0.5.0](https://www.github.com/AccessKit/accesskit/compare/accesskit_windows-v0.4.0...accesskit_windows-v0.5.0) (2022-09-23)
### ⚠ BREAKING CHANGES
* Basic live regions (#128)
* **platforms/windows:** Bump windows-rs dependency (#126)
### Features
* Basic live regions ([#128](https://www.github.com/AccessKit/accesskit/issues/128)) ([03d745b](https://www.github.com/AccessKit/accesskit/commit/03d745b891147175bde2693cc10b96a2f6e31f39))
### Miscellaneous Chores
* **platforms/windows:** Bump windows-rs dependency ([#126](https://www.github.com/AccessKit/accesskit/issues/126)) ([472a75e](https://www.github.com/AccessKit/accesskit/commit/472a75e4214b90396f3282f247df08100ed8362d))
### Dependencies
* The following workspace dependencies were updated
* dependencies
* accesskit bumped from 0.4.0 to 0.5.0
* accesskit_consumer bumped from 0.4.0 to 0.5.0
## [0.4.0](https://www.github.com/AccessKit/accesskit/compare/accesskit_windows-v0.3.0...accesskit_windows-v0.4.0) (2022-07-22)
### ⚠ BREAKING CHANGES
* String indices are always in UTF-8 code units (#114)
* **platforms/windows:** Refactor window subclassing to avoid lifetime issue (#120)
* **platforms/windows:** Simplify the adapter API by always boxing the tree source (#119)
* Drop unused tree IDs (#113)
* **platforms/windows:** Migrate to windows-rs 0.37 (#109)
* Switch to NonZeroU128 for NodeIDs (#99)
### Features
* **platforms/windows:** Win32 subclassing support ([#118](https://www.github.com/AccessKit/accesskit/issues/118)) ([60c69b7](https://www.github.com/AccessKit/accesskit/commit/60c69b7b8a18ca8db62a84495b9e71a6e8140204))
* **platforms/winit:** New winit adapter ([#121](https://www.github.com/AccessKit/accesskit/issues/121)) ([fdc274e](https://www.github.com/AccessKit/accesskit/commit/fdc274e7d3a901873d2ad0c7a4824a19111787ef))
### 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))
* **platforms/windows:** Print usage text to the terminal from the Windows example ([#103](https://www.github.com/AccessKit/accesskit/issues/103)) ([7fba3ce](https://www.github.com/AccessKit/accesskit/commit/7fba3ce55345d7787f08d2ae60d841dd13b27693))
* **platforms/windows:** Restore the optimization of the FragmentRoot method ([#116](https://www.github.com/AccessKit/accesskit/issues/116)) ([d48c31b](https://www.github.com/AccessKit/accesskit/commit/d48c31b41f35baebe59bb654b38dd48265062b14))
* Switch to NonZeroU128 for NodeIDs ([#99](https://www.github.com/AccessKit/accesskit/issues/99)) ([25a1a52](https://www.github.com/AccessKit/accesskit/commit/25a1a52c4562b163bfcc8c625a233c00a41aacf2))
### Miscellaneous Chores
* **platforms/windows:** Migrate to windows-rs 0.37 ([#109](https://www.github.com/AccessKit/accesskit/issues/109)) ([1065e11](https://www.github.com/AccessKit/accesskit/commit/1065e11421176a8abc37ef579cb47d973c968462))
### Code Refactoring
* Drop unused tree IDs ([#113](https://www.github.com/AccessKit/accesskit/issues/113)) ([ca60770](https://www.github.com/AccessKit/accesskit/commit/ca607702cee13c93fe538d2faec88e474261f7ab))
* **platforms/windows:** Refactor window subclassing to avoid lifetime issue ([#120](https://www.github.com/AccessKit/accesskit/issues/120)) ([37579aa](https://www.github.com/AccessKit/accesskit/commit/37579aa8dd0c019ffaf4eac1b0bf1f7a8c719323))
* **platforms/windows:** Simplify the adapter API by always boxing the tree source ([#119](https://www.github.com/AccessKit/accesskit/issues/119)) ([27d5c78](https://www.github.com/AccessKit/accesskit/commit/27d5c78afa0f8d1ae3b626265da8bccd3e5b09d1))
* 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
* accesskit_consumer bumped from 0.3.0 to 0.4.0
## [0.3.0](https://www.github.com/AccessKit/accesskit/compare/accesskit_windows-v0.2.0...accesskit_windows-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
* accesskit_consumer bumped from 0.2.0 to 0.3.0

1843
vendor/accesskit_windows/Cargo.lock generated vendored Normal file

File diff suppressed because it is too large Load Diff

89
vendor/accesskit_windows/Cargo.toml vendored Normal file
View File

@@ -0,0 +1,89 @@
# 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_windows"
version = "0.25.0"
authors = ["The AccessKit contributors"]
build = false
autolib = false
autobins = false
autoexamples = false
autotests = false
autobenches = false
description = "AccessKit UI accessibility infrastructure: Windows adapter"
readme = "README.md"
keywords = [
"gui",
"ui",
"accessibility",
]
categories = ["gui"]
license = "MIT OR Apache-2.0"
repository = "https://github.com/AccessKit/accesskit"
[package.metadata.docs.rs]
default-target = "x86_64-pc-windows-msvc"
targets = []
[lib]
name = "accesskit_windows"
path = "src/lib.rs"
[[example]]
name = "hello_world"
path = "examples/hello_world.rs"
[dependencies.accesskit]
version = "0.18.0"
[dependencies.accesskit_consumer]
version = "0.27.0"
[dependencies.hashbrown]
version = "0.15"
features = ["default-hasher"]
default-features = false
[dependencies.paste]
version = "1.0"
[dependencies.static_assertions]
version = "1.1.0"
[dependencies.windows]
version = "0.58.0"
features = [
"implement",
"Win32_Foundation",
"Win32_Graphics_Gdi",
"Win32_System_Com",
"Win32_System_LibraryLoader",
"Win32_System_Ole",
"Win32_System_Variant",
"Win32_UI_Accessibility",
"Win32_UI_Input_KeyboardAndMouse",
"Win32_UI_WindowsAndMessaging",
]
[dependencies.windows-core]
version = "0.58.0"
[dev-dependencies.once_cell]
version = "1.13.0"
[dev-dependencies.scopeguard]
version = "1.1.0"
[dev-dependencies.winit]
version = "0.30"

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

@@ -0,0 +1,3 @@
# AccessKit Windows adapter
This is the Windows adapter for [AccessKit](https://accesskit.dev/). It exposes an AccessKit accessibility tree through the UI Automation API.

View File

@@ -0,0 +1,364 @@
// Based on the create_window sample in windows-samples-rs.
use accesskit::{
Action, ActionHandler, ActionRequest, ActivationHandler, Live, Node, NodeId, Rect, Role, Tree,
TreeUpdate,
};
use accesskit_windows::Adapter;
use once_cell::sync::Lazy;
use std::cell::RefCell;
use windows::{
core::*,
Win32::{
Foundation::*,
Graphics::Gdi::ValidateRect,
System::LibraryLoader::GetModuleHandleW,
UI::{Input::KeyboardAndMouse::*, WindowsAndMessaging::*},
},
};
static WINDOW_CLASS_ATOM: Lazy<u16> = Lazy::new(|| {
let class_name = w!("AccessKitTest");
let wc = WNDCLASSW {
hCursor: unsafe { LoadCursorW(None, IDC_ARROW) }.unwrap(),
hInstance: unsafe { GetModuleHandleW(None) }.unwrap().into(),
lpszClassName: class_name,
style: CS_HREDRAW | CS_VREDRAW,
lpfnWndProc: Some(wndproc),
..Default::default()
};
let atom = unsafe { RegisterClassW(&wc) };
if atom == 0 {
panic!("{}", Error::from_win32());
}
atom
});
const WINDOW_TITLE: &str = "Hello world";
const WINDOW_ID: NodeId = NodeId(0);
const BUTTON_1_ID: NodeId = NodeId(1);
const BUTTON_2_ID: NodeId = NodeId(2);
const ANNOUNCEMENT_ID: NodeId = NodeId(3);
const INITIAL_FOCUS: NodeId = BUTTON_1_ID;
const BUTTON_1_RECT: Rect = Rect {
x0: 20.0,
y0: 20.0,
x1: 100.0,
y1: 60.0,
};
const BUTTON_2_RECT: Rect = Rect {
x0: 20.0,
y0: 60.0,
x1: 100.0,
y1: 100.0,
};
const SET_FOCUS_MSG: u32 = WM_USER;
const CLICK_MSG: u32 = WM_USER + 1;
fn build_button(id: NodeId, label: &str) -> Node {
let rect = match id {
BUTTON_1_ID => BUTTON_1_RECT,
BUTTON_2_ID => BUTTON_2_RECT,
_ => unreachable!(),
};
let mut node = Node::new(Role::Button);
node.set_bounds(rect);
node.set_label(label);
node.add_action(Action::Focus);
node.add_action(Action::Click);
node
}
fn build_announcement(text: &str) -> Node {
let mut node = Node::new(Role::Label);
node.set_value(text);
node.set_live(Live::Polite);
node
}
struct InnerWindowState {
focus: NodeId,
announcement: Option<String>,
}
impl InnerWindowState {
fn build_root(&mut self) -> Node {
let mut node = Node::new(Role::Window);
node.set_children(vec![BUTTON_1_ID, BUTTON_2_ID]);
if self.announcement.is_some() {
node.push_child(ANNOUNCEMENT_ID);
}
node
}
}
impl ActivationHandler for InnerWindowState {
fn request_initial_tree(&mut self) -> Option<TreeUpdate> {
println!("Initial tree requested");
let root = self.build_root();
let button_1 = build_button(BUTTON_1_ID, "Button 1");
let button_2 = build_button(BUTTON_2_ID, "Button 2");
let tree = Tree::new(WINDOW_ID);
let mut result = TreeUpdate {
nodes: vec![
(WINDOW_ID, root),
(BUTTON_1_ID, button_1),
(BUTTON_2_ID, button_2),
],
tree: Some(tree),
focus: self.focus,
};
if let Some(announcement) = &self.announcement {
result
.nodes
.push((ANNOUNCEMENT_ID, build_announcement(announcement)));
}
Some(result)
}
}
struct WindowState {
adapter: RefCell<Adapter>,
inner_state: RefCell<InnerWindowState>,
}
impl WindowState {
fn set_focus(&self, focus: NodeId) {
self.inner_state.borrow_mut().focus = focus;
let mut adapter = self.adapter.borrow_mut();
if let Some(events) = adapter.update_if_active(|| TreeUpdate {
nodes: vec![],
tree: None,
focus,
}) {
drop(adapter);
events.raise();
}
}
fn press_button(&self, id: NodeId) {
let mut inner_state = self.inner_state.borrow_mut();
let text = if id == BUTTON_1_ID {
"You pressed button 1"
} else {
"You pressed button 2"
};
inner_state.announcement = Some(text.into());
let mut adapter = self.adapter.borrow_mut();
if let Some(events) = adapter.update_if_active(|| {
let announcement = build_announcement(text);
let root = inner_state.build_root();
TreeUpdate {
nodes: vec![(ANNOUNCEMENT_ID, announcement), (WINDOW_ID, root)],
tree: None,
focus: inner_state.focus,
}
}) {
drop(adapter);
drop(inner_state);
events.raise();
}
}
}
unsafe fn get_window_state(window: HWND) -> *const WindowState {
GetWindowLongPtrW(window, GWLP_USERDATA) as _
}
fn update_window_focus_state(window: HWND, is_focused: bool) {
let state = unsafe { &*get_window_state(window) };
let mut adapter = state.adapter.borrow_mut();
if let Some(events) = adapter.update_window_focus_state(is_focused) {
drop(adapter);
events.raise();
}
}
struct WindowCreateParams(NodeId);
struct SimpleActionHandler {
window: HWND,
}
unsafe impl Send for SimpleActionHandler {}
unsafe impl Sync for SimpleActionHandler {}
impl ActionHandler for SimpleActionHandler {
fn do_action(&mut self, request: ActionRequest) {
match request.action {
Action::Focus => {
unsafe {
PostMessageW(
self.window,
SET_FOCUS_MSG,
WPARAM(0),
LPARAM(request.target.0 as _),
)
}
.unwrap();
}
Action::Click => {
unsafe {
PostMessageW(
self.window,
CLICK_MSG,
WPARAM(0),
LPARAM(request.target.0 as _),
)
}
.unwrap();
}
_ => (),
}
}
}
extern "system" fn wndproc(window: HWND, message: u32, wparam: WPARAM, lparam: LPARAM) -> LRESULT {
match message {
WM_NCCREATE => {
let create_struct: &CREATESTRUCTW = unsafe { &mut *(lparam.0 as *mut _) };
let create_params: Box<WindowCreateParams> =
unsafe { Box::from_raw(create_struct.lpCreateParams as _) };
let WindowCreateParams(initial_focus) = *create_params;
let inner_state = RefCell::new(InnerWindowState {
focus: initial_focus,
announcement: None,
});
let adapter = Adapter::new(window, false, SimpleActionHandler { window });
let state = Box::new(WindowState {
adapter: RefCell::new(adapter),
inner_state,
});
unsafe { SetWindowLongPtrW(window, GWLP_USERDATA, Box::into_raw(state) as _) };
unsafe { DefWindowProcW(window, message, wparam, lparam) }
}
WM_PAINT => {
unsafe { ValidateRect(window, None) }.unwrap();
LRESULT(0)
}
WM_DESTROY => {
let ptr = unsafe { SetWindowLongPtrW(window, GWLP_USERDATA, 0) };
if ptr != 0 {
drop(unsafe { Box::<WindowState>::from_raw(ptr as _) });
}
unsafe { PostQuitMessage(0) };
LRESULT(0)
}
WM_GETOBJECT => {
let state_ptr = unsafe { get_window_state(window) };
if state_ptr.is_null() {
// We need to be prepared to gracefully handle WM_GETOBJECT
// while the window is being destroyed; this can happen if
// the thread is using a COM STA.
return unsafe { DefWindowProcW(window, message, wparam, lparam) };
}
let state = unsafe { &*state_ptr };
let mut adapter = state.adapter.borrow_mut();
let mut inner_state = state.inner_state.borrow_mut();
let result = adapter.handle_wm_getobject(wparam, lparam, &mut *inner_state);
drop(inner_state);
drop(adapter);
result.map_or_else(
|| unsafe { DefWindowProcW(window, message, wparam, lparam) },
|result| result.into(),
)
}
WM_SETFOCUS | WM_EXITMENULOOP | WM_EXITSIZEMOVE => {
update_window_focus_state(window, true);
LRESULT(0)
}
WM_KILLFOCUS | WM_ENTERMENULOOP | WM_ENTERSIZEMOVE => {
update_window_focus_state(window, false);
LRESULT(0)
}
WM_KEYDOWN => match VIRTUAL_KEY(wparam.0 as u16) {
VK_TAB => {
let state = unsafe { &*get_window_state(window) };
let old_focus = state.inner_state.borrow().focus;
let new_focus = if old_focus == BUTTON_1_ID {
BUTTON_2_ID
} else {
BUTTON_1_ID
};
state.set_focus(new_focus);
LRESULT(0)
}
VK_SPACE => {
let state = unsafe { &*get_window_state(window) };
let id = state.inner_state.borrow().focus;
state.press_button(id);
LRESULT(0)
}
_ => unsafe { DefWindowProcW(window, message, wparam, lparam) },
},
SET_FOCUS_MSG => {
let id = NodeId(lparam.0 as _);
if id == BUTTON_1_ID || id == BUTTON_2_ID {
let state = unsafe { &*get_window_state(window) };
state.set_focus(id);
}
LRESULT(0)
}
CLICK_MSG => {
let id = NodeId(lparam.0 as _);
if id == BUTTON_1_ID || id == BUTTON_2_ID {
let state = unsafe { &*get_window_state(window) };
state.press_button(id);
}
LRESULT(0)
}
_ => unsafe { DefWindowProcW(window, message, wparam, lparam) },
}
}
fn create_window(title: &str, initial_focus: NodeId) -> Result<HWND> {
let create_params = Box::new(WindowCreateParams(initial_focus));
let window = unsafe {
CreateWindowExW(
Default::default(),
PCWSTR(*WINDOW_CLASS_ATOM as usize as _),
&HSTRING::from(title),
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
None,
None,
GetModuleHandleW(None).unwrap(),
Some(Box::into_raw(create_params) as _),
)?
};
if window.is_invalid() {
return Err(Error::from_win32());
}
Ok(window)
}
fn main() -> Result<()> {
println!("This example has no visible GUI, and a keyboard interface:");
println!("- [Tab] switches focus between two logical buttons.");
println!("- [Space] 'presses' the button, adding static text in a live region announcing that it was pressed.");
println!("Enable Narrator with [Win]+[Ctrl]+[Enter] (or [Win]+[Enter] on older versions of Windows).");
let window = create_window(WINDOW_TITLE, INITIAL_FOCUS)?;
let _ = unsafe { ShowWindow(window, SW_SHOW) };
let mut message = MSG::default();
while unsafe { GetMessageW(&mut message, HWND::default(), 0, 0) }.into() {
let _ = unsafe { TranslateMessage(&message) };
unsafe { DispatchMessageW(&message) };
}
Ok(())
}

587
vendor/accesskit_windows/src/adapter.rs vendored Normal file
View File

@@ -0,0 +1,587 @@
// Copyright 2022 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::{
ActionHandler, ActivationHandler, Live, Node as NodeProvider, NodeId, Role, Tree as TreeData,
TreeUpdate,
};
use accesskit_consumer::{FilterResult, Node, Tree, TreeChangeHandler};
use hashbrown::{HashMap, HashSet};
use std::fmt::{Debug, Formatter};
use std::sync::{atomic::Ordering, Arc};
use windows::Win32::{
Foundation::*,
UI::{Accessibility::*, WindowsAndMessaging::*},
};
use crate::{
context::{ActionHandlerNoMut, ActionHandlerWrapper, Context},
filters::filter,
node::{NodeWrapper, PlatformNode},
util::QueuedEvent,
window_handle::WindowHandle,
};
fn focus_event(context: &Arc<Context>, node_id: NodeId) -> QueuedEvent {
let platform_node = PlatformNode::new(context, node_id);
let element: IRawElementProviderSimple = platform_node.into();
QueuedEvent::Simple {
element,
event_id: UIA_AutomationFocusChangedEventId,
}
}
struct AdapterChangeHandler<'a> {
context: &'a Arc<Context>,
queue: Vec<QueuedEvent>,
text_changed: HashSet<NodeId>,
selection_changed: HashMap<NodeId, SelectionChanges>,
}
impl<'a> AdapterChangeHandler<'a> {
fn new(context: &'a Arc<Context>) -> Self {
Self {
context,
queue: Vec::new(),
text_changed: HashSet::new(),
selection_changed: HashMap::new(),
}
}
}
impl AdapterChangeHandler<'_> {
fn insert_text_change_if_needed_parent(&mut self, node: Node) {
if !node.supports_text_ranges() {
return;
}
let id = node.id();
if self.text_changed.contains(&id) {
return;
}
let platform_node = PlatformNode::new(self.context, node.id());
let element: IRawElementProviderSimple = platform_node.into();
// Text change events must come before selection change
// events. It doesn't matter if text change events come
// before other events.
self.queue.insert(
0,
QueuedEvent::Simple {
element,
event_id: UIA_Text_TextChangedEventId,
},
);
self.text_changed.insert(id);
}
fn insert_text_change_if_needed(&mut self, node: &Node) {
if node.role() != Role::TextRun {
return;
}
if let Some(node) = node.filtered_parent(&filter) {
self.insert_text_change_if_needed_parent(node);
}
}
fn handle_selection_state_change(&mut self, node: &Node, is_selected: bool) {
// If `node` belongs to a selection container, then map the events with the
// selection container as the key because |FinalizeSelectionEvents| needs to
// determine whether or not there is only one element selected in order to
// optimize what platform events are sent.
let key = if let Some(container) = node.selection_container(&filter) {
container.id()
} else {
node.id()
};
let changes = self
.selection_changed
.entry(key)
.or_insert_with(|| SelectionChanges {
added_items: HashSet::new(),
removed_items: HashSet::new(),
});
if is_selected {
changes.added_items.insert(node.id());
} else {
changes.removed_items.insert(node.id());
}
}
fn enqueue_selection_changes(&mut self, tree: &Tree) {
let tree_state = tree.state();
for (id, changes) in self.selection_changed.iter() {
let Some(node) = tree_state.node_by_id(*id) else {
continue;
};
// Determine if `node` is a selection container with one selected child in
// order to optimize what platform events are sent.
let mut container = None;
let mut only_selected_child = None;
if node.is_container_with_selectable_children() {
container = Some(node);
for child in node.filtered_children(filter) {
if let Some(true) = child.is_selected() {
if only_selected_child.is_none() {
only_selected_child = Some(child);
} else {
only_selected_child = None;
break;
}
}
}
}
if let Some(only_selected_child) = only_selected_child {
self.queue.push(QueuedEvent::Simple {
element: PlatformNode::new(self.context, only_selected_child.id()).into(),
event_id: UIA_SelectionItem_ElementSelectedEventId,
});
self.queue.push(QueuedEvent::PropertyChanged {
element: PlatformNode::new(self.context, only_selected_child.id()).into(),
property_id: UIA_SelectionItemIsSelectedPropertyId,
old_value: false.into(),
new_value: true.into(),
});
for child_id in changes.removed_items.iter() {
let platform_node = PlatformNode::new(self.context, *child_id);
self.queue.push(QueuedEvent::PropertyChanged {
element: platform_node.into(),
property_id: UIA_SelectionItemIsSelectedPropertyId,
old_value: true.into(),
new_value: false.into(),
});
}
} else {
// Per UIA documentation, beyond the "invalidate limit" we're supposed to
// fire a 'SelectionInvalidated' event. The exact value isn't specified,
// but System.Windows.Automation.Provider uses a value of 20.
const INVALIDATE_LIMIT: usize = 20;
if let Some(container) = container.filter(|_| {
changes.added_items.len() + changes.removed_items.len() > INVALIDATE_LIMIT
}) {
let platform_node = PlatformNode::new(self.context, container.id());
self.queue.push(QueuedEvent::Simple {
element: platform_node.into(),
event_id: UIA_Selection_InvalidatedEventId,
});
} else {
let container_is_multiselectable =
container.is_some_and(|c| c.is_multiselectable());
for added_id in changes.added_items.iter() {
self.queue.push(QueuedEvent::Simple {
element: PlatformNode::new(self.context, *added_id).into(),
event_id: match container_is_multiselectable {
true => UIA_SelectionItem_ElementAddedToSelectionEventId,
false => UIA_SelectionItem_ElementSelectedEventId,
},
});
self.queue.push(QueuedEvent::PropertyChanged {
element: PlatformNode::new(self.context, *added_id).into(),
property_id: UIA_SelectionItemIsSelectedPropertyId,
old_value: false.into(),
new_value: true.into(),
});
}
for removed_id in changes.removed_items.iter() {
self.queue.push(QueuedEvent::Simple {
element: PlatformNode::new(self.context, *removed_id).into(),
event_id: UIA_SelectionItem_ElementRemovedFromSelectionEventId,
});
self.queue.push(QueuedEvent::PropertyChanged {
element: PlatformNode::new(self.context, *removed_id).into(),
property_id: UIA_SelectionItemIsSelectedPropertyId,
old_value: true.into(),
new_value: false.into(),
});
}
}
}
}
}
}
struct SelectionChanges {
added_items: HashSet<NodeId>,
removed_items: HashSet<NodeId>,
}
impl TreeChangeHandler for AdapterChangeHandler<'_> {
fn node_added(&mut self, node: &Node) {
self.insert_text_change_if_needed(node);
if filter(node) != FilterResult::Include {
return;
}
let wrapper = NodeWrapper(node);
if wrapper.name().is_some() && node.live() != Live::Off {
let platform_node = PlatformNode::new(self.context, node.id());
let element: IRawElementProviderSimple = platform_node.into();
self.queue.push(QueuedEvent::Simple {
element,
event_id: UIA_LiveRegionChangedEventId,
});
}
if wrapper.is_selection_item_pattern_supported() && wrapper.is_selected() {
self.handle_selection_state_change(node, true);
}
}
fn node_updated(&mut self, old_node: &Node, new_node: &Node) {
if old_node.raw_value() != new_node.raw_value() {
self.insert_text_change_if_needed(new_node);
}
let old_node_was_filtered_out = filter(old_node) != FilterResult::Include;
if filter(new_node) != FilterResult::Include {
if !old_node_was_filtered_out {
let old_wrapper = NodeWrapper(old_node);
if old_wrapper.is_selection_item_pattern_supported() && old_wrapper.is_selected() {
self.handle_selection_state_change(old_node, false);
}
}
return;
}
let platform_node = PlatformNode::new(self.context, new_node.id());
let element: IRawElementProviderSimple = platform_node.into();
let old_wrapper = NodeWrapper(old_node);
let new_wrapper = NodeWrapper(new_node);
new_wrapper.enqueue_property_changes(&mut self.queue, &element, &old_wrapper);
let new_name = new_wrapper.name();
if new_name.is_some()
&& new_node.live() != Live::Off
&& (new_node.live() != old_node.live()
|| old_node_was_filtered_out
|| new_name != old_wrapper.name())
{
self.queue.push(QueuedEvent::Simple {
element,
event_id: UIA_LiveRegionChangedEventId,
});
}
if new_wrapper.is_selection_item_pattern_supported()
&& (new_wrapper.is_selected() != old_wrapper.is_selected()
|| (old_node_was_filtered_out && new_wrapper.is_selected()))
{
self.handle_selection_state_change(new_node, new_wrapper.is_selected());
}
}
fn focus_moved(&mut self, _old_node: Option<&Node>, new_node: Option<&Node>) {
if let Some(new_node) = new_node {
self.queue.push(focus_event(self.context, new_node.id()));
}
}
fn node_removed(&mut self, node: &Node) {
self.insert_text_change_if_needed(node);
if filter(node) != FilterResult::Include {
return;
}
let wrapper = NodeWrapper(node);
if wrapper.is_selection_item_pattern_supported() {
self.handle_selection_state_change(node, false);
}
}
// TODO: handle other events (#20)
}
const PLACEHOLDER_ROOT_ID: NodeId = NodeId(0);
enum State {
Inactive {
hwnd: WindowHandle,
is_window_focused: bool,
action_handler: Arc<dyn ActionHandlerNoMut + Send + Sync>,
},
Placeholder(Arc<Context>),
Active(Arc<Context>),
}
impl Debug for State {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
match self {
State::Inactive {
hwnd,
is_window_focused,
action_handler: _,
} => f
.debug_struct("Inactive")
.field("hwnd", hwnd)
.field("is_window_focused", is_window_focused)
.field("action_handler", &"ActionHandler")
.finish(),
State::Placeholder(context) => f.debug_tuple("Placeholder").field(context).finish(),
State::Active(context) => f.debug_tuple("Active").field(context).finish(),
}
}
}
#[derive(Debug)]
pub struct Adapter {
state: State,
}
impl Adapter {
/// Creates a new Windows platform adapter.
///
/// The action handler may or may not be called on the thread that owns
/// the window.
///
/// This must not be called while handling the `WM_GETOBJECT` message,
/// because this function must initialize UI Automation before
/// that message is handled. This is necessary to prevent a race condition
/// that leads to nested `WM_GETOBJECT` messages and, in some cases,
/// assistive technologies not realizing that the window natively implements.
/// UIA. See [AccessKit issue #37](https://github.com/AccessKit/accesskit/issues/37)
/// for more details.
pub fn new(
hwnd: HWND,
is_window_focused: bool,
action_handler: impl 'static + ActionHandler + Send,
) -> Self {
Self::with_wrapped_action_handler(
hwnd,
is_window_focused,
Arc::new(ActionHandlerWrapper::new(action_handler)),
)
}
// Currently required by the test infrastructure
pub(crate) fn with_wrapped_action_handler(
hwnd: HWND,
is_window_focused: bool,
action_handler: Arc<dyn ActionHandlerNoMut + Send + Sync>,
) -> Self {
init_uia();
let state = State::Inactive {
hwnd: hwnd.into(),
is_window_focused,
action_handler,
};
Self { state }
}
/// If and only if the tree has been initialized, call the provided function
/// and apply the resulting update. Note: If the caller's implementation of
/// [`ActivationHandler::request_initial_tree`] initially returned `None`,
/// the [`TreeUpdate`] returned by the provided function must contain
/// a full tree.
///
/// If a [`QueuedEvents`] instance is returned, the caller must call
/// [`QueuedEvents::raise`] on it.
///
/// This method may be safely called on any thread, but refer to
/// [`QueuedEvents::raise`] for restrictions on the context in which
/// it should be called.
pub fn update_if_active(
&mut self,
update_factory: impl FnOnce() -> TreeUpdate,
) -> Option<QueuedEvents> {
match &self.state {
State::Inactive { .. } => None,
State::Placeholder(context) => {
let is_window_focused = context.read_tree().state().is_host_focused();
let tree = Tree::new(update_factory(), is_window_focused);
*context.tree.write().unwrap() = tree;
context.is_placeholder.store(false, Ordering::SeqCst);
let result = context
.read_tree()
.state()
.focus_id()
.map(|id| QueuedEvents(vec![focus_event(context, id)]));
self.state = State::Active(Arc::clone(context));
result
}
State::Active(context) => {
let mut handler = AdapterChangeHandler::new(context);
let mut tree = context.tree.write().unwrap();
tree.update_and_process_changes(update_factory(), &mut handler);
handler.enqueue_selection_changes(&tree);
Some(QueuedEvents(handler.queue))
}
}
}
/// Update the tree state based on whether the window is focused.
///
/// If a [`QueuedEvents`] instance is returned, the caller must call
/// [`QueuedEvents::raise`] on it.
///
/// This method may be safely called on any thread, but refer to
/// [`QueuedEvents::raise`] for restrictions on the context in which
/// it should be called.
pub fn update_window_focus_state(&mut self, is_focused: bool) -> Option<QueuedEvents> {
match &mut self.state {
State::Inactive {
is_window_focused, ..
} => {
*is_window_focused = is_focused;
None
}
State::Placeholder(context) => {
let mut handler = AdapterChangeHandler::new(context);
let mut tree = context.tree.write().unwrap();
tree.update_host_focus_state_and_process_changes(is_focused, &mut handler);
Some(QueuedEvents(handler.queue))
}
State::Active(context) => {
let mut handler = AdapterChangeHandler::new(context);
let mut tree = context.tree.write().unwrap();
tree.update_host_focus_state_and_process_changes(is_focused, &mut handler);
Some(QueuedEvents(handler.queue))
}
}
}
/// Handle the `WM_GETOBJECT` window message. The accessibility tree
/// is lazily initialized if necessary using the provided
/// [`ActivationHandler`] implementation.
///
/// This returns an `Option` so the caller can pass the message
/// to `DefWindowProc` if AccessKit decides not to handle it.
/// The optional value is an `Into<LRESULT>` rather than simply an `LRESULT`
/// so the necessary call to UIA, which may lead to a nested `WM_GETOBJECT`
/// message, can be done outside of any lock that the caller might hold
/// on the `Adapter` or window state, while still abstracting away
/// the details of that call to UIA.
pub fn handle_wm_getobject<H: ActivationHandler + ?Sized>(
&mut self,
wparam: WPARAM,
lparam: LPARAM,
activation_handler: &mut H,
) -> Option<impl Into<LRESULT>> {
// Don't bother with MSAA object IDs that are asking for something other
// than the client area of the window. DefWindowProc can handle those.
// First, cast the lparam to i32, to handle inconsistent conversion
// behavior in senders.
let objid = normalize_objid(lparam);
if objid < 0 && objid != UiaRootObjectId && objid != OBJID_CLIENT.0 {
return None;
}
let (hwnd, platform_node) = match &self.state {
State::Inactive {
hwnd,
is_window_focused,
action_handler,
} => match activation_handler.request_initial_tree() {
Some(initial_state) => {
let hwnd = *hwnd;
let tree = Tree::new(initial_state, *is_window_focused);
let context = Context::new(hwnd, tree, Arc::clone(action_handler), false);
let node_id = context.read_tree().state().root_id();
let platform_node = PlatformNode::new(&context, node_id);
self.state = State::Active(context);
(hwnd, platform_node)
}
None => {
let hwnd = *hwnd;
let placeholder_update = TreeUpdate {
nodes: vec![(PLACEHOLDER_ROOT_ID, NodeProvider::new(Role::Window))],
tree: Some(TreeData::new(PLACEHOLDER_ROOT_ID)),
focus: PLACEHOLDER_ROOT_ID,
};
let placeholder_tree = Tree::new(placeholder_update, *is_window_focused);
let context =
Context::new(hwnd, placeholder_tree, Arc::clone(action_handler), true);
let platform_node = PlatformNode::unspecified_root(&context);
self.state = State::Placeholder(context);
(hwnd, platform_node)
}
},
State::Placeholder(context) => (context.hwnd, PlatformNode::unspecified_root(context)),
State::Active(context) => {
let node_id = context.read_tree().state().root_id();
(context.hwnd, PlatformNode::new(context, node_id))
}
};
let el: IRawElementProviderSimple = platform_node.into();
Some(WmGetObjectResult {
hwnd,
wparam,
lparam,
el,
})
}
}
fn init_uia() {
// `UiaLookupId` is a cheap way of forcing UIA to initialize itself.
unsafe {
UiaLookupId(
AutomationIdentifierType_Property,
&ControlType_Property_GUID,
)
};
}
#[cfg(any(target_arch = "x86_64", target_arch = "aarch64"))]
fn normalize_objid(lparam: LPARAM) -> i32 {
(lparam.0 & 0xFFFFFFFF) as _
}
#[cfg(not(any(target_arch = "x86_64", target_arch = "aarch64")))]
fn normalize_objid(lparam: LPARAM) -> i32 {
lparam.0 as _
}
struct WmGetObjectResult {
hwnd: WindowHandle,
wparam: WPARAM,
lparam: LPARAM,
el: IRawElementProviderSimple,
}
impl From<WmGetObjectResult> for LRESULT {
fn from(this: WmGetObjectResult) -> Self {
unsafe { UiaReturnRawElementProvider(this.hwnd.0, this.wparam, this.lparam, &this.el) }
}
}
/// Events generated by a tree update.
#[must_use = "events must be explicitly raised"]
pub struct QueuedEvents(Vec<QueuedEvent>);
impl QueuedEvents {
/// Raise all queued events synchronously.
///
/// The window may receive `WM_GETOBJECT` messages during this call.
/// This means that any locks required by the `WM_GETOBJECT` handler
/// must not be held when this method is called.
///
/// This method should be called on the thread that owns the window.
/// It's not clear whether this is a strict requirement of UIA itself,
/// but based on the known behavior of UIA, MSAA, and some ATs,
/// it's strongly recommended.
pub fn raise(self) {
for event in self.0 {
match event {
QueuedEvent::Simple { element, event_id } => {
unsafe { UiaRaiseAutomationEvent(&element, event_id) }.unwrap();
}
QueuedEvent::PropertyChanged {
element,
property_id,
old_value,
new_value,
} => {
unsafe {
UiaRaiseAutomationPropertyChangedEvent(
&element,
property_id,
&old_value,
&new_value,
)
}
.unwrap();
}
}
}
}
}
// We explicitly want to allow the queued events to be sent to the UI thread,
// so implement Send even though windows-rs doesn't implement it for all
// contained types. This is safe because we're not using COM threading.
unsafe impl Send for QueuedEvents {}

75
vendor/accesskit_windows/src/context.rs vendored Normal file
View File

@@ -0,0 +1,75 @@
// 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::{ActionHandler, ActionRequest, Point};
use accesskit_consumer::Tree;
use std::fmt::{Debug, Formatter};
use std::sync::{atomic::AtomicBool, Arc, Mutex, RwLock, RwLockReadGuard};
use crate::{util::*, window_handle::WindowHandle};
pub(crate) trait ActionHandlerNoMut {
fn do_action(&self, request: ActionRequest);
}
pub(crate) struct ActionHandlerWrapper<H: ActionHandler + Send>(Mutex<H>);
impl<H: 'static + ActionHandler + Send> ActionHandlerWrapper<H> {
pub(crate) fn new(inner: H) -> Self {
Self(Mutex::new(inner))
}
}
impl<H: ActionHandler + Send> ActionHandlerNoMut for ActionHandlerWrapper<H> {
fn do_action(&self, request: ActionRequest) {
self.0.lock().unwrap().do_action(request)
}
}
pub(crate) struct Context {
pub(crate) hwnd: WindowHandle,
pub(crate) tree: RwLock<Tree>,
pub(crate) action_handler: Arc<dyn ActionHandlerNoMut + Send + Sync>,
pub(crate) is_placeholder: AtomicBool,
}
impl Debug for Context {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
f.debug_struct("Context")
.field("hwnd", &self.hwnd)
.field("tree", &self.tree)
.field("action_handler", &"ActionHandler")
.field("is_placeholder", &self.is_placeholder)
.finish()
}
}
impl Context {
pub(crate) fn new(
hwnd: WindowHandle,
tree: Tree,
action_handler: Arc<dyn ActionHandlerNoMut + Send + Sync>,
is_placeholder: bool,
) -> Arc<Self> {
Arc::new(Self {
hwnd,
tree: RwLock::new(tree),
action_handler,
is_placeholder: AtomicBool::new(is_placeholder),
})
}
pub(crate) fn read_tree(&self) -> RwLockReadGuard<'_, Tree> {
self.tree.read().unwrap()
}
pub(crate) fn client_top_left(&self) -> Point {
client_top_left(self.hwnd)
}
pub(crate) fn do_action(&self, request: ActionRequest) {
self.action_handler.do_action(request);
}
}

View File

@@ -0,0 +1,8 @@
// 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.
pub(crate) use accesskit_consumer::{
common_filter as filter, common_filter_with_root_exception as filter_with_root_exception,
};

22
vendor/accesskit_windows/src/lib.rs vendored Normal file
View File

@@ -0,0 +1,22 @@
// 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.
mod context;
mod filters;
mod node;
mod text;
mod util;
mod window_handle;
mod adapter;
pub use adapter::{Adapter, QueuedEvents};
mod subclass;
pub use subclass::SubclassingAdapter;
pub use windows::Win32::Foundation::{HWND, LPARAM, LRESULT, WPARAM};
#[cfg(test)]
mod tests;

1079
vendor/accesskit_windows/src/node.rs vendored Normal file

File diff suppressed because it is too large Load Diff

188
vendor/accesskit_windows/src/subclass.rs vendored Normal file
View File

@@ -0,0 +1,188 @@
// Copyright 2022 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::{ActionHandler, ActivationHandler, TreeUpdate};
use std::{
cell::{Cell, RefCell},
ffi::c_void,
mem::transmute,
};
use windows::{
core::*,
Win32::{Foundation::*, UI::WindowsAndMessaging::*},
};
use crate::{Adapter, QueuedEvents};
fn win32_error() -> ! {
panic!("{}", Error::from_win32())
}
// Work around a difference between the SetWindowLongPtrW API definition
// in windows-rs on 32-bit and 64-bit Windows.
#[cfg(any(target_arch = "x86_64", target_arch = "aarch64"))]
type LongPtr = isize;
#[cfg(not(any(target_arch = "x86_64", target_arch = "aarch64")))]
type LongPtr = i32;
const PROP_NAME: PCWSTR = w!("AccessKitAdapter");
struct SubclassState {
adapter: Adapter,
activation_handler: Box<dyn ActivationHandler>,
}
struct SubclassImpl {
hwnd: HWND,
state: RefCell<SubclassState>,
prev_wnd_proc: WNDPROC,
window_destroyed: Cell<bool>,
}
extern "system" fn wnd_proc(window: HWND, message: u32, wparam: WPARAM, lparam: LPARAM) -> LRESULT {
let handle = unsafe { GetPropW(window, PROP_NAME) };
let impl_ptr = handle.0 as *const SubclassImpl;
assert!(!impl_ptr.is_null());
let r#impl = unsafe { &*impl_ptr };
match message {
WM_GETOBJECT => {
let mut state = r#impl.state.borrow_mut();
let state_mut = &mut *state;
if let Some(result) = state_mut.adapter.handle_wm_getobject(
wparam,
lparam,
&mut *state_mut.activation_handler,
) {
drop(state);
return result.into();
}
}
WM_SETFOCUS | WM_EXITMENULOOP | WM_EXITSIZEMOVE => {
r#impl.update_window_focus_state(true);
}
WM_KILLFOCUS | WM_ENTERMENULOOP | WM_ENTERSIZEMOVE => {
r#impl.update_window_focus_state(false);
}
WM_NCDESTROY => {
r#impl.window_destroyed.set(true);
}
_ => (),
}
unsafe { CallWindowProcW(r#impl.prev_wnd_proc, window, message, wparam, lparam) }
}
impl SubclassImpl {
fn new(
hwnd: HWND,
activation_handler: impl 'static + ActivationHandler,
action_handler: impl 'static + ActionHandler + Send,
) -> Box<Self> {
let adapter = Adapter::new(hwnd, false, action_handler);
let state = RefCell::new(SubclassState {
adapter,
activation_handler: Box::new(activation_handler),
});
Box::new(Self {
hwnd,
state,
prev_wnd_proc: None,
window_destroyed: Cell::new(false),
})
}
fn install(&mut self) {
unsafe {
SetPropW(
self.hwnd,
PROP_NAME,
HANDLE(self as *const SubclassImpl as _),
)
}
.unwrap();
let result =
unsafe { SetWindowLongPtrW(self.hwnd, GWLP_WNDPROC, wnd_proc as *const c_void as _) };
if result == 0 {
win32_error();
}
self.prev_wnd_proc = unsafe { transmute::<LongPtr, WNDPROC>(result) };
}
fn update_window_focus_state(&self, is_focused: bool) {
let mut state = self.state.borrow_mut();
if let Some(events) = state.adapter.update_window_focus_state(is_focused) {
drop(state);
events.raise();
}
}
fn uninstall(&self) {
if self.window_destroyed.get() {
return;
}
let result = unsafe {
SetWindowLongPtrW(
self.hwnd,
GWLP_WNDPROC,
transmute::<WNDPROC, LongPtr>(self.prev_wnd_proc),
)
};
if result == 0 {
win32_error();
}
unsafe { RemovePropW(self.hwnd, PROP_NAME) }.unwrap();
}
}
/// Uses [Win32 subclassing] to handle `WM_GETOBJECT` messages on a window
/// that provides no other way of adding custom message handlers.
///
/// [Win32 subclassing]: https://docs.microsoft.com/en-us/windows/win32/controls/subclassing-overview
pub struct SubclassingAdapter(Box<SubclassImpl>);
impl SubclassingAdapter {
/// Creates a new Windows platform adapter using window subclassing.
/// This must be done before the window is shown or focused
/// for the first time.
///
/// This must be called on the thread that owns the window. The activation
/// handler will always be called on that thread. The action handler
/// may or may not be called on that thread.
pub fn new(
hwnd: HWND,
activation_handler: impl 'static + ActivationHandler,
action_handler: impl 'static + ActionHandler + Send,
) -> Self {
let mut r#impl = SubclassImpl::new(hwnd, activation_handler, action_handler);
r#impl.install();
Self(r#impl)
}
/// If and only if the tree has been initialized, call the provided function
/// and apply the resulting update. Note: If the caller's implementation of
/// [`ActivationHandler::request_initial_tree`] initially returned `None`,
/// the [`TreeUpdate`] returned by the provided function must contain
/// a full tree.
///
/// If a [`QueuedEvents`] instance is returned, the caller must call
/// [`QueuedEvents::raise`] on it.
pub fn update_if_active(
&mut self,
update_factory: impl FnOnce() -> TreeUpdate,
) -> Option<QueuedEvents> {
// SAFETY: We use `RefCell::borrow_mut` here, even though
// `RefCell::get_mut` is allowed (because this method takes
// a mutable self reference), just in case there's some way
// this method can be called from within the subclassed window
// procedure, e.g. via `ActivationHandler`.
let mut state = self.0.state.borrow_mut();
state.adapter.update_if_active(update_factory)
}
}
impl Drop for SubclassingAdapter {
fn drop(&mut self) {
self.0.uninstall();
}
}

View File

@@ -0,0 +1,336 @@
// Copyright 2022 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::{ActionHandler, ActivationHandler};
use once_cell::sync::Lazy;
use std::{
cell::RefCell,
sync::{Arc, Condvar, Mutex},
thread,
time::Duration,
};
use windows as Windows;
use windows::{
core::*,
Win32::{
Foundation::*,
Graphics::Gdi::ValidateRect,
System::{Com::*, LibraryLoader::GetModuleHandleW},
UI::{Accessibility::*, WindowsAndMessaging::*},
},
};
use crate::window_handle::WindowHandle;
use super::{
context::{ActionHandlerNoMut, ActionHandlerWrapper},
Adapter,
};
const DEFAULT_TIMEOUT: Duration = Duration::from_secs(5);
static WINDOW_CLASS_ATOM: Lazy<u16> = Lazy::new(|| {
let class_name = w!("AccessKitTest");
let wc = WNDCLASSW {
hCursor: unsafe { LoadCursorW(None, IDC_ARROW) }.unwrap(),
hInstance: unsafe { GetModuleHandleW(None) }.unwrap().into(),
lpszClassName: class_name,
style: CS_HREDRAW | CS_VREDRAW,
lpfnWndProc: Some(wndproc),
..Default::default()
};
let atom = unsafe { RegisterClassW(&wc) };
if atom == 0 {
panic!("{}", Error::from_win32());
}
atom
});
struct WindowState {
activation_handler: RefCell<Box<dyn ActivationHandler>>,
adapter: RefCell<Adapter>,
}
unsafe fn get_window_state(window: HWND) -> *const WindowState {
GetWindowLongPtrW(window, GWLP_USERDATA) as _
}
fn update_window_focus_state(window: HWND, is_focused: bool) {
let state = unsafe { &*get_window_state(window) };
let mut adapter = state.adapter.borrow_mut();
if let Some(events) = adapter.update_window_focus_state(is_focused) {
events.raise();
}
}
struct WindowCreateParams {
activation_handler: Box<dyn ActivationHandler>,
action_handler: Arc<dyn ActionHandlerNoMut + Send + Sync>,
}
extern "system" fn wndproc(window: HWND, message: u32, wparam: WPARAM, lparam: LPARAM) -> LRESULT {
match message {
WM_NCCREATE => {
let create_struct: &CREATESTRUCTW = unsafe { &mut *(lparam.0 as *mut _) };
let create_params: Box<WindowCreateParams> =
unsafe { Box::from_raw(create_struct.lpCreateParams as _) };
let WindowCreateParams {
activation_handler,
action_handler,
} = *create_params;
let adapter = Adapter::with_wrapped_action_handler(window, false, action_handler);
let state = Box::new(WindowState {
activation_handler: RefCell::new(activation_handler),
adapter: RefCell::new(adapter),
});
unsafe { SetWindowLongPtrW(window, GWLP_USERDATA, Box::into_raw(state) as _) };
unsafe { DefWindowProcW(window, message, wparam, lparam) }
}
WM_PAINT => {
unsafe { ValidateRect(window, None) }.unwrap();
LRESULT(0)
}
WM_DESTROY => {
let ptr = unsafe { SetWindowLongPtrW(window, GWLP_USERDATA, 0) };
if ptr != 0 {
drop(unsafe { Box::<WindowState>::from_raw(ptr as _) });
}
unsafe { PostQuitMessage(0) };
LRESULT(0)
}
WM_GETOBJECT => {
let state_ptr = unsafe { get_window_state(window) };
if state_ptr.is_null() {
// We need to be prepared to gracefully handle WM_GETOBJECT
// while the window is being destroyed; this can happen if
// the thread is using a COM STA.
return unsafe { DefWindowProcW(window, message, wparam, lparam) };
}
let state = unsafe { &*state_ptr };
let mut adapter = state.adapter.borrow_mut();
let mut activation_handler = state.activation_handler.borrow_mut();
let result = adapter.handle_wm_getobject(wparam, lparam, &mut **activation_handler);
drop(activation_handler);
drop(adapter);
result.map_or_else(
|| unsafe { DefWindowProcW(window, message, wparam, lparam) },
|result| result.into(),
)
}
WM_SETFOCUS | WM_EXITMENULOOP | WM_EXITSIZEMOVE => {
update_window_focus_state(window, true);
LRESULT(0)
}
WM_KILLFOCUS | WM_ENTERMENULOOP | WM_ENTERSIZEMOVE => {
update_window_focus_state(window, false);
LRESULT(0)
}
_ => unsafe { DefWindowProcW(window, message, wparam, lparam) },
}
}
fn create_window(
title: &str,
activation_handler: impl 'static + ActivationHandler,
action_handler: impl 'static + ActionHandler + Send,
) -> Result<HWND> {
let create_params = Box::new(WindowCreateParams {
activation_handler: Box::new(activation_handler),
action_handler: Arc::new(ActionHandlerWrapper::new(action_handler)),
});
let window = unsafe {
CreateWindowExW(
Default::default(),
PCWSTR(*WINDOW_CLASS_ATOM as usize as _),
&HSTRING::from(title),
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
None,
None,
GetModuleHandleW(None).unwrap(),
Some(Box::into_raw(create_params) as _),
)?
};
if window.is_invalid() {
return Err(Error::from_win32());
}
Ok(window)
}
pub(crate) struct Scope {
pub(crate) uia: IUIAutomation,
pub(crate) window: WindowHandle,
}
impl Scope {
pub(crate) fn show_and_focus_window(&self) {
let _ = unsafe { ShowWindow(self.window.0, SW_SHOW) };
let _ = unsafe { SetForegroundWindow(self.window.0) };
}
}
// It's not safe to run these UI-related tests concurrently.
pub(crate) static MUTEX: Mutex<()> = Mutex::new(());
pub(crate) fn scope<F>(
window_title: &str,
activation_handler: impl 'static + ActivationHandler + Send,
action_handler: impl 'static + ActionHandler + Send,
f: F,
) -> Result<()>
where
F: FnOnce(&Scope) -> Result<()>,
{
let _lock_guard = MUTEX.lock().unwrap();
let window_mutex: Mutex<Option<WindowHandle>> = Mutex::new(None);
let window_cv = Condvar::new();
thread::scope(|thread_scope| {
thread_scope.spawn(|| {
// We explicitly don't want to initialize COM on the provider thread,
// because we want to make sure that the provider side of UIA works
// even if COM is never initialized on the provider thread
// (as is the case if the window is never shown), or if COM is
// initialized after the window is shown (as is the case,
// at least on some Windows 10 machines, due to IME support).
let window = create_window(window_title, activation_handler, action_handler).unwrap();
{
let mut state = window_mutex.lock().unwrap();
*state = Some(window.into());
window_cv.notify_one();
}
let mut message = MSG::default();
while unsafe { GetMessageW(&mut message, HWND::default(), 0, 0) }.into() {
let _ = unsafe { TranslateMessage(&message) };
unsafe { DispatchMessageW(&message) };
}
});
let window = {
let state = window_mutex.lock().unwrap();
let mut state = if state.is_none() {
window_cv.wait(state).unwrap()
} else {
state
};
state.take().unwrap()
};
let _window_guard = scopeguard::guard((), |_| {
unsafe { PostMessageW(window.0, WM_CLOSE, WPARAM(0), LPARAM(0)) }.unwrap()
});
// We must initialize COM before creating the UIA client. The MTA option
// is cleaner by far, especially when we want to wait for a UIA event
// handler to be called, and there's no reason not to use it here.
// Note that we don't initialize COM this way on the provider thread,
// as explained above. It's also important that we let the provider
// thread do its forced initialization of UIA, in an environment
// where COM has not been initialized, before we create the UIA client,
// which also triggers UIA initialization, in a thread where COM
// _has_ been initialized. This way, we ensure that the provider side
// of UIA works even if it is set up in an environment where COM
// has not been initialized, and that this sequence of events
// doesn't prevent the UIA client from working.
unsafe { CoInitializeEx(None, COINIT_MULTITHREADED) }.unwrap();
let _com_guard = scopeguard::guard((), |_| unsafe { CoUninitialize() });
let uia: IUIAutomation =
unsafe { CoCreateInstance(&CUIAutomation8, None, CLSCTX_INPROC_SERVER) }?;
let s = Scope { uia, window };
f(&s)
})
}
/// This must only be used to wrap UIA elements returned by a UIA client
/// that was created in the MTA. Those are safe to send between threads.
struct SendableUiaElement(IUIAutomationElement);
unsafe impl Send for SendableUiaElement {}
pub(crate) struct ReceivedFocusEvent {
mutex: Mutex<Option<SendableUiaElement>>,
cv: Condvar,
}
impl ReceivedFocusEvent {
fn new() -> Arc<Self> {
Arc::new(Self {
mutex: Mutex::new(None),
cv: Condvar::new(),
})
}
pub(crate) fn wait<F>(&self, f: F) -> IUIAutomationElement
where
F: Fn(&IUIAutomationElement) -> bool,
{
let mut received = self.mutex.lock().unwrap();
loop {
if let Some(SendableUiaElement(element)) = received.take() {
if f(&element) {
return element;
}
}
let (lock, result) = self.cv.wait_timeout(received, DEFAULT_TIMEOUT).unwrap();
assert!(!result.timed_out());
received = lock;
}
}
fn put(&self, element: IUIAutomationElement) {
let mut received = self.mutex.lock().unwrap();
*received = Some(SendableUiaElement(element));
self.cv.notify_one();
}
}
#[implement(Windows::Win32::UI::Accessibility::IUIAutomationFocusChangedEventHandler)]
pub(crate) struct FocusEventHandler {
received: Arc<ReceivedFocusEvent>,
}
// Because we create a UIA client in the COM MTA, this event handler
// _will_ be called from a different thread, and possibly multiple threads
// at once.
static_assertions::assert_impl_all!(FocusEventHandler: Send, Sync);
impl FocusEventHandler {
#[allow(clippy::new_ret_no_self)] // it does return self, but wrapped
pub(crate) fn new() -> (
IUIAutomationFocusChangedEventHandler,
Arc<ReceivedFocusEvent>,
) {
let received = ReceivedFocusEvent::new();
(
Self {
received: Arc::clone(&received),
}
.into(),
received,
)
}
}
#[allow(non_snake_case)]
impl IUIAutomationFocusChangedEventHandler_Impl for FocusEventHandler_Impl {
fn HandleFocusChangedEvent(&self, sender: Option<&IUIAutomationElement>) -> Result<()> {
self.received.put(sender.unwrap().clone());
Ok(())
}
}
mod simple;
mod subclassed;

View File

@@ -0,0 +1,196 @@
// Copyright 2022 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::{
Action, ActionHandler, ActionRequest, ActivationHandler, Node, NodeId, Role, Tree, TreeUpdate,
};
use windows::{core::*, Win32::UI::Accessibility::*};
use super::*;
const WINDOW_TITLE: &str = "Simple test";
const WINDOW_ID: NodeId = NodeId(0);
const BUTTON_1_ID: NodeId = NodeId(1);
const BUTTON_2_ID: NodeId = NodeId(2);
fn make_button(label: &str) -> Node {
let mut node = Node::new(Role::Button);
node.set_label(label);
node.add_action(Action::Focus);
node
}
fn get_initial_state() -> TreeUpdate {
let mut root = Node::new(Role::Window);
root.set_children(vec![BUTTON_1_ID, BUTTON_2_ID]);
let button_1 = make_button("Button 1");
let button_2 = make_button("Button 2");
TreeUpdate {
nodes: vec![
(WINDOW_ID, root),
(BUTTON_1_ID, button_1),
(BUTTON_2_ID, button_2),
],
tree: Some(Tree::new(WINDOW_ID)),
focus: BUTTON_1_ID,
}
}
pub struct NullActionHandler;
impl ActionHandler for NullActionHandler {
fn do_action(&mut self, _request: ActionRequest) {}
}
struct SimpleActivationHandler;
impl ActivationHandler for SimpleActivationHandler {
fn request_initial_tree(&mut self) -> Option<TreeUpdate> {
Some(get_initial_state())
}
}
fn scope<F>(f: F) -> Result<()>
where
F: FnOnce(&Scope) -> Result<()>,
{
super::scope(
WINDOW_TITLE,
SimpleActivationHandler {},
NullActionHandler {},
f,
)
}
#[test]
fn has_native_uia() -> Result<()> {
scope(|s| {
let has_native_uia: bool = unsafe { UiaHasServerSideProvider(s.window.0) }.into();
assert!(has_native_uia);
Ok(())
})
}
fn is_button_named(element: &IUIAutomationElement, expected_name: &str) -> bool {
let control_type = unsafe { element.CurrentControlType() }.unwrap();
let name = unsafe { element.CurrentName() }.unwrap();
let name: String = name.try_into().unwrap();
control_type == UIA_ButtonControlTypeId && name == expected_name
}
fn is_button_1(element: &IUIAutomationElement) -> bool {
is_button_named(element, "Button 1")
}
fn is_button_2(element: &IUIAutomationElement) -> bool {
is_button_named(element, "Button 2")
}
#[test]
fn navigation() -> Result<()> {
scope(|s| {
let root = unsafe { s.uia.ElementFromHandle(s.window.0) }?;
let walker = unsafe { s.uia.ControlViewWalker() }?;
// The children of the window include the children that we provide,
// but also the title bar provided by the OS. We know that our own
// children are in the order we specified, but we don't know
// their position relative to the title bar. In fact, Windows
// has changed this in the past.
//
// Note that a UIA client would normally use the UIA condition feature
// to traverse the tree looking for an element that meets
// some condition. But we want to be explicit about navigating
// forward (and backward below) through only the immediate children.
// We'll accept the performance hit of multiple cross-thread calls
// (insignificant in this case) to achieve that.
let mut button_1_forward: Option<IUIAutomationElement> = None;
let mut wrapped_child = unsafe { walker.GetFirstChildElement(&root) };
while let Ok(child) = wrapped_child {
if is_button_1(&child) {
button_1_forward = Some(child);
break;
}
wrapped_child = unsafe { walker.GetNextSiblingElement(&child) };
}
let button_1_forward = button_1_forward.unwrap();
let mut button_2_forward: Option<IUIAutomationElement> = None;
let wrapped_child = unsafe { walker.GetNextSiblingElement(&button_1_forward) };
if let Ok(child) = wrapped_child {
if is_button_2(&child) {
button_2_forward = Some(child);
}
}
let _button_2_forward = button_2_forward.unwrap();
let mut button_2_backward: Option<IUIAutomationElement> = None;
let mut wrapped_child = unsafe { walker.GetLastChildElement(&root) };
while let Ok(child) = wrapped_child {
if is_button_2(&child) {
button_2_backward = Some(child);
break;
}
wrapped_child = unsafe { walker.GetPreviousSiblingElement(&child) };
}
let button_2_backward = button_2_backward.unwrap();
let mut button_1_backward: Option<IUIAutomationElement> = None;
let wrapped_child = unsafe { walker.GetPreviousSiblingElement(&button_2_backward) };
if let Ok(child) = wrapped_child {
if is_button_1(&child) {
button_1_backward = Some(child);
}
}
let button_1_backward = button_1_backward.unwrap();
let equal: bool =
unsafe { s.uia.CompareElements(&button_1_forward, &button_1_backward) }?.into();
assert!(equal);
let parent = unsafe { walker.GetParentElement(&button_1_forward) }?;
let equal: bool = unsafe { s.uia.CompareElements(&parent, &root) }?.into();
assert!(equal);
let desktop_root = unsafe { s.uia.GetRootElement() }?;
let parent = unsafe { walker.GetParentElement(&root) }?;
let equal: bool = unsafe { s.uia.CompareElements(&parent, &desktop_root) }?.into();
assert!(equal);
let wrapped_child = unsafe { walker.GetFirstChildElement(&button_1_forward) };
assert_eq!(Err(Error::empty()), wrapped_child);
let wrapped_child = unsafe { walker.GetLastChildElement(&button_1_forward) };
assert_eq!(Err(Error::empty()), wrapped_child);
Ok(())
})
}
#[test]
fn focus() -> Result<()> {
scope(|s| {
let (focus_event_handler, received_focus_event) = FocusEventHandler::new();
unsafe {
s.uia
.AddFocusChangedEventHandler(None, &focus_event_handler)
}?;
s.show_and_focus_window();
let focus_from_event = received_focus_event.wait(is_button_1);
let has_focus: bool = unsafe { focus_from_event.CurrentHasKeyboardFocus() }?.into();
assert!(has_focus);
let is_focusable: bool = unsafe { focus_from_event.CurrentIsKeyboardFocusable() }?.into();
assert!(is_focusable);
let focus_on_demand = unsafe { s.uia.GetFocusedElement() }?;
let equal: bool =
unsafe { s.uia.CompareElements(&focus_from_event, &focus_on_demand) }?.into();
assert!(equal);
Ok(())
})
}

View File

@@ -0,0 +1,103 @@
// Copyright 2022 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::{
Action, ActionHandler, ActionRequest, ActivationHandler, Node, NodeId, Role, Tree, TreeUpdate,
};
use windows::Win32::{Foundation::*, UI::Accessibility::*};
use winit::{
application::ApplicationHandler,
event::WindowEvent,
event_loop::{ActiveEventLoop, EventLoop},
platform::windows::EventLoopBuilderExtWindows,
raw_window_handle::{HasWindowHandle, RawWindowHandle},
window::{Window, WindowId},
};
use super::MUTEX;
use crate::SubclassingAdapter;
const WINDOW_TITLE: &str = "Simple test";
const WINDOW_ID: NodeId = NodeId(0);
const BUTTON_1_ID: NodeId = NodeId(1);
const BUTTON_2_ID: NodeId = NodeId(2);
fn make_button(label: &str) -> Node {
let mut node = Node::new(Role::Button);
node.set_label(label);
node.add_action(Action::Focus);
node
}
fn get_initial_state() -> TreeUpdate {
let mut root = Node::new(Role::Window);
root.set_children(vec![BUTTON_1_ID, BUTTON_2_ID]);
let button_1 = make_button("Button 1");
let button_2 = make_button("Button 2");
TreeUpdate {
nodes: vec![
(WINDOW_ID, root),
(BUTTON_1_ID, button_1),
(BUTTON_2_ID, button_2),
],
tree: Some(Tree::new(WINDOW_ID)),
focus: BUTTON_1_ID,
}
}
pub struct NullActionHandler;
impl ActionHandler for NullActionHandler {
fn do_action(&mut self, _request: ActionRequest) {}
}
struct SimpleActivationHandler;
impl ActivationHandler for SimpleActivationHandler {
fn request_initial_tree(&mut self) -> Option<TreeUpdate> {
Some(get_initial_state())
}
}
// This module uses winit for the purpose of testing with a real third-party
// window implementation that we don't control.
struct TestApplication;
impl ApplicationHandler<()> for TestApplication {
fn window_event(&mut self, _: &ActiveEventLoop, _: WindowId, _: WindowEvent) {}
fn resumed(&mut self, event_loop: &ActiveEventLoop) {
let window_attributes = Window::default_attributes()
.with_title(WINDOW_TITLE)
.with_visible(false);
let window = event_loop.create_window(window_attributes).unwrap();
let hwnd = match window.window_handle().unwrap().as_raw() {
RawWindowHandle::Win32(handle) => HWND(handle.hwnd.get() as *mut core::ffi::c_void),
RawWindowHandle::WinRt(_) => unimplemented!(),
_ => unreachable!(),
};
let adapter =
SubclassingAdapter::new(hwnd, SimpleActivationHandler {}, NullActionHandler {});
assert!(unsafe { UiaHasServerSideProvider(hwnd) }.as_bool());
drop(window);
drop(adapter);
event_loop.exit();
}
}
#[test]
fn has_native_uia() {
// This test is simple enough that we know it's fine to run entirely
// on one thread, so we don't need a full multithreaded test harness.
// Still, we must prevent this test from running concurrently with other
// tests, especially the focus test.
let _lock_guard = MUTEX.lock().unwrap();
let event_loop = EventLoop::builder().with_any_thread(true).build().unwrap();
let mut state = TestApplication {};
event_loop.run_app(&mut state).unwrap();
}

601
vendor/accesskit_windows/src/text.rs vendored Normal file
View File

@@ -0,0 +1,601 @@
// Copyright 2022 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.
#![allow(non_upper_case_globals)]
use accesskit::{Action, ActionData, ActionRequest};
use accesskit_consumer::{
Node, TextPosition as Position, TextRange as Range, TreeState, WeakTextRange as WeakRange,
};
use std::sync::{Arc, RwLock, Weak};
use windows::{
core::*,
Win32::{Foundation::*, System::Com::*, UI::Accessibility::*},
};
use crate::{context::Context, node::PlatformNode, util::*};
fn upgrade_range<'a>(weak: &WeakRange, tree_state: &'a TreeState) -> Result<Range<'a>> {
if let Some(range) = weak.upgrade(tree_state) {
Ok(range)
} else {
Err(element_not_available())
}
}
fn upgrade_range_node<'a>(weak: &WeakRange, tree_state: &'a TreeState) -> Result<Node<'a>> {
if let Some(node) = weak.upgrade_node(tree_state) {
Ok(node)
} else {
Err(element_not_available())
}
}
fn weak_comparable_position_from_endpoint(
range: &WeakRange,
endpoint: TextPatternRangeEndpoint,
) -> Result<&(Vec<usize>, usize)> {
match endpoint {
TextPatternRangeEndpoint_Start => Ok(range.start_comparable()),
TextPatternRangeEndpoint_End => Ok(range.end_comparable()),
_ => Err(invalid_arg()),
}
}
fn position_from_endpoint<'a>(
range: &Range<'a>,
endpoint: TextPatternRangeEndpoint,
) -> Result<Position<'a>> {
match endpoint {
TextPatternRangeEndpoint_Start => Ok(range.start()),
TextPatternRangeEndpoint_End => Ok(range.end()),
_ => Err(invalid_arg()),
}
}
fn set_endpoint_position<'a>(
range: &mut Range<'a>,
endpoint: TextPatternRangeEndpoint,
pos: Position<'a>,
) -> Result<()> {
match endpoint {
TextPatternRangeEndpoint_Start => {
range.set_start(pos);
}
TextPatternRangeEndpoint_End => {
range.set_end(pos);
}
_ => {
return Err(invalid_arg());
}
}
Ok(())
}
fn back_to_unit_start(start: Position, unit: TextUnit) -> Result<Position> {
match unit {
TextUnit_Character => {
// If we get here, this position is at the start of a non-degenerate
// range, so it's always at the start of a character.
debug_assert!(!start.is_document_end());
Ok(start)
}
TextUnit_Format => {
if start.is_format_start() {
Ok(start)
} else {
Ok(start.backward_to_format_start())
}
}
TextUnit_Word => {
if start.is_word_start() {
Ok(start)
} else {
Ok(start.backward_to_word_start())
}
}
TextUnit_Line => {
if start.is_line_start() {
Ok(start)
} else {
Ok(start.backward_to_line_start())
}
}
TextUnit_Paragraph => {
if start.is_paragraph_start() {
Ok(start)
} else {
Ok(start.backward_to_paragraph_start())
}
}
TextUnit_Page => {
if start.is_page_start() {
Ok(start)
} else {
Ok(start.backward_to_page_start())
}
}
TextUnit_Document => {
if start.is_document_start() {
Ok(start)
} else {
Ok(start.document_start())
}
}
_ => Err(invalid_arg()),
}
}
fn move_forward_to_start(pos: Position, unit: TextUnit) -> Result<Position> {
match unit {
TextUnit_Character => Ok(pos.forward_to_character_start()),
TextUnit_Format => Ok(pos.forward_to_format_start()),
TextUnit_Word => Ok(pos.forward_to_word_start()),
TextUnit_Line => Ok(pos.forward_to_line_start()),
TextUnit_Paragraph => Ok(pos.forward_to_paragraph_start()),
TextUnit_Page => Ok(pos.forward_to_page_start()),
TextUnit_Document => Ok(pos.document_end()),
_ => Err(invalid_arg()),
}
}
fn move_forward_to_end(pos: Position, unit: TextUnit) -> Result<Position> {
match unit {
TextUnit_Character => Ok(pos.forward_to_character_end()),
TextUnit_Format => Ok(pos.forward_to_format_end()),
TextUnit_Word => Ok(pos.forward_to_word_end()),
TextUnit_Line => Ok(pos.forward_to_line_end()),
TextUnit_Paragraph => Ok(pos.forward_to_paragraph_end()),
TextUnit_Page => Ok(pos.forward_to_page_end()),
TextUnit_Document => Ok(pos.document_end()),
_ => Err(invalid_arg()),
}
}
fn move_backward(pos: Position, unit: TextUnit) -> Result<Position> {
match unit {
TextUnit_Character => Ok(pos.backward_to_character_start()),
TextUnit_Format => Ok(pos.backward_to_format_start()),
TextUnit_Word => Ok(pos.backward_to_word_start()),
TextUnit_Line => Ok(pos.backward_to_line_start()),
TextUnit_Paragraph => Ok(pos.backward_to_paragraph_start()),
TextUnit_Page => Ok(pos.backward_to_page_start()),
TextUnit_Document => Ok(pos.document_start()),
_ => Err(invalid_arg()),
}
}
fn move_position(
mut pos: Position,
unit: TextUnit,
to_end: bool,
count: i32,
) -> Result<(Position, i32)> {
let forward = count > 0;
let count = count.abs();
let mut moved = 0i32;
for _ in 0..count {
let at_end = if forward {
pos.is_document_end()
} else {
pos.is_document_start()
};
if at_end {
break;
}
pos = if forward {
if to_end {
move_forward_to_end(pos, unit)
} else {
move_forward_to_start(pos, unit)
}
} else {
move_backward(pos, unit)
}?;
moved += 1;
}
if !forward {
moved = -moved;
}
Ok((pos, moved))
}
#[implement(ITextRangeProvider)]
pub(crate) struct PlatformRange {
context: Weak<Context>,
state: RwLock<WeakRange>,
}
impl PlatformRange {
pub(crate) fn new(context: &Weak<Context>, range: Range) -> Self {
Self {
context: context.clone(),
state: RwLock::new(range.downgrade()),
}
}
fn upgrade_context(&self) -> Result<Arc<Context>> {
upgrade(&self.context)
}
fn with_tree_state_and_context<F, T>(&self, f: F) -> Result<T>
where
F: FnOnce(&TreeState, &Context) -> Result<T>,
{
let context = self.upgrade_context()?;
let tree = context.read_tree();
f(tree.state(), &context)
}
fn with_tree_state<F, T>(&self, f: F) -> Result<T>
where
F: FnOnce(&TreeState) -> Result<T>,
{
self.with_tree_state_and_context(|state, _| f(state))
}
fn upgrade_node<'a>(&self, tree_state: &'a TreeState) -> Result<Node<'a>> {
let state = self.state.read().unwrap();
upgrade_range_node(&state, tree_state)
}
fn with_node<F, T>(&self, f: F) -> Result<T>
where
F: FnOnce(Node) -> Result<T>,
{
self.with_tree_state(|tree_state| {
let node = self.upgrade_node(tree_state)?;
f(node)
})
}
fn upgrade_for_read<'a>(&self, tree_state: &'a TreeState) -> Result<Range<'a>> {
let state = self.state.read().unwrap();
upgrade_range(&state, tree_state)
}
fn read_with_context<F, T>(&self, f: F) -> Result<T>
where
F: FnOnce(Range, &Context) -> Result<T>,
{
self.with_tree_state_and_context(|tree_state, context| {
let range = self.upgrade_for_read(tree_state)?;
f(range, context)
})
}
fn read<F, T>(&self, f: F) -> Result<T>
where
F: FnOnce(Range) -> Result<T>,
{
self.read_with_context(|range, _| f(range))
}
fn write<F, T>(&self, f: F) -> Result<T>
where
F: FnOnce(&mut Range) -> Result<T>,
{
self.with_tree_state(|tree_state| {
let mut state = self.state.write().unwrap();
let mut range = upgrade_range(&state, tree_state)?;
let result = f(&mut range);
*state = range.downgrade();
result
})
}
fn do_action<F>(&self, f: F) -> Result<()>
where
for<'a> F: FnOnce(Range<'a>) -> ActionRequest,
{
let context = self.upgrade_context()?;
let tree = context.read_tree();
let range = self.upgrade_for_read(tree.state())?;
let request = f(range);
drop(tree);
context.do_action(request);
Ok(())
}
fn require_same_context(&self, other: &PlatformRange) -> Result<()> {
if self.context.ptr_eq(&other.context) {
Ok(())
} else {
Err(invalid_arg())
}
}
}
impl Clone for PlatformRange {
fn clone(&self) -> Self {
PlatformRange {
context: self.context.clone(),
state: RwLock::new(self.state.read().unwrap().clone()),
}
}
}
// Some text range methods take another text range interface pointer as a
// parameter. We need to cast these interface pointers to their underlying
// implementations. We assume that AccessKit is the only UIA provider
// within this process. This seems a safe assumption for most AccessKit users.
#[allow(non_snake_case)]
impl ITextRangeProvider_Impl for PlatformRange_Impl {
fn Clone(&self) -> Result<ITextRangeProvider> {
Ok(self.this.clone().into())
}
fn Compare(&self, other: Option<&ITextRangeProvider>) -> Result<BOOL> {
let other = unsafe { required_param(other)?.as_impl() };
Ok((self.context.ptr_eq(&other.context)
&& *self.state.read().unwrap() == *other.state.read().unwrap())
.into())
}
fn CompareEndpoints(
&self,
endpoint: TextPatternRangeEndpoint,
other: Option<&ITextRangeProvider>,
other_endpoint: TextPatternRangeEndpoint,
) -> Result<i32> {
let other = unsafe { required_param(other)?.as_impl() };
if std::ptr::eq(other as *const _, &self.this as *const _) {
// Comparing endpoints within the same range can be done
// safely without upgrading the range. This allows ATs
// to determine whether an old range is degenerate even if
// that range is no longer valid.
let state = self.state.read().unwrap();
let other_state = other.state.read().unwrap();
let pos = weak_comparable_position_from_endpoint(&state, endpoint)?;
let other_pos = weak_comparable_position_from_endpoint(&other_state, other_endpoint)?;
let result = pos.cmp(other_pos);
return Ok(result as i32);
}
self.require_same_context(other)?;
self.with_tree_state(|tree_state| {
let range = self.upgrade_for_read(tree_state)?;
let other_range = other.upgrade_for_read(tree_state)?;
if range.node().id() != other_range.node().id() {
return Err(invalid_arg());
}
let pos = position_from_endpoint(&range, endpoint)?;
let other_pos = position_from_endpoint(&other_range, other_endpoint)?;
let result = pos.partial_cmp(&other_pos).unwrap();
Ok(result as i32)
})
}
fn ExpandToEnclosingUnit(&self, unit: TextUnit) -> Result<()> {
if unit == TextUnit_Document {
// Handle document as a special case so we can get to a document
// range even if the current endpoints are now invalid.
// Based on observed behavior, Narrator needs this ability.
return self.with_tree_state(|tree_state| {
let mut state = self.state.write().unwrap();
let node = upgrade_range_node(&state, tree_state)?;
*state = node.document_range().downgrade();
Ok(())
});
}
self.write(|range| {
let start = range.start();
if unit == TextUnit_Character && start.is_document_end() {
// We know from experimentation that some Windows ATs
// expect ExpandToEnclosingUnit(TextUnit_Character)
// to do nothing if the range is degenerate at the end
// of the document.
return Ok(());
}
let start = back_to_unit_start(start, unit)?;
range.set_start(start);
if !start.is_document_end() {
let end = move_forward_to_end(start, unit)?;
range.set_end(end);
}
Ok(())
})
}
fn FindAttribute(
&self,
_id: UIA_TEXTATTRIBUTE_ID,
_value: &VARIANT,
_backward: BOOL,
) -> Result<ITextRangeProvider> {
// TODO: implement when we support variable formatting (part of rich text)
// Justification: JUCE doesn't implement this.
Err(Error::empty())
}
fn FindText(
&self,
_text: &BSTR,
_backward: BOOL,
_ignore_case: BOOL,
) -> Result<ITextRangeProvider> {
// TODO: implement when there's a real-world use case that requires it
// Justification: Quorum doesn't implement this and is being used
// by blind students.
Err(Error::empty())
}
fn GetAttributeValue(&self, id: UIA_TEXTATTRIBUTE_ID) -> Result<VARIANT> {
match id {
UIA_IsReadOnlyAttributeId => {
// TBD: do we ever want to support mixed read-only/editable text?
self.with_node(|node| {
let value = node.is_read_only();
Ok(value.into())
})
}
UIA_CaretPositionAttributeId => self.read(|range| {
let mut value = CaretPosition_Unknown;
if range.is_degenerate() {
let pos = range.start();
if pos.is_line_start() {
value = CaretPosition_BeginningOfLine;
} else if pos.is_line_end() {
value = CaretPosition_EndOfLine;
}
}
Ok(value.0.into())
}),
// TODO: implement more attributes
_ => {
let value = unsafe { UiaGetReservedNotSupportedValue() }.unwrap();
Ok(value.into())
}
}
}
fn GetBoundingRectangles(&self) -> Result<*mut SAFEARRAY> {
self.read_with_context(|range, context| {
let rects = range.bounding_boxes();
if rects.is_empty() {
return Ok(std::ptr::null_mut());
}
let client_top_left = context.client_top_left();
let mut result = Vec::<f64>::with_capacity(rects.len() * 4);
for rect in rects {
result.push(rect.x0 + client_top_left.x);
result.push(rect.y0 + client_top_left.y);
result.push(rect.width());
result.push(rect.height());
}
Ok(safe_array_from_f64_slice(&result))
})
}
fn GetEnclosingElement(&self) -> Result<IRawElementProviderSimple> {
self.with_node(|node| {
// Revisit this if we eventually support embedded objects.
Ok(PlatformNode {
context: self.context.clone(),
node_id: Some(node.id()),
}
.into())
})
}
fn GetText(&self, _max_length: i32) -> Result<BSTR> {
// The Microsoft docs imply that the provider isn't _required_
// to truncate text at the max length, so we just ignore it.
self.read(|range| {
let mut result = WideString::default();
range.write_text(&mut result).unwrap();
Ok(result.into())
})
}
fn Move(&self, unit: TextUnit, count: i32) -> Result<i32> {
self.write(|range| {
let degenerate = range.is_degenerate();
let start = range.start();
let start = if degenerate {
start
} else {
back_to_unit_start(start, unit)?
};
let (start, moved) = move_position(start, unit, false, count)?;
if moved != 0 {
range.set_start(start);
let end = if degenerate || start.is_document_end() {
start
} else {
move_forward_to_end(start, unit)?
};
range.set_end(end);
}
Ok(moved)
})
}
fn MoveEndpointByUnit(
&self,
endpoint: TextPatternRangeEndpoint,
unit: TextUnit,
count: i32,
) -> Result<i32> {
self.write(|range| {
let pos = position_from_endpoint(range, endpoint)?;
let (pos, moved) =
move_position(pos, unit, endpoint == TextPatternRangeEndpoint_End, count)?;
set_endpoint_position(range, endpoint, pos)?;
Ok(moved)
})
}
fn MoveEndpointByRange(
&self,
endpoint: TextPatternRangeEndpoint,
other: Option<&ITextRangeProvider>,
other_endpoint: TextPatternRangeEndpoint,
) -> Result<()> {
let other = unsafe { required_param(other)?.as_impl() };
self.require_same_context(other)?;
// We have to obtain the tree state and ranges manually to avoid
// lifetime issues, and work with the two locks in a specific order
// to avoid deadlock.
self.with_tree_state(|tree_state| {
let other_range = other.upgrade_for_read(tree_state)?;
let mut state = self.state.write().unwrap();
let mut range = upgrade_range(&state, tree_state)?;
if range.node().id() != other_range.node().id() {
return Err(invalid_arg());
}
let pos = position_from_endpoint(&other_range, other_endpoint)?;
set_endpoint_position(&mut range, endpoint, pos)?;
*state = range.downgrade();
Ok(())
})
}
fn Select(&self) -> Result<()> {
self.do_action(|range| ActionRequest {
action: Action::SetTextSelection,
target: range.node().id(),
data: Some(ActionData::SetTextSelection(range.to_text_selection())),
})
}
fn AddToSelection(&self) -> Result<()> {
// AccessKit doesn't support multiple text selections.
Err(invalid_operation())
}
fn RemoveFromSelection(&self) -> Result<()> {
// AccessKit doesn't support multiple text selections.
Err(invalid_operation())
}
fn ScrollIntoView(&self, align_to_top: BOOL) -> Result<()> {
self.do_action(|range| {
let position = if align_to_top.into() {
range.start()
} else {
range.end()
};
ActionRequest {
action: Action::ScrollIntoView,
target: position.inner_node().id(),
data: None,
}
})
}
fn GetChildren(&self) -> Result<*mut SAFEARRAY> {
// We don't support embedded objects in text.
Ok(safe_array_from_com_slice(&[]))
}
}
// Ensures that `PlatformRange` is actually safe to use in the free-threaded
// manner that we advertise via `ProviderOptions`.
#[test]
fn platform_range_impl_send_sync() {
fn assert_send_sync<T: Send + Sync>() {}
assert_send_sync::<PlatformRange>();
}

272
vendor/accesskit_windows/src/util.rs vendored Normal file
View File

@@ -0,0 +1,272 @@
// Copyright 2022 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::Point;
use accesskit_consumer::TreeState;
use std::{
fmt::{self, Write},
sync::{Arc, Weak},
};
use windows::{
core::*,
Win32::{
Foundation::*,
Graphics::Gdi::*,
System::{Com::*, Ole::*, Variant::*},
UI::{Accessibility::*, WindowsAndMessaging::*},
},
};
use crate::window_handle::WindowHandle;
#[derive(Clone, Default, PartialEq, Eq)]
pub(crate) struct WideString(Vec<u16>);
impl Write for WideString {
fn write_str(&mut self, s: &str) -> fmt::Result {
self.0.extend(s.encode_utf16());
Ok(())
}
fn write_char(&mut self, c: char) -> fmt::Result {
self.0.extend_from_slice(c.encode_utf16(&mut [0; 2]));
Ok(())
}
}
impl From<WideString> for BSTR {
fn from(value: WideString) -> Self {
Self::from_wide(&value.0).unwrap()
}
}
pub(crate) struct Variant(VARIANT);
impl From<Variant> for VARIANT {
fn from(variant: Variant) -> Self {
variant.0
}
}
impl Variant {
pub(crate) fn empty() -> Self {
Self(VARIANT::default())
}
pub(crate) fn is_empty(&self) -> bool {
self.0.is_empty()
}
}
impl From<BSTR> for Variant {
fn from(value: BSTR) -> Self {
Self(value.into())
}
}
impl From<WideString> for Variant {
fn from(value: WideString) -> Self {
BSTR::from(value).into()
}
}
impl From<&str> for Variant {
fn from(value: &str) -> Self {
let mut result = WideString::default();
result.write_str(value).unwrap();
result.into()
}
}
impl From<String> for Variant {
fn from(value: String) -> Self {
value.as_str().into()
}
}
impl From<IUnknown> for Variant {
fn from(value: IUnknown) -> Self {
Self(value.into())
}
}
impl From<i32> for Variant {
fn from(value: i32) -> Self {
Self(value.into())
}
}
impl From<f64> for Variant {
fn from(value: f64) -> Self {
Self(value.into())
}
}
impl From<ToggleState> for Variant {
fn from(value: ToggleState) -> Self {
Self(value.0.into())
}
}
impl From<LiveSetting> for Variant {
fn from(value: LiveSetting) -> Self {
Self(value.0.into())
}
}
impl From<CaretPosition> for Variant {
fn from(value: CaretPosition) -> Self {
Self(value.0.into())
}
}
impl From<UIA_CONTROLTYPE_ID> for Variant {
fn from(value: UIA_CONTROLTYPE_ID) -> Self {
Self(value.0.into())
}
}
impl From<OrientationType> for Variant {
fn from(value: OrientationType) -> Self {
Self(value.0.into())
}
}
impl From<bool> for Variant {
fn from(value: bool) -> Self {
Self(value.into())
}
}
impl<T: Into<Variant>> From<Option<T>> for Variant {
fn from(value: Option<T>) -> Self {
value.map_or_else(Self::empty, T::into)
}
}
fn safe_array_from_primitive_slice<T>(vt: VARENUM, slice: &[T]) -> *mut SAFEARRAY {
let sa = unsafe { SafeArrayCreateVector(VARENUM(vt.0), 0, slice.len().try_into().unwrap()) };
if sa.is_null() {
panic!("SAFEARRAY allocation failed");
}
for (i, item) in slice.iter().enumerate() {
let i: i32 = i.try_into().unwrap();
unsafe { SafeArrayPutElement(&*sa, &i, (item as *const T) as *const _) }.unwrap();
}
sa
}
pub(crate) fn safe_array_from_i32_slice(slice: &[i32]) -> *mut SAFEARRAY {
safe_array_from_primitive_slice(VT_I4, slice)
}
pub(crate) fn safe_array_from_f64_slice(slice: &[f64]) -> *mut SAFEARRAY {
safe_array_from_primitive_slice(VT_R8, slice)
}
pub(crate) fn safe_array_from_com_slice(slice: &[IUnknown]) -> *mut SAFEARRAY {
let sa = unsafe { SafeArrayCreateVector(VT_UNKNOWN, 0, slice.len().try_into().unwrap()) };
if sa.is_null() {
panic!("SAFEARRAY allocation failed");
}
for (i, item) in slice.iter().enumerate() {
let i: i32 = i.try_into().unwrap();
unsafe { SafeArrayPutElement(&*sa, &i, std::mem::transmute_copy(item)) }.unwrap();
}
sa
}
pub(crate) enum QueuedEvent {
Simple {
element: IRawElementProviderSimple,
event_id: UIA_EVENT_ID,
},
PropertyChanged {
element: IRawElementProviderSimple,
property_id: UIA_PROPERTY_ID,
old_value: VARIANT,
new_value: VARIANT,
},
}
pub(crate) fn not_implemented() -> Error {
E_NOTIMPL.into()
}
pub(crate) fn invalid_arg() -> Error {
E_INVALIDARG.into()
}
pub(crate) fn required_param<T>(param: Option<&T>) -> Result<&T> {
param.map_or_else(|| Err(invalid_arg()), Ok)
}
pub(crate) fn element_not_available() -> Error {
HRESULT(UIA_E_ELEMENTNOTAVAILABLE as _).into()
}
pub(crate) fn element_not_enabled() -> Error {
HRESULT(UIA_E_ELEMENTNOTENABLED as _).into()
}
pub(crate) fn invalid_operation() -> Error {
HRESULT(UIA_E_INVALIDOPERATION as _).into()
}
pub(crate) fn client_top_left(hwnd: WindowHandle) -> Point {
let mut result = POINT::default();
// If ClientToScreen fails, that means the window is gone.
// That's an unexpected condition, so we should fail loudly.
unsafe { ClientToScreen(hwnd.0, &mut result) }.unwrap();
Point::new(result.x.into(), result.y.into())
}
pub(crate) fn window_title(hwnd: WindowHandle) -> Option<BSTR> {
// The following is an old hack to get the window caption without ever
// sending messages to the window itself, even if the window is in
// the same process but possibly a separate thread. This prevents
// possible hangs and sluggishness. This hack has been proven to work
// over nearly 20 years on every version of Windows back to XP.
let result = unsafe { DefWindowProcW(hwnd.0, WM_GETTEXTLENGTH, WPARAM(0), LPARAM(0)) };
if result.0 <= 0 {
return None;
}
let capacity = (result.0 as usize) + 1; // make room for the null
let mut buffer = Vec::<u16>::with_capacity(capacity);
let result = unsafe {
DefWindowProcW(
hwnd.0,
WM_GETTEXT,
WPARAM(capacity),
LPARAM(buffer.as_mut_ptr() as _),
)
};
if result.0 <= 0 {
return None;
}
let len = result.0 as usize;
unsafe { buffer.set_len(len) };
Some(BSTR::from_wide(&buffer).unwrap())
}
pub(crate) fn toolkit_description(state: &TreeState) -> Option<WideString> {
state.toolkit_name().map(|name| {
let mut result = WideString::default();
result.write_str(name).unwrap();
if let Some(version) = state.toolkit_version() {
result.write_char(' ').unwrap();
result.write_str(version).unwrap();
}
result
})
}
pub(crate) fn upgrade<T>(weak: &Weak<T>) -> Result<Arc<T>> {
if let Some(strong) = weak.upgrade() {
Ok(strong)
} else {
Err(element_not_available())
}
}

View File

@@ -0,0 +1,32 @@
// Copyright 2024 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 windows::Win32::Foundation::HWND;
#[repr(transparent)]
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct WindowHandle(pub HWND);
unsafe impl Send for WindowHandle {}
unsafe impl Sync for WindowHandle {}
impl From<HWND> for WindowHandle {
fn from(value: HWND) -> Self {
Self(value)
}
}
impl From<WindowHandle> for HWND {
fn from(value: WindowHandle) -> Self {
value.0
}
}
#[cfg(test)]
mod tests {
use super::*;
static_assertions::assert_impl_all!(WindowHandle: Send, Sync);
}

View File

@@ -0,0 +1 @@
{"files":{"CHANGELOG.md":"77234283e3c4d17a477b0b4fc38cbd70510dac428f85e6caf306625a1a614352","Cargo.lock":"4b03840434ab5d299db2bacd749017d746fd3e95dbf519ff66c9e83d05f804a2","Cargo.toml":"0e12e6d29c4325bb28190a2f413c3d3e1179d5b0984b3bbeb34949e65701842c","README.md":"94659613e5f5b01f3e6e6823ad4355191172884a04c35b460816c347eb90a15b","examples/mixed_handlers.rs":"38c08816a898f72998ad1d54997d0cd707c87072e5238519983b3341781df075","examples/simple.rs":"0f18cc7c52db0dae613cc2490f87ae75f6daf133a433c3e337156229224fc4c3","src/lib.rs":"e0b0188b5117f5a58688ec6886167698600266a2f60657db57f21d8ca3e0dbd1","src/platform_impl/android.rs":"060bbccd16d492ed58d75e47a24d77bf04b9cf497864145de6de93edce9759dc","src/platform_impl/macos.rs":"9bb36fff123be11afadc7a7f8c09d2b8d04d3f091ad3f6bf23bec55ff933ebf1","src/platform_impl/mod.rs":"7bd9ce32dbdd50903add37e53af398d876d6d570f8b563aaeb57f2b728031aa7","src/platform_impl/null.rs":"0bad7fd53d810d9076ef1cc6feef3e1e68930c26a0677a4fdb38ce36c8658c96","src/platform_impl/unix.rs":"116c505a50fc7ba3c6eb9bc17d6c6dd6065082a8bc246e8889199d4153d1ece3","src/platform_impl/windows.rs":"7222ee5c2c519e5f1a195d9724f720ebf84fa6b6ac11547370f2fb66ec98417b"},"package":"34d941bb8c414caba6e206de669c7dc0dbeb305640ea890772ee422a40e6b89f"}

767
vendor/accesskit_winit/CHANGELOG.md vendored Normal file
View File

@@ -0,0 +1,767 @@
# Changelog
* The following workspace dependencies were updated
* dependencies
* accesskit_macos bumped from 0.1.4 to 0.1.5
* The following workspace dependencies were updated
* dependencies
* accesskit bumped from 0.8.0 to 0.8.1
* accesskit_windows bumped from 0.10.0 to 0.10.1
* accesskit_macos bumped from 0.2.0 to 0.2.1
* The following workspace dependencies were updated
* dependencies
* accesskit_windows bumped from 0.10.1 to 0.10.2
* accesskit_macos bumped from 0.2.1 to 0.3.0
* The following workspace dependencies were updated
* dependencies
* accesskit_macos bumped from 0.3.0 to 0.4.0
* The following workspace dependencies were updated
* dependencies
* accesskit_windows bumped from 0.10.3 to 0.10.4
* accesskit_macos bumped from 0.4.1 to 0.4.2
* accesskit_unix bumped from 0.1.0 to 0.1.1
* The following workspace dependencies were updated
* dependencies
* accesskit_unix bumped from 0.3.0 to 0.3.1
* The following workspace dependencies were updated
* dependencies
* accesskit bumped from 0.10.0 to 0.10.1
* accesskit_windows bumped from 0.13.0 to 0.13.1
* accesskit_macos bumped from 0.6.0 to 0.6.1
* accesskit_unix bumped from 0.3.1 to 0.3.2
* The following workspace dependencies were updated
* dependencies
* accesskit_windows bumped from 0.13.1 to 0.13.2
* The following workspace dependencies were updated
* dependencies
* accesskit_macos bumped from 0.6.1 to 0.6.2
* The following workspace dependencies were updated
* dependencies
* accesskit bumped from 0.10.1 to 0.11.0
* accesskit_windows bumped from 0.13.2 to 0.13.3
* accesskit_macos bumped from 0.6.2 to 0.6.3
* accesskit_unix bumped from 0.3.2 to 0.3.3
* The following workspace dependencies were updated
* dependencies
* accesskit_macos bumped from 0.7.0 to 0.7.1
* The following workspace dependencies were updated
* dependencies
* accesskit bumped from 0.11.0 to 0.11.1
* accesskit_windows bumped from 0.14.0 to 0.14.1
* accesskit_macos bumped from 0.7.1 to 0.8.0
* accesskit_unix bumped from 0.5.0 to 0.5.1
* The following workspace dependencies were updated
* dependencies
* accesskit bumped from 0.11.1 to 0.11.2
* accesskit_windows bumped from 0.14.1 to 0.14.2
* accesskit_macos bumped from 0.8.0 to 0.9.0
* accesskit_unix bumped from 0.5.1 to 0.5.2
* The following workspace dependencies were updated
* dependencies
* accesskit_windows bumped from 0.14.2 to 0.14.3
* The following workspace dependencies were updated
* dependencies
* accesskit_windows bumped from 0.16.0 to 0.16.1
* accesskit_unix bumped from 0.7.1 to 0.7.2
* The following workspace dependencies were updated
* dependencies
* accesskit_unix bumped from 0.7.2 to 0.7.3
* The following workspace dependencies were updated
* dependencies
* accesskit_windows bumped from 0.16.1 to 0.16.2
* The following workspace dependencies were updated
* dependencies
* accesskit bumped from 0.12.2 to 0.12.3
* accesskit_windows bumped from 0.16.2 to 0.16.3
* accesskit_macos bumped from 0.11.0 to 0.11.1
* accesskit_unix bumped from 0.7.3 to 0.7.4
* The following workspace dependencies were updated
* dependencies
* accesskit_unix bumped from 0.7.4 to 0.7.5
* The following workspace dependencies were updated
* dependencies
* accesskit_windows bumped from 0.16.3 to 0.16.4
* The following workspace dependencies were updated
* dependencies
* accesskit_windows bumped from 0.18.0 to 0.18.1
* accesskit_macos bumped from 0.13.0 to 0.13.1
* accesskit_unix bumped from 0.9.0 to 0.9.1
* The following workspace dependencies were updated
* dependencies
* accesskit_windows bumped from 0.18.1 to 0.18.2
* accesskit_macos bumped from 0.13.1 to 0.13.2
* accesskit_unix bumped from 0.9.1 to 0.9.2
* The following workspace dependencies were updated
* dependencies
* accesskit_windows bumped from 0.18.2 to 0.19.0
* accesskit_macos bumped from 0.13.2 to 0.14.0
* accesskit_unix bumped from 0.9.2 to 0.10.0
* The following workspace dependencies were updated
* dependencies
* accesskit_windows bumped from 0.19.0 to 0.20.0
* accesskit_macos bumped from 0.14.0 to 0.15.0
* accesskit_unix bumped from 0.10.0 to 0.10.1
* The following workspace dependencies were updated
* dependencies
* accesskit_unix bumped from 0.11.0 to 0.11.1
* The following workspace dependencies were updated
* dependencies
* accesskit bumped from 0.16.2 to 0.16.3
* accesskit_windows bumped from 0.23.1 to 0.23.2
* accesskit_macos bumped from 0.17.2 to 0.17.3
* accesskit_unix bumped from 0.12.2 to 0.12.3
* The following workspace dependencies were updated
* dependencies
* accesskit_macos bumped from 0.17.3 to 0.17.4
* The following workspace dependencies were updated
* dependencies
* accesskit bumped from 0.17.0 to 0.17.1
* accesskit_windows bumped from 0.24.0 to 0.24.1
* accesskit_macos bumped from 0.18.0 to 0.18.1
* accesskit_unix bumped from 0.13.0 to 0.13.1
## [0.25.0](https://github.com/AccessKit/accesskit/compare/accesskit_winit-v0.24.0...accesskit_winit-v0.25.0) (2025-03-08)
### ⚠ BREAKING CHANGES
* Make accesskit_android an optional dependency of accesskit_winit ([#524](https://github.com/AccessKit/accesskit/issues/524))
### Bug Fixes
* Make accesskit_android an optional dependency of accesskit_winit ([#524](https://github.com/AccessKit/accesskit/issues/524)) ([bb17d44](https://github.com/AccessKit/accesskit/commit/bb17d449b601eaffad1c7201ec5bf8de241bb8f8))
## [0.24.0](https://github.com/AccessKit/accesskit/compare/accesskit_winit-v0.23.1...accesskit_winit-v0.24.0) (2025-03-06)
### ⚠ BREAKING CHANGES
* Add event loop parameter to winit adapter constructors ([#517](https://github.com/AccessKit/accesskit/issues/517))
* Drop `Tree::app_name` ([#492](https://github.com/AccessKit/accesskit/issues/492))
### Features
* Android adapter ([#500](https://github.com/AccessKit/accesskit/issues/500)) ([7e65ac7](https://github.com/AccessKit/accesskit/commit/7e65ac77d7e108ac5b9f3722f488a2fdf2e3b3e0))
### Bug Fixes
* Update winit to 0.30.9 ([#511](https://github.com/AccessKit/accesskit/issues/511)) ([0be21e6](https://github.com/AccessKit/accesskit/commit/0be21e6a2979af483b573b1c9b07c677286b871d))
### Code Refactoring
* Add event loop parameter to winit adapter constructors ([#517](https://github.com/AccessKit/accesskit/issues/517)) ([0d15f24](https://github.com/AccessKit/accesskit/commit/0d15f246a301a68af4424f7602c2f3be25da9327))
* Drop `Tree::app_name` ([#492](https://github.com/AccessKit/accesskit/issues/492)) ([089794c](https://github.com/AccessKit/accesskit/commit/089794c8f74957e91a19ae3df508e2a892f39ebc))
### Dependencies
* The following workspace dependencies were updated
* dependencies
* accesskit bumped from 0.17.1 to 0.18.0
* accesskit_windows bumped from 0.24.1 to 0.25.0
* accesskit_macos bumped from 0.18.1 to 0.19.0
* accesskit_unix bumped from 0.13.1 to 0.14.0
## [0.23.0](https://github.com/AccessKit/accesskit/compare/accesskit_winit-v0.22.4...accesskit_winit-v0.23.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))
* 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))
### Dependencies
* The following workspace dependencies were updated
* dependencies
* accesskit bumped from 0.16.3 to 0.17.0
* accesskit_windows bumped from 0.23.2 to 0.24.0
* accesskit_macos bumped from 0.17.4 to 0.18.0
* accesskit_unix bumped from 0.12.3 to 0.13.0
## [0.22.2](https://github.com/AccessKit/accesskit/compare/accesskit_winit-v0.22.1...accesskit_winit-v0.22.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
* accesskit_windows bumped from 0.23.0 to 0.23.1
* accesskit_macos bumped from 0.17.1 to 0.17.2
* accesskit_unix bumped from 0.12.1 to 0.12.2
## [0.22.1](https://github.com/AccessKit/accesskit/compare/accesskit_winit-v0.22.0...accesskit_winit-v0.22.1) (2024-09-24)
### Bug Fixes
* Use the new HWND type on accesskit_winit ([#453](https://github.com/AccessKit/accesskit/issues/453)) ([68a2462](https://github.com/AccessKit/accesskit/commit/68a24629381f0b18f6ed1ee008fe72ce9330092e))
### Dependencies
* The following workspace dependencies were updated
* dependencies
* accesskit bumped from 0.16.0 to 0.16.1
* accesskit_windows bumped from 0.22.0 to 0.23.0
* accesskit_macos bumped from 0.17.0 to 0.17.1
* accesskit_unix bumped from 0.12.0 to 0.12.1
## [0.22.0](https://github.com/AccessKit/accesskit/compare/accesskit_winit-v0.21.1...accesskit_winit-v0.22.0) (2024-06-29)
### ⚠ BREAKING CHANGES
* Rename the `StaticText` role to `Label` ([#434](https://github.com/AccessKit/accesskit/issues/434))
### 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
* accesskit_windows bumped from 0.21.0 to 0.22.0
* accesskit_macos bumped from 0.16.0 to 0.17.0
* accesskit_unix bumped from 0.11.1 to 0.12.0
## [0.21.0](https://github.com/AccessKit/accesskit/compare/accesskit_winit-v0.20.4...accesskit_winit-v0.21.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))
### Dependencies
* The following workspace dependencies were updated
* dependencies
* accesskit bumped from 0.14.0 to 0.15.0
* accesskit_windows bumped from 0.20.0 to 0.21.0
* accesskit_macos bumped from 0.15.0 to 0.16.0
* accesskit_unix bumped from 0.10.1 to 0.11.0
## [0.20.0](https://github.com/AccessKit/accesskit/compare/accesskit_winit-v0.19.0...accesskit_winit-v0.20.0) (2024-04-30)
### ⚠ BREAKING CHANGES
* Update winit to 0.30 ([#397](https://github.com/AccessKit/accesskit/issues/397))
* Drop `NodeClassSet` ([#389](https://github.com/AccessKit/accesskit/issues/389))
### 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))
* Update winit to 0.30 ([#397](https://github.com/AccessKit/accesskit/issues/397)) ([de93be3](https://github.com/AccessKit/accesskit/commit/de93be387c03a438fbf598670207e578686e6bcf))
### Code Refactoring
* Drop `NodeClassSet` ([#389](https://github.com/AccessKit/accesskit/issues/389)) ([1b153ed](https://github.com/AccessKit/accesskit/commit/1b153ed51f8421cdba2dc98beca2e8f5f8c781bc))
### Dependencies
* The following workspace dependencies were updated
* dependencies
* accesskit bumped from 0.13.0 to 0.14.0
* accesskit_windows bumped from 0.17.0 to 0.18.0
* accesskit_macos bumped from 0.12.0 to 0.13.0
* accesskit_unix bumped from 0.8.0 to 0.9.0
## [0.19.0](https://github.com/AccessKit/accesskit/compare/accesskit_winit-v0.18.7...accesskit_winit-v0.19.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
* accesskit_windows bumped from 0.16.4 to 0.17.0
* accesskit_macos bumped from 0.11.1 to 0.12.0
* accesskit_unix bumped from 0.7.5 to 0.8.0
## [0.18.1](https://github.com/AccessKit/accesskit/compare/accesskit_winit-v0.18.0...accesskit_winit-v0.18.1) (2024-01-11)
### Bug Fixes
* Run our own async executor on Unix ([#337](https://github.com/AccessKit/accesskit/issues/337)) ([8f937ba](https://github.com/AccessKit/accesskit/commit/8f937baaa510dd96da196501822b82f75f05b595))
* Show an error at compile-time if no raw-window-handle feature is enabled for the winit adapter ([#339](https://github.com/AccessKit/accesskit/issues/339)) ([a24f5fd](https://github.com/AccessKit/accesskit/commit/a24f5fd443a683a6194b54244052ff3e1cc05de6))
### Dependencies
* The following workspace dependencies were updated
* dependencies
* accesskit_unix bumped from 0.7.0 to 0.7.1
## [0.18.0](https://github.com/AccessKit/accesskit/compare/accesskit_winit-v0.17.0...accesskit_winit-v0.18.0) (2024-01-03)
### ⚠ BREAKING CHANGES
* Lazily activate Unix adapters ([#324](https://github.com/AccessKit/accesskit/issues/324))
* Remove `accesskit_winit::Adapter::update` ([#325](https://github.com/AccessKit/accesskit/issues/325))
### Bug Fixes
* Lazily activate Unix adapters ([#324](https://github.com/AccessKit/accesskit/issues/324)) ([54ed036](https://github.com/AccessKit/accesskit/commit/54ed036c99d87428a8eb5bb03fd77e9e31562d4c))
* Remove `accesskit_winit::Adapter::update` ([#325](https://github.com/AccessKit/accesskit/issues/325)) ([f121bff](https://github.com/AccessKit/accesskit/commit/f121bffe9e651fd2ac6deb882f57e1c9b613b7eb))
### Dependencies
* The following workspace dependencies were updated
* dependencies
* accesskit bumped from 0.12.1 to 0.12.2
* accesskit_windows bumped from 0.15.1 to 0.16.0
* accesskit_macos bumped from 0.10.1 to 0.11.0
* accesskit_unix bumped from 0.6.2 to 0.7.0
## [0.17.0](https://github.com/AccessKit/accesskit/compare/accesskit_winit-v0.16.1...accesskit_winit-v0.17.0) (2023-12-14)
### ⚠ BREAKING CHANGES
* Force a semver break for the winit rwh feature additions ([#322](https://github.com/AccessKit/accesskit/issues/322))
### Bug Fixes
* Add a `rwh_05` feature flag to `accesskit_winit` ([#319](https://github.com/AccessKit/accesskit/issues/319)) ([f4d279c](https://github.com/AccessKit/accesskit/commit/f4d279c5ece16df2925c0e31dc82eaf192c40cd0))
* Force a semver break for the winit rwh feature additions ([#322](https://github.com/AccessKit/accesskit/issues/322)) ([61acdb0](https://github.com/AccessKit/accesskit/commit/61acdb0ea083263c88a00ad4db637b25863852c0))
### Dependencies
* The following workspace dependencies were updated
* dependencies
* accesskit_unix bumped from 0.6.1 to 0.6.2
## [0.16.1](https://github.com/AccessKit/accesskit/compare/accesskit_winit-v0.16.0...accesskit_winit-v0.16.1) (2023-11-05)
### Bug Fixes
* Account for window decorations when `accesskit_winit::Adapter::process_event` receives a resizing event on Unix ([#312](https://github.com/AccessKit/accesskit/issues/312)) ([e2b264c](https://github.com/AccessKit/accesskit/commit/e2b264c2e5b0fb699576f2ece905509c38ffc9be))
## [0.16.0](https://github.com/AccessKit/accesskit/compare/accesskit_winit-v0.15.0...accesskit_winit-v0.16.0) (2023-11-04)
### ⚠ BREAKING CHANGES
* Rename `accesskit_winit::Adapter::on_event` to `process_event` ([#307](https://github.com/AccessKit/accesskit/issues/307))
* Bump winit to 0.29 ([#256](https://github.com/AccessKit/accesskit/issues/256))
### deps
* Bump winit to 0.29 ([#256](https://github.com/AccessKit/accesskit/issues/256)) ([4eb21ff](https://github.com/AccessKit/accesskit/commit/4eb21ff64256fcf0a16ab831554b06b80de9b36e))
### 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))
* Use raw-window-handle 0.6 ([#310](https://github.com/AccessKit/accesskit/issues/310)) ([3fa69ab](https://github.com/AccessKit/accesskit/commit/3fa69ab4d9216b51b651d3cf2a9c8217a77069f4))
### Code Refactoring
* Rename `accesskit_winit::Adapter::on_event` to `process_event` ([#307](https://github.com/AccessKit/accesskit/issues/307)) ([6fbebde](https://github.com/AccessKit/accesskit/commit/6fbebdeb9d1e96b1776ed1faf7ad21d9cc0a68df))
### Dependencies
* The following workspace dependencies were updated
* dependencies
* accesskit bumped from 0.12.0 to 0.12.1
* accesskit_windows bumped from 0.15.0 to 0.15.1
* accesskit_macos bumped from 0.10.0 to 0.10.1
* accesskit_unix bumped from 0.6.0 to 0.6.1
## [0.15.0](https://github.com/AccessKit/accesskit/compare/accesskit_winit-v0.14.4...accesskit_winit-v0.15.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))
* Make `ActionHandler::do_action` take `&mut self` ([#296](https://github.com/AccessKit/accesskit/issues/296))
* 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
* 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
* Fix doc build for accesskit_winit ([#281](https://github.com/AccessKit/accesskit/issues/281)) ([e3b38b8](https://github.com/AccessKit/accesskit/commit/e3b38b8164d0c5442a5a1904165e2b05847376c2))
### Code Refactoring
* 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))
* Make `ActionHandler::do_action` take `&mut self` ([#296](https://github.com/AccessKit/accesskit/issues/296)) ([4fc7846](https://github.com/AccessKit/accesskit/commit/4fc7846d732d61fb45c023060ebab96801a0053e))
* 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
* accesskit_windows bumped from 0.14.3 to 0.15.0
* accesskit_macos bumped from 0.9.0 to 0.10.0
* accesskit_unix bumped from 0.5.2 to 0.6.0
## [0.14.0](https://github.com/AccessKit/accesskit/compare/accesskit_winit-v0.13.0...accesskit_winit-v0.14.0) (2023-05-21)
### Features
* Add features for async runtimes on Unix ([#248](https://github.com/AccessKit/accesskit/issues/248)) ([b56b4ea](https://github.com/AccessKit/accesskit/commit/b56b4ea7c967ee5a1dae21a2fa0dcd385346031e))
### Dependencies
* The following workspace dependencies were updated
* dependencies
* accesskit_unix bumped from 0.4.0 to 0.5.0
## [0.13.0](https://github.com/AccessKit/accesskit/compare/accesskit_winit-v0.12.5...accesskit_winit-v0.13.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))
### Dependencies
* The following workspace dependencies were updated
* dependencies
* accesskit_windows bumped from 0.13.3 to 0.14.0
* accesskit_macos bumped from 0.6.3 to 0.7.0
* accesskit_unix bumped from 0.3.3 to 0.4.0
## [0.12.0](https://github.com/AccessKit/accesskit/compare/accesskit_winit-v0.11.0...accesskit_winit-v0.12.0) (2023-02-18)
### Features
* Feature-gate the Unix adapter in accesskit_winit ([#214](https://github.com/AccessKit/accesskit/issues/214)) ([be95807](https://github.com/AccessKit/accesskit/commit/be95807dda64f2a49b4d20cc9084b14a7aa2844e))
## [0.11.0](https://github.com/AccessKit/accesskit/compare/accesskit_winit-v0.10.0...accesskit_winit-v0.11.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
* accesskit_windows bumped from 0.12.0 to 0.13.0
* accesskit_macos bumped from 0.5.0 to 0.6.0
* accesskit_unix bumped from 0.2.0 to 0.3.0
## [0.10.0](https://github.com/AccessKit/accesskit/compare/accesskit_winit-v0.9.1...accesskit_winit-v0.10.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
* accesskit_windows bumped from 0.11.0 to 0.12.0
* accesskit_macos bumped from 0.4.2 to 0.5.0
* accesskit_unix bumped from 0.1.1 to 0.2.0
## [0.9.1](https://github.com/AccessKit/accesskit/compare/accesskit_winit-v0.9.0...accesskit_winit-v0.9.1) (2023-02-05)
### Bug Fixes
* Don't force winit's X11 and Wayland features to be enabled ([#209](https://github.com/AccessKit/accesskit/issues/209)) ([a3ed357](https://github.com/AccessKit/accesskit/commit/a3ed35754ad8f69a8ed54adacc30b6d57c19329a))
## [0.9.0](https://github.com/AccessKit/accesskit/compare/accesskit_winit-v0.8.1...accesskit_winit-v0.9.0) (2023-02-02)
### ⚠ BREAKING CHANGES
* Update winit to 0.28 ([#207](https://github.com/AccessKit/accesskit/issues/207))
### Miscellaneous Chores
* Update winit to 0.28 ([#207](https://github.com/AccessKit/accesskit/issues/207)) ([3ff0cf5](https://github.com/AccessKit/accesskit/commit/3ff0cf59f982af504499142a3804f7aeeb4defe0))
### Dependencies
* The following workspace dependencies were updated
* dependencies
* accesskit_windows bumped from 0.10.4 to 0.11.0
## [0.8.0](https://github.com/AccessKit/accesskit/compare/accesskit_winit-v0.7.3...accesskit_winit-v0.8.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))
### Dependencies
* The following workspace dependencies were updated
* dependencies
* accesskit_windows bumped from 0.10.2 to 0.10.3
* accesskit_macos bumped from 0.4.0 to 0.4.1
## [0.7.0](https://github.com/AccessKit/accesskit/compare/accesskit_winit-v0.6.6...accesskit_winit-v0.7.0) (2022-11-29)
### ⚠ BREAKING CHANGES
* Move lazy initialization from the core platform adapter to the caller ([#179](https://github.com/AccessKit/accesskit/issues/179))
### Code Refactoring
* Move lazy initialization from the core platform adapter to the caller ([#179](https://github.com/AccessKit/accesskit/issues/179)) ([f35c941](https://github.com/AccessKit/accesskit/commit/f35c941f395f3162db376a69cfaaaf770d376267))
### Dependencies
* The following workspace dependencies were updated
* dependencies
* accesskit_windows bumped from 0.9.3 to 0.10.0
* accesskit_macos bumped from 0.1.5 to 0.2.0
### [0.6.4](https://www.github.com/AccessKit/accesskit/compare/accesskit_winit-v0.6.3...accesskit_winit-v0.6.4) (2022-11-25)
### Bug Fixes
* Reduce the winit version requirement to match egui ([#170](https://www.github.com/AccessKit/accesskit/issues/170)) ([1d27482](https://www.github.com/AccessKit/accesskit/commit/1d27482221140c1f3b3e3eaf93e7feaf8105611d))
## [0.6.0](https://www.github.com/AccessKit/accesskit/compare/accesskit_winit-v0.5.1...accesskit_winit-v0.6.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))
### Bug Fixes
* **platforms/macos:** Fix macOS crate version number ([#161](https://www.github.com/AccessKit/accesskit/issues/161)) ([e0a6a40](https://www.github.com/AccessKit/accesskit/commit/e0a6a401050cdcaea4efa870ed77ae94388f1ce0))
* **platforms/windows:** Re-export the windows-rs HWND type ([#159](https://www.github.com/AccessKit/accesskit/issues/159)) ([389187a](https://www.github.com/AccessKit/accesskit/commit/389187ac5e96895ed1763d14d315d2f8f4256460))
### [0.5.1](https://www.github.com/AccessKit/accesskit/compare/accesskit_winit-v0.5.0...accesskit_winit-v0.5.1) (2022-11-17)
### Bug Fixes
* **platforms/winit:** Eliminate some problematic indirect dependencies ([#154](https://www.github.com/AccessKit/accesskit/issues/154)) ([58048ae](https://www.github.com/AccessKit/accesskit/commit/58048aebedc293eda5c5819ea66db9b40b8926b0))
### Dependencies
* The following workspace dependencies were updated
* dependencies
* accesskit bumped from 0.7.0 to 0.8.0
## [0.5.0](https://www.github.com/AccessKit/accesskit/compare/accesskit_winit-v0.4.0...accesskit_winit-v0.5.0) (2022-11-14)
### Features
* **platforms/winit:** Allow a custom action handler ([#149](https://www.github.com/AccessKit/accesskit/issues/149)) ([cdb1a16](https://www.github.com/AccessKit/accesskit/commit/cdb1a164de06f18cad497409a514f270a8336b4c))
## [0.4.0](https://www.github.com/AccessKit/accesskit/compare/accesskit_winit-v0.3.3...accesskit_winit-v0.4.0) (2022-11-12)
### ⚠ BREAKING CHANGES
* **platforms/windows:** Update to windows-rs 0.42.0 (#148)
### 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))
* **platforms/windows:** Update to windows-rs 0.42.0 ([#148](https://www.github.com/AccessKit/accesskit/issues/148)) ([70d1a89](https://www.github.com/AccessKit/accesskit/commit/70d1a89f51fd6c3a32b7192d9d7f3937db09d196))
### [0.3.3](https://www.github.com/AccessKit/accesskit/compare/accesskit_winit-v0.3.2...accesskit_winit-v0.3.3) (2022-11-11)
### Dependencies
* The following workspace dependencies were updated
* dependencies
* accesskit bumped from 0.6.1 to 0.7.0
### [0.3.2](https://www.github.com/AccessKit/accesskit/compare/accesskit_winit-v0.3.1...accesskit_winit-v0.3.2) (2022-10-11)
### Bug Fixes
* **platforms/winit:** Derive `Debug` on `ActionRequestEvent` ([#141](https://www.github.com/AccessKit/accesskit/issues/141)) ([8b84c75](https://www.github.com/AccessKit/accesskit/commit/8b84c7547c6fdb52cd6d5c6d79f812dc614f08dd))
### [0.3.1](https://www.github.com/AccessKit/accesskit/compare/accesskit_winit-v0.3.0...accesskit_winit-v0.3.1) (2022-10-10)
### Dependencies
* The following workspace dependencies were updated
* dependencies
* accesskit bumped from 0.6.0 to 0.6.1
## [0.3.0](https://www.github.com/AccessKit/accesskit/compare/accesskit_winit-v0.2.1...accesskit_winit-v0.3.0) (2022-10-09)
### ⚠ BREAKING CHANGES
* Wrap `TreeUpdate` nodes in `Arc` (#135)
* Store node ID in `TreeUpdate`, not `accesskit::Node` (#132)
### Code Refactoring
* 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.2.1](https://www.github.com/AccessKit/accesskit/compare/accesskit_winit-v0.2.0...accesskit_winit-v0.2.1) (2022-10-03)
### Dependencies
* The following workspace dependencies were updated
* dependencies
* accesskit bumped from 0.5.0 to 0.5.1
## [0.2.0](https://www.github.com/AccessKit/accesskit/compare/accesskit_winit-v0.1.0...accesskit_winit-v0.2.0) (2022-09-23)
### ⚠ BREAKING CHANGES
* Basic live regions (#128)
* **platforms/windows:** Bump windows-rs dependency (#126)
* **platforms/winit:** Bump winit dependency (#125)
### Features
* Basic live regions ([#128](https://www.github.com/AccessKit/accesskit/issues/128)) ([03d745b](https://www.github.com/AccessKit/accesskit/commit/03d745b891147175bde2693cc10b96a2f6e31f39))
### Miscellaneous Chores
* **platforms/windows:** Bump windows-rs dependency ([#126](https://www.github.com/AccessKit/accesskit/issues/126)) ([472a75e](https://www.github.com/AccessKit/accesskit/commit/472a75e4214b90396f3282f247df08100ed8362d))
* **platforms/winit:** Bump winit dependency ([#125](https://www.github.com/AccessKit/accesskit/issues/125)) ([6026c1b](https://www.github.com/AccessKit/accesskit/commit/6026c1b2ecede3ca2f2076075ed158000154b34e))
### Dependencies
* The following workspace dependencies were updated
* dependencies
* accesskit bumped from 0.4.0 to 0.5.0
## 0.1.0 (2022-07-22)
### Features
* **platforms/winit:** New winit adapter ([#121](https://www.github.com/AccessKit/accesskit/issues/121)) ([fdc274e](https://www.github.com/AccessKit/accesskit/commit/fdc274e7d3a901873d2ad0c7a4824a19111787ef))
### Dependencies
* The following workspace dependencies were updated
* dependencies
* accesskit bumped from 0.3.0 to 0.4.0

2652
vendor/accesskit_winit/Cargo.lock generated vendored Normal file

File diff suppressed because it is too large Load Diff

110
vendor/accesskit_winit/Cargo.toml vendored Normal file
View File

@@ -0,0 +1,110 @@
# 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_winit"
version = "0.25.0"
authors = ["The AccessKit contributors"]
build = false
autolib = false
autobins = false
autoexamples = false
autotests = false
autobenches = false
description = "AccessKit UI accessibility infrastructure: winit adapter"
readme = "README.md"
keywords = [
"gui",
"ui",
"accessibility",
"winit",
]
categories = ["gui"]
license = "Apache-2.0"
repository = "https://github.com/AccessKit/accesskit"
[features]
async-io = ["accesskit_unix/async-io"]
default = [
"accesskit_unix",
"async-io",
"rwh_06",
"winit/x11",
"winit/wayland",
]
rwh_05 = [
"winit/rwh_05",
"dep:rwh_05",
]
rwh_06 = [
"winit/rwh_06",
"dep:rwh_06",
]
tokio = ["accesskit_unix/tokio"]
[lib]
name = "accesskit_winit"
path = "src/lib.rs"
[[example]]
name = "mixed_handlers"
path = "examples/mixed_handlers.rs"
[[example]]
name = "simple"
path = "examples/simple.rs"
[dependencies.accesskit]
version = "0.18.0"
[dependencies.rwh_05]
version = "0.5"
features = ["std"]
optional = true
package = "raw-window-handle"
[dependencies.rwh_06]
version = "0.6.2"
features = ["std"]
optional = true
package = "raw-window-handle"
[dependencies.winit]
version = "0.30.5"
default-features = false
[dev-dependencies.winit]
version = "0.30.5"
features = [
"x11",
"wayland",
"wayland-dlopen",
"wayland-csd-adwaita",
]
default-features = false
[target.'cfg(any(target_os = "linux", target_os = "dragonfly", target_os = "freebsd", target_os = "openbsd", target_os = "netbsd"))'.dependencies.accesskit_unix]
version = "0.14.0"
optional = true
default-features = false
[target.'cfg(target_os = "android")'.dependencies.accesskit_android]
version = "0.1.0"
features = ["embedded-dex"]
optional = true
[target.'cfg(target_os = "macos")'.dependencies.accesskit_macos]
version = "0.19.0"
[target.'cfg(target_os = "windows")'.dependencies.accesskit_windows]
version = "0.25.0"

16
vendor/accesskit_winit/README.md vendored Normal file
View File

@@ -0,0 +1,16 @@
# AccessKit winit adapter
This is the winit adapter for [AccessKit](https://accesskit.dev/). It exposes an AccessKit accessibility tree through the platform-native accessibility API on any platform supported by AccessKit. On platforms not supported by AccessKit, this adapter does nothing, but still compiles.
## Compatibility with async runtimes
The following only applies on Linux/Unix:
While this crate's API is purely blocking, it internally spawns asynchronous tasks on an executor.
- If you use tokio, make sure to enable the `tokio` feature of this crate.
- If you use another async runtime or if you don't use one at all, the default feature will suit your needs.
## Android activity compatibility
The Android implementation of this adapter currently only works with [GameActivity](https://developer.android.com/games/agdk/game-activity), which is one of the two activity implementations that winit currently supports.

View File

@@ -0,0 +1,300 @@
use accesskit::{
Action, ActionRequest, ActivationHandler, Live, Node, NodeId, Rect, Role, Tree, TreeUpdate,
};
use accesskit_winit::{Adapter, Event as AccessKitEvent, WindowEvent as AccessKitWindowEvent};
use std::{
error::Error,
sync::{Arc, Mutex},
};
use winit::{
application::ApplicationHandler,
event::{ElementState, KeyEvent, WindowEvent},
event_loop::{ActiveEventLoop, EventLoop, EventLoopProxy},
keyboard::Key,
window::{Window, WindowId},
};
const WINDOW_TITLE: &str = "Hello world";
const WINDOW_ID: NodeId = NodeId(0);
const BUTTON_1_ID: NodeId = NodeId(1);
const BUTTON_2_ID: NodeId = NodeId(2);
const ANNOUNCEMENT_ID: NodeId = NodeId(3);
const INITIAL_FOCUS: NodeId = BUTTON_1_ID;
const BUTTON_1_RECT: Rect = Rect {
x0: 20.0,
y0: 20.0,
x1: 100.0,
y1: 60.0,
};
const BUTTON_2_RECT: Rect = Rect {
x0: 20.0,
y0: 60.0,
x1: 100.0,
y1: 100.0,
};
fn build_button(id: NodeId, label: &str) -> Node {
let rect = match id {
BUTTON_1_ID => BUTTON_1_RECT,
BUTTON_2_ID => BUTTON_2_RECT,
_ => unreachable!(),
};
let mut node = Node::new(Role::Button);
node.set_bounds(rect);
node.set_label(label);
node.add_action(Action::Focus);
node.add_action(Action::Click);
node
}
fn build_announcement(text: &str) -> Node {
let mut node = Node::new(Role::Label);
node.set_value(text);
node.set_live(Live::Polite);
node
}
struct UiState {
focus: NodeId,
announcement: Option<String>,
}
impl UiState {
fn new() -> Arc<Mutex<Self>> {
Arc::new(Mutex::new(Self {
focus: INITIAL_FOCUS,
announcement: None,
}))
}
fn build_root(&mut self) -> Node {
let mut node = Node::new(Role::Window);
node.set_children(vec![BUTTON_1_ID, BUTTON_2_ID]);
if self.announcement.is_some() {
node.push_child(ANNOUNCEMENT_ID);
}
node.set_label(WINDOW_TITLE);
node
}
fn build_initial_tree(&mut self) -> TreeUpdate {
let root = self.build_root();
let button_1 = build_button(BUTTON_1_ID, "Button 1");
let button_2 = build_button(BUTTON_2_ID, "Button 2");
let tree = Tree::new(WINDOW_ID);
let mut result = TreeUpdate {
nodes: vec![
(WINDOW_ID, root),
(BUTTON_1_ID, button_1),
(BUTTON_2_ID, button_2),
],
tree: Some(tree),
focus: self.focus,
};
if let Some(announcement) = &self.announcement {
result
.nodes
.push((ANNOUNCEMENT_ID, build_announcement(announcement)));
}
result
}
fn set_focus(&mut self, adapter: &mut Adapter, focus: NodeId) {
self.focus = focus;
adapter.update_if_active(|| TreeUpdate {
nodes: vec![],
tree: None,
focus,
});
}
fn press_button(&mut self, adapter: &mut Adapter, id: NodeId) {
let text = if id == BUTTON_1_ID {
"You pressed button 1"
} else {
"You pressed button 2"
};
self.announcement = Some(text.into());
adapter.update_if_active(|| {
let announcement = build_announcement(text);
let root = self.build_root();
TreeUpdate {
nodes: vec![(ANNOUNCEMENT_ID, announcement), (WINDOW_ID, root)],
tree: None,
focus: self.focus,
}
});
}
}
struct TearoffActivationHandler {
state: Arc<Mutex<UiState>>,
}
impl ActivationHandler for TearoffActivationHandler {
fn request_initial_tree(&mut self) -> Option<TreeUpdate> {
Some(self.state.lock().unwrap().build_initial_tree())
}
}
struct WindowState {
window: Window,
adapter: Adapter,
ui: Arc<Mutex<UiState>>,
}
impl WindowState {
fn new(window: Window, adapter: Adapter, ui: Arc<Mutex<UiState>>) -> Self {
Self {
window,
adapter,
ui,
}
}
}
struct Application {
event_loop_proxy: EventLoopProxy<AccessKitEvent>,
window: Option<WindowState>,
}
impl Application {
fn new(event_loop_proxy: EventLoopProxy<AccessKitEvent>) -> Self {
Self {
event_loop_proxy,
window: None,
}
}
fn create_window(&mut self, event_loop: &ActiveEventLoop) -> Result<(), Box<dyn Error>> {
let window_attributes = Window::default_attributes()
.with_title(WINDOW_TITLE)
.with_visible(false);
let window = event_loop.create_window(window_attributes)?;
let ui = UiState::new();
let activation_handler = TearoffActivationHandler {
state: Arc::clone(&ui),
};
let adapter = Adapter::with_mixed_handlers(
event_loop,
&window,
activation_handler,
self.event_loop_proxy.clone(),
);
window.set_visible(true);
self.window = Some(WindowState::new(window, adapter, ui));
Ok(())
}
}
impl ApplicationHandler<AccessKitEvent> for Application {
fn window_event(&mut self, _: &ActiveEventLoop, _: WindowId, event: WindowEvent) {
let window = match &mut self.window {
Some(window) => window,
None => return,
};
let adapter = &mut window.adapter;
let state = &mut window.ui;
adapter.process_event(&window.window, &event);
match event {
WindowEvent::CloseRequested => {
self.window = None;
}
WindowEvent::KeyboardInput {
event:
KeyEvent {
logical_key: virtual_code,
state: ElementState::Pressed,
..
},
..
} => match virtual_code {
Key::Named(winit::keyboard::NamedKey::Tab) => {
let mut state = state.lock().unwrap();
let new_focus = if state.focus == BUTTON_1_ID {
BUTTON_2_ID
} else {
BUTTON_1_ID
};
state.set_focus(adapter, new_focus);
}
Key::Named(winit::keyboard::NamedKey::Space) => {
let mut state = state.lock().unwrap();
let id = state.focus;
state.press_button(adapter, id);
}
_ => (),
},
_ => (),
}
}
fn user_event(&mut self, _: &ActiveEventLoop, user_event: AccessKitEvent) {
let window = match &mut self.window {
Some(window) => window,
None => return,
};
let adapter = &mut window.adapter;
let state = &mut window.ui;
match user_event.window_event {
AccessKitWindowEvent::InitialTreeRequested => unreachable!(),
AccessKitWindowEvent::ActionRequested(ActionRequest { action, target, .. }) => {
if target == BUTTON_1_ID || target == BUTTON_2_ID {
let mut state = state.lock().unwrap();
match action {
Action::Focus => {
state.set_focus(adapter, target);
}
Action::Click => {
state.press_button(adapter, target);
}
_ => (),
}
}
}
AccessKitWindowEvent::AccessibilityDeactivated => (),
}
}
fn resumed(&mut self, event_loop: &ActiveEventLoop) {
self.create_window(event_loop)
.expect("failed to create initial window");
}
fn about_to_wait(&mut self, event_loop: &ActiveEventLoop) {
if self.window.is_none() {
event_loop.exit();
}
}
}
fn main() -> Result<(), Box<dyn Error>> {
println!("This example has no visible GUI, and a keyboard interface:");
println!("- [Tab] switches focus between two logical buttons.");
println!("- [Space] 'presses' the button, adding static text in a live region announcing that it was pressed.");
#[cfg(target_os = "windows")]
println!("Enable Narrator with [Win]+[Ctrl]+[Enter] (or [Win]+[Enter] on older versions of Windows).");
#[cfg(all(
feature = "accesskit_unix",
any(
target_os = "linux",
target_os = "dragonfly",
target_os = "freebsd",
target_os = "netbsd",
target_os = "openbsd"
)
))]
println!("Enable Orca with [Super]+[Alt]+[S].");
let event_loop = EventLoop::with_user_event().build()?;
let mut state = Application::new(event_loop.create_proxy());
event_loop.run_app(&mut state).map_err(Into::into)
}

View File

@@ -0,0 +1,276 @@
use accesskit::{Action, ActionRequest, Live, Node, NodeId, Rect, Role, Tree, TreeUpdate};
use accesskit_winit::{Adapter, Event as AccessKitEvent, WindowEvent as AccessKitWindowEvent};
use std::error::Error;
use winit::{
application::ApplicationHandler,
event::{ElementState, KeyEvent, WindowEvent},
event_loop::{ActiveEventLoop, EventLoop, EventLoopProxy},
keyboard::Key,
window::{Window, WindowId},
};
const WINDOW_TITLE: &str = "Hello world";
const WINDOW_ID: NodeId = NodeId(0);
const BUTTON_1_ID: NodeId = NodeId(1);
const BUTTON_2_ID: NodeId = NodeId(2);
const ANNOUNCEMENT_ID: NodeId = NodeId(3);
const INITIAL_FOCUS: NodeId = BUTTON_1_ID;
const BUTTON_1_RECT: Rect = Rect {
x0: 20.0,
y0: 20.0,
x1: 100.0,
y1: 60.0,
};
const BUTTON_2_RECT: Rect = Rect {
x0: 20.0,
y0: 60.0,
x1: 100.0,
y1: 100.0,
};
fn build_button(id: NodeId, label: &str) -> Node {
let rect = match id {
BUTTON_1_ID => BUTTON_1_RECT,
BUTTON_2_ID => BUTTON_2_RECT,
_ => unreachable!(),
};
let mut node = Node::new(Role::Button);
node.set_bounds(rect);
node.set_label(label);
node.add_action(Action::Focus);
node.add_action(Action::Click);
node
}
fn build_announcement(text: &str) -> Node {
let mut node = Node::new(Role::Label);
node.set_value(text);
node.set_live(Live::Polite);
node
}
struct UiState {
focus: NodeId,
announcement: Option<String>,
}
impl UiState {
fn new() -> Self {
Self {
focus: INITIAL_FOCUS,
announcement: None,
}
}
fn build_root(&mut self) -> Node {
let mut node = Node::new(Role::Window);
node.set_children(vec![BUTTON_1_ID, BUTTON_2_ID]);
if self.announcement.is_some() {
node.push_child(ANNOUNCEMENT_ID);
}
node.set_label(WINDOW_TITLE);
node
}
fn build_initial_tree(&mut self) -> TreeUpdate {
let root = self.build_root();
let button_1 = build_button(BUTTON_1_ID, "Button 1");
let button_2 = build_button(BUTTON_2_ID, "Button 2");
let tree = Tree::new(WINDOW_ID);
let mut result = TreeUpdate {
nodes: vec![
(WINDOW_ID, root),
(BUTTON_1_ID, button_1),
(BUTTON_2_ID, button_2),
],
tree: Some(tree),
focus: self.focus,
};
if let Some(announcement) = &self.announcement {
result
.nodes
.push((ANNOUNCEMENT_ID, build_announcement(announcement)));
}
result
}
fn set_focus(&mut self, adapter: &mut Adapter, focus: NodeId) {
self.focus = focus;
adapter.update_if_active(|| TreeUpdate {
nodes: vec![],
tree: None,
focus,
});
}
fn press_button(&mut self, adapter: &mut Adapter, id: NodeId) {
let text = if id == BUTTON_1_ID {
"You pressed button 1"
} else {
"You pressed button 2"
};
self.announcement = Some(text.into());
adapter.update_if_active(|| {
let announcement = build_announcement(text);
let root = self.build_root();
TreeUpdate {
nodes: vec![(ANNOUNCEMENT_ID, announcement), (WINDOW_ID, root)],
tree: None,
focus: self.focus,
}
});
}
}
struct WindowState {
window: Window,
adapter: Adapter,
ui: UiState,
}
impl WindowState {
fn new(window: Window, adapter: Adapter, ui: UiState) -> Self {
Self {
window,
adapter,
ui,
}
}
}
struct Application {
event_loop_proxy: EventLoopProxy<AccessKitEvent>,
window: Option<WindowState>,
}
impl Application {
fn new(event_loop_proxy: EventLoopProxy<AccessKitEvent>) -> Self {
Self {
event_loop_proxy,
window: None,
}
}
fn create_window(&mut self, event_loop: &ActiveEventLoop) -> Result<(), Box<dyn Error>> {
let window_attributes = Window::default_attributes()
.with_title(WINDOW_TITLE)
.with_visible(false);
let window = event_loop.create_window(window_attributes)?;
let adapter =
Adapter::with_event_loop_proxy(event_loop, &window, self.event_loop_proxy.clone());
window.set_visible(true);
self.window = Some(WindowState::new(window, adapter, UiState::new()));
Ok(())
}
}
impl ApplicationHandler<AccessKitEvent> for Application {
fn window_event(&mut self, _: &ActiveEventLoop, _: WindowId, event: WindowEvent) {
let window = match &mut self.window {
Some(window) => window,
None => return,
};
let adapter = &mut window.adapter;
let state = &mut window.ui;
adapter.process_event(&window.window, &event);
match event {
WindowEvent::CloseRequested => {
self.window = None;
}
WindowEvent::KeyboardInput {
event:
KeyEvent {
logical_key: virtual_code,
state: ElementState::Pressed,
..
},
..
} => match virtual_code {
Key::Named(winit::keyboard::NamedKey::Tab) => {
let new_focus = if state.focus == BUTTON_1_ID {
BUTTON_2_ID
} else {
BUTTON_1_ID
};
state.set_focus(adapter, new_focus);
}
Key::Named(winit::keyboard::NamedKey::Space) => {
let id = state.focus;
state.press_button(adapter, id);
}
_ => (),
},
_ => (),
}
}
fn user_event(&mut self, _: &ActiveEventLoop, user_event: AccessKitEvent) {
let window = match &mut self.window {
Some(window) => window,
None => return,
};
let adapter = &mut window.adapter;
let state = &mut window.ui;
match user_event.window_event {
AccessKitWindowEvent::InitialTreeRequested => {
adapter.update_if_active(|| state.build_initial_tree());
}
AccessKitWindowEvent::ActionRequested(ActionRequest { action, target, .. }) => {
if target == BUTTON_1_ID || target == BUTTON_2_ID {
match action {
Action::Focus => {
state.set_focus(adapter, target);
}
Action::Click => {
state.press_button(adapter, target);
}
_ => (),
}
}
}
AccessKitWindowEvent::AccessibilityDeactivated => (),
}
}
fn resumed(&mut self, event_loop: &ActiveEventLoop) {
self.create_window(event_loop)
.expect("failed to create initial window");
}
fn about_to_wait(&mut self, event_loop: &ActiveEventLoop) {
if self.window.is_none() {
event_loop.exit();
}
}
}
fn main() -> Result<(), Box<dyn Error>> {
println!("This example has no visible GUI, and a keyboard interface:");
println!("- [Tab] switches focus between two logical buttons.");
println!("- [Space] 'presses' the button, adding static text in a live region announcing that it was pressed.");
#[cfg(target_os = "windows")]
println!("Enable Narrator with [Win]+[Ctrl]+[Enter] (or [Win]+[Enter] on older versions of Windows).");
#[cfg(all(
feature = "accesskit_unix",
any(
target_os = "linux",
target_os = "dragonfly",
target_os = "freebsd",
target_os = "netbsd",
target_os = "openbsd"
)
))]
println!("Enable Orca with [Super]+[Alt]+[S].");
let event_loop = EventLoop::with_user_event().build()?;
let mut state = Application::new(event_loop.create_proxy());
event_loop.run_app(&mut state).map_err(Into::into)
}

249
vendor/accesskit_winit/src/lib.rs vendored Normal file
View File

@@ -0,0 +1,249 @@
// Copyright 2022 The AccessKit Authors. All rights reserved.
// Licensed under the Apache License, Version 2.0 (found in
// the LICENSE-APACHE file).
/// ## Compatibility with async runtimes
///
/// The following only applies on Linux/Unix:
///
/// While this crate's API is purely blocking, it internally spawns asynchronous tasks on an executor.
///
/// - If you use tokio, make sure to enable the `tokio` feature of this crate.
/// - If you use another async runtime or if you don't use one at all, the default feature will suit your needs.
#[cfg(all(
feature = "accesskit_unix",
any(
target_os = "linux",
target_os = "dragonfly",
target_os = "freebsd",
target_os = "netbsd",
target_os = "openbsd"
),
not(feature = "async-io"),
not(feature = "tokio")
))]
compile_error!("Either \"async-io\" (default) or \"tokio\" feature must be enabled.");
#[cfg(all(
feature = "accesskit_unix",
any(
target_os = "linux",
target_os = "dragonfly",
target_os = "freebsd",
target_os = "netbsd",
target_os = "openbsd"
),
feature = "async-io",
feature = "tokio"
))]
compile_error!(
"Both \"async-io\" (default) and \"tokio\" features cannot be enabled at the same time."
);
#[cfg(all(not(feature = "rwh_05"), not(feature = "rwh_06")))]
compile_error!("Either \"rwh_06\" (default) or \"rwh_05\" feature must be enabled.");
#[cfg(all(feature = "rwh_05", feature = "rwh_06"))]
compile_error!(
"Both \"rwh_06\" (default) and \"rwh_05\" features cannot be enabled at the same time."
);
use accesskit::{ActionHandler, ActionRequest, ActivationHandler, DeactivationHandler, TreeUpdate};
use winit::{
event::WindowEvent as WinitWindowEvent,
event_loop::{ActiveEventLoop, EventLoopProxy},
window::{Window, WindowId},
};
#[cfg(feature = "rwh_05")]
#[allow(unused)]
use rwh_05 as raw_window_handle;
#[cfg(feature = "rwh_06")]
#[allow(unused)]
use rwh_06 as raw_window_handle;
mod platform_impl;
#[derive(Debug)]
pub struct Event {
pub window_id: WindowId,
pub window_event: WindowEvent,
}
#[derive(Debug)]
pub enum WindowEvent {
InitialTreeRequested,
ActionRequested(ActionRequest),
AccessibilityDeactivated,
}
struct WinitActivationHandler<T: From<Event> + Send + 'static> {
window_id: WindowId,
proxy: EventLoopProxy<T>,
}
impl<T: From<Event> + Send + 'static> ActivationHandler for WinitActivationHandler<T> {
fn request_initial_tree(&mut self) -> Option<TreeUpdate> {
let event = Event {
window_id: self.window_id,
window_event: WindowEvent::InitialTreeRequested,
};
self.proxy.send_event(event.into()).ok();
None
}
}
struct WinitActionHandler<T: From<Event> + Send + 'static> {
window_id: WindowId,
proxy: EventLoopProxy<T>,
}
impl<T: From<Event> + Send + 'static> ActionHandler for WinitActionHandler<T> {
fn do_action(&mut self, request: ActionRequest) {
let event = Event {
window_id: self.window_id,
window_event: WindowEvent::ActionRequested(request),
};
self.proxy.send_event(event.into()).ok();
}
}
struct WinitDeactivationHandler<T: From<Event> + Send + 'static> {
window_id: WindowId,
proxy: EventLoopProxy<T>,
}
impl<T: From<Event> + Send + 'static> DeactivationHandler for WinitDeactivationHandler<T> {
fn deactivate_accessibility(&mut self) {
let event = Event {
window_id: self.window_id,
window_event: WindowEvent::AccessibilityDeactivated,
};
self.proxy.send_event(event.into()).ok();
}
}
pub struct Adapter {
inner: platform_impl::Adapter,
}
impl Adapter {
/// Creates a new AccessKit adapter for a winit window. This must be done
/// before the window is shown for the first time. This means that you must
/// use [`winit::window::WindowAttributes::with_visible`] to make the window
/// initially invisible, then create the adapter, then show the window.
///
/// This constructor uses a winit event loop proxy to deliver AccessKit
/// events to the main event loop. The primary disadvantage of this approach
/// is that it's not possible to synchronously return an initial tree
/// in response to the [`WindowEvent::InitialTreeRequested`] event,
/// so some platform adapters will have to use a temporary placeholder tree
/// until you send the first update. For an optimal implementation,
/// consider using [`Adapter::with_direct_handlers`] or
/// [`Adapter::with_mixed_handlers`] instead.
pub fn with_event_loop_proxy<T: From<Event> + Send + 'static>(
event_loop: &ActiveEventLoop,
window: &Window,
proxy: EventLoopProxy<T>,
) -> Self {
let window_id = window.id();
let activation_handler = WinitActivationHandler {
window_id,
proxy: proxy.clone(),
};
let action_handler = WinitActionHandler {
window_id,
proxy: proxy.clone(),
};
let deactivation_handler = WinitDeactivationHandler { window_id, proxy };
Self::with_direct_handlers(
event_loop,
window,
activation_handler,
action_handler,
deactivation_handler,
)
}
/// Creates a new AccessKit adapter for a winit window. This must be done
/// before the window is shown for the first time. This means that you must
/// use [`winit::window::WindowAttributes::with_visible`] to make the window
/// initially invisible, then create the adapter, then show the window.
///
/// Use this if you want to provide your own AccessKit handler callbacks
/// rather than dispatching requests through the winit event loop. This is
/// especially useful for the activation handler, because depending on
/// your application's architecture, implementing the handler directly may
/// allow you to return an initial tree synchronously, rather than requiring
/// some platform adapters to use a placeholder tree until you send
/// the first update. However, remember that each of these handlers may be
/// called on any thread, depending on the underlying platform adapter.
pub fn with_direct_handlers(
event_loop: &ActiveEventLoop,
window: &Window,
activation_handler: impl 'static + ActivationHandler + Send,
action_handler: impl 'static + ActionHandler + Send,
deactivation_handler: impl 'static + DeactivationHandler + Send,
) -> Self {
let inner = platform_impl::Adapter::new(
event_loop,
window,
activation_handler,
action_handler,
deactivation_handler,
);
Self { inner }
}
/// Creates a new AccessKit adapter for a winit window. This must be done
/// before the window is shown for the first time. This means that you must
/// use [`winit::window::WindowAttributes::with_visible`] to make the window
/// initially invisible, then create the adapter, then show the window.
///
/// This constructor provides a mix of the approaches used by
/// [`Adapter::with_event_loop_proxy`] and [`Adapter::with_direct_handlers`].
/// It uses the event loop proxy for the action request and deactivation
/// events, which can be handled asynchronously with no drawback,
/// while using a direct, caller-provided activation handler that can
/// return the initial tree synchronously. Remember that the thread on which
/// the activation handler is called is platform-dependent.
pub fn with_mixed_handlers<T: From<Event> + Send + 'static>(
event_loop: &ActiveEventLoop,
window: &Window,
activation_handler: impl 'static + ActivationHandler + Send,
proxy: EventLoopProxy<T>,
) -> Self {
let window_id = window.id();
let action_handler = WinitActionHandler {
window_id,
proxy: proxy.clone(),
};
let deactivation_handler = WinitDeactivationHandler { window_id, proxy };
Self::with_direct_handlers(
event_loop,
window,
activation_handler,
action_handler,
deactivation_handler,
)
}
/// Allows reacting to window events.
///
/// This must be called whenever a new window event is received
/// and before it is handled by the application.
pub fn process_event(&mut self, window: &Window, event: &WinitWindowEvent) {
self.inner.process_event(window, event);
}
/// If and only if the tree has been initialized, call the provided function
/// and apply the resulting update. Note: If the caller's implementation of
/// [`ActivationHandler::request_initial_tree`] initially returned `None`,
/// or if the caller created the adapter using [`EventLoopProxy`], then
/// the [`TreeUpdate`] returned by the provided function must contain
/// a full tree.
pub fn update_if_active(&mut self, updater: impl FnOnce() -> TreeUpdate) {
self.inner.update_if_active(updater);
}
}

View File

@@ -0,0 +1,50 @@
// Copyright 2025 The AccessKit Authors. All rights reserved.
// Licensed under the Apache License, Version 2.0 (found in
// the LICENSE-APACHE file).
use accesskit::{ActionHandler, ActivationHandler, DeactivationHandler, TreeUpdate};
use accesskit_android::{
jni::{objects::JObject, JavaVM},
InjectingAdapter,
};
use winit::{
event::WindowEvent, event_loop::ActiveEventLoop, platform::android::ActiveEventLoopExtAndroid,
window::Window,
};
pub struct Adapter {
adapter: InjectingAdapter,
}
impl Adapter {
pub fn new(
event_loop: &ActiveEventLoop,
_window: &Window,
activation_handler: impl 'static + ActivationHandler + Send,
action_handler: impl 'static + ActionHandler + Send,
_deactivation_handler: impl 'static + DeactivationHandler,
) -> Self {
let app = event_loop.android_app();
let vm = unsafe { JavaVM::from_raw(app.vm_as_ptr() as *mut _) }.unwrap();
let mut env = vm.get_env().unwrap();
let activity = unsafe { JObject::from_raw(app.activity_as_ptr() as *mut _) };
let view = env
.get_field(
&activity,
"mSurfaceView",
"Lcom/google/androidgamesdk/GameActivity$InputEnabledSurfaceView;",
)
.unwrap()
.l()
.unwrap();
let adapter =
InjectingAdapter::new(&mut env, &view, activation_handler, action_handler).unwrap();
Self { adapter }
}
pub fn update_if_active(&mut self, updater: impl FnOnce() -> TreeUpdate) {
self.adapter.update_if_active(updater);
}
pub fn process_event(&mut self, _window: &Window, _event: &WindowEvent) {}
}

View File

@@ -0,0 +1,55 @@
// Copyright 2022 The AccessKit Authors. All rights reserved.
// Licensed under the Apache License, Version 2.0 (found in
// the LICENSE-APACHE file).
#[cfg(feature = "rwh_05")]
use crate::raw_window_handle::{HasRawWindowHandle, RawWindowHandle};
#[cfg(feature = "rwh_06")]
use crate::raw_window_handle::{HasWindowHandle, RawWindowHandle};
use accesskit::{ActionHandler, ActivationHandler, DeactivationHandler, TreeUpdate};
use accesskit_macos::SubclassingAdapter;
use winit::{event::WindowEvent, event_loop::ActiveEventLoop, window::Window};
pub struct Adapter {
adapter: SubclassingAdapter,
}
impl Adapter {
pub fn new(
_event_loop: &ActiveEventLoop,
window: &Window,
activation_handler: impl 'static + ActivationHandler,
action_handler: impl 'static + ActionHandler,
_deactivation_handler: impl 'static + DeactivationHandler,
) -> Self {
#[cfg(feature = "rwh_05")]
let view = match window.raw_window_handle() {
RawWindowHandle::AppKit(handle) => handle.ns_view,
RawWindowHandle::UiKit(_) => unimplemented!(),
_ => unreachable!(),
};
#[cfg(feature = "rwh_06")]
let view = match window.window_handle().unwrap().as_raw() {
RawWindowHandle::AppKit(handle) => handle.ns_view.as_ptr(),
RawWindowHandle::UiKit(_) => unimplemented!(),
_ => unreachable!(),
};
let adapter = unsafe { SubclassingAdapter::new(view, activation_handler, action_handler) };
Self { adapter }
}
pub fn update_if_active(&mut self, updater: impl FnOnce() -> TreeUpdate) {
if let Some(events) = self.adapter.update_if_active(updater) {
events.raise();
}
}
pub fn process_event(&mut self, _window: &Window, event: &WindowEvent) {
if let WindowEvent::Focused(is_focused) = event {
if let Some(events) = self.adapter.update_view_focus_state(*is_focused) {
events.raise();
}
}
}
}

View File

@@ -0,0 +1,50 @@
// Copyright 2022 The AccessKit Authors. All rights reserved.
// Licensed under the Apache License, Version 2.0 (found in
// the LICENSE-APACHE file).
// Based loosely on winit's src/platform_impl/mod.rs.
pub use self::platform::*;
#[cfg(target_os = "windows")]
#[path = "windows.rs"]
mod platform;
#[cfg(target_os = "macos")]
#[path = "macos.rs"]
mod platform;
#[cfg(all(
feature = "accesskit_unix",
any(
target_os = "linux",
target_os = "dragonfly",
target_os = "freebsd",
target_os = "netbsd",
target_os = "openbsd"
)
))]
#[path = "unix.rs"]
mod platform;
#[cfg(all(feature = "accesskit_android", target_os = "android"))]
#[path = "android.rs"]
mod platform;
#[cfg(not(any(
target_os = "windows",
target_os = "macos",
all(
feature = "accesskit_unix",
any(
target_os = "linux",
target_os = "dragonfly",
target_os = "freebsd",
target_os = "netbsd",
target_os = "openbsd"
)
),
all(feature = "accesskit_android", target_os = "android")
)))]
#[path = "null.rs"]
mod platform;

View File

@@ -0,0 +1,24 @@
// Copyright 2022 The AccessKit Authors. All rights reserved.
// Licensed under the Apache License, Version 2.0 (found in
// the LICENSE-APACHE file).
use accesskit::{ActionHandler, ActivationHandler, DeactivationHandler, TreeUpdate};
use winit::{event::WindowEvent, event_loop::ActiveEventLoop, window::Window};
pub struct Adapter;
impl Adapter {
pub fn new(
_event_loop: &ActiveEventLoop,
_window: &Window,
_activation_handler: impl 'static + ActivationHandler,
_action_handler: impl 'static + ActionHandler,
_deactivation_handler: impl 'static + DeactivationHandler,
) -> Self {
Self {}
}
pub fn update_if_active(&mut self, _updater: impl FnOnce() -> TreeUpdate) {}
pub fn process_event(&mut self, _window: &Window, _event: &WindowEvent) {}
}

View File

@@ -0,0 +1,77 @@
// Copyright 2022 The AccessKit Authors. All rights reserved.
// Licensed under the Apache License, Version 2.0 (found in
// the LICENSE-APACHE file).
use accesskit::{ActionHandler, ActivationHandler, DeactivationHandler, Rect, TreeUpdate};
use accesskit_unix::Adapter as UnixAdapter;
use winit::{event::WindowEvent, event_loop::ActiveEventLoop, window::Window};
pub struct Adapter {
adapter: UnixAdapter,
}
impl Adapter {
pub fn new(
_event_loop: &ActiveEventLoop,
_window: &Window,
activation_handler: impl 'static + ActivationHandler + Send,
action_handler: impl 'static + ActionHandler + Send,
deactivation_handler: impl 'static + DeactivationHandler + Send,
) -> Self {
let adapter = UnixAdapter::new(activation_handler, action_handler, deactivation_handler);
Self { adapter }
}
fn set_root_window_bounds(&mut self, outer: Rect, inner: Rect) {
self.adapter.set_root_window_bounds(outer, inner);
}
pub fn update_if_active(&mut self, updater: impl FnOnce() -> TreeUpdate) {
self.adapter.update_if_active(updater);
}
fn update_window_focus_state(&mut self, is_focused: bool) {
self.adapter.update_window_focus_state(is_focused);
}
pub fn process_event(&mut self, window: &Window, event: &WindowEvent) {
match event {
WindowEvent::Moved(outer_position) => {
let outer_position: (_, _) = outer_position.cast::<f64>().into();
let outer_size: (_, _) = window.outer_size().cast::<f64>().into();
let inner_position: (_, _) = window
.inner_position()
.unwrap_or_default()
.cast::<f64>()
.into();
let inner_size: (_, _) = window.inner_size().cast::<f64>().into();
self.set_root_window_bounds(
Rect::from_origin_size(outer_position, outer_size),
Rect::from_origin_size(inner_position, inner_size),
)
}
WindowEvent::Resized(inner_size) => {
let outer_position: (_, _) = window
.outer_position()
.unwrap_or_default()
.cast::<f64>()
.into();
let outer_size: (_, _) = window.outer_size().cast::<f64>().into();
let inner_position: (_, _) = window
.inner_position()
.unwrap_or_default()
.cast::<f64>()
.into();
let inner_size: (_, _) = inner_size.cast::<f64>().into();
self.set_root_window_bounds(
Rect::from_origin_size(outer_position, outer_size),
Rect::from_origin_size(inner_position, inner_size),
)
}
WindowEvent::Focused(is_focused) => {
self.update_window_focus_state(*is_focused);
}
_ => (),
}
}
}

View File

@@ -0,0 +1,49 @@
// Copyright 2022 The AccessKit Authors. All rights reserved.
// Licensed under the Apache License, Version 2.0 (found in
// the LICENSE-APACHE file).
#[cfg(feature = "rwh_05")]
use crate::raw_window_handle::{HasRawWindowHandle, RawWindowHandle};
#[cfg(feature = "rwh_06")]
use crate::raw_window_handle::{HasWindowHandle, RawWindowHandle};
use accesskit::{ActionHandler, ActivationHandler, DeactivationHandler, TreeUpdate};
use accesskit_windows::{SubclassingAdapter, HWND};
use winit::{event::WindowEvent, event_loop::ActiveEventLoop, window::Window};
pub struct Adapter {
adapter: SubclassingAdapter,
}
impl Adapter {
pub fn new(
_event_loop: &ActiveEventLoop,
window: &Window,
activation_handler: impl 'static + ActivationHandler,
action_handler: impl 'static + ActionHandler + Send,
_deactivation_handler: impl 'static + DeactivationHandler,
) -> Self {
#[cfg(feature = "rwh_05")]
let hwnd = match window.raw_window_handle() {
RawWindowHandle::Win32(handle) => handle.hwnd,
RawWindowHandle::WinRt(_) => unimplemented!(),
_ => unreachable!(),
};
#[cfg(feature = "rwh_06")]
let hwnd = match window.window_handle().unwrap().as_raw() {
RawWindowHandle::Win32(handle) => handle.hwnd.get() as *mut _,
RawWindowHandle::WinRt(_) => unimplemented!(),
_ => unreachable!(),
};
let adapter = SubclassingAdapter::new(HWND(hwnd), activation_handler, action_handler);
Self { adapter }
}
pub fn update_if_active(&mut self, updater: impl FnOnce() -> TreeUpdate) {
if let Some(events) = self.adapter.update_if_active(updater) {
events.raise();
}
}
pub fn process_event(&mut self, _window: &Window, _event: &WindowEvent) {}
}

1
vendor/adler2/.cargo-checksum.json vendored Normal file
View File

@@ -0,0 +1 @@
{"files":{"CHANGELOG.md":"04fa29ec6eb6b05b706247ecac2cbc7075792dbfcea0bf52715782cf42132e94","Cargo.lock":"3e44ced212a9e7ddc0a5450bcebb48ec67f32a058529856458efa36415554e53","Cargo.toml":"8f30dbd092f3acc475b9d339736cd7b64c6489bc47cd234a7f2232fc52e2d490","LICENSE-0BSD":"861399f8c21c042b110517e76dc6b63a2b334276c8cf17412fc3c8908ca8dc17","LICENSE-APACHE":"8ada45cd9f843acf64e4722ae262c622a2b3b3007c7310ef36ac1061a30f6adb","LICENSE-MIT":"23f18e03dc49df91622fe2a76176497404e46ced8a715d9d2b67a7446571cca3","README.md":"cd955d5d6a49161e6f7a04df4a5963581b66ed43fd5096b2dedca8e295efe4f9","RELEASE_PROCESS.md":"a86cd10fc70f167f8d00e9e4ce0c6b4ebdfa1865058390dffd1e0ad4d3e68d9d","benches/bench.rs":"d67bef1c7f36ed300a8fbcf9d50b9dfdead1fd340bf87a4d47d99a0c1c042c04","src/algo.rs":"932c2bc591d13fe4470185125617b5aaa660a3898f23b553acc85df0bf49dded","src/lib.rs":"4acd41668fe30daffa37084e7e223f268957b816afc1864ffb3f5d6d7adf0890"},"package":"320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa"}

84
vendor/adler2/CHANGELOG.md vendored Normal file
View File

@@ -0,0 +1,84 @@
# Changelog
All notable changes to this project will be documented in this file.
---
## [2.0.1](https://github.com/Frommi/miniz_oxide/compare/2.0.0..2.0.1) - 2025-06-09
### Other
- Remove `compiler-builtins` from `rustc-dep-of-std` dependencies - ([7cdbd39](https://github.com/Frommi/miniz_oxide/commit/7cdbd3925a7f61cc075f44367b5d383861571b0a)) - Trevor Gross
---
## [2.0.0](https://github.com/Frommi/miniz_oxide/compare/1.0.2..2.0.0) - 2024-08-04
First release of adler2 - fork of adler crate as the original is unmaintained and archived
##### Changes since last version of Adler:
### Bug Fixes
- **(core)** change to rust 2021 edition, update repository info and links, update author info - ([867b115](https://github.com/Frommi/miniz_oxide/commit/867b115bad79bf62098f2acccc81bf53ec5a125d)) - oyvindln
- **(core)** simplify some code and fix benches - ([128fb9c](https://github.com/Frommi/miniz_oxide/commit/128fb9cb6cad5c3a54fb0b6c68549d80b79a1fe0)) - oyvindln
### Changelog of original adler crate
---
## [1.0.2 - 2021-02-26](https://github.com/jonas-schievink/adler/releases/tag/v1.0.2)
- Fix doctest on big-endian systems ([#9]).
[#9]: https://github.com/jonas-schievink/adler/pull/9
## [1.0.1 - 2020-11-08](https://github.com/jonas-schievink/adler/releases/tag/v1.0.1)
### Fixes
- Fix documentation on docs.rs.
## [1.0.0 - 2020-11-08](https://github.com/jonas-schievink/adler/releases/tag/v1.0.0)
### Fixes
- Fix `cargo test --no-default-features` ([#5]).
### Improvements
- Extended and clarified documentation.
- Added more rustdoc examples.
- Extended CI to test the crate with `--no-default-features`.
### Breaking Changes
- `adler32_reader` now takes its generic argument by value instead of as a `&mut`.
- Renamed `adler32_reader` to `adler32`.
## [0.2.3 - 2020-07-11](https://github.com/jonas-schievink/adler/releases/tag/v0.2.3)
- Process 4 Bytes at a time, improving performance by up to 50% ([#2]).
## [0.2.2 - 2020-06-27](https://github.com/jonas-schievink/adler/releases/tag/v0.2.2)
- Bump MSRV to 1.31.0.
## [0.2.1 - 2020-06-27](https://github.com/jonas-schievink/adler/releases/tag/v0.2.1)
- Add a few `#[inline]` annotations to small functions.
- Fix CI badge.
- Allow integration into libstd.
## [0.2.0 - 2020-06-27](https://github.com/jonas-schievink/adler/releases/tag/v0.2.0)
- Support `#![no_std]` when using `default-features = false`.
- Improve performance by around 7x.
- Support Rust 1.8.0.
- Improve API naming.
## [0.1.0 - 2020-06-26](https://github.com/jonas-schievink/adler/releases/tag/v0.1.0)
Initial release.
[#2]: https://github.com/jonas-schievink/adler/pull/2
[#5]: https://github.com/jonas-schievink/adler/pull/5

16
vendor/adler2/Cargo.lock generated vendored Normal file
View File

@@ -0,0 +1,16 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 4
[[package]]
name = "adler2"
version = "2.0.1"
dependencies = [
"rustc-std-workspace-core",
]
[[package]]
name = "rustc-std-workspace-core"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1956f5517128a2b6f23ab2dadf1a976f4f5b27962e7724c2bf3d45e539ec098c"

91
vendor/adler2/Cargo.toml vendored Normal file
View File

@@ -0,0 +1,91 @@
# 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"
name = "adler2"
version = "2.0.1"
authors = [
"Jonas Schievink <jonasschievink@gmail.com>",
"oyvindln <oyvindln@users.noreply.github.com>",
]
build = false
exclude = [".*"]
autolib = false
autobins = false
autoexamples = false
autotests = false
autobenches = false
description = "A simple clean-room implementation of the Adler-32 checksum"
documentation = "https://docs.rs/adler2/"
readme = "README.md"
keywords = [
"checksum",
"integrity",
"hash",
"adler32",
"zlib",
]
categories = ["algorithms"]
license = "0BSD OR MIT OR Apache-2.0"
repository = "https://github.com/oyvindln/adler2"
[package.metadata.docs.rs]
rustdoc-args = ["--cfg=docsrs"]
[package.metadata.release]
no-dev-version = true
pre-release-commit-message = "Release {{version}}"
tag-message = "{{version}}"
[[package.metadata.release.pre-release-replacements]]
file = "CHANGELOG.md"
replace = """
## Unreleased
No changes.
## [{{version}} - {{date}}](https://github.com/jonas-schievink/adler/releases/tag/v{{version}})
"""
search = """
## Unreleased
"""
[[package.metadata.release.pre-release-replacements]]
file = "README.md"
replace = 'adler = "{{version}}"'
search = 'adler = "[a-z0-9\\.-]+"'
[[package.metadata.release.pre-release-replacements]]
file = "src/lib.rs"
replace = "https://docs.rs/adler/{{version}}"
search = 'https://docs.rs/adler/[a-z0-9\.-]+'
[features]
default = ["std"]
rustc-dep-of-std = ["core"]
std = []
[lib]
name = "adler2"
path = "src/lib.rs"
[[bench]]
name = "bench"
path = "benches/bench.rs"
harness = false
[dependencies.core]
version = "1.0.0"
optional = true
package = "rustc-std-workspace-core"
[dev-dependencies]

12
vendor/adler2/LICENSE-0BSD vendored Normal file
View File

@@ -0,0 +1,12 @@
Copyright (C) Jonas Schievink <jonasschievink@gmail.com>
Permission to use, copy, modify, and/or distribute this software for
any purpose with or without fee is hereby granted.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.

201
vendor/adler2/LICENSE-APACHE vendored Normal file
View File

@@ -0,0 +1,201 @@
Apache License
Version 2.0, January 2004
https://www.apache.org/licenses/LICENSE-2.0
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
https://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

23
vendor/adler2/LICENSE-MIT vendored Normal file
View File

@@ -0,0 +1,23 @@
Permission is hereby granted, free of charge, to any
person obtaining a copy of this software and associated
documentation files (the "Software"), to deal in the
Software without restriction, including without
limitation the rights to use, copy, modify, merge,
publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software
is furnished to do so, subject to the following
conditions:
The above copyright notice and this permission notice
shall be included in all copies or substantial portions
of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.

46
vendor/adler2/README.md vendored Normal file
View File

@@ -0,0 +1,46 @@
# Adler-32 checksums for Rust
This is a fork of the adler crate as the [original](https://github.com/jonas-schievink/adler) has been archived and is no longer updated by it's author
[![crates.io](https://img.shields.io/crates/v/adler.svg)](https://crates.io/crates/adler)
[![docs.rs](https://docs.rs/adler/badge.svg)](https://docs.rs/adler/)
![CI](https://github.com/jonas-schievink/adler/workflows/CI/badge.svg)
This crate provides a simple implementation of the Adler-32 checksum, used in
the zlib compression format.
Please refer to the [changelog](CHANGELOG.md) to see what changed in the last
releases.
## Features
- Permissively licensed (0BSD) clean-room implementation.
- Zero dependencies.
- Zero `unsafe`.
- Decent performance (3-4 GB/s) (see note).
- Supports `#![no_std]` (with `default-features = false`).
## Usage
Add an entry to your `Cargo.toml`:
```toml
[dependencies]
adler2 = "2.0.0"
```
Check the [API Documentation](https://docs.rs/adler/) for how to use the
crate's functionality.
## Rust version support
Currently, this crate supports all Rust versions starting at Rust 1.56.0.
Bumping the Minimum Supported Rust Version (MSRV) is *not* considered a breaking
change, but will not be done without good reasons. The latest 3 stable Rust
versions will always be supported no matter what.
## Performance
Due to the way the algorithm works this crate and the fact that it's not possible to use explicit simd in safe rust currently, this crate benefits drastically from being compiled with newer cpu instructions enabled (using e.g ```RUSTFLAGS=-C target-feature'+sse4.1``` or ```-C target-cpu=x86-64-v2```/```-C target-cpu=x86-64-v3``` arguments depending on what cpu support is being targeted.)
Judging by the crate benchmarks, on a Ryzen 5600, compiling with SSE 4.1 (enabled in x86-64-v2 feature level) enabled can give a ~50-150% speedup, enabling the LZCNT instruction (enabled in x86-64-v3 feature level) can give a further ~50% speedup,

13
vendor/adler2/RELEASE_PROCESS.md vendored Normal file
View File

@@ -0,0 +1,13 @@
# What to do to publish a new release
1. Ensure all notable changes are in the changelog under "Unreleased".
2. Execute `cargo release <level>` to bump version(s), tag and publish
everything. External subcommand, must be installed with `cargo install
cargo-release`.
`<level>` can be one of `major|minor|patch`. If this is the first release
(`0.1.0`), use `minor`, since the version starts out as `0.0.0`.
3. Go to the GitHub releases, edit the just-pushed tag. Copy the release notes
from the changelog.

109
vendor/adler2/benches/bench.rs vendored Normal file
View File

@@ -0,0 +1,109 @@
extern crate adler2;
extern crate criterion;
use adler2::{adler32_slice, Adler32};
use criterion::{criterion_group, criterion_main, Criterion, Throughput};
fn simple(c: &mut Criterion) {
{
const SIZE: usize = 100;
let mut group = c.benchmark_group("simple-100b");
group.throughput(Throughput::Bytes(SIZE as u64));
group.bench_function("zeroes-100", |bencher| {
bencher.iter(|| {
adler32_slice(&[0; SIZE]);
});
});
group.bench_function("ones-100", |bencher| {
bencher.iter(|| {
adler32_slice(&[0xff; SIZE]);
});
});
}
{
const SIZE: usize = 1024;
let mut group = c.benchmark_group("simple-1k");
group.throughput(Throughput::Bytes(SIZE as u64));
group.bench_function("zeroes-1k", |bencher| {
bencher.iter(|| {
adler32_slice(&[0; SIZE]);
});
});
group.bench_function("ones-1k", |bencher| {
bencher.iter(|| {
adler32_slice(&[0xff; SIZE]);
});
});
}
{
const SIZE: usize = 1024 * 1024;
let mut group = c.benchmark_group("simple-1m");
group.throughput(Throughput::Bytes(SIZE as u64));
group.bench_function("zeroes-1m", |bencher| {
bencher.iter(|| {
adler32_slice(&[0; SIZE]);
});
});
group.bench_function("ones-1m", |bencher| {
bencher.iter(|| {
adler32_slice(&[0xff; SIZE]);
});
});
}
}
fn chunked(c: &mut Criterion) {
const SIZE: usize = 16 * 1024 * 1024;
let data = vec![0xAB; SIZE];
let mut group = c.benchmark_group("chunked-16m");
group.throughput(Throughput::Bytes(SIZE as u64));
group.bench_function("5552", |bencher| {
bencher.iter(|| {
let mut h = Adler32::new();
for chunk in data.chunks(5552) {
h.write_slice(chunk);
}
h.checksum()
});
});
group.bench_function("8k", |bencher| {
bencher.iter(|| {
let mut h = Adler32::new();
for chunk in data.chunks(8 * 1024) {
h.write_slice(chunk);
}
h.checksum()
});
});
group.bench_function("64k", |bencher| {
bencher.iter(|| {
let mut h = Adler32::new();
for chunk in data.chunks(64 * 1024) {
h.write_slice(chunk);
}
h.checksum()
});
});
group.bench_function("1m", |bencher| {
bencher.iter(|| {
let mut h = Adler32::new();
for chunk in data.chunks(1024 * 1024) {
h.write_slice(chunk);
}
h.checksum()
});
});
}
criterion_group!(benches, simple, chunked);
criterion_main!(benches);

155
vendor/adler2/src/algo.rs vendored Normal file
View File

@@ -0,0 +1,155 @@
use crate::Adler32;
use std::ops::{AddAssign, MulAssign, RemAssign};
impl Adler32 {
pub(crate) fn compute(&mut self, bytes: &[u8]) {
// The basic algorithm is, for every byte:
// a = (a + byte) % MOD
// b = (b + a) % MOD
// where MOD = 65521.
//
// For efficiency, we can defer the `% MOD` operations as long as neither a nor b overflows:
// - Between calls to `write`, we ensure that a and b are always in range 0..MOD.
// - We use 32-bit arithmetic in this function.
// - Therefore, a and b must not increase by more than 2^32-MOD without performing a `% MOD`
// operation.
//
// According to Wikipedia, b is calculated as follows for non-incremental checksumming:
// b = n×D1 + (n1)×D2 + (n2)×D3 + ... + Dn + n*1 (mod 65521)
// Where n is the number of bytes and Di is the i-th Byte. We need to change this to account
// for the previous values of a and b, as well as treat every input Byte as being 255:
// b_inc = n×255 + (n-1)×255 + ... + 255 + n*65520
// Or in other words:
// b_inc = n*65520 + n(n+1)/2*255
// The max chunk size is thus the largest value of n so that b_inc <= 2^32-65521.
// 2^32-65521 = n*65520 + n(n+1)/2*255
// Plugging this into an equation solver since I can't math gives n = 5552.18..., so 5552.
//
// On top of the optimization outlined above, the algorithm can also be parallelized with a
// bit more work:
//
// Note that b is a linear combination of a vector of input bytes (D1, ..., Dn).
//
// If we fix some value k<N and rewrite indices 1, ..., N as
//
// 1_1, 1_2, ..., 1_k, 2_1, ..., 2_k, ..., (N/k)_k,
//
// then we can express a and b in terms of sums of smaller sequences kb and ka:
//
// ka(j) := D1_j + D2_j + ... + D(N/k)_j where j <= k
// kb(j) := (N/k)*D1_j + (N/k-1)*D2_j + ... + D(N/k)_j where j <= k
//
// a = ka(1) + ka(2) + ... + ka(k) + 1
// b = k*(kb(1) + kb(2) + ... + kb(k)) - 1*ka(2) - ... - (k-1)*ka(k) + N
//
// We use this insight to unroll the main loop and process k=4 bytes at a time.
// The resulting code is highly amenable to SIMD acceleration, although the immediate speedups
// stem from increased pipeline parallelism rather than auto-vectorization.
//
// This technique is described in-depth (here:)[https://software.intel.com/content/www/us/\
// en/develop/articles/fast-computation-of-fletcher-checksums.html]
const MOD: u32 = 65521;
const CHUNK_SIZE: usize = 5552 * 4;
let mut a = u32::from(self.a);
let mut b = u32::from(self.b);
let mut a_vec = U32X4([0; 4]);
let mut b_vec = a_vec;
let (bytes, remainder) = bytes.split_at(bytes.len() - bytes.len() % 4);
// iterate over 4 bytes at a time
let chunk_iter = bytes.chunks_exact(CHUNK_SIZE);
let remainder_chunk = chunk_iter.remainder();
for chunk in chunk_iter {
for byte_vec in chunk.chunks_exact(4) {
let val = U32X4::from(byte_vec);
a_vec += val;
b_vec += a_vec;
}
b += CHUNK_SIZE as u32 * a;
a_vec %= MOD;
b_vec %= MOD;
b %= MOD;
}
// special-case the final chunk because it may be shorter than the rest
for byte_vec in remainder_chunk.chunks_exact(4) {
let val = U32X4::from(byte_vec);
a_vec += val;
b_vec += a_vec;
}
b += remainder_chunk.len() as u32 * a;
a_vec %= MOD;
b_vec %= MOD;
b %= MOD;
// combine the sub-sum results into the main sum
b_vec *= 4;
b_vec.0[1] += MOD - a_vec.0[1];
b_vec.0[2] += (MOD - a_vec.0[2]) * 2;
b_vec.0[3] += (MOD - a_vec.0[3]) * 3;
for &av in a_vec.0.iter() {
a += av;
}
for &bv in b_vec.0.iter() {
b += bv;
}
// iterate over the remaining few bytes in serial
for &byte in remainder.iter() {
a += u32::from(byte);
b += a;
}
self.a = (a % MOD) as u16;
self.b = (b % MOD) as u16;
}
}
#[derive(Copy, Clone)]
struct U32X4([u32; 4]);
impl U32X4 {
#[inline]
fn from(bytes: &[u8]) -> Self {
U32X4([
u32::from(bytes[0]),
u32::from(bytes[1]),
u32::from(bytes[2]),
u32::from(bytes[3]),
])
}
}
impl AddAssign<Self> for U32X4 {
#[inline]
fn add_assign(&mut self, other: Self) {
// Implement this in a primitive manner to help out the compiler a bit.
self.0[0] += other.0[0];
self.0[1] += other.0[1];
self.0[2] += other.0[2];
self.0[3] += other.0[3];
}
}
impl RemAssign<u32> for U32X4 {
#[inline]
fn rem_assign(&mut self, quotient: u32) {
self.0[0] %= quotient;
self.0[1] %= quotient;
self.0[2] %= quotient;
self.0[3] %= quotient;
}
}
impl MulAssign<u32> for U32X4 {
#[inline]
fn mul_assign(&mut self, rhs: u32) {
self.0[0] *= rhs;
self.0[1] *= rhs;
self.0[2] *= rhs;
self.0[3] *= rhs;
}
}

287
vendor/adler2/src/lib.rs vendored Normal file
View File

@@ -0,0 +1,287 @@
//! Adler-32 checksum implementation.
//!
//! This implementation features:
//!
//! - Permissively licensed (0BSD) clean-room implementation.
//! - Zero dependencies.
//! - Zero `unsafe`.
//! - Decent performance (3-4 GB/s).
//! - `#![no_std]` support (with `default-features = false`).
#![doc(html_root_url = "https://docs.rs/adler2/2.0.0")]
// Deny a few warnings in doctests, since rustdoc `allow`s many warnings by default
#![doc(test(attr(deny(unused_imports, unused_must_use))))]
#![cfg_attr(docsrs, feature(doc_cfg))]
#![warn(missing_debug_implementations)]
#![forbid(unsafe_code)]
#![cfg_attr(not(feature = "std"), no_std)]
#[cfg(not(feature = "std"))]
extern crate core as std;
mod algo;
use std::hash::Hasher;
#[cfg(feature = "std")]
use std::io::{self, BufRead};
/// Adler-32 checksum calculator.
///
/// An instance of this type is equivalent to an Adler-32 checksum: It can be created in the default
/// state via [`new`] (or the provided `Default` impl), or from a precalculated checksum via
/// [`from_checksum`], and the currently stored checksum can be fetched via [`checksum`].
///
/// This type also implements `Hasher`, which makes it easy to calculate Adler-32 checksums of any
/// type that implements or derives `Hash`. This also allows using Adler-32 in a `HashMap`, although
/// that is not recommended (while every checksum is a hash function, they are not necessarily a
/// good one).
///
/// # Examples
///
/// Basic, piecewise checksum calculation:
///
/// ```
/// use adler2::Adler32;
///
/// let mut adler = Adler32::new();
///
/// adler.write_slice(&[0, 1, 2]);
/// adler.write_slice(&[3, 4, 5]);
///
/// assert_eq!(adler.checksum(), 0x00290010);
/// ```
///
/// Using `Hash` to process structures:
///
/// ```
/// use std::hash::Hash;
/// use adler2::Adler32;
///
/// #[derive(Hash)]
/// struct Data {
/// byte: u8,
/// word: u16,
/// big: u64,
/// }
///
/// let mut adler = Adler32::new();
///
/// let data = Data { byte: 0x1F, word: 0xABCD, big: !0 };
/// data.hash(&mut adler);
///
/// // hash value depends on architecture endianness
/// if cfg!(target_endian = "little") {
/// assert_eq!(adler.checksum(), 0x33410990);
/// }
/// if cfg!(target_endian = "big") {
/// assert_eq!(adler.checksum(), 0x331F0990);
/// }
///
/// ```
///
/// [`new`]: #method.new
/// [`from_checksum`]: #method.from_checksum
/// [`checksum`]: #method.checksum
#[derive(Debug, Copy, Clone)]
pub struct Adler32 {
a: u16,
b: u16,
}
impl Adler32 {
/// Creates a new Adler-32 instance with default state.
#[inline]
pub fn new() -> Self {
Self::default()
}
/// Creates an `Adler32` instance from a precomputed Adler-32 checksum.
///
/// This allows resuming checksum calculation without having to keep the `Adler32` instance
/// around.
///
/// # Example
///
/// ```
/// # use adler2::Adler32;
/// let parts = [
/// "rust",
/// "acean",
/// ];
/// let whole = adler2::adler32_slice(b"rustacean");
///
/// let mut sum = Adler32::new();
/// sum.write_slice(parts[0].as_bytes());
/// let partial = sum.checksum();
///
/// // ...later
///
/// let mut sum = Adler32::from_checksum(partial);
/// sum.write_slice(parts[1].as_bytes());
/// assert_eq!(sum.checksum(), whole);
/// ```
#[inline]
pub const fn from_checksum(sum: u32) -> Self {
Adler32 {
a: sum as u16,
b: (sum >> 16) as u16,
}
}
/// Returns the calculated checksum at this point in time.
#[inline]
pub fn checksum(&self) -> u32 {
(u32::from(self.b) << 16) | u32::from(self.a)
}
/// Adds `bytes` to the checksum calculation.
///
/// If efficiency matters, this should be called with Byte slices that contain at least a few
/// thousand Bytes.
pub fn write_slice(&mut self, bytes: &[u8]) {
self.compute(bytes);
}
}
impl Default for Adler32 {
#[inline]
fn default() -> Self {
Adler32 { a: 1, b: 0 }
}
}
impl Hasher for Adler32 {
#[inline]
fn finish(&self) -> u64 {
u64::from(self.checksum())
}
fn write(&mut self, bytes: &[u8]) {
self.write_slice(bytes);
}
}
/// Calculates the Adler-32 checksum of a byte slice.
///
/// This is a convenience function around the [`Adler32`] type.
///
/// [`Adler32`]: struct.Adler32.html
pub fn adler32_slice(data: &[u8]) -> u32 {
let mut h = Adler32::new();
h.write_slice(data);
h.checksum()
}
/// Calculates the Adler-32 checksum of a `BufRead`'s contents.
///
/// The passed `BufRead` implementor will be read until it reaches EOF (or until it reports an
/// error).
///
/// If you only have a `Read` implementor, you can wrap it in `std::io::BufReader` before calling
/// this function.
///
/// # Errors
///
/// Any error returned by the reader are bubbled up by this function.
///
/// # Examples
///
/// ```no_run
/// # fn run() -> Result<(), Box<dyn std::error::Error>> {
/// use adler2::adler32;
///
/// use std::fs::File;
/// use std::io::BufReader;
///
/// let file = File::open("input.txt")?;
/// let mut file = BufReader::new(file);
///
/// adler32(&mut file)?;
/// # Ok(()) }
/// # fn main() { run().unwrap() }
/// ```
#[cfg(feature = "std")]
#[cfg_attr(docsrs, doc(cfg(feature = "std")))]
pub fn adler32<R: BufRead>(mut reader: R) -> io::Result<u32> {
let mut h = Adler32::new();
loop {
let len = {
let buf = reader.fill_buf()?;
if buf.is_empty() {
return Ok(h.checksum());
}
h.write_slice(buf);
buf.len()
};
reader.consume(len);
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn zeroes() {
assert_eq!(adler32_slice(&[]), 1);
assert_eq!(adler32_slice(&[0]), 1 | 1 << 16);
assert_eq!(adler32_slice(&[0, 0]), 1 | 2 << 16);
assert_eq!(adler32_slice(&[0; 100]), 0x00640001);
assert_eq!(adler32_slice(&[0; 1024]), 0x04000001);
assert_eq!(adler32_slice(&[0; 1024 * 1024]), 0x00f00001);
}
#[test]
fn ones() {
assert_eq!(adler32_slice(&[0xff; 1024]), 0x79a6fc2e);
assert_eq!(adler32_slice(&[0xff; 1024 * 1024]), 0x8e88ef11);
}
#[test]
fn mixed() {
assert_eq!(adler32_slice(&[1]), 2 | 2 << 16);
assert_eq!(adler32_slice(&[40]), 41 | 41 << 16);
assert_eq!(adler32_slice(&[0xA5; 1024 * 1024]), 0xd5009ab1);
}
/// Example calculation from https://en.wikipedia.org/wiki/Adler-32.
#[test]
fn wiki() {
assert_eq!(adler32_slice(b"Wikipedia"), 0x11E60398);
}
#[test]
fn resume() {
let mut adler = Adler32::new();
adler.write_slice(&[0xff; 1024]);
let partial = adler.checksum();
assert_eq!(partial, 0x79a6fc2e); // from above
adler.write_slice(&[0xff; 1024 * 1024 - 1024]);
assert_eq!(adler.checksum(), 0x8e88ef11); // from above
// Make sure that we can resume computing from the partial checksum via `from_checksum`.
let mut adler = Adler32::from_checksum(partial);
adler.write_slice(&[0xff; 1024 * 1024 - 1024]);
assert_eq!(adler.checksum(), 0x8e88ef11); // from above
}
#[cfg(feature = "std")]
#[test]
fn bufread() {
use std::io::BufReader;
fn test(data: &[u8], checksum: u32) {
// `BufReader` uses an 8 KB buffer, so this will test buffer refilling.
let mut buf = BufReader::new(data);
let real_sum = adler32(&mut buf).unwrap();
assert_eq!(checksum, real_sum);
}
test(&[], 1);
test(&[0; 1024], 0x04000001);
test(&[0; 1024 * 1024], 0x00f00001);
test(&[0xA5; 1024 * 1024], 0xd5009ab1);
}
}

View File

@@ -0,0 +1 @@
{"files":{"COPYING":"01c266bced4a434da0051174d6bee16a4c82cf634e2679b6155d40d75012390f","Cargo.toml":"88c12a803c6c06c47cd9dabc8bcdba81f35d3bab637221d2106a86a543532731","DESIGN.md":"59c960e1b73b1d7fb41e4df6c0c1b1fcf44dd2ebc8a349597a7d0595f8cb5130","LICENSE-MIT":"0f96a83840e146e43c0ec96a22ec1f392e0680e6c1226e6f3ba87e0740af850f","README.md":"afc4d559a98cf190029af0bf320fc0022725e349cd2a303aac860254e28f3c53","UNLICENSE":"7e12e5df4bae12cb21581ba157ced20e1986a0508dd10d0e8a4ab9a4cf94e85c","rustfmt.toml":"1ca600239a27401c4a43f363cf3f38183a212affc1f31bff3ae93234bbaec228","src/ahocorasick.rs":"c699c07df70be45c666e128509ad571a7649d2073e4ae16ac1efd6793c9c6890","src/automaton.rs":"22258a3e118672413119f8f543a9b912cce954e63524575c0ebfdf9011f9c2dd","src/dfa.rs":"bfef1a94c5e7410584b1beb4e857b40d1ae2031b881cbc06fb1300409bbd555f","src/lib.rs":"2a92d5c5e930f2d306508802e8a929135e1f41c9f5f8deda8f7eb98947179dd2","src/macros.rs":"c6c52ae05b24433cffaca7b78b3645d797862c5d5feffddf9f54909095ed6e05","src/nfa/contiguous.rs":"aeb6ee5fd80eea04decbc4b46aa27d1ab270b78d416a644da25b7934f009ee66","src/nfa/mod.rs":"ee7b3109774d14bbad5239c16bb980dd6b8185ec136d94fbaf2f0dc27d5ffa15","src/nfa/noncontiguous.rs":"de94f02b04efd8744fb096759a8897c22012b0e0ca3ace161fd87c71befefe04","src/packed/api.rs":"160d3b10823316f7b0924e13c3afd222c8a7db5c0a00432401f311ef27d6a1b7","src/packed/ext.rs":"66be06fde8558429da23a290584d4b9fae665bf64c2578db4fe5f5f3ee864869","src/packed/mod.rs":"0020cd6f07ba5c8955923a9516d7f758864260eda53a6b6f629131c45ddeec62","src/packed/pattern.rs":"1e3a289a730c141fc30b295811e372d046c6619c7fd670308299b889a06c7673","src/packed/rabinkarp.rs":"403146eb1d838a84601d171393542340513cd1ee7ff750f2372161dd47746586","src/packed/teddy/README.md":"3a43194b64e221543d885176aba3beb1224a927385a20eca842daf6b0ea2f342","src/packed/teddy/builder.rs":"08ec116a4a842a2bb1221d296a2515ef3672c54906bed588fb733364c07855d3","src/packed/teddy/generic.rs":"ea252ab05b32cea7dd9d71e332071d243db7dd0362e049252a27e5881ba2bf39","src/packed/teddy/mod.rs":"17d741f7e2fb9dbac5ba7d1bd4542cf1e35e9f146ace728e23fe6bbed20028b2","src/packed/tests.rs":"8e2f56eb3890ed3876ecb47d3121996e416563127b6430110d7b516df3f83b4b","src/packed/vector.rs":"70c325cfa6f7c5c4c9a6af7b133b75a29e65990a7fe0b9a4c4ce3c3d5a0fe587","src/tests.rs":"c68192ab97b6161d0d6ee96fefd80cc7d14e4486ddcd8d1f82b5c92432c24ed5","src/transducer.rs":"02daa33a5d6dac41dcfd67f51df7c0d4a91c5131c781fb54c4de3520c585a6e1","src/util/alphabet.rs":"6dc22658a38deddc0279892035b18870d4585069e35ba7c7e649a24509acfbcc","src/util/buffer.rs":"f9e37f662c46c6ecd734458dedbe76c3bb0e84a93b6b0117c0d4ad3042413891","src/util/byte_frequencies.rs":"2fb85b381c038c1e44ce94294531cdcd339dca48b1e61f41455666e802cbbc9e","src/util/debug.rs":"ab301ad59aa912529cb97233a54a05914dd3cb2ec43e6fec7334170b97ac5998","src/util/error.rs":"ecccd60e7406305023efcc6adcc826eeeb083ab8f7fbfe3d97469438cd4c4e5c","src/util/int.rs":"e264e6abebf5622b59f6500210773db36048371c4e509c930263334095959a52","src/util/mod.rs":"7ab28d11323ecdbd982087f32eb8bceeee84f1a2583f3aae27039c36d58cf12c","src/util/prefilter.rs":"9fa4498f18bf70478b1996c1a013698b626d15f119aa81dbc536673c9f045718","src/util/primitives.rs":"f89f3fa1d8db4e37de9ca767c6d05e346404837cade6d063bba68972fafa610b","src/util/remapper.rs":"9f12d911583a325c11806eeceb46d0dfec863cfcfa241aed84d31af73da746e5","src/util/search.rs":"6af803e08b8b8c8a33db100623f1621b0d741616524ce40893d8316897f27ffe","src/util/special.rs":"7d2f9cb9dd9771f59816e829b2d96b1239996f32939ba98764e121696c52b146"},"package":"8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916"}

3
vendor/aho-corasick/COPYING vendored Normal file
View File

@@ -0,0 +1,3 @@
This project is dual-licensed under the Unlicense and MIT licenses.
You may use this code under the terms of either license.

74
vendor/aho-corasick/Cargo.toml vendored Normal file
View File

@@ -0,0 +1,74 @@
# 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.60.0"
name = "aho-corasick"
version = "1.1.3"
authors = ["Andrew Gallant <jamslam@gmail.com>"]
exclude = [
"/aho-corasick-debug",
"/benchmarks",
"/tmp",
]
autotests = false
description = "Fast multiple substring searching."
homepage = "https://github.com/BurntSushi/aho-corasick"
readme = "README.md"
keywords = [
"string",
"search",
"text",
"pattern",
"multi",
]
categories = ["text-processing"]
license = "Unlicense OR MIT"
repository = "https://github.com/BurntSushi/aho-corasick"
[package.metadata.docs.rs]
all-features = true
rustdoc-args = [
"--cfg",
"docsrs",
"--generate-link-to-definition",
]
[profile.bench]
debug = 2
[profile.release]
debug = 2
[lib]
name = "aho_corasick"
[dependencies.log]
version = "0.4.17"
optional = true
[dependencies.memchr]
version = "2.4.0"
optional = true
default-features = false
[dev-dependencies.doc-comment]
version = "0.3.3"
[features]
default = [
"std",
"perf-literal",
]
logging = ["dep:log"]
perf-literal = ["dep:memchr"]
std = ["memchr?/std"]

481
vendor/aho-corasick/DESIGN.md vendored Normal file
View File

@@ -0,0 +1,481 @@
This document describes the internal design of this crate, which is an object
lesson in what happens when you take a fairly simple old algorithm like
Aho-Corasick and make it fast and production ready.
The target audience of this document is Rust programmers that have some
familiarity with string searching, however, one does not need to know the
Aho-Corasick algorithm in order to read this (it is explained below). One
should, however, know what a trie is. (If you don't, go read its Wikipedia
article.)
The center-piece of this crate is an implementation of Aho-Corasick. On its
own, Aho-Corasick isn't that complicated. The complex pieces come from the
different variants of Aho-Corasick implemented in this crate. Specifically,
they are:
* Aho-Corasick as a noncontiguous NFA. States have their transitions
represented sparsely, and each state puts its transitions in its own separate
allocation. Hence the same "noncontiguous."
* Aho-Corasick as a contiguous NFA. This NFA uses a single allocation to
represent the transitions of all states. That is, transitions are laid out
contiguously in memory. Moreover, states near the starting state are
represented densely, such that finding the next state ID takes a constant
number of instructions.
* Aho-Corasick as a DFA. In this case, all states are represented densely in
a transition table that uses one allocation.
* Supporting "standard" match semantics, along with its overlapping variant,
in addition to leftmost-first and leftmost-longest semantics. The "standard"
semantics are typically what you see in a textbook description of
Aho-Corasick. However, Aho-Corasick is also useful as an optimization in
regex engines, which often use leftmost-first or leftmost-longest semantics.
Thus, it is useful to implement those semantics here. The "standard" and
"leftmost" search algorithms are subtly different, and also require slightly
different construction algorithms.
* Support for ASCII case insensitive matching.
* Support for accelerating searches when the patterns all start with a small
number of fixed bytes. Or alternatively, when the patterns all contain a
small number of rare bytes. (Searching for these bytes uses SIMD vectorized
code courtesy of `memchr`.)
* Transparent support for alternative SIMD vectorized search routines for
smaller number of literals, such as the Teddy algorithm. We called these
"packed" search routines because they use SIMD. They can often be an order of
magnitude faster than just Aho-Corasick, but don't scale as well.
* Support for searching streams. This can reuse most of the underlying code,
but does require careful buffering support.
* Support for anchored searches, which permit efficient "is prefix" checks for
a large number of patterns.
When you combine all of this together along with trying to make everything as
fast as possible, what you end up with is enitrely too much code with too much
`unsafe`. Alas, I was not smart enough to figure out how to reduce it. Instead,
we will explain it.
# Basics
The fundamental problem this crate is trying to solve is to determine the
occurrences of possibly many patterns in a haystack. The naive way to solve
this is to look for a match for each pattern at each position in the haystack:
for i in 0..haystack.len():
for p in patterns.iter():
if haystack[i..].starts_with(p.bytes()):
return Match(p.id(), i, i + p.bytes().len())
Those four lines are effectively all this crate does. The problem with those
four lines is that they are very slow, especially when you're searching for a
large number of patterns.
While there are many different algorithms available to solve this, a popular
one is Aho-Corasick. It's a common solution because it's not too hard to
implement, scales quite well even when searching for thousands of patterns and
is generally pretty fast. Aho-Corasick does well here because, regardless of
the number of patterns you're searching for, it always visits each byte in the
haystack exactly once. This means, generally speaking, adding more patterns to
an Aho-Corasick automaton does not make it slower. (Strictly speaking, however,
this is not true, since a larger automaton will make less effective use of the
CPU's cache.)
Aho-Corasick can be succinctly described as a trie with state transitions
between some of the nodes that efficiently instruct the search algorithm to
try matching alternative keys in the trie. The trick is that these state
transitions are arranged such that each byte of input needs to be inspected
only once. These state transitions are typically called "failure transitions,"
because they instruct the searcher (the thing traversing the automaton while
reading from the haystack) what to do when a byte in the haystack does not
correspond to a valid transition in the current state of the trie.
More formally, a failure transition points to a state in the automaton that may
lead to a match whose prefix is a proper suffix of the path traversed through
the trie so far. (If no such proper suffix exists, then the failure transition
points back to the start state of the trie, effectively restarting the search.)
This is perhaps simpler to explain pictorally. For example, let's say we built
an Aho-Corasick automaton with the following patterns: 'abcd' and 'cef'. The
trie looks like this:
a - S1 - b - S2 - c - S3 - d - S4*
/
S0 - c - S5 - e - S6 - f - S7*
where states marked with a `*` are match states (meaning, the search algorithm
should stop and report a match to the caller).
So given this trie, it should be somewhat straight-forward to see how it can
be used to determine whether any particular haystack *starts* with either
`abcd` or `cef`. It's easy to express this in code:
fn has_prefix(trie: &Trie, haystack: &[u8]) -> bool {
let mut state_id = trie.start();
// If the empty pattern is in trie, then state_id is a match state.
if trie.is_match(state_id) {
return true;
}
for (i, &b) in haystack.iter().enumerate() {
state_id = match trie.next_state(state_id, b) {
Some(id) => id,
// If there was no transition for this state and byte, then we know
// the haystack does not start with one of the patterns in our trie.
None => return false,
};
if trie.is_match(state_id) {
return true;
}
}
false
}
And that's pretty much it. All we do is move through the trie starting with the
bytes at the beginning of the haystack. If we find ourselves in a position
where we can't move, or if we've looked through the entire haystack without
seeing a match state, then we know the haystack does not start with any of the
patterns in the trie.
The meat of the Aho-Corasick algorithm is in how we add failure transitions to
our trie to keep searching efficient. Specifically, it permits us to not only
check whether a haystack *starts* with any one of a number of patterns, but
rather, whether the haystack contains any of a number of patterns *anywhere* in
the haystack.
As mentioned before, failure transitions connect a proper suffix of the path
traversed through the trie before, with a path that leads to a match that has a
prefix corresponding to that proper suffix. So in our case, for patterns `abcd`
and `cef`, with a haystack `abcef`, we want to transition to state `S5` (from
the diagram above) from `S3` upon seeing that the byte following `c` is not
`d`. Namely, the proper suffix in this example is `c`, which is a prefix of
`cef`. So the modified diagram looks like this:
a - S1 - b - S2 - c - S3 - d - S4*
/ /
/ ----------------
/ /
S0 - c - S5 - e - S6 - f - S7*
One thing that isn't shown in this diagram is that *all* states have a failure
transition, but only `S3` has a *non-trivial* failure transition. That is, all
other states have a failure transition back to the start state. So if our
haystack was `abzabcd`, then the searcher would transition back to `S0` after
seeing `z`, which effectively restarts the search. (Because there is no pattern
in our trie that has a prefix of `bz` or `z`.)
The code for traversing this *automaton* or *finite state machine* (it is no
longer just a trie) is not that much different from the `has_prefix` code
above:
fn contains(fsm: &FiniteStateMachine, haystack: &[u8]) -> bool {
let mut state_id = fsm.start();
// If the empty pattern is in fsm, then state_id is a match state.
if fsm.is_match(state_id) {
return true;
}
for (i, &b) in haystack.iter().enumerate() {
// While the diagram above doesn't show this, we may wind up needing
// to follow multiple failure transitions before we land on a state
// in which we can advance. Therefore, when searching for the next
// state, we need to loop until we don't see a failure transition.
//
// This loop terminates because the start state has no empty
// transitions. Every transition from the start state either points to
// another state, or loops back to the start state.
loop {
match fsm.next_state(state_id, b) {
Some(id) => {
state_id = id;
break;
}
// Unlike our code above, if there was no transition for this
// state, then we don't quit. Instead, we look for this state's
// failure transition and follow that instead.
None => {
state_id = fsm.next_fail_state(state_id);
}
};
}
if fsm.is_match(state_id) {
return true;
}
}
false
}
Other than the complication around traversing failure transitions, this code
is still roughly "traverse the automaton with bytes from the haystack, and quit
when a match is seen."
And that concludes our section on the basics. While we didn't go deep into how
the automaton is built (see `src/nfa/noncontiguous.rs`, which has detailed
comments about that), the basic structure of Aho-Corasick should be reasonably
clear.
# NFAs and DFAs
There are generally two types of finite automata: non-deterministic finite
automata (NFA) and deterministic finite automata (DFA). The difference between
them is, principally, that an NFA can be in multiple states at once. This is
typically accomplished by things called _epsilon_ transitions, where one could
move to a new state without consuming any bytes from the input. (The other
mechanism by which NFAs can be in more than one state is where the same byte in
a particular state transitions to multiple distinct states.) In contrast, a DFA
can only ever be in one state at a time. A DFA has no epsilon transitions, and
for any given state, a byte transitions to at most one other state.
By this formulation, the Aho-Corasick automaton described in the previous
section is an NFA. This is because failure transitions are, effectively,
epsilon transitions. That is, whenever the automaton is in state `S`, it is
actually in the set of states that are reachable by recursively following
failure transitions from `S` until you reach the start state. (This means
that, for example, the start state is always active since the start state is
reachable via failure transitions from any state in the automaton.)
NFAs have a lot of nice properties. They tend to be easier to construct, and
also tend to use less memory. However, their primary downside is that they are
typically slower to execute a search with. For example, the code above showing
how to search with an Aho-Corasick automaton needs to potentially iterate
through many failure transitions for every byte of input. While this is a
fairly small amount of overhead, this can add up, especially if the automaton
has a lot of overlapping patterns with a lot of failure transitions.
A DFA's search code, by contrast, looks like this:
fn contains(dfa: &DFA, haystack: &[u8]) -> bool {
let mut state_id = dfa.start();
// If the empty pattern is in dfa, then state_id is a match state.
if dfa.is_match(state_id) {
return true;
}
for (i, &b) in haystack.iter().enumerate() {
// An Aho-Corasick DFA *never* has a missing state that requires
// failure transitions to be followed. One byte of input advances the
// automaton by one state. Always.
state_id = dfa.next_state(state_id, b);
if dfa.is_match(state_id) {
return true;
}
}
false
}
The search logic here is much simpler than for the NFA, and this tends to
translate into significant performance benefits as well, since there's a lot
less work being done for each byte in the haystack. How is this accomplished?
It's done by pre-following all failure transitions for all states for all bytes
in the alphabet, and then building a single state transition table. Building
this DFA can be much more costly than building the NFA, and use much more
memory, but the better performance can be worth it.
Users of this crate can actually choose between using one of two possible NFAs
(noncontiguous or contiguous) or a DFA. By default, a contiguous NFA is used,
in most circumstances, but if the number of patterns is small enough a DFA will
be used. A contiguous NFA is chosen because it uses orders of magnitude less
memory than a DFA, takes only a little longer to build than a noncontiguous
NFA and usually gets pretty close to the search speed of a DFA. (Callers can
override this automatic selection via the `AhoCorasickBuilder::start_kind`
configuration.)
# More DFA tricks
As described in the previous section, one of the downsides of using a DFA
is that it uses more memory and can take longer to build. One small way of
mitigating these concerns is to map the alphabet used by the automaton into
a smaller space. Typically, the alphabet of a DFA has 256 elements in it:
one element for each possible value that fits into a byte. However, in many
cases, one does not need the full alphabet. For example, if all patterns in an
Aho-Corasick automaton are ASCII letters, then this only uses up 52 distinct
bytes. As far as the automaton is concerned, the rest of the 204 bytes are
indistinguishable from one another: they will never disrciminate between a
match or a non-match. Therefore, in cases like that, the alphabet can be shrunk
to just 53 elements. One for each ASCII letter, and then another to serve as a
placeholder for every other unused byte.
In practice, this library doesn't quite compute the optimal set of equivalence
classes, but it's close enough in most cases. The key idea is that this then
allows the transition table for the DFA to be potentially much smaller. The
downside of doing this, however, is that since the transition table is defined
in terms of this smaller alphabet space, every byte in the haystack must be
re-mapped to this smaller space. This requires an additional 256-byte table.
In practice, this can lead to a small search time hit, but it can be difficult
to measure. Moreover, it can sometimes lead to faster search times for bigger
automata, since it could be difference between more parts of the automaton
staying in the CPU cache or not.
One other trick for DFAs employed by this crate is the notion of premultiplying
state identifiers. Specifically, the normal way to compute the next transition
in a DFA is via the following (assuming that the transition table is laid out
sequentially in memory, in row-major order, where the rows are states):
next_state_id = dfa.transitions[current_state_id * 256 + current_byte]
However, since the value `256` is a fixed constant, we can actually premultiply
the state identifiers in the table when we build the table initially. Then, the
next transition computation simply becomes:
next_state_id = dfa.transitions[current_state_id + current_byte]
This doesn't seem like much, but when this is being executed for every byte of
input that you're searching, saving that extra multiplication instruction can
add up.
The same optimization works even when equivalence classes are enabled, as
described above. The only difference is that the premultiplication is by the
total number of equivalence classes instead of 256.
There isn't much downside to premultiplying state identifiers, other than it
imposes a smaller limit on the total number of states in the DFA. Namely, with
premultiplied state identifiers, you run out of room in your state identifier
representation more rapidly than if the identifiers are just state indices.
Both equivalence classes and premultiplication are always enabled. There is a
`AhoCorasickBuilder::byte_classes` configuration, but disabling this just makes
it so there are always 256 equivalence classes, i.e., every class corresponds
to precisely one byte. When it's disabled, the equivalence class map itself is
still used. The purpose of disabling it is when one is debugging the underlying
automaton. It can be easier to comprehend when it uses actual byte values for
its transitions instead of equivalence classes.
# Match semantics
One of the more interesting things about this implementation of Aho-Corasick
that (as far as this author knows) separates it from other implementations, is
that it natively supports leftmost-first and leftmost-longest match semantics.
Briefly, match semantics refer to the decision procedure by which searching
will disambiguate matches when there are multiple to choose from:
* **standard** match semantics emits matches as soon as they are detected by
the automaton. This is typically equivalent to the textbook non-overlapping
formulation of Aho-Corasick.
* **leftmost-first** match semantics means that 1) the next match is the match
starting at the leftmost position and 2) among multiple matches starting at
the same leftmost position, the match corresponding to the pattern provided
first by the caller is reported.
* **leftmost-longest** is like leftmost-first, except when there are multiple
matches starting at the same leftmost position, the pattern corresponding to
the longest match is returned.
(The crate API documentation discusses these differences, with examples, in
more depth on the `MatchKind` type.)
The reason why supporting these match semantics is important is because it
gives the user more control over the match procedure. For example,
leftmost-first permits users to implement match priority by simply putting the
higher priority patterns first. Leftmost-longest, on the other hand, permits
finding the longest possible match, which might be useful when trying to find
words matching a dictionary. Additionally, regex engines often want to use
Aho-Corasick as an optimization when searching for an alternation of literals.
In order to preserve correct match semantics, regex engines typically can't use
the standard textbook definition directly, since regex engines will implement
either leftmost-first (Perl-like) or leftmost-longest (POSIX) match semantics.
Supporting leftmost semantics requires a couple key changes:
* Constructing the Aho-Corasick automaton changes a bit in both how the trie is
constructed and how failure transitions are found. Namely, only a subset
of the failure transitions are added. Specifically, only the failure
transitions that either do not occur after a match or do occur after a match
but preserve that match are kept. (More details on this can be found in
`src/nfa/noncontiguous.rs`.)
* The search algorithm changes slightly. Since we are looking for the leftmost
match, we cannot quit as soon as a match is detected. Instead, after a match
is detected, we must keep searching until either the end of the input or
until a dead state is seen. (Dead states are not used for standard match
semantics. Dead states mean that searching should stop after a match has been
found.)
Most other implementations of Aho-Corasick do support leftmost match semantics,
but they do it with more overhead at search time, or even worse, with a queue
of matches and sophisticated hijinks to disambiguate the matches. While our
construction algorithm becomes a bit more complicated, the correct match
semantics fall out from the structure of the automaton itself.
# Overlapping matches
One of the nice properties of an Aho-Corasick automaton is that it can report
all possible matches, even when they overlap with one another. In this mode,
the match semantics don't matter, since all possible matches are reported.
Overlapping searches work just like regular searches, except the state
identifier at which the previous search left off is carried over to the next
search, so that it can pick up where it left off. If there are additional
matches at that state, then they are reported before resuming the search.
Enabling leftmost-first or leftmost-longest match semantics causes the
automaton to use a subset of all failure transitions, which means that
overlapping searches cannot be used. Therefore, if leftmost match semantics are
used, attempting to do an overlapping search will return an error (or panic
when using the infallible APIs). Thus, to get overlapping searches, the caller
must use the default standard match semantics. This behavior was chosen because
there are only two alternatives, which were deemed worse:
* Compile two automatons internally, one for standard semantics and one for
the semantics requested by the caller (if not standard).
* Create a new type, distinct from the `AhoCorasick` type, which has different
capabilities based on the configuration options.
The first is untenable because of the amount of memory used by the automaton.
The second increases the complexity of the API too much by adding too many
types that do similar things. It is conceptually much simpler to keep all
searching isolated to a single type.
# Stream searching
Since Aho-Corasick is an automaton, it is possible to do partial searches on
partial parts of the haystack, and then resume that search on subsequent pieces
of the haystack. This is useful when the haystack you're trying to search is
not stored contiguously in memory, or if one does not want to read the entire
haystack into memory at once.
Currently, only standard semantics are supported for stream searching. This is
some of the more complicated code in this crate, and is something I would very
much like to improve. In particular, it currently has the restriction that it
must buffer at least enough of the haystack in memory in order to fit the
longest possible match. The difficulty in getting stream searching right is
that the implementation choices (such as the buffer size) often impact what the
API looks like and what it's allowed to do.
# Prefilters
In some cases, Aho-Corasick is not the fastest way to find matches containing
multiple patterns. Sometimes, the search can be accelerated using highly
optimized SIMD routines. For example, consider searching the following
patterns:
Sherlock
Moriarty
Watson
It is plausible that it would be much faster to quickly look for occurrences of
the leading bytes, `S`, `M` or `W`, before trying to start searching via the
automaton. Indeed, this is exactly what this crate will do.
When there are more than three distinct starting bytes, then this crate will
look for three distinct bytes occurring at any position in the patterns, while
preferring bytes that are heuristically determined to be rare over others. For
example:
Abuzz
Sanchez
Vasquez
Topaz
Waltz
Here, we have more than 3 distinct starting bytes, but all of the patterns
contain `z`, which is typically a rare byte. In this case, the prefilter will
scan for `z`, back up a bit, and then execute the Aho-Corasick automaton.
If all of that fails, then a packed multiple substring algorithm will be
attempted. Currently, the only algorithm available for this is Teddy, but more
may be added in the future. Teddy is unlike the above prefilters in that it
confirms its own matches, so when Teddy is active, it might not be necessary
for Aho-Corasick to run at all. However, the current Teddy implementation
only works in `x86_64` when SSSE3 or AVX2 are available or in `aarch64`
(using NEON), and moreover, only works _well_ when there are a small number
of patterns (say, less than 100). Teddy also requires the haystack to be of a
certain length (more than 16-34 bytes). When the haystack is shorter than that,
Rabin-Karp is used instead. (See `src/packed/rabinkarp.rs`.)
There is a more thorough description of Teddy at
[`src/packed/teddy/README.md`](src/packed/teddy/README.md).

21
vendor/aho-corasick/LICENSE-MIT vendored Normal file
View File

@@ -0,0 +1,21 @@
The MIT License (MIT)
Copyright (c) 2015 Andrew Gallant
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

174
vendor/aho-corasick/README.md vendored Normal file
View File

@@ -0,0 +1,174 @@
aho-corasick
============
A library for finding occurrences of many patterns at once with SIMD
acceleration in some cases. This library provides multiple pattern
search principally through an implementation of the
[Aho-Corasick algorithm](https://en.wikipedia.org/wiki/Aho%E2%80%93Corasick_algorithm),
which builds a finite state machine for executing searches in linear time.
Features include case insensitive matching, overlapping matches, fast searching
via SIMD and optional full DFA construction and search & replace in streams.
[![Build status](https://github.com/BurntSushi/aho-corasick/workflows/ci/badge.svg)](https://github.com/BurntSushi/aho-corasick/actions)
[![crates.io](https://img.shields.io/crates/v/aho-corasick.svg)](https://crates.io/crates/aho-corasick)
Dual-licensed under MIT or the [UNLICENSE](https://unlicense.org/).
### Documentation
https://docs.rs/aho-corasick
### Usage
Run `cargo add aho-corasick` to automatically add this crate as a dependency
in your `Cargo.toml` file.
### Example: basic searching
This example shows how to search for occurrences of multiple patterns
simultaneously. Each match includes the pattern that matched along with the
byte offsets of the match.
```rust
use aho_corasick::{AhoCorasick, PatternID};
let patterns = &["apple", "maple", "Snapple"];
let haystack = "Nobody likes maple in their apple flavored Snapple.";
let ac = AhoCorasick::new(patterns).unwrap();
let mut matches = vec![];
for mat in ac.find_iter(haystack) {
matches.push((mat.pattern(), mat.start(), mat.end()));
}
assert_eq!(matches, vec![
(PatternID::must(1), 13, 18),
(PatternID::must(0), 28, 33),
(PatternID::must(2), 43, 50),
]);
```
### Example: ASCII case insensitivity
This is like the previous example, but matches `Snapple` case insensitively
using `AhoCorasickBuilder`:
```rust
use aho_corasick::{AhoCorasick, PatternID};
let patterns = &["apple", "maple", "snapple"];
let haystack = "Nobody likes maple in their apple flavored Snapple.";
let ac = AhoCorasick::builder()
.ascii_case_insensitive(true)
.build(patterns)
.unwrap();
let mut matches = vec![];
for mat in ac.find_iter(haystack) {
matches.push((mat.pattern(), mat.start(), mat.end()));
}
assert_eq!(matches, vec![
(PatternID::must(1), 13, 18),
(PatternID::must(0), 28, 33),
(PatternID::must(2), 43, 50),
]);
```
### Example: replacing matches in a stream
This example shows how to execute a search and replace on a stream without
loading the entire stream into memory first.
```rust,ignore
use aho_corasick::AhoCorasick;
let patterns = &["fox", "brown", "quick"];
let replace_with = &["sloth", "grey", "slow"];
// In a real example, these might be `std::fs::File`s instead. All you need to
// do is supply a pair of `std::io::Read` and `std::io::Write` implementations.
let rdr = "The quick brown fox.";
let mut wtr = vec![];
let ac = AhoCorasick::new(patterns).unwrap();
ac.stream_replace_all(rdr.as_bytes(), &mut wtr, replace_with)
.expect("stream_replace_all failed");
assert_eq!(b"The slow grey sloth.".to_vec(), wtr);
```
### Example: finding the leftmost first match
In the textbook description of Aho-Corasick, its formulation is typically
structured such that it reports all possible matches, even when they overlap
with another. In many cases, overlapping matches may not be desired, such as
the case of finding all successive non-overlapping matches like you might with
a standard regular expression.
Unfortunately the "obvious" way to modify the Aho-Corasick algorithm to do
this doesn't always work in the expected way, since it will report matches as
soon as they are seen. For example, consider matching the regex `Samwise|Sam`
against the text `Samwise`. Most regex engines (that are Perl-like, or
non-POSIX) will report `Samwise` as a match, but the standard Aho-Corasick
algorithm modified for reporting non-overlapping matches will report `Sam`.
A novel contribution of this library is the ability to change the match
semantics of Aho-Corasick (without additional search time overhead) such that
`Samwise` is reported instead. For example, here's the standard approach:
```rust
use aho_corasick::AhoCorasick;
let patterns = &["Samwise", "Sam"];
let haystack = "Samwise";
let ac = AhoCorasick::new(patterns).unwrap();
let mat = ac.find(haystack).expect("should have a match");
assert_eq!("Sam", &haystack[mat.start()..mat.end()]);
```
And now here's the leftmost-first version, which matches how a Perl-like
regex will work:
```rust
use aho_corasick::{AhoCorasick, MatchKind};
let patterns = &["Samwise", "Sam"];
let haystack = "Samwise";
let ac = AhoCorasick::builder()
.match_kind(MatchKind::LeftmostFirst)
.build(patterns)
.unwrap();
let mat = ac.find(haystack).expect("should have a match");
assert_eq!("Samwise", &haystack[mat.start()..mat.end()]);
```
In addition to leftmost-first semantics, this library also supports
leftmost-longest semantics, which match the POSIX behavior of a regular
expression alternation. See `MatchKind` in the docs for more details.
### Minimum Rust version policy
This crate's minimum supported `rustc` version is `1.60.0`.
The current policy is that the minimum Rust version required to use this crate
can be increased in minor version updates. For example, if `crate 1.0` requires
Rust 1.20.0, then `crate 1.0.z` for all values of `z` will also require Rust
1.20.0 or newer. However, `crate 1.y` for `y > 0` may require a newer minimum
version of Rust.
In general, this crate will be conservative with respect to the minimum
supported version of Rust.
### FFI bindings
* [G-Research/ahocorasick_rs](https://github.com/G-Research/ahocorasick_rs/)
is a Python wrapper for this library.
* [tmikus/ahocorasick_rs](https://github.com/tmikus/ahocorasick_rs) is a Go
wrapper for this library.

24
vendor/aho-corasick/UNLICENSE vendored Normal file
View File

@@ -0,0 +1,24 @@
This is free and unencumbered software released into the public domain.
Anyone is free to copy, modify, publish, use, compile, sell, or
distribute this software, either in source code form or as a compiled
binary, for any purpose, commercial or non-commercial, and by any
means.
In jurisdictions that recognize copyright laws, the author or authors
of this software dedicate any and all copyright interest in the
software to the public domain. We make this dedication for the benefit
of the public at large and to the detriment of our heirs and
successors. We intend this dedication to be an overt act of
relinquishment in perpetuity of all present and future rights to this
software under copyright law.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
OTHER DEALINGS IN THE SOFTWARE.
For more information, please refer to <http://unlicense.org/>

2
vendor/aho-corasick/rustfmt.toml vendored Normal file
View File

@@ -0,0 +1,2 @@
max_width = 79
use_small_heuristics = "max"

2789
vendor/aho-corasick/src/ahocorasick.rs vendored Normal file

File diff suppressed because it is too large Load Diff

1608
vendor/aho-corasick/src/automaton.rs vendored Normal file

File diff suppressed because it is too large Load Diff

835
vendor/aho-corasick/src/dfa.rs vendored Normal file
View File

@@ -0,0 +1,835 @@
/*!
Provides direct access to a DFA implementation of Aho-Corasick.
This is a low-level API that generally only needs to be used in niche
circumstances. When possible, prefer using [`AhoCorasick`](crate::AhoCorasick)
instead of a DFA directly. Using an `DFA` directly is typically only necessary
when one needs access to the [`Automaton`] trait implementation.
*/
use alloc::{vec, vec::Vec};
use crate::{
automaton::Automaton,
nfa::noncontiguous,
util::{
alphabet::ByteClasses,
error::{BuildError, MatchError},
int::{Usize, U32},
prefilter::Prefilter,
primitives::{IteratorIndexExt, PatternID, SmallIndex, StateID},
search::{Anchored, MatchKind, StartKind},
special::Special,
},
};
/// A DFA implementation of Aho-Corasick.
///
/// When possible, prefer using [`AhoCorasick`](crate::AhoCorasick) instead of
/// this type directly. Using a `DFA` directly is typically only necessary when
/// one needs access to the [`Automaton`] trait implementation.
///
/// This DFA can only be built by first constructing a [`noncontiguous::NFA`].
/// Both [`DFA::new`] and [`Builder::build`] do this for you automatically, but
/// [`Builder::build_from_noncontiguous`] permits doing it explicitly.
///
/// A DFA provides the best possible search performance (in this crate) via two
/// mechanisms:
///
/// * All states use a dense representation for their transitions.
/// * All failure transitions are pre-computed such that they are never
/// explicitly handled at search time.
///
/// These two facts combined mean that every state transition is performed
/// using a constant number of instructions. However, this comes at
/// great cost. The memory usage of a DFA can be quite exorbitant.
/// It is potentially multiple orders of magnitude greater than a
/// [`contiguous::NFA`](crate::nfa::contiguous::NFA) for example. In exchange,
/// a DFA will typically have better search speed than a `contiguous::NFA`, but
/// not by orders of magnitude.
///
/// Unless you have a small number of patterns or memory usage is not a concern
/// and search performance is critical, a DFA is usually not the best choice.
///
/// Moreover, unlike the NFAs in this crate, it is costly for a DFA to
/// support for anchored and unanchored search configurations. Namely,
/// since failure transitions are pre-computed, supporting both anchored
/// and unanchored searches requires a duplication of the transition table,
/// making the memory usage of such a DFA ever bigger. (The NFAs in this crate
/// unconditionally support both anchored and unanchored searches because there
/// is essentially no added cost for doing so.) It is for this reason that
/// a DFA's support for anchored and unanchored searches can be configured
/// via [`Builder::start_kind`]. By default, a DFA only supports unanchored
/// searches.
///
/// # Example
///
/// This example shows how to build an `DFA` directly and use it to execute
/// [`Automaton::try_find`]:
///
/// ```
/// use aho_corasick::{
/// automaton::Automaton,
/// dfa::DFA,
/// Input, Match,
/// };
///
/// let patterns = &["b", "abc", "abcd"];
/// let haystack = "abcd";
///
/// let nfa = DFA::new(patterns).unwrap();
/// assert_eq!(
/// Some(Match::must(0, 1..2)),
/// nfa.try_find(&Input::new(haystack))?,
/// );
/// # Ok::<(), Box<dyn std::error::Error>>(())
/// ```
///
/// It is also possible to implement your own version of `try_find`. See the
/// [`Automaton`] documentation for an example.
#[derive(Clone)]
pub struct DFA {
/// The DFA transition table. IDs in this table are pre-multiplied. So
/// instead of the IDs being 0, 1, 2, 3, ..., they are 0*stride, 1*stride,
/// 2*stride, 3*stride, ...
trans: Vec<StateID>,
/// The matches for every match state in this DFA. This is first indexed by
/// state index (so that's `sid >> stride2`) and then by order in which the
/// matches are meant to occur.
matches: Vec<Vec<PatternID>>,
/// The amount of heap memory used, in bytes, by the inner Vecs of
/// 'matches'.
matches_memory_usage: usize,
/// The length of each pattern. This is used to compute the start offset
/// of a match.
pattern_lens: Vec<SmallIndex>,
/// A prefilter for accelerating searches, if one exists.
prefilter: Option<Prefilter>,
/// The match semantics built into this DFA.
match_kind: MatchKind,
/// The total number of states in this DFA.
state_len: usize,
/// The alphabet size, or total number of equivalence classes, for this
/// DFA. Note that the actual number of transitions in each state is
/// stride=2^stride2, where stride is the smallest power of 2 greater than
/// or equal to alphabet_len. We do things this way so that we can use
/// bitshifting to go from a state ID to an index into 'matches'.
alphabet_len: usize,
/// The exponent with a base 2, such that stride=2^stride2. Given a state
/// index 'i', its state identifier is 'i << stride2'. Given a state
/// identifier 'sid', its state index is 'sid >> stride2'.
stride2: usize,
/// The equivalence classes for this DFA. All transitions are defined on
/// equivalence classes and not on the 256 distinct byte values.
byte_classes: ByteClasses,
/// The length of the shortest pattern in this automaton.
min_pattern_len: usize,
/// The length of the longest pattern in this automaton.
max_pattern_len: usize,
/// The information required to deduce which states are "special" in this
/// DFA.
special: Special,
}
impl DFA {
/// Create a new Aho-Corasick DFA using the default configuration.
///
/// Use a [`Builder`] if you want to change the configuration.
pub fn new<I, P>(patterns: I) -> Result<DFA, BuildError>
where
I: IntoIterator<Item = P>,
P: AsRef<[u8]>,
{
DFA::builder().build(patterns)
}
/// A convenience method for returning a new Aho-Corasick DFA builder.
///
/// This usually permits one to just import the `DFA` type.
pub fn builder() -> Builder {
Builder::new()
}
}
impl DFA {
/// A sentinel state ID indicating that a search should stop once it has
/// entered this state. When a search stops, it returns a match if one has
/// been found, otherwise no match. A DFA always has an actual dead state
/// at this ID.
///
/// N.B. DFAs, unlike NFAs, do not have any notion of a FAIL state.
/// Namely, the whole point of a DFA is that the FAIL state is completely
/// compiled away. That is, DFA construction involves pre-computing the
/// failure transitions everywhere, such that failure transitions are no
/// longer used at search time. This, combined with its uniformly dense
/// representation, are the two most important factors in why it's faster
/// than the NFAs in this crate.
const DEAD: StateID = StateID::new_unchecked(0);
/// Adds the given pattern IDs as matches to the given state and also
/// records the added memory usage.
fn set_matches(
&mut self,
sid: StateID,
pids: impl Iterator<Item = PatternID>,
) {
let index = (sid.as_usize() >> self.stride2).checked_sub(2).unwrap();
let mut at_least_one = false;
for pid in pids {
self.matches[index].push(pid);
self.matches_memory_usage += PatternID::SIZE;
at_least_one = true;
}
assert!(at_least_one, "match state must have non-empty pids");
}
}
// SAFETY: 'start_state' always returns a valid state ID, 'next_state' always
// returns a valid state ID given a valid state ID. We otherwise claim that
// all other methods are correct as well.
unsafe impl Automaton for DFA {
#[inline(always)]
fn start_state(&self, anchored: Anchored) -> Result<StateID, MatchError> {
// Either of the start state IDs can be DEAD, in which case, support
// for that type of search is not provided by this DFA. Which start
// state IDs are inactive depends on the 'StartKind' configuration at
// DFA construction time.
match anchored {
Anchored::No => {
let start = self.special.start_unanchored_id;
if start == DFA::DEAD {
Err(MatchError::invalid_input_unanchored())
} else {
Ok(start)
}
}
Anchored::Yes => {
let start = self.special.start_anchored_id;
if start == DFA::DEAD {
Err(MatchError::invalid_input_anchored())
} else {
Ok(start)
}
}
}
}
#[inline(always)]
fn next_state(
&self,
_anchored: Anchored,
sid: StateID,
byte: u8,
) -> StateID {
let class = self.byte_classes.get(byte);
self.trans[(sid.as_u32() + u32::from(class)).as_usize()]
}
#[inline(always)]
fn is_special(&self, sid: StateID) -> bool {
sid <= self.special.max_special_id
}
#[inline(always)]
fn is_dead(&self, sid: StateID) -> bool {
sid == DFA::DEAD
}
#[inline(always)]
fn is_match(&self, sid: StateID) -> bool {
!self.is_dead(sid) && sid <= self.special.max_match_id
}
#[inline(always)]
fn is_start(&self, sid: StateID) -> bool {
sid == self.special.start_unanchored_id
|| sid == self.special.start_anchored_id
}
#[inline(always)]
fn match_kind(&self) -> MatchKind {
self.match_kind
}
#[inline(always)]
fn patterns_len(&self) -> usize {
self.pattern_lens.len()
}
#[inline(always)]
fn pattern_len(&self, pid: PatternID) -> usize {
self.pattern_lens[pid].as_usize()
}
#[inline(always)]
fn min_pattern_len(&self) -> usize {
self.min_pattern_len
}
#[inline(always)]
fn max_pattern_len(&self) -> usize {
self.max_pattern_len
}
#[inline(always)]
fn match_len(&self, sid: StateID) -> usize {
debug_assert!(self.is_match(sid));
let offset = (sid.as_usize() >> self.stride2) - 2;
self.matches[offset].len()
}
#[inline(always)]
fn match_pattern(&self, sid: StateID, index: usize) -> PatternID {
debug_assert!(self.is_match(sid));
let offset = (sid.as_usize() >> self.stride2) - 2;
self.matches[offset][index]
}
#[inline(always)]
fn memory_usage(&self) -> usize {
use core::mem::size_of;
(self.trans.len() * size_of::<u32>())
+ (self.matches.len() * size_of::<Vec<PatternID>>())
+ self.matches_memory_usage
+ (self.pattern_lens.len() * size_of::<SmallIndex>())
+ self.prefilter.as_ref().map_or(0, |p| p.memory_usage())
}
#[inline(always)]
fn prefilter(&self) -> Option<&Prefilter> {
self.prefilter.as_ref()
}
}
impl core::fmt::Debug for DFA {
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
use crate::{
automaton::{fmt_state_indicator, sparse_transitions},
util::debug::DebugByte,
};
writeln!(f, "dfa::DFA(")?;
for index in 0..self.state_len {
let sid = StateID::new_unchecked(index << self.stride2);
// While we do currently include the FAIL state in the transition
// table (to simplify construction), it is never actually used. It
// poses problems with the code below because it gets treated as
// a match state incidentally when it is, of course, not. So we
// special case it. The fail state is always the first state after
// the dead state.
//
// If the construction is changed to remove the fail state (it
// probably should be), then this special case should be updated.
if index == 1 {
writeln!(f, "F {:06}:", sid.as_usize())?;
continue;
}
fmt_state_indicator(f, self, sid)?;
write!(f, "{:06}: ", sid.as_usize())?;
let it = (0..self.byte_classes.alphabet_len()).map(|class| {
(class.as_u8(), self.trans[sid.as_usize() + class])
});
for (i, (start, end, next)) in sparse_transitions(it).enumerate() {
if i > 0 {
write!(f, ", ")?;
}
if start == end {
write!(
f,
"{:?} => {:?}",
DebugByte(start),
next.as_usize()
)?;
} else {
write!(
f,
"{:?}-{:?} => {:?}",
DebugByte(start),
DebugByte(end),
next.as_usize()
)?;
}
}
write!(f, "\n")?;
if self.is_match(sid) {
write!(f, " matches: ")?;
for i in 0..self.match_len(sid) {
if i > 0 {
write!(f, ", ")?;
}
let pid = self.match_pattern(sid, i);
write!(f, "{}", pid.as_usize())?;
}
write!(f, "\n")?;
}
}
writeln!(f, "match kind: {:?}", self.match_kind)?;
writeln!(f, "prefilter: {:?}", self.prefilter.is_some())?;
writeln!(f, "state length: {:?}", self.state_len)?;
writeln!(f, "pattern length: {:?}", self.patterns_len())?;
writeln!(f, "shortest pattern length: {:?}", self.min_pattern_len)?;
writeln!(f, "longest pattern length: {:?}", self.max_pattern_len)?;
writeln!(f, "alphabet length: {:?}", self.alphabet_len)?;
writeln!(f, "stride: {:?}", 1 << self.stride2)?;
writeln!(f, "byte classes: {:?}", self.byte_classes)?;
writeln!(f, "memory usage: {:?}", self.memory_usage())?;
writeln!(f, ")")?;
Ok(())
}
}
/// A builder for configuring an Aho-Corasick DFA.
///
/// This builder has a subset of the options available to a
/// [`AhoCorasickBuilder`](crate::AhoCorasickBuilder). Of the shared options,
/// their behavior is identical.
#[derive(Clone, Debug)]
pub struct Builder {
noncontiguous: noncontiguous::Builder,
start_kind: StartKind,
byte_classes: bool,
}
impl Default for Builder {
fn default() -> Builder {
Builder {
noncontiguous: noncontiguous::Builder::new(),
start_kind: StartKind::Unanchored,
byte_classes: true,
}
}
}
impl Builder {
/// Create a new builder for configuring an Aho-Corasick DFA.
pub fn new() -> Builder {
Builder::default()
}
/// Build an Aho-Corasick DFA from the given iterator of patterns.
///
/// A builder may be reused to create more DFAs.
pub fn build<I, P>(&self, patterns: I) -> Result<DFA, BuildError>
where
I: IntoIterator<Item = P>,
P: AsRef<[u8]>,
{
let nnfa = self.noncontiguous.build(patterns)?;
self.build_from_noncontiguous(&nnfa)
}
/// Build an Aho-Corasick DFA from the given noncontiguous NFA.
///
/// Note that when this method is used, only the `start_kind` and
/// `byte_classes` settings on this builder are respected. The other
/// settings only apply to the initial construction of the Aho-Corasick
/// automaton. Since using this method requires that initial construction
/// has already completed, all settings impacting only initial construction
/// are no longer relevant.
pub fn build_from_noncontiguous(
&self,
nnfa: &noncontiguous::NFA,
) -> Result<DFA, BuildError> {
debug!("building DFA");
let byte_classes = if self.byte_classes {
nnfa.byte_classes().clone()
} else {
ByteClasses::singletons()
};
let state_len = match self.start_kind {
StartKind::Unanchored | StartKind::Anchored => nnfa.states().len(),
StartKind::Both => {
// These unwraps are OK because we know that the number of
// NFA states is < StateID::LIMIT which is in turn less than
// i32::MAX. Thus, there is always room to multiply by 2.
// Finally, the number of states is always at least 4 in the
// NFA (DEAD, FAIL, START-UNANCHORED, START-ANCHORED), so the
// subtraction of 4 is okay.
//
// Note that we subtract 4 because the "anchored" part of
// the DFA duplicates the unanchored part (without failure
// transitions), but reuses the DEAD, FAIL and START states.
nnfa.states()
.len()
.checked_mul(2)
.unwrap()
.checked_sub(4)
.unwrap()
}
};
let trans_len =
match state_len.checked_shl(byte_classes.stride2().as_u32()) {
Some(trans_len) => trans_len,
None => {
return Err(BuildError::state_id_overflow(
StateID::MAX.as_u64(),
usize::MAX.as_u64(),
))
}
};
StateID::new(trans_len.checked_sub(byte_classes.stride()).unwrap())
.map_err(|e| {
BuildError::state_id_overflow(
StateID::MAX.as_u64(),
e.attempted(),
)
})?;
let num_match_states = match self.start_kind {
StartKind::Unanchored | StartKind::Anchored => {
nnfa.special().max_match_id.as_usize().checked_sub(1).unwrap()
}
StartKind::Both => nnfa
.special()
.max_match_id
.as_usize()
.checked_sub(1)
.unwrap()
.checked_mul(2)
.unwrap(),
};
let mut dfa = DFA {
trans: vec![DFA::DEAD; trans_len],
matches: vec![vec![]; num_match_states],
matches_memory_usage: 0,
pattern_lens: nnfa.pattern_lens_raw().to_vec(),
prefilter: nnfa.prefilter().map(|p| p.clone()),
match_kind: nnfa.match_kind(),
state_len,
alphabet_len: byte_classes.alphabet_len(),
stride2: byte_classes.stride2(),
byte_classes,
min_pattern_len: nnfa.min_pattern_len(),
max_pattern_len: nnfa.max_pattern_len(),
// The special state IDs are set later.
special: Special::zero(),
};
match self.start_kind {
StartKind::Both => {
self.finish_build_both_starts(nnfa, &mut dfa);
}
StartKind::Unanchored => {
self.finish_build_one_start(Anchored::No, nnfa, &mut dfa);
}
StartKind::Anchored => {
self.finish_build_one_start(Anchored::Yes, nnfa, &mut dfa)
}
}
debug!(
"DFA built, <states: {:?}, size: {:?}, \
alphabet len: {:?}, stride: {:?}>",
dfa.state_len,
dfa.memory_usage(),
dfa.byte_classes.alphabet_len(),
dfa.byte_classes.stride(),
);
// The vectors can grow ~twice as big during construction because a
// Vec amortizes growth. But here, let's shrink things back down to
// what we actually need since we're never going to add more to it.
dfa.trans.shrink_to_fit();
dfa.pattern_lens.shrink_to_fit();
dfa.matches.shrink_to_fit();
// TODO: We might also want to shrink each Vec inside of `dfa.matches`,
// or even better, convert it to one contiguous allocation. But I think
// I went with nested allocs for good reason (can't remember), so this
// may be tricky to do. I decided not to shrink them here because it
// might require a fair bit of work to do. It's unclear whether it's
// worth it.
Ok(dfa)
}
/// Finishes building a DFA for either unanchored or anchored searches,
/// but NOT both.
fn finish_build_one_start(
&self,
anchored: Anchored,
nnfa: &noncontiguous::NFA,
dfa: &mut DFA,
) {
// This function always succeeds because we check above that all of the
// states in the NFA can be mapped to DFA state IDs.
let stride2 = dfa.stride2;
let old2new = |oldsid: StateID| {
StateID::new_unchecked(oldsid.as_usize() << stride2)
};
for (oldsid, state) in nnfa.states().iter().with_state_ids() {
let newsid = old2new(oldsid);
if state.is_match() {
dfa.set_matches(newsid, nnfa.iter_matches(oldsid));
}
sparse_iter(
nnfa,
oldsid,
&dfa.byte_classes,
|byte, class, mut oldnextsid| {
if oldnextsid == noncontiguous::NFA::FAIL {
if anchored.is_anchored() {
oldnextsid = noncontiguous::NFA::DEAD;
} else if state.fail() == noncontiguous::NFA::DEAD {
// This is a special case that avoids following
// DEAD transitions in a non-contiguous NFA.
// Following these transitions is pretty slow
// because the non-contiguous NFA will always use
// a sparse representation for it (because the
// DEAD state is usually treated as a sentinel).
// The *vast* majority of failure states are DEAD
// states, so this winds up being pretty slow if
// we go through the non-contiguous NFA state
// transition logic. Instead, just do it ourselves.
oldnextsid = noncontiguous::NFA::DEAD;
} else {
oldnextsid = nnfa.next_state(
Anchored::No,
state.fail(),
byte,
);
}
}
dfa.trans[newsid.as_usize() + usize::from(class)] =
old2new(oldnextsid);
},
);
}
// Now that we've remapped all the IDs in our states, all that's left
// is remapping the special state IDs.
let old = nnfa.special();
let new = &mut dfa.special;
new.max_special_id = old2new(old.max_special_id);
new.max_match_id = old2new(old.max_match_id);
if anchored.is_anchored() {
new.start_unanchored_id = DFA::DEAD;
new.start_anchored_id = old2new(old.start_anchored_id);
} else {
new.start_unanchored_id = old2new(old.start_unanchored_id);
new.start_anchored_id = DFA::DEAD;
}
}
/// Finishes building a DFA that supports BOTH unanchored and anchored
/// searches. It works by inter-leaving unanchored states with anchored
/// states in the same transition table. This way, we avoid needing to
/// re-shuffle states afterward to ensure that our states still look like
/// DEAD, MATCH, ..., START-UNANCHORED, START-ANCHORED, NON-MATCH, ...
///
/// Honestly this is pretty inscrutable... Simplifications are most
/// welcome.
fn finish_build_both_starts(
&self,
nnfa: &noncontiguous::NFA,
dfa: &mut DFA,
) {
let stride2 = dfa.stride2;
let stride = 1 << stride2;
let mut remap_unanchored = vec![DFA::DEAD; nnfa.states().len()];
let mut remap_anchored = vec![DFA::DEAD; nnfa.states().len()];
let mut is_anchored = vec![false; dfa.state_len];
let mut newsid = DFA::DEAD;
let next_dfa_id =
|sid: StateID| StateID::new_unchecked(sid.as_usize() + stride);
for (oldsid, state) in nnfa.states().iter().with_state_ids() {
if oldsid == noncontiguous::NFA::DEAD
|| oldsid == noncontiguous::NFA::FAIL
{
remap_unanchored[oldsid] = newsid;
remap_anchored[oldsid] = newsid;
newsid = next_dfa_id(newsid);
} else if oldsid == nnfa.special().start_unanchored_id
|| oldsid == nnfa.special().start_anchored_id
{
if oldsid == nnfa.special().start_unanchored_id {
remap_unanchored[oldsid] = newsid;
remap_anchored[oldsid] = DFA::DEAD;
} else {
remap_unanchored[oldsid] = DFA::DEAD;
remap_anchored[oldsid] = newsid;
is_anchored[newsid.as_usize() >> stride2] = true;
}
if state.is_match() {
dfa.set_matches(newsid, nnfa.iter_matches(oldsid));
}
sparse_iter(
nnfa,
oldsid,
&dfa.byte_classes,
|_, class, oldnextsid| {
let class = usize::from(class);
if oldnextsid == noncontiguous::NFA::FAIL {
dfa.trans[newsid.as_usize() + class] = DFA::DEAD;
} else {
dfa.trans[newsid.as_usize() + class] = oldnextsid;
}
},
);
newsid = next_dfa_id(newsid);
} else {
let unewsid = newsid;
newsid = next_dfa_id(newsid);
let anewsid = newsid;
newsid = next_dfa_id(newsid);
remap_unanchored[oldsid] = unewsid;
remap_anchored[oldsid] = anewsid;
is_anchored[anewsid.as_usize() >> stride2] = true;
if state.is_match() {
dfa.set_matches(unewsid, nnfa.iter_matches(oldsid));
dfa.set_matches(anewsid, nnfa.iter_matches(oldsid));
}
sparse_iter(
nnfa,
oldsid,
&dfa.byte_classes,
|byte, class, oldnextsid| {
let class = usize::from(class);
if oldnextsid == noncontiguous::NFA::FAIL {
let oldnextsid =
if state.fail() == noncontiguous::NFA::DEAD {
noncontiguous::NFA::DEAD
} else {
nnfa.next_state(
Anchored::No,
state.fail(),
byte,
)
};
dfa.trans[unewsid.as_usize() + class] = oldnextsid;
} else {
dfa.trans[unewsid.as_usize() + class] = oldnextsid;
dfa.trans[anewsid.as_usize() + class] = oldnextsid;
}
},
);
}
}
for i in 0..dfa.state_len {
let sid = i << stride2;
if is_anchored[i] {
for next in dfa.trans[sid..][..stride].iter_mut() {
*next = remap_anchored[*next];
}
} else {
for next in dfa.trans[sid..][..stride].iter_mut() {
*next = remap_unanchored[*next];
}
}
}
// Now that we've remapped all the IDs in our states, all that's left
// is remapping the special state IDs.
let old = nnfa.special();
let new = &mut dfa.special;
new.max_special_id = remap_anchored[old.max_special_id];
new.max_match_id = remap_anchored[old.max_match_id];
new.start_unanchored_id = remap_unanchored[old.start_unanchored_id];
new.start_anchored_id = remap_anchored[old.start_anchored_id];
}
/// Set the desired match semantics.
///
/// This only applies when using [`Builder::build`] and not
/// [`Builder::build_from_noncontiguous`].
///
/// See
/// [`AhoCorasickBuilder::match_kind`](crate::AhoCorasickBuilder::match_kind)
/// for more documentation and examples.
pub fn match_kind(&mut self, kind: MatchKind) -> &mut Builder {
self.noncontiguous.match_kind(kind);
self
}
/// Enable ASCII-aware case insensitive matching.
///
/// This only applies when using [`Builder::build`] and not
/// [`Builder::build_from_noncontiguous`].
///
/// See
/// [`AhoCorasickBuilder::ascii_case_insensitive`](crate::AhoCorasickBuilder::ascii_case_insensitive)
/// for more documentation and examples.
pub fn ascii_case_insensitive(&mut self, yes: bool) -> &mut Builder {
self.noncontiguous.ascii_case_insensitive(yes);
self
}
/// Enable heuristic prefilter optimizations.
///
/// This only applies when using [`Builder::build`] and not
/// [`Builder::build_from_noncontiguous`].
///
/// See
/// [`AhoCorasickBuilder::prefilter`](crate::AhoCorasickBuilder::prefilter)
/// for more documentation and examples.
pub fn prefilter(&mut self, yes: bool) -> &mut Builder {
self.noncontiguous.prefilter(yes);
self
}
/// Sets the starting state configuration for the automaton.
///
/// See
/// [`AhoCorasickBuilder::start_kind`](crate::AhoCorasickBuilder::start_kind)
/// for more documentation and examples.
pub fn start_kind(&mut self, kind: StartKind) -> &mut Builder {
self.start_kind = kind;
self
}
/// A debug setting for whether to attempt to shrink the size of the
/// automaton's alphabet or not.
///
/// This should never be enabled unless you're debugging an automaton.
/// Namely, disabling byte classes makes transitions easier to reason
/// about, since they use the actual bytes instead of equivalence classes.
/// Disabling this confers no performance benefit at search time.
///
/// See
/// [`AhoCorasickBuilder::byte_classes`](crate::AhoCorasickBuilder::byte_classes)
/// for more documentation and examples.
pub fn byte_classes(&mut self, yes: bool) -> &mut Builder {
self.byte_classes = yes;
self
}
}
/// Iterate over all possible equivalence class transitions in this state.
/// The closure is called for all transitions with a distinct equivalence
/// class, even those not explicitly represented in this sparse state. For
/// any implicitly defined transitions, the given closure is called with
/// the fail state ID.
///
/// The closure is guaranteed to be called precisely
/// `byte_classes.alphabet_len()` times, once for every possible class in
/// ascending order.
fn sparse_iter<F: FnMut(u8, u8, StateID)>(
nnfa: &noncontiguous::NFA,
oldsid: StateID,
classes: &ByteClasses,
mut f: F,
) {
let mut prev_class = None;
let mut byte = 0usize;
for t in nnfa.iter_trans(oldsid) {
while byte < usize::from(t.byte()) {
let rep = byte.as_u8();
let class = classes.get(rep);
byte += 1;
if prev_class != Some(class) {
f(rep, class, noncontiguous::NFA::FAIL);
prev_class = Some(class);
}
}
let rep = t.byte();
let class = classes.get(rep);
byte += 1;
if prev_class != Some(class) {
f(rep, class, t.next());
prev_class = Some(class);
}
}
for b in byte..=255 {
let rep = b.as_u8();
let class = classes.get(rep);
if prev_class != Some(class) {
f(rep, class, noncontiguous::NFA::FAIL);
prev_class = Some(class);
}
}
}

326
vendor/aho-corasick/src/lib.rs vendored Normal file
View File

@@ -0,0 +1,326 @@
/*!
A library for finding occurrences of many patterns at once. This library
provides multiple pattern search principally through an implementation of the
[Aho-Corasick algorithm](https://en.wikipedia.org/wiki/Aho%E2%80%93Corasick_algorithm),
which builds a fast finite state machine for executing searches in linear time.
Additionally, this library provides a number of configuration options for
building the automaton that permit controlling the space versus time trade
off. Other features include simple ASCII case insensitive matching, finding
overlapping matches, replacements, searching streams and even searching and
replacing text in streams.
Finally, unlike most other Aho-Corasick implementations, this one
supports enabling [leftmost-first](MatchKind::LeftmostFirst) or
[leftmost-longest](MatchKind::LeftmostLongest) match semantics, using a
(seemingly) novel alternative construction algorithm. For more details on what
match semantics means, see the [`MatchKind`] type.
# Overview
This section gives a brief overview of the primary types in this crate:
* [`AhoCorasick`] is the primary type and represents an Aho-Corasick automaton.
This is the type you use to execute searches.
* [`AhoCorasickBuilder`] can be used to build an Aho-Corasick automaton, and
supports configuring a number of options.
* [`Match`] represents a single match reported by an Aho-Corasick automaton.
Each match has two pieces of information: the pattern that matched and the
start and end byte offsets corresponding to the position in the haystack at
which it matched.
# Example: basic searching
This example shows how to search for occurrences of multiple patterns
simultaneously. Each match includes the pattern that matched along with the
byte offsets of the match.
```
use aho_corasick::{AhoCorasick, PatternID};
let patterns = &["apple", "maple", "Snapple"];
let haystack = "Nobody likes maple in their apple flavored Snapple.";
let ac = AhoCorasick::new(patterns).unwrap();
let mut matches = vec![];
for mat in ac.find_iter(haystack) {
matches.push((mat.pattern(), mat.start(), mat.end()));
}
assert_eq!(matches, vec![
(PatternID::must(1), 13, 18),
(PatternID::must(0), 28, 33),
(PatternID::must(2), 43, 50),
]);
```
# Example: case insensitivity
This is like the previous example, but matches `Snapple` case insensitively
using `AhoCorasickBuilder`:
```
use aho_corasick::{AhoCorasick, PatternID};
let patterns = &["apple", "maple", "snapple"];
let haystack = "Nobody likes maple in their apple flavored Snapple.";
let ac = AhoCorasick::builder()
.ascii_case_insensitive(true)
.build(patterns)
.unwrap();
let mut matches = vec![];
for mat in ac.find_iter(haystack) {
matches.push((mat.pattern(), mat.start(), mat.end()));
}
assert_eq!(matches, vec![
(PatternID::must(1), 13, 18),
(PatternID::must(0), 28, 33),
(PatternID::must(2), 43, 50),
]);
```
# Example: replacing matches in a stream
This example shows how to execute a search and replace on a stream without
loading the entire stream into memory first.
```
# #[cfg(feature = "std")] {
use aho_corasick::AhoCorasick;
# fn example() -> Result<(), std::io::Error> {
let patterns = &["fox", "brown", "quick"];
let replace_with = &["sloth", "grey", "slow"];
// In a real example, these might be `std::fs::File`s instead. All you need to
// do is supply a pair of `std::io::Read` and `std::io::Write` implementations.
let rdr = "The quick brown fox.";
let mut wtr = vec![];
let ac = AhoCorasick::new(patterns).unwrap();
ac.try_stream_replace_all(rdr.as_bytes(), &mut wtr, replace_with)?;
assert_eq!(b"The slow grey sloth.".to_vec(), wtr);
# Ok(()) }; example().unwrap()
# }
```
# Example: finding the leftmost first match
In the textbook description of Aho-Corasick, its formulation is typically
structured such that it reports all possible matches, even when they overlap
with another. In many cases, overlapping matches may not be desired, such as
the case of finding all successive non-overlapping matches like you might with
a standard regular expression.
Unfortunately the "obvious" way to modify the Aho-Corasick algorithm to do
this doesn't always work in the expected way, since it will report matches as
soon as they are seen. For example, consider matching the regex `Samwise|Sam`
against the text `Samwise`. Most regex engines (that are Perl-like, or
non-POSIX) will report `Samwise` as a match, but the standard Aho-Corasick
algorithm modified for reporting non-overlapping matches will report `Sam`.
A novel contribution of this library is the ability to change the match
semantics of Aho-Corasick (without additional search time overhead) such that
`Samwise` is reported instead. For example, here's the standard approach:
```
use aho_corasick::AhoCorasick;
let patterns = &["Samwise", "Sam"];
let haystack = "Samwise";
let ac = AhoCorasick::new(patterns).unwrap();
let mat = ac.find(haystack).expect("should have a match");
assert_eq!("Sam", &haystack[mat.start()..mat.end()]);
```
And now here's the leftmost-first version, which matches how a Perl-like
regex will work:
```
use aho_corasick::{AhoCorasick, MatchKind};
let patterns = &["Samwise", "Sam"];
let haystack = "Samwise";
let ac = AhoCorasick::builder()
.match_kind(MatchKind::LeftmostFirst)
.build(patterns)
.unwrap();
let mat = ac.find(haystack).expect("should have a match");
assert_eq!("Samwise", &haystack[mat.start()..mat.end()]);
```
In addition to leftmost-first semantics, this library also supports
leftmost-longest semantics, which match the POSIX behavior of a regular
expression alternation. See [`MatchKind`] for more details.
# Prefilters
While an Aho-Corasick automaton can perform admirably when compared to more
naive solutions, it is generally slower than more specialized algorithms that
are accelerated using vector instructions such as SIMD.
For that reason, this library will internally use a "prefilter" to attempt
to accelerate searches when possible. Currently, this library has several
different algorithms it might use depending on the patterns provided. Once the
number of patterns gets too big, prefilters are no longer used.
While a prefilter is generally good to have on by default since it works
well in the common case, it can lead to less predictable or even sub-optimal
performance in some cases. For that reason, prefilters can be explicitly
disabled via [`AhoCorasickBuilder::prefilter`].
# Lower level APIs
This crate also provides several sub-modules that collectively expose many of
the implementation details of the main [`AhoCorasick`] type. Most users of this
library can completely ignore the submodules and their contents, but if you
needed finer grained control, some parts of them may be useful to you. Here is
a brief overview of each and why you might want to use them:
* The [`packed`] sub-module contains a lower level API for using fast
vectorized routines for finding a small number of patterns in a haystack.
You might want to use this API when you want to completely side-step using
Aho-Corasick automata. Otherwise, the fast vectorized routines are used
automatically as prefilters for `AhoCorasick` searches whenever possible.
* The [`automaton`] sub-module provides a lower level finite state
machine interface that the various Aho-Corasick implementations in
this crate implement. This sub-module's main contribution is the
[`Automaton`](automaton::Automaton) trait, which permits manually walking the
state transitions of an Aho-Corasick automaton.
* The [`dfa`] and [`nfa`] sub-modules provide DFA and NFA implementations of
the aforementioned `Automaton` trait. The main reason one might want to use
these sub-modules is to get access to a type that implements the `Automaton`
trait. (The top-level `AhoCorasick` type does not implement the `Automaton`
trait.)
As mentioned above, if you aren't sure whether you need these sub-modules,
you should be able to safely ignore them and just focus on the [`AhoCorasick`]
type.
# Crate features
This crate exposes a few features for controlling dependency usage and whether
this crate can be used without the standard library.
* **std** -
Enables support for the standard library. This feature is enabled by
default. When disabled, only `core` and `alloc` are used. At an API
level, enabling `std` enables `std::error::Error` trait impls for the
various error types, and higher level stream search routines such as
[`AhoCorasick::try_stream_find_iter`]. But the `std` feature is also required
to enable vectorized prefilters. Prefilters can greatly accelerate searches,
but generally only apply when the number of patterns is small (less than
~100).
* **perf-literal** -
Enables support for literal prefilters that use vectorized routines from
external crates. This feature is enabled by default. If you're only using
Aho-Corasick for large numbers of patterns or otherwise can abide lower
throughput when searching with a small number of patterns, then it is
reasonable to disable this feature.
* **logging** -
Enables a dependency on the `log` crate and emits messages to aide in
diagnostics. This feature is disabled by default.
*/
#![no_std]
#![deny(missing_docs)]
#![deny(rustdoc::broken_intra_doc_links)]
#![cfg_attr(docsrs, feature(doc_auto_cfg))]
extern crate alloc;
#[cfg(any(test, feature = "std"))]
extern crate std;
#[cfg(doctest)]
doc_comment::doctest!("../README.md");
#[cfg(feature = "std")]
pub use crate::ahocorasick::StreamFindIter;
pub use crate::{
ahocorasick::{
AhoCorasick, AhoCorasickBuilder, AhoCorasickKind, FindIter,
FindOverlappingIter,
},
util::{
error::{BuildError, MatchError, MatchErrorKind},
primitives::{PatternID, PatternIDError},
search::{Anchored, Input, Match, MatchKind, Span, StartKind},
},
};
#[macro_use]
mod macros;
mod ahocorasick;
pub mod automaton;
pub mod dfa;
pub mod nfa;
pub mod packed;
#[cfg(test)]
mod tests;
// I wrote out the module for implementing fst::Automaton only to later realize
// that this would make fst a public dependency and fst is not at 1.0 yet. I
// decided to just keep the code in tree, but build it only during tests.
//
// TODO: I think I've changed my mind again. I'm considering pushing it out
// into either a separate crate or into 'fst' directly as an optional feature.
// #[cfg(test)]
// #[allow(dead_code)]
// mod transducer;
pub(crate) mod util;
#[cfg(test)]
mod testoibits {
use std::panic::{RefUnwindSafe, UnwindSafe};
use super::*;
fn assert_all<T: Send + Sync + UnwindSafe + RefUnwindSafe>() {}
#[test]
fn oibits_main() {
assert_all::<AhoCorasick>();
assert_all::<AhoCorasickBuilder>();
assert_all::<AhoCorasickKind>();
assert_all::<FindIter>();
assert_all::<FindOverlappingIter>();
assert_all::<BuildError>();
assert_all::<MatchError>();
assert_all::<MatchErrorKind>();
assert_all::<Anchored>();
assert_all::<Input>();
assert_all::<Match>();
assert_all::<MatchKind>();
assert_all::<Span>();
assert_all::<StartKind>();
}
#[test]
fn oibits_automaton() {
use crate::{automaton, dfa::DFA};
assert_all::<automaton::FindIter<DFA>>();
assert_all::<automaton::FindOverlappingIter<DFA>>();
#[cfg(feature = "std")]
assert_all::<automaton::StreamFindIter<DFA, std::io::Stdin>>();
assert_all::<automaton::OverlappingState>();
assert_all::<automaton::Prefilter>();
assert_all::<automaton::Candidate>();
}
#[test]
fn oibits_packed() {
use crate::packed;
assert_all::<packed::Config>();
assert_all::<packed::Builder>();
assert_all::<packed::Searcher>();
assert_all::<packed::FindIter>();
assert_all::<packed::MatchKind>();
}
}

18
vendor/aho-corasick/src/macros.rs vendored Normal file
View File

@@ -0,0 +1,18 @@
#![allow(unused_macros)]
macro_rules! log {
($($tt:tt)*) => {
#[cfg(feature = "logging")]
{
$($tt)*
}
}
}
macro_rules! debug {
($($tt:tt)*) => { log!(log::debug!($($tt)*)) }
}
macro_rules! trace {
($($tt:tt)*) => { log!(log::trace!($($tt)*)) }
}

Some files were not shown because too many files have changed in this diff Show More