From a1f3c71b7fd21e0e9decfee474f9dfffa2bf932d Mon Sep 17 00:00:00 2001 From: Emil Ernerfeldt Date: Tue, 28 Nov 2023 10:46:18 +0100 Subject: [PATCH] Remove dependency on `tts` (#3651) We were using [`tts`](https://github.com/ndarilek/tts-rs) for the web-only screen reader. This was overkill, to say the least. It is now replaced with ten lines of `web-sys` calls. --- Cargo.lock | 243 ---------------------- crates/eframe/Cargo.toml | 7 +- crates/eframe/src/web/app_runner.rs | 6 +- crates/eframe/src/web/mod.rs | 1 + crates/eframe/src/web/screen_reader.rs | 57 ++--- crates/egui/src/memory.rs | 2 +- crates/egui_demo_app/Cargo.toml | 7 +- crates/egui_demo_app/src/backend_panel.rs | 7 +- scripts/wasm_bindgen_check.sh | 2 +- 9 files changed, 29 insertions(+), 303 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 41061aac..569421b9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -490,29 +490,6 @@ dependencies = [ "serde", ] -[[package]] -name = "bindgen" -version = "0.68.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "726e4313eb6ec35d2730258ad4e15b547ee75d6afaa1361a922e78e59b7d8078" -dependencies = [ - "bitflags 2.4.0", - "cexpr", - "clang-sys", - "lazy_static", - "lazycell", - "log", - "peeking_take_while", - "prettyplease", - "proc-macro2", - "quote", - "regex", - "rustc-hash", - "shlex", - "syn 2.0.37", - "which", -] - [[package]] name = "bit-set" version = "0.5.3" @@ -677,15 +654,6 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6d43a04d8753f35258c91f8ec639f792891f748a1edbd759cf1dcea3382ad83c" -[[package]] -name = "cexpr" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6fac387a98bb7c37292057cffc56d62ecb629900026402633ae9160df93a8766" -dependencies = [ - "nom", -] - [[package]] name = "cfg-expr" version = "0.15.5" @@ -764,17 +732,6 @@ version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7a0e87cdf78571d9fbeff16861c37a006cd718d2433dc6d5b80beaae367d899a" -[[package]] -name = "clang-sys" -version = "1.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c688fc74432808e3eb684cae8830a86be1d66a2bd58e1f248ed0960a590baf6f" -dependencies = [ - "glob", - "libc", - "libloading 0.7.4", -] - [[package]] name = "clap" version = "3.2.25" @@ -1058,41 +1015,6 @@ dependencies = [ "winapi", ] -[[package]] -name = "darling" -version = "0.13.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a01d95850c592940db9b8194bc39f4bc0e89dee5c4265e4b1807c34a9aba453c" -dependencies = [ - "darling_core", - "darling_macro", -] - -[[package]] -name = "darling_core" -version = "0.13.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "859d65a907b6852c9361e3185c862aae7fafd2887876799fa55f5f99dc40d610" -dependencies = [ - "fnv", - "ident_case", - "proc-macro2", - "quote", - "strsim", - "syn 1.0.109", -] - -[[package]] -name = "darling_macro" -version = "0.13.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c972679f83bdf9c42bd905396b6c3588a843a17f0f16dfcfa3e2c5d57441835" -dependencies = [ - "darling_core", - "quote", - "syn 1.0.109", -] - [[package]] name = "data-url" version = "0.2.0" @@ -1177,33 +1099,6 @@ version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9ea835d29036a4087793836fa931b08837ad5e957da9e23886b29586fb9b6650" -[[package]] -name = "dyn-clonable" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4e9232f0e607a262ceb9bd5141a3dfb3e4db6994b31989bbfd845878cba59fd4" -dependencies = [ - "dyn-clonable-impl", - "dyn-clone", -] - -[[package]] -name = "dyn-clonable-impl" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "558e40ea573c374cf53507fd240b7ee2f5477df7cfebdb97323ec61c719399c5" -dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.109", -] - -[[package]] -name = "dyn-clone" -version = "1.0.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23d2f3407d9a573d666de4b5bdf10569d73ca9478087346697dcbae6244bfbcd" - [[package]] name = "ecolor" version = "0.24.0" @@ -1243,7 +1138,6 @@ dependencies = [ "serde", "static_assertions", "thiserror", - "tts", "wasm-bindgen", "wasm-bindgen-futures", "web-sys", @@ -1843,12 +1737,6 @@ dependencies = [ "system-deps", ] -[[package]] -name = "glob" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b" - [[package]] name = "glow" version = "0.12.3" @@ -2161,12 +2049,6 @@ dependencies = [ "cc", ] -[[package]] -name = "ident_case" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" - [[package]] name = "idna" version = "0.4.0" @@ -2363,12 +2245,6 @@ version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" -[[package]] -name = "lazycell" -version = "1.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55" - [[package]] name = "libc" version = "0.2.148" @@ -2614,35 +2490,6 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "27b02d87554356db9e9a873add8782d4ea6e3e58ea071a9adb9a2e8ddb884a8b" -[[package]] -name = "ndk-glue" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0434fabdd2c15e0aab768ca31d5b7b333717f03cf02037d5a0a3ff3c278ed67f" -dependencies = [ - "libc", - "log", - "ndk", - "ndk-context", - "ndk-macro", - "ndk-sys", - "once_cell", - "parking_lot", -] - -[[package]] -name = "ndk-macro" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0df7ac00c4672f9d5aece54ee3347520b7e20f158656c7db2e6de01902eb7a6c" -dependencies = [ - "darling", - "proc-macro-crate", - "proc-macro2", - "quote", - "syn 1.0.109", -] - [[package]] name = "ndk-sys" version = "0.4.1+23.1.7779620" @@ -2876,12 +2723,6 @@ dependencies = [ "ttf-parser", ] -[[package]] -name = "oxilangtag" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d91edf4fbb970279443471345a4e8c491bf05bb283b3e6c88e4e606fd8c181b" - [[package]] name = "pango-sys" version = "0.16.3" @@ -2929,12 +2770,6 @@ version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "de3145af08024dea9fa9914f381a17b8fc6034dfb00f3a84013f7ff43f29ed4c" -[[package]] -name = "peeking_take_while" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "19b17cddbe7ec3f8bc800887bab5e717348c95ea2ca0b1bf0837fb964dc67099" - [[package]] name = "percent-encoding" version = "2.3.0" @@ -3047,16 +2882,6 @@ version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e8cf8e6a8aa66ce33f63993ffc4ea4271eb5b0530a9002db8455ea6050c77bfa" -[[package]] -name = "prettyplease" -version = "0.2.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae005bd773ab59b4725093fd7df83fd7892f7d8eafb48dbd7de6e024e4215f9d" -dependencies = [ - "proc-macro2", - "syn 2.0.37", -] - [[package]] name = "proc-macro-crate" version = "1.3.1" @@ -3541,12 +3366,6 @@ dependencies = [ "digest", ] -[[package]] -name = "shlex" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a7cee0529a6d40f580e7a5e6c495c8fbfe21b7b52795ed4bb5e62cdf92bc6380" - [[package]] name = "signal-hook-registry" version = "1.4.1" @@ -3640,26 +3459,6 @@ dependencies = [ "winapi", ] -[[package]] -name = "speech-dispatcher" -version = "0.16.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5727d53c474ba5ada07784ad7d203cf896a74854cfee0eb32376b00759eb2972" -dependencies = [ - "lazy_static", - "libc", - "speech-dispatcher-sys", -] - -[[package]] -name = "speech-dispatcher-sys" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c3e8acdf2b1f4bb13f1813b40b52f3edf4cc94d8a55fe713a584f672a10388d" -dependencies = [ - "bindgen", -] - [[package]] name = "spin" version = "0.5.2" @@ -3706,12 +3505,6 @@ dependencies = [ "float-cmp", ] -[[package]] -name = "strsim" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" - [[package]] name = "svgtypes" version = "0.8.2" @@ -3989,30 +3782,6 @@ version = "0.19.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a464a4b34948a5f67fddd2b823c62d9d92e44be75058b99939eae6c5b6960b33" -[[package]] -name = "tts" -version = "0.25.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aee57eae77c7059f02e9ae166cd3ef4973e62c859b1eeaf9a738032a5b1c38e4" -dependencies = [ - "cocoa-foundation", - "core-foundation", - "dyn-clonable", - "jni", - "lazy_static", - "libc", - "log", - "ndk-context", - "ndk-glue", - "objc", - "oxilangtag", - "speech-dispatcher", - "thiserror", - "wasm-bindgen", - "web-sys", - "windows 0.51.1", -] - [[package]] name = "type-map" version = "0.5.0" @@ -4484,18 +4253,6 @@ dependencies = [ "web-sys", ] -[[package]] -name = "which" -version = "4.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87ba24419a2078cd2b0f2ede2691b6c66d8e47836da3b6db8265ebad47afbfc7" -dependencies = [ - "either", - "home", - "once_cell", - "rustix 0.38.14", -] - [[package]] name = "widestring" version = "1.0.2" diff --git a/crates/eframe/Cargo.toml b/crates/eframe/Cargo.toml index df4fe36e..17679076 100644 --- a/crates/eframe/Cargo.toml +++ b/crates/eframe/Cargo.toml @@ -32,6 +32,7 @@ default = [ "default_fonts", "glow", "wayland", + "web_screen_reader", "winit/default", "x11", ] @@ -84,7 +85,10 @@ wayland = ["egui-winit/wayland"] ## Enable screen reader support (requires `ctx.options_mut(|o| o.screen_reader = true);`) on web. ## ## For other platforms, use the `accesskit` feature instead. -web_screen_reader = ["tts"] +web_screen_reader = [ + "web-sys/SpeechSynthesis", + "web-sys/SpeechSynthesisUtterance", +] ## Use [`wgpu`](https://docs.rs/wgpu) for painting (via [`egui-wgpu`](https://github.com/emilk/egui/tree/master/crates/egui-wgpu)). ## This overrides the `glow` feature. @@ -207,5 +211,4 @@ web-sys = { version = "0.3.58", features = [ # optional web: egui-wgpu = { version = "0.24.0", path = "../egui-wgpu", optional = true } # if wgpu is used, use it without (!) winit raw-window-handle = { workspace = true, optional = true } -tts = { version = "0.25", optional = true, default-features = false } wgpu = { workspace = true, optional = true } diff --git a/crates/eframe/src/web/app_runner.rs b/crates/eframe/src/web/app_runner.rs index e8f771bd..f5aab09a 100644 --- a/crates/eframe/src/web/app_runner.rs +++ b/crates/eframe/src/web/app_runner.rs @@ -13,7 +13,6 @@ pub struct AppRunner { app: Box, pub(crate) needs_repaint: std::sync::Arc, last_save_time: f64, - screen_reader: super::screen_reader::ScreenReader, pub(crate) text_cursor_pos: Option, pub(crate) mutable_text_under_cursor: bool, @@ -113,7 +112,6 @@ impl AppRunner { app, needs_repaint, last_save_time: now_sec(), - screen_reader: Default::default(), text_cursor_pos: None, mutable_text_under_cursor: false, textures_delta: Default::default(), @@ -235,9 +233,9 @@ impl AppRunner { } fn handle_platform_output(&mut self, platform_output: egui::PlatformOutput) { + #[cfg(feature = "web_screen_reader")] if self.egui_ctx.options(|o| o.screen_reader) { - self.screen_reader - .speak(&platform_output.events_description()); + super::screen_reader::speak(&platform_output.events_description()); } let egui::PlatformOutput { diff --git a/crates/eframe/src/web/mod.rs b/crates/eframe/src/web/mod.rs index 85e50ea2..cb5d6937 100644 --- a/crates/eframe/src/web/mod.rs +++ b/crates/eframe/src/web/mod.rs @@ -12,6 +12,7 @@ mod web_logger; mod web_runner; /// Access to the browser screen reader. +#[cfg(feature = "web_screen_reader")] pub mod screen_reader; /// Access to local browser storage. diff --git a/crates/eframe/src/web/screen_reader.rs b/crates/eframe/src/web/screen_reader.rs index f4b37f20..addebcfb 100644 --- a/crates/eframe/src/web/screen_reader.rs +++ b/crates/eframe/src/web/screen_reader.rs @@ -1,51 +1,20 @@ -/// Screen reader support. -pub struct ScreenReader { - #[cfg(feature = "tts")] - tts: Option, -} - -#[cfg(not(feature = "tts"))] -#[allow(clippy::derivable_impls)] // False positive -impl Default for ScreenReader { - fn default() -> Self { - Self {} +/// Speak the given text out loud. +pub fn speak(text: &str) { + if text.is_empty() { + return; } -} -#[cfg(feature = "tts")] -impl Default for ScreenReader { - fn default() -> Self { - let tts = match tts::Tts::default() { - Ok(screen_reader) => { - log::debug!("Initialized screen reader."); - Some(screen_reader) - } - Err(err) => { - log::warn!("Failed to load screen reader: {}", err); - None - } - }; - Self { tts } - } -} + if let Some(window) = web_sys::window() { + log::debug!("Speaking {text:?}"); -impl ScreenReader { - /// Speak the given text out loud. - #[cfg(not(feature = "tts"))] - #[allow(clippy::unused_self)] - pub fn speak(&mut self, _text: &str) {} + if let Ok(speech_synthesis) = window.speech_synthesis() { + speech_synthesis.cancel(); // interrupt previous speech, if any - /// Speak the given text out loud. - #[cfg(feature = "tts")] - pub fn speak(&mut self, text: &str) { - if text.is_empty() { - return; - } - if let Some(tts) = &mut self.tts { - log::debug!("Speaking: {:?}", text); - let interrupt = true; - if let Err(err) = tts.speak(text, interrupt) { - log::warn!("Failed to read: {}", err); + if let Ok(utterance) = web_sys::SpeechSynthesisUtterance::new_with_text(text) { + utterance.set_rate(1.0); + utterance.set_pitch(1.0); + utterance.set_volume(1.0); + speech_synthesis.speak(&utterance); } } } diff --git a/crates/egui/src/memory.rs b/crates/egui/src/memory.rs index 97057980..fb15fdd3 100644 --- a/crates/egui/src/memory.rs +++ b/crates/egui/src/memory.rs @@ -199,7 +199,7 @@ pub struct Options { /// /// Screen readers is an experimental feature of egui, and not supported on all platforms. /// - /// `eframe` supports it only on web, using the `web_screen_reader` feature flag, + /// `eframe` supports it only on web, /// but you should consider using [AccessKit](https://github.com/AccessKit/accesskit) instead, /// which `eframe` supports. pub screen_reader: bool, diff --git a/crates/egui_demo_app/Cargo.toml b/crates/egui_demo_app/Cargo.toml index 6fe18445..b3c749b4 100644 --- a/crates/egui_demo_app/Cargo.toml +++ b/crates/egui_demo_app/Cargo.toml @@ -19,7 +19,7 @@ crate-type = ["cdylib", "rlib"] default = ["glow", "persistence"] # image_viewer adds about 0.9 MB of WASM -web_app = ["http", "persistence", "web_screen_reader"] +web_app = ["http", "persistence"] http = ["ehttp", "image", "poll-promise", "egui_extras/image"] image_viewer = ["image", "egui_extras/all_loaders", "rfd"] @@ -27,7 +27,6 @@ persistence = ["eframe/persistence", "egui/persistence", "serde"] puffin = ["eframe/puffin", "dep:puffin", "dep:puffin_http"] serde = ["dep:serde", "egui_demo_lib/serde", "egui/serde"] syntect = ["egui_demo_lib/syntect"] -web_screen_reader = ["eframe/web_screen_reader"] # experimental glow = ["eframe/glow"] wgpu = ["eframe/wgpu", "bytemuck"] @@ -37,7 +36,9 @@ chrono = { version = "0.4", default-features = false, features = [ "js-sys", "wasmbind", ] } -eframe = { version = "0.24.0", path = "../eframe", default-features = false } +eframe = { version = "0.24.0", path = "../eframe", default-features = false, features = [ + "web_screen_reader", +] } egui = { version = "0.24.0", path = "../egui", features = [ "callstack", "extra_debug_asserts", diff --git a/crates/egui_demo_app/src/backend_panel.rs b/crates/egui_demo_app/src/backend_panel.rs index b9165703..09a92d31 100644 --- a/crates/egui_demo_app/src/backend_panel.rs +++ b/crates/egui_demo_app/src/backend_panel.rs @@ -94,15 +94,12 @@ impl BackendPanel { self.egui_windows.checkboxes(ui); #[cfg(debug_assertions)] - { + if ui.ctx().style().debug.debug_on_hover_with_all_modifiers { ui.separator(); - if ui.ctx().style().debug.debug_on_hover_with_all_modifiers { - ui.label("Press down all modifiers and hover a widget to see a callstack for it"); - } + ui.label("Press down all modifiers and hover a widget to see a callstack for it"); } #[cfg(target_arch = "wasm32")] - #[cfg(feature = "web_screen-reader")] { ui.separator(); let mut screen_reader = ui.ctx().options(|o| o.screen_reader); diff --git a/scripts/wasm_bindgen_check.sh b/scripts/wasm_bindgen_check.sh index 18c24628..c36af407 100755 --- a/scripts/wasm_bindgen_check.sh +++ b/scripts/wasm_bindgen_check.sh @@ -12,7 +12,7 @@ else fi CRATE_NAME="egui_demo_app" -FEATURES="glow,http,persistence,web_screen_reader" +FEATURES="glow,http,persistence" # This is required to enable the web_sys clipboard API which eframe web uses # https://rustwasm.github.io/wasm-bindgen/api/web_sys/struct.Clipboard.html