From e63ad8dcae01d3ae658944c618a2c7627d9903ad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc=20Esp=C3=ADn?= Date: Sun, 22 Oct 2023 17:42:52 +0200 Subject: [PATCH 1/4] feat: Event Loop ticker for components (#345) * feat: Event Loop ticker for components * improvements and fixes * improvements * use_camera improvements * improvements * simplified * clean up * clean up --- .vscode/settings.json | 3 +- crates/hooks/src/use_accessibility.rs | 2 +- crates/hooks/src/use_animation.rs | 47 +++++++--- crates/hooks/src/use_animation_transition.rs | 37 +++++--- crates/hooks/src/use_camera.rs | 27 ++---- crates/hooks/src/use_focus.rs | 2 +- crates/hooks/src/use_node.rs | 4 +- crates/hooks/src/use_platform.rs | 28 +++++- crates/renderer/src/app.rs | 11 +++ crates/renderer/src/event_loop.rs | 3 +- crates/testing/src/config.rs | 99 +++++++++++--------- crates/testing/src/launch.rs | 2 + crates/testing/src/test_handler.rs | 61 +++++++----- 13 files changed, 203 insertions(+), 123 deletions(-) diff --git a/.vscode/settings.json b/.vscode/settings.json index 27cc6116c..d01413707 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,6 +1,7 @@ { "rust-analyzer.cargo.features": [ "devtools", - "log" + "log", + "use_camera" ] } \ No newline at end of file diff --git a/crates/hooks/src/use_accessibility.rs b/crates/hooks/src/use_accessibility.rs index 5467aa6cb..1717b2c72 100644 --- a/crates/hooks/src/use_accessibility.rs +++ b/crates/hooks/src/use_accessibility.rs @@ -66,7 +66,7 @@ mod test { let mut utils = launch_test_with_config( use_focus_app, - TestingConfig::default().with_size((100.0, 100.0).into()), + *TestingConfig::default().with_size((100.0, 100.0).into()), ); // Initial state diff --git a/crates/hooks/src/use_animation.rs b/crates/hooks/src/use_animation.rs index 1caad2148..b6ab36135 100644 --- a/crates/hooks/src/use_animation.rs +++ b/crates/hooks/src/use_animation.rs @@ -1,12 +1,9 @@ use dioxus_core::ScopeState; use dioxus_hooks::{use_state, UseState}; -use std::time::Duration; -use tokio::time::interval; +use tokio::time::Instant; use uuid::Uuid; -use crate::Animation; - -const ANIMATION_MS: i32 = 16; // Assume 60 FPS for now +use crate::{use_platform, Animation, UsePlatform}; /// Manage the lifecyle of an [Animation]. #[derive(Clone)] @@ -15,14 +12,16 @@ pub struct AnimationManager<'a> { current_animation_id: &'a UseState>, value: &'a UseState, cx: &'a ScopeState, + platform: UsePlatform, } impl<'a> AnimationManager<'a> { /// Start the given [Animation]. pub fn start(&self, mut anim: Animation) { let new_id = Uuid::new_v4(); - let mut index = 0; + let platform = self.platform.clone(); + let mut ticker = platform.new_ticker(); let value = self.value.clone(); let current_animation_id = self.current_animation_id.clone(); @@ -31,8 +30,16 @@ impl<'a> AnimationManager<'a> { // Spawn the animation that will run at 1ms speed self.cx.spawn(async move { - let mut ticker = interval(Duration::from_millis(ANIMATION_MS as u64)); + platform.request_animation_frame(); + + let mut index = 0; + let mut prev_frame = Instant::now(); + loop { + // Wait for the event loop to tick + ticker.tick().await; + platform.request_animation_frame(); + // Stop running the animation if it was removed if *current_animation_id.current() == Some(new_id) { // Remove the current animation if it has finished @@ -41,12 +48,10 @@ impl<'a> AnimationManager<'a> { break; } - // Advance one tick + index += prev_frame.elapsed().as_millis() as i32; value.set(anim.move_value(index)); - index += ANIMATION_MS; - // Wait 1m - ticker.tick().await; + prev_frame = Instant::now(); } else { break; } @@ -102,12 +107,14 @@ pub fn use_animation(cx: &ScopeState, init_value: impl FnOnce() -> f64) -> Anima let current_animation_id = use_state(cx, || None); let init_value = *cx.use_hook(init_value); let value = use_state(cx, || init_value); + let platform = use_platform(cx); AnimationManager { current_animation_id, value, cx, init_value, + platform, } } @@ -139,20 +146,24 @@ mod test { let mut utils = launch_test(use_animation_app); + // Disable event loop ticker + utils.config().enable_ticker(false); + // Initial state utils.wait_for_update().await; assert_eq!(utils.root().get(0).layout().unwrap().width(), 0.0); // State somewhere in the middle - utils.wait_for_update().await; + sleep(Duration::from_millis(32)).await; utils.wait_for_update().await; let width = utils.root().get(0).layout().unwrap().width(); assert!(width > 0.0); assert!(width < 100.0); - sleep(Duration::from_millis(50)).await; + // Enable event loop ticker + utils.config().enable_ticker(true); // State in the end utils.wait_for_update().await; @@ -189,26 +200,34 @@ mod test { let mut utils = launch_test(use_animation_app); + // Disable event loop ticker + utils.config().enable_ticker(false); + // Initial state utils.wait_for_update().await; assert_eq!(utils.root().get(0).layout().unwrap().width(), 10.0); // State somewhere in the middle - utils.wait_for_update().await; + sleep(Duration::from_millis(32)).await; utils.wait_for_update().await; let width = utils.root().get(0).layout().unwrap().width(); assert!(width > 10.0); + // Trigger the click event to restart the animation utils.push_event(FreyaEvent::Mouse { name: "click".to_string(), cursor: (5.0, 5.0).into(), button: Some(MouseButton::Left), }); + // Enable event loop ticker + utils.config().enable_ticker(true); + // State has been restarted utils.wait_for_update().await; + utils.wait_for_update().await; let width = utils.root().get(0).layout().unwrap().width(); assert_eq!(width, 10.0); diff --git a/crates/hooks/src/use_animation_transition.rs b/crates/hooks/src/use_animation_transition.rs index 6487e37f0..1164dd0c9 100644 --- a/crates/hooks/src/use_animation_transition.rs +++ b/crates/hooks/src/use_animation_transition.rs @@ -2,13 +2,10 @@ use dioxus_core::ScopeState; use dioxus_hooks::{use_memo, use_state, UseFutureDep, UseState}; use freya_engine::prelude::Color; use freya_node_state::Parse; -use std::time::Duration; -use tokio::time::interval; +use tokio::time::Instant; use uuid::Uuid; -use crate::{Animation, TransitionAnimation}; - -const ANIMATION_MS: i32 = 16; // Assume 60 FPS for now +use crate::{use_platform, Animation, TransitionAnimation, UsePlatform}; /// Configure a `Transition` animation. #[derive(Clone, Debug, Copy, PartialEq)] @@ -145,6 +142,8 @@ pub struct TransitionsManager<'a> { current_animation_id: &'a UseState>, /// The scope. cx: &'a ScopeState, + /// Platform APIs + platform: UsePlatform, } impl<'a> TransitionsManager<'a> { @@ -165,6 +164,8 @@ impl<'a> TransitionsManager<'a> { fn run_with_animation(&self, mut animation: Animation) { let animation_id = Uuid::new_v4(); + let platform = self.platform.clone(); + let mut ticker = platform.new_ticker(); let transitions = self.transitions.clone(); let transitions_storage = self.transitions_storage.clone(); let current_animation_id = self.current_animation_id.clone(); @@ -174,9 +175,16 @@ impl<'a> TransitionsManager<'a> { // Spawn the animation that will run at 1ms speed self.cx.spawn(async move { - let mut ticker = interval(Duration::from_millis(ANIMATION_MS as u64)); + platform.request_animation_frame(); + let mut index = 0; + let mut prev_frame = Instant::now(); + loop { + // Wait for the event loop to tick + ticker.tick().await; + platform.request_animation_frame(); + // Stop running the animation if it's no longer selected if *current_animation_id.current() == Some(animation_id) { // Remove the current animation if it has finished @@ -185,7 +193,7 @@ impl<'a> TransitionsManager<'a> { break; } - // Advance one tick + index += prev_frame.elapsed().as_millis() as i32; let value = animation.move_value(index); transitions_storage.with_mut(|storage| { for (i, storage) in storage.iter_mut().enumerate() { @@ -195,10 +203,7 @@ impl<'a> TransitionsManager<'a> { } }); - index += ANIMATION_MS; - - // Wait 1ms - ticker.tick().await; + prev_frame = Instant::now(); } else { break; } @@ -278,6 +283,7 @@ where let current_animation_id = use_state(cx, || None); let transitions = use_memo(cx, dependencies.clone(), &mut init); let transitions_storage = use_state(cx, || animations_map(transitions)); + let platform = use_platform(cx); use_memo(cx, dependencies, { let storage_setter = transitions_storage.setter(); @@ -292,6 +298,7 @@ where transitions_storage, cx, transition_animation: transition, + platform, } } @@ -332,20 +339,24 @@ mod test { let mut utils = launch_test(use_animation_transition_app); + // Disable event loop ticker + utils.config().enable_ticker(false); + // Initial state utils.wait_for_update().await; assert_eq!(utils.root().get(0).layout().unwrap().width(), 0.0); // State somewhere in the middle - utils.wait_for_update().await; + sleep(Duration::from_millis(32)).await; utils.wait_for_update().await; let width = utils.root().get(0).layout().unwrap().width(); assert!(width > 0.0); assert!(width < 100.0); - sleep(Duration::from_millis(50)).await; + // Enable event loop ticker + utils.config().enable_ticker(true); // State in the end utils.wait_for_update().await; diff --git a/crates/hooks/src/use_camera.rs b/crates/hooks/src/use_camera.rs index c33c9b1ce..f1d58e954 100644 --- a/crates/hooks/src/use_camera.rs +++ b/crates/hooks/src/use_camera.rs @@ -1,33 +1,20 @@ -use std::{ - sync::{Arc, Mutex}, - time::Duration, -}; +use std::sync::{Arc, Mutex}; use crate::use_platform; use dioxus_core::{AttributeValue, ScopeState}; use dioxus_hooks::{to_owned, use_effect, use_state, UseState}; -use freya_common::EventMessage; use freya_node_state::{CustomAttributeValues, ImageReference}; -use nokhwa::{pixel_format::RgbFormat, utils::RequestedFormat, Camera, NokhwaError}; -use tokio::time::sleep; - pub use nokhwa::utils::{CameraIndex, RequestedFormatType, Resolution}; +use nokhwa::{pixel_format::RgbFormat, utils::RequestedFormat, Camera, NokhwaError}; /// Configuration for a camera pub struct CameraSettings { - frame_rate: u32, camera_index: CameraIndex, resolution: Option, camera_format: RequestedFormatType, } impl CameraSettings { - /// Specify a frame rate - pub fn with_frame_rate(mut self, frame_rate: u32) -> Self { - self.frame_rate = frame_rate; - self - } - /// Specify a camera index pub fn with_camera_index(mut self, camera_index: CameraIndex) -> Self { self.camera_index = camera_index; @@ -50,7 +37,6 @@ impl CameraSettings { impl Default for CameraSettings { fn default() -> Self { Self { - frame_rate: 30, camera_index: CameraIndex::Index(0), resolution: None, camera_format: RequestedFormatType::AbsoluteHighestFrameRate, @@ -89,11 +75,11 @@ pub fn use_camera( .unwrap_or_else(handle_error); } - let frame_rate = camera_settings.frame_rate; - let fps = 1000 / frame_rate; + let mut ticker = platform.new_ticker(); loop { - sleep(Duration::from_millis(fps as u64)).await; + // Wait for the event loop to tick + ticker.tick().await; // Capture the next frame let frame = camera.frame(); @@ -104,9 +90,10 @@ pub fn use_camera( image_reference.lock().unwrap().replace(bts); // Request the renderer to rerender - platform.send(EventMessage::RequestRerender).unwrap(); + platform.request_animation_frame(); } else if let Err(err) = frame { handle_error(err); + break; } } } else if let Err(err) = camera { diff --git a/crates/hooks/src/use_focus.rs b/crates/hooks/src/use_focus.rs index 0a9d83dd0..4aeacc730 100644 --- a/crates/hooks/src/use_focus.rs +++ b/crates/hooks/src/use_focus.rs @@ -93,7 +93,7 @@ mod test { let mut utils = launch_test_with_config( use_focus_app, - TestingConfig::default().with_size((100.0, 100.0).into()), + *TestingConfig::default().with_size((100.0, 100.0).into()), ); // Initial state diff --git a/crates/hooks/src/use_node.rs b/crates/hooks/src/use_node.rs index 58249d17f..39a264df9 100644 --- a/crates/hooks/src/use_node.rs +++ b/crates/hooks/src/use_node.rs @@ -77,14 +77,14 @@ mod test { let mut utils = launch_test_with_config( use_node_app, - TestingConfig::default().with_size((500.0, 800.0).into()), + *TestingConfig::default().with_size((500.0, 800.0).into()), ); utils.wait_for_update().await; let root = utils.root().get(0); assert_eq!(root.get(0).text().unwrap().parse::(), Ok(500.0 * 0.5)); - utils.set_config(TestingConfig::default().with_size((300.0, 800.0).into())); + utils.config().with_size((300.0, 800.0).into()); utils.wait_for_update().await; let root = utils.root().get(0); diff --git a/crates/hooks/src/use_platform.rs b/crates/hooks/src/use_platform.rs index 40f78ec70..fc77e5c03 100644 --- a/crates/hooks/src/use_platform.rs +++ b/crates/hooks/src/use_platform.rs @@ -1,10 +1,13 @@ +use std::sync::Arc; + use dioxus_core::ScopeState; use freya_common::EventMessage; -use tokio::sync::mpsc::UnboundedSender; +use tokio::sync::{broadcast, mpsc::UnboundedSender}; use winit::event_loop::EventLoopProxy; #[derive(Clone)] pub struct UsePlatform { + ticker: Arc>, event_loop_proxy: Option>, platform_emitter: Option>, } @@ -28,11 +31,34 @@ impl UsePlatform { } Ok(()) } + + pub fn request_animation_frame(&self) { + self.send(EventMessage::RequestRerender).ok(); + } + + pub fn new_ticker(&self) -> Ticker { + Ticker { + inner: self.ticker.resubscribe(), + } + } } pub fn use_platform(cx: &ScopeState) -> UsePlatform { UsePlatform { event_loop_proxy: cx.consume_context::>(), platform_emitter: cx.consume_context::>(), + ticker: cx + .consume_context::>>() + .expect("This is not expected, and likely a bug. Please, report it."), + } +} + +pub struct Ticker { + inner: broadcast::Receiver<()>, +} + +impl Ticker { + pub async fn tick(&mut self) { + self.inner.recv().await.ok(); } } diff --git a/crates/renderer/src/app.rs b/crates/renderer/src/app.rs index 885b1b33c..312319d09 100644 --- a/crates/renderer/src/app.rs +++ b/crates/renderer/src/app.rs @@ -11,6 +11,7 @@ use futures::{ pin_mut, task::{self, ArcWake}, }; +use tokio::sync::broadcast; use tokio::{ select, sync::{mpsc, watch, Notify}, @@ -65,6 +66,8 @@ pub struct App { accessibility: NativeAccessibility, font_collection: FontCollection, + + ticker_sender: broadcast::Sender<()>, } impl App { @@ -114,6 +117,7 @@ impl App { focus_sender, focus_receiver, font_collection, + ticker_sender: broadcast::channel(5).0, } } @@ -126,6 +130,9 @@ impl App { self.vdom .base_scope() .provide_context(self.focus_receiver.clone()); + self.vdom + .base_scope() + .provide_context(Arc::new(self.ticker_sender.subscribe())); } /// Make the first build of the VirtualDOM. @@ -321,4 +328,8 @@ impl App { self.accessibility .focus_next_node(direction, &self.focus_sender) } + + pub fn tick(&self) { + self.ticker_sender.send(()).unwrap(); + } } diff --git a/crates/renderer/src/event_loop.rs b/crates/renderer/src/event_loop.rs index e36da4e53..a835c28a9 100644 --- a/crates/renderer/src/event_loop.rs +++ b/crates/renderer/src/event_loop.rs @@ -45,7 +45,7 @@ pub fn run_event_loop( app.accessibility().set_accessibility_focus(id); } Event::UserEvent(EventMessage::RequestRerender) => { - app.render(&hovered_node); + app.window_env().window().request_redraw(); } Event::UserEvent(EventMessage::RequestRelayout) => { app.process_layout(); @@ -83,6 +83,7 @@ pub fn run_event_loop( Event::RedrawRequested(_) => { app.process_layout(); app.render(&hovered_node); + app.tick(); } Event::WindowEvent { event, .. } if app.on_window_event(&event) => { match event { diff --git a/crates/testing/src/config.rs b/crates/testing/src/config.rs index b88179378..74217c7a3 100644 --- a/crates/testing/src/config.rs +++ b/crates/testing/src/config.rs @@ -1,46 +1,53 @@ -use std::time::Duration; - -use torin::geometry::Size2D; - -/// Configuration for [`crate::test_handler::TestingHandler`]. -pub struct TestingConfig { - vdom_timeout: Duration, - size: Size2D, -} - -impl Default for TestingConfig { - fn default() -> Self { - Self { - vdom_timeout: Duration::from_millis(16), - size: Size2D::from((500.0, 500.0)), - } - } -} - -impl TestingConfig { - pub fn new() -> Self { - TestingConfig::default() - } - - /// Specify a custom canvas size. - pub fn with_size(mut self, size: Size2D) -> Self { - self.size = size; - self - } - - /// Specify a custom duration for the VirtualDOM polling timeout, default is 16ms. - pub fn with_vdom_timeout(mut self, vdom_timeout: Duration) -> Self { - self.vdom_timeout = vdom_timeout; - self - } - - /// Get the canvas size. - pub fn size(&self) -> Size2D { - self.size - } - - /// Get the VirtualDOM polling timeout. - pub fn vdom_timeout(&self) -> Duration { - self.vdom_timeout - } -} +use std::time::Duration; + +use torin::geometry::Size2D; + +/// Configuration for [`crate::test_handler::TestingHandler`]. +#[derive(Clone, Copy)] +pub struct TestingConfig { + pub(crate) vdom_timeout: Duration, + pub(crate) size: Size2D, + pub(crate) run_ticker: bool, +} + +impl Default for TestingConfig { + fn default() -> Self { + Self { + vdom_timeout: Duration::from_millis(16), + size: Size2D::from((500.0, 500.0)), + run_ticker: true, + } + } +} + +impl TestingConfig { + pub fn new() -> Self { + TestingConfig::default() + } + + /// Specify a custom canvas size. + pub fn with_size(&mut self, size: Size2D) -> &mut Self { + self.size = size; + self + } + + /// Specify a custom duration for the VirtualDOM polling timeout, default is 16ms. + pub fn with_vdom_timeout(&mut self, vdom_timeout: Duration) -> &mut Self { + self.vdom_timeout = vdom_timeout; + self + } + + /// Get the canvas size. + pub fn size(&self) -> Size2D { + self.size + } + + /// Get the VirtualDOM polling timeout. + pub fn vdom_timeout(&self) -> Duration { + self.vdom_timeout + } + + pub fn enable_ticker(&mut self, ticker: bool) { + self.run_ticker = ticker; + } +} diff --git a/crates/testing/src/launch.rs b/crates/testing/src/launch.rs index 6b6e69fe3..8f7bfe49c 100644 --- a/crates/testing/src/launch.rs +++ b/crates/testing/src/launch.rs @@ -10,6 +10,7 @@ use freya_hooks::{use_init_accessibility, use_init_focus}; use freya_layout::Layers; use rustc_hash::FxHashMap; use std::sync::{Arc, Mutex}; +use tokio::sync::broadcast; use tokio::sync::mpsc::unbounded_channel; pub use freya_core::events::FreyaEvent; @@ -52,6 +53,7 @@ pub fn launch_test_with_config(root: Component<()>, config: TestingConfig) -> Te platform_event_emitter, platform_event_receiver, accessibility_state, + ticker_sender: broadcast::channel(5).0, }; handler.init_dom(); diff --git a/crates/testing/src/test_handler.rs b/crates/testing/src/test_handler.rs index f720af975..98dc5561d 100644 --- a/crates/testing/src/test_handler.rs +++ b/crates/testing/src/test_handler.rs @@ -1,14 +1,18 @@ +use std::sync::Arc; +use std::time::Duration; + use accesskit::NodeId as AccessibilityId; use dioxus_core::VirtualDom; use freya_common::EventMessage; use freya_core::prelude::*; use freya_engine::prelude::FontCollection; +use tokio::sync::broadcast; use tokio::sync::mpsc::{UnboundedReceiver, UnboundedSender}; use torin::geometry::{Area, Size2D}; pub use freya_core::events::FreyaEvent; pub use freya_elements::events::mouse::MouseButton; -use tokio::time::timeout; +use tokio::time::{sleep, timeout}; use crate::test_node::TestNode; use crate::test_utils::TestUtils; @@ -32,6 +36,8 @@ pub struct TestingHandler { pub(crate) accessibility_state: SharedAccessibilityState, pub(crate) config: TestingConfig, + + pub(crate) ticker_sender: broadcast::Sender<()>, } impl TestingHandler { @@ -44,9 +50,9 @@ impl TestingHandler { fdom.init_dom(mutations, SCALE_FACTOR as f32); } - /// Replace the current [`TestingConfig`]. - pub fn set_config(&mut self, config: TestingConfig) { - self.config = config; + /// Get a mutable reference to the current [`TestingConfig`]. + pub fn config(&mut self) -> &mut TestingConfig { + &mut self.config } /// Provide some values to the app @@ -54,6 +60,9 @@ impl TestingHandler { self.vdom .base_scope() .provide_context(self.platform_event_emitter.clone()); + self.vdom + .base_scope() + .provide_context(Arc::new(self.ticker_sender.subscribe())); } /// Wait and apply new changes @@ -64,32 +73,36 @@ impl TestingHandler { let vdom = &mut self.vdom; - // Handle platform events + // Handle platform and VDOM events loop { - let ev = self.platform_event_receiver.try_recv(); - - if let Ok(ev) = ev { - #[allow(clippy::match_single_binding)] - if let EventMessage::FocusAccessibilityNode(node_id) = ev { - self.accessibility_state - .lock() - .unwrap() - .set_focus(Some(node_id)); - } - } else { + let platform_ev = self.platform_event_receiver.try_recv(); + let vdom_ev = self.event_receiver.try_recv(); + + if vdom_ev.is_err() && platform_ev.is_err() { break; } - } - // Handle virtual dom events - loop { - let ev = self.event_receiver.try_recv(); + if let Ok(ev) = platform_ev { + match ev { + EventMessage::RequestRerender => { + if self.config.run_ticker { + sleep(Duration::from_millis(16)).await; + self.ticker_sender.send(()).unwrap(); + } + } + EventMessage::FocusAccessibilityNode(node_id) => { + self.accessibility_state + .lock() + .unwrap() + .set_focus(Some(node_id)); + } + _ => {} + } + } - if let Ok(ev) = ev { + if let Ok(ev) = vdom_ev { vdom.handle_event(&ev.name, ev.data.any(), ev.element_id, false); vdom.process_events(); - } else { - break; } } @@ -107,6 +120,8 @@ impl TestingHandler { self.wait_for_work(self.config.size()); + self.ticker_sender.send(()).unwrap(); + (must_repaint, must_relayout) } From 9d55a89adf97f45a758d3b5f1cb0027f1877a40c Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sun, 22 Oct 2023 17:43:52 +0200 Subject: [PATCH 2/4] fix(deps): update all non-major dependencies (#335) * fix(deps): update all non-major dependencies * fix(deps): update all non-major dependencies * wip * revert raw-window-handle and accesskit * fixes --------- Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> Co-authored-by: marc2332 --- .github/workflows/rust.yml | 3 + Cargo.toml | 22 +++---- crates/components/Cargo.toml | 2 +- crates/elements/Cargo.toml | 2 +- crates/engine/src/mocked.rs | 78 ++++++++++------------- crates/engine/src/skia.rs | 1 + crates/freya/Cargo.toml | 1 + crates/hooks/Cargo.toml | 4 +- crates/layout/Cargo.toml | 2 +- crates/renderer/src/elements/image.rs | 4 +- crates/renderer/src/elements/label.rs | 2 +- crates/renderer/src/elements/paragraph.rs | 6 +- crates/renderer/src/elements/rect.rs | 2 +- crates/renderer/src/elements/svg.rs | 2 +- crates/renderer/src/renderer.rs | 2 +- crates/renderer/src/window.rs | 2 +- crates/renderer/src/wireframe.rs | 2 +- crates/state/Cargo.toml | 6 +- crates/state/src/custom_attributes.rs | 2 +- 19 files changed, 71 insertions(+), 74 deletions(-) diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index bdf29eab6..1d6168c4f 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -52,3 +52,6 @@ jobs: if: runner.os == 'Linux' with: token: ${{ secrets.CODECOV_TOKEN }} + - name: Make sure the mocked Skia bindings are on sync + if: runner.os == 'Linux' + run: cargo build --package freya --features mocked-engine-development --no-default-features diff --git a/Cargo.toml b/Cargo.toml index 5e5abe267..d76472d74 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -37,21 +37,21 @@ dioxus-core = { version = "0.4" } dioxus-hot-reload = { version = "0.4", features = ["file_watcher"] } dioxus-router = { version = "0.4", default-features = false } -skia-safe = { version = "0.66.3", features = ["gl", "textlayout", "svg"] } +skia-safe = { version = "0.67.0", features = ["gl", "textlayout", "svg"] } gl = "0.14.0" -glutin = "0.30.6" +glutin = "0.30.10" glutin-winit = "0.3.0" raw-window-handle = "0.5.1" -winit = "0.28.2" -tokio = { version = "1.23.0", features = ["sync", "rt-multi-thread", "time", "macros"] } +winit = "0.28.7" +tokio = { version = "1.33.0", features = ["sync", "rt-multi-thread", "time", "macros"] } accesskit = { version = "0.11.0", features = ["serde"]} accesskit_winit = "0.14.1" -zbus = "3.13.1" +zbus = "3.14.1" -euclid = "0.22.7" -uuid = { version = "1.2.2", features = ["v4"]} -futures = "0.3.25" +euclid = "0.22.9" +uuid = { version = "1.4.1", features = ["v4"]} +futures = "0.3.28" anymap = "0.12.1" tracing = "0.1" tracing-subscriber = "0.3.17" @@ -64,9 +64,9 @@ tokio = { workspace = true } dioxus = { workspace = true } freya = { workspace = true } freya-node-state = { workspace = true } -reqwest = { version = "0.11.13", features = ["json"] } -serde = "1.0.152" -tracing-subscriber = "0.2.25" +reqwest = { version = "0.11.22", features = ["json"] } +serde = "1.0.189" +tracing-subscriber = "0.3.17" dioxus-std = { version = "0.4", features = ["utils", "i18n"] } rand = "0.8.5" dioxus-router = { workspace = true } diff --git a/crates/components/Cargo.toml b/crates/components/Cargo.toml index b38aa9f5a..839fda116 100644 --- a/crates/components/Cargo.toml +++ b/crates/components/Cargo.toml @@ -34,7 +34,7 @@ tokio = { workspace = true } tracing = { workspace = true } open = "5" -reqwest = { version = "0.11.13", features = ["json"] } +reqwest = { version = "0.11.22", features = ["json"] } [dev-dependencies] freya = { path = "../freya" } diff --git a/crates/elements/Cargo.toml b/crates/elements/Cargo.toml index da9a636d4..ba0f6e41d 100644 --- a/crates/elements/Cargo.toml +++ b/crates/elements/Cargo.toml @@ -25,4 +25,4 @@ winit = { workspace = true } tokio = { workspace = true } accesskit = { workspace = true } -keyboard-types = "0.6.2" +keyboard-types = "0.7.0" diff --git a/crates/engine/src/mocked.rs b/crates/engine/src/mocked.rs index 6eb0e1690..b8e3eca08 100644 --- a/crates/engine/src/mocked.rs +++ b/crates/engine/src/mocked.rs @@ -2,6 +2,7 @@ #![allow(non_upper_case_globals)] #![allow(clippy::upper_case_acronyms)] #![allow(non_camel_case_types)] +#![allow(unused_variables)] use std::ops::*; @@ -167,7 +168,7 @@ impl Matrix { unimplemented!("This is mocked") } - pub fn set_rotate(&self, _degrees: f32, _pivot: impl Into>) -> &mut Self { + pub fn set_rotate(&mut self, _degrees: f32, _pivot: impl Into>) -> &mut Self { unimplemented!("This is mocked") } } @@ -420,7 +421,7 @@ impl TextStyle { unimplemented!("This is mocked") } - pub fn decoration_mut(&mut self) -> &mut Decoration { + pub fn set_decoration(&mut self, decoration: &Decoration) { unimplemented!("This is mocked") } @@ -708,7 +709,7 @@ impl Paragraph { unimplemented!("This is mocked") } - pub fn paint(&self, _canvas: &mut Canvas, _p: impl Into) { + pub fn paint(&self, _canvas: &Canvas, _p: impl Into) { unimplemented!("This is mocked") } @@ -947,43 +948,43 @@ impl Canvas { unimplemented!("This is mocked") } - pub fn concat(&mut self, _matrix: &Matrix) { + pub fn concat(&self, _matrix: &Matrix) { unimplemented!("This is mocked") } - pub fn clip_rect(&mut self, _rect: Rect, _clip: ClipOp, _: bool) { + pub fn clip_rect(&self, _rect: Rect, _clip: ClipOp, _: bool) { unimplemented!("This is mocked") } pub fn draw_image_nine( - &mut self, + &self, _image: Image, _center: IRect, _dst: Rect, _filter_mode: FilterMode, _paint: Option<&Paint>, - ) -> &mut Self { + ) -> &Self { unimplemented!("This is mocked") } - pub fn draw_rect(&mut self, _rect: Rect, _paint: &Paint) -> &mut Self { + pub fn draw_rect(&self, _rect: Rect, _paint: &Paint) -> &Self { unimplemented!("This is mocked") } - pub fn draw_path(&mut self, _path: &Path, _paint: &Paint) -> &mut Self { + pub fn draw_path(&self, _path: &Path, _paint: &Paint) -> &Self { unimplemented!("This is mocked") } pub fn clip_path( - &mut self, + &self, _path: &Path, _op: impl Into>, _do_anti_alias: impl Into>, - ) -> &mut Self { + ) -> &Self { unimplemented!("This is mocked") } - pub fn translate(&mut self, _d: impl Into) -> &mut Self { + pub fn translate(&self, _d: impl Into) -> &Self { unimplemented!("This is mocked") } @@ -995,21 +996,11 @@ impl Canvas { unimplemented!("This is mocked") } - pub fn draw_line( - &mut self, - _p1: impl Into, - _p2: impl Into, - _paint: &Paint, - ) -> &mut Self { + pub fn draw_line(&self, _p1: impl Into, _p2: impl Into, _paint: &Paint) -> &Self { unimplemented!("This is mocked") } - pub fn draw_circle( - &mut self, - _center: impl Into, - _radius: f32, - _paint: &Paint, - ) -> &mut Self { + pub fn draw_circle(&self, _center: impl Into, _radius: f32, _paint: &Paint) -> &Self { unimplemented!("This is mocked") } } @@ -1132,7 +1123,7 @@ impl Image { pub struct Data; impl Data { - pub fn new_bytes(_bytes: &[u8]) -> Self { + pub unsafe fn new_bytes(_bytes: &[u8]) -> Self { unimplemented!("This is mocked") } } @@ -1328,7 +1319,7 @@ pub mod svg { unimplemented!("This is mocked") } - pub fn render(&self, _canvas: &mut Canvas) { + pub fn render(&self, _canvas: &Canvas) { unimplemented!("This is mocked") } } @@ -1353,7 +1344,7 @@ impl From<(i32, i32)> for Size { pub struct Surface; impl Surface { - pub fn canvas(&self) -> Canvas { + pub fn canvas(&mut self) -> Canvas { unimplemented!("This is mocked") } @@ -1436,12 +1427,14 @@ impl DirectContext { use std::ffi::c_void; #[repr(u8)] +#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] pub enum Protected { No, Yes, } -#[derive(Clone, Copy)] +#[derive(Copy, Clone, PartialEq, Eq, Debug)] +#[repr(C)] pub struct FramebufferInfo { pub fboid: i32, pub format: Format, @@ -1450,11 +1443,7 @@ pub struct FramebufferInfo { impl Default for FramebufferInfo { fn default() -> Self { - Self { - fboid: 0, - format: 0, - protected: Protected::No, - } + unimplemented!("This is mocked") } } @@ -1466,16 +1455,7 @@ pub fn wrap_backend_render_target( color_space: impl Into>, surface_props: Option<&SurfaceProps>, ) -> Option { - Surface::from_ptr(unsafe { - sb::C_SkSurfaces_WrapBackendRenderTarget( - context.native_mut(), - backend_render_target.native(), - origin, - color_type.into_native(), - color_space.into().into_ptr_or_null(), - surface_props.native_ptr_or_null(), - ) - }) + unimplemented!("This is mocked") } pub struct Interface; @@ -1534,3 +1514,15 @@ impl BackendRenderTarget { unimplemented!("This is mocked") } } + +pub mod backend_render_targets { + use crate::prelude::*; + pub fn make_gl( + (width, height): (i32, i32), + sample_count: impl Into>, + stencil_bits: usize, + info: FramebufferInfo, + ) -> BackendRenderTarget { + unimplemented!("This is mocked") + } +} diff --git a/crates/engine/src/skia.rs b/crates/engine/src/skia.rs index e73b8784e..38cb695be 100644 --- a/crates/engine/src/skia.rs +++ b/crates/engine/src/skia.rs @@ -1,6 +1,7 @@ pub use skia_safe::{ font_style::{Slant, Weight, Width}, gpu::{ + backend_render_targets, gl::{Format, FramebufferInfo, Interface}, surfaces::wrap_backend_render_target, BackendRenderTarget, DirectContext, RecordingContext, SurfaceOrigin, diff --git a/crates/freya/Cargo.toml b/crates/freya/Cargo.toml index 11187017e..1b3008aa7 100644 --- a/crates/freya/Cargo.toml +++ b/crates/freya/Cargo.toml @@ -19,6 +19,7 @@ no-default-features = true log = ["dep:tracing", "dep:tracing-subscriber"] devtools = ["dep:freya-devtools", "freya-dom/shared"] use_camera = ["freya-hooks/use_camera"] +mocked-engine-development = ["freya-engine/mocked-engine"] # This is just for the CI default = ["freya-engine/skia-engine"] [dependencies] diff --git a/crates/hooks/Cargo.toml b/crates/hooks/Cargo.toml index eedf87bdd..762167197 100644 --- a/crates/hooks/Cargo.toml +++ b/crates/hooks/Cargo.toml @@ -38,10 +38,10 @@ accesskit = { workspace = true } euclid = { workspace = true } uuid = { workspace = true } -tween = "2.0.0" +tween = "2.0.1" ropey = "1.6.0" nokhwa = { version = "0.10.4", features = ["input-native"], optional = true } -bytes = "1.3.0" +bytes = "1.5.0" [dev-dependencies] dioxus = { workspace = true } diff --git a/crates/layout/Cargo.toml b/crates/layout/Cargo.toml index dcde1a117..f5355221f 100644 --- a/crates/layout/Cargo.toml +++ b/crates/layout/Cargo.toml @@ -33,4 +33,4 @@ tokio = { workspace = true } accesskit = { workspace = true } rustc-hash= { workspace = true } -uuid = { version = "1.2.2", features = ["v4"]} \ No newline at end of file +uuid = { version = "1.4.1", features = ["v4"]} \ No newline at end of file diff --git a/crates/renderer/src/elements/image.rs b/crates/renderer/src/elements/image.rs index 18c520a30..7a8e9f14d 100644 --- a/crates/renderer/src/elements/image.rs +++ b/crates/renderer/src/elements/image.rs @@ -5,11 +5,11 @@ use freya_node_state::{References, Style}; use torin::geometry::Area; /// Render an `image` element -pub fn render_image(area: &Area, node_ref: &DioxusNode, canvas: &mut Canvas) { +pub fn render_image(area: &Area, node_ref: &DioxusNode, canvas: &Canvas) { let node_style = node_ref.get::