Skip to content

Commit

Permalink
Implement FrameThrottled for Web
Browse files Browse the repository at this point in the history
  • Loading branch information
daxpedda committed Jun 17, 2023
1 parent 0fb68dc commit 02afd22
Show file tree
Hide file tree
Showing 6 changed files with 92 additions and 4 deletions.
8 changes: 8 additions & 0 deletions src/platform_impl/web/event_loop/window_target.rs
Original file line number Diff line number Diff line change
Expand Up @@ -719,6 +719,14 @@ impl<T> EventLoopWindowTarget<T> {
}
},
);

let runner = self.runner.clone();
canvas.on_frame_throttle(move || {
runner.send_event(Event::WindowEvent {
window_id: RootWindowId(id),
event: WindowEvent::FrameThrottled,
})
})
}

pub fn available_monitors(&self) -> VecDequeIter<MonitorHandle> {
Expand Down
17 changes: 15 additions & 2 deletions src/platform_impl/web/web_sys/canvas.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use super::super::WindowId;
use super::event_handle::EventListenerHandle;
use super::media_query_handle::MediaQueryListHandle;
use super::pointer::PointerHandler;
use super::{event, ButtonsState, ResizeScaleHandle};
use super::{event, ButtonsState, FrameThrottlingHandler, ResizeScaleHandle};
use crate::dpi::{LogicalPosition, PhysicalPosition, PhysicalSize};
use crate::error::OsError as RootOE;
use crate::event::{Force, MouseButton, MouseScrollDelta};
Expand Down Expand Up @@ -37,6 +37,7 @@ pub struct Canvas {
on_dark_mode: Option<MediaQueryListHandle>,
pointer_handler: PointerHandler,
on_resize_scale: Option<ResizeScaleHandle>,
frame_throttling_handler: FrameThrottlingHandler,
}

pub struct Common {
Expand Down Expand Up @@ -87,7 +88,7 @@ impl Canvas {

Ok(Canvas {
common: Common {
window,
window: window.clone(),
raw: canvas,
old_size: Rc::default(),
current_size: Rc::default(),
Expand All @@ -105,6 +106,7 @@ impl Canvas {
on_dark_mode: None,
pointer_handler: PointerHandler::new(),
on_resize_scale: None,
frame_throttling_handler: FrameThrottlingHandler::new(window),
})
}

Expand Down Expand Up @@ -365,6 +367,13 @@ impl Canvas {
));
}

pub(crate) fn on_frame_throttle<F>(&mut self, f: F)
where
F: 'static + FnMut(),
{
self.frame_throttling_handler.on_frame_throttle(f)
}

pub fn request_fullscreen(&self) {
self.common.request_fullscreen()
}
Expand All @@ -373,6 +382,10 @@ impl Canvas {
self.common.is_fullscreen()
}

pub fn request_frame_throttling_hint(&self) {
self.frame_throttling_handler.request();
}

pub(crate) fn handle_scale_change<T: 'static>(
&self,
runner: &super::super::event_loop::runner::Shared<T>,
Expand Down
62 changes: 62 additions & 0 deletions src/platform_impl/web/web_sys/frame_throttling.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
use std::cell::Cell;
use std::rc::Rc;
use wasm_bindgen::closure::Closure;
use wasm_bindgen::JsCast;

pub struct FrameThrottlingHandler {
window: web_sys::Window,
closure: Closure<dyn FnMut()>,
handle: Rc<Cell<Option<i32>>>,
}

impl FrameThrottlingHandler {
pub fn new(window: web_sys::Window) -> Self {
let handle = Rc::new(Cell::new(None));
let closure = Closure::new({
let handle = handle.clone();
move || handle.set(None)
});

Self {
window,
closure,
handle,
}
}

pub fn on_frame_throttle<F>(&mut self, mut f: F)
where
F: 'static + FnMut(),
{
let handle = self.handle.clone();
self.closure = Closure::new(move || {
handle.set(None);
f();
})
}

pub fn request(&self) {
if let Some(handle) = self.handle.take() {
self.window
.cancel_animation_frame(handle)
.expect("Failed to cancel animation frame");
}

let handle = self
.window
.request_animation_frame(self.closure.as_ref().unchecked_ref())
.expect("Failed to request animation frame");

self.handle.set(Some(handle));
}
}

impl Drop for FrameThrottlingHandler {
fn drop(&mut self) {
if let Some(handle) = self.handle.take() {
self.window
.cancel_animation_frame(handle)
.expect("Failed to cancel animation frame");
}
}
}
2 changes: 2 additions & 0 deletions src/platform_impl/web/web_sys/mod.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
mod canvas;
pub mod event;
mod event_handle;
mod frame_throttling;
mod media_query_handle;
mod pointer;
mod resize_scaling;
Expand All @@ -9,6 +10,7 @@ mod timeout;
pub use self::canvas::Canvas;
pub use self::event::ButtonsState;
pub use self::event_handle::EventListenerHandle;
pub use self::frame_throttling::FrameThrottlingHandler;
pub use self::resize_scaling::ResizeScaleHandle;
pub use self::timeout::{IdleCallback, Timeout};

Expand Down
5 changes: 4 additions & 1 deletion src/platform_impl/web/window.rs
Original file line number Diff line number Diff line change
Expand Up @@ -353,7 +353,10 @@ impl Window {

#[inline]
pub fn request_frame_throttling_hint(&self) -> Result<(), NotSupportedError> {
Err(NotSupportedError::new())
self.inner.dispatch(move |inner| {
inner.canvas.borrow().request_frame_throttling_hint();
});
Ok(())
}

#[inline]
Expand Down
2 changes: 1 addition & 1 deletion src/window.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1139,7 +1139,7 @@ impl Window {
///
/// - **Wayland:** Uses frame callbacks. The user must perform drawing operation resulting in
/// `wl_surface.commit`(eglSwapBuffers, etc) after issueing a request.
/// - ** macOS / Windows / iOS / Android / Web / X11 / Orbital:** Not supported.
/// - ** macOS / Windows / iOS / Android / X11 / Orbital:** Not supported.
///
/// [`FrameThrottled`]: crate::event::WindowEvent::FrameThrottled.
#[inline]
Expand Down

0 comments on commit 02afd22

Please sign in to comment.