Custom cursor improvements (#3292)

This commit is contained in:
daxpedda 2023-12-23 16:12:29 +01:00 committed by GitHub
parent 37946e0a3a
commit e5310ade08
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
18 changed files with 152 additions and 101 deletions

View file

@ -1,6 +1,8 @@
use std::{
cell::RefCell,
future, mem,
future,
hash::{Hash, Hasher},
mem,
ops::DerefMut,
rc::{self, Rc},
sync::{self, Arc},
@ -25,7 +27,7 @@ use self::thread_safe::ThreadSafe;
use super::{backend::Style, r#async::AsyncSender, EventLoopWindowTarget};
#[derive(Debug)]
pub enum CustomCursorBuilder {
pub(crate) enum CustomCursorBuilder {
Image(CursorImage),
Url {
url: String,
@ -35,35 +37,6 @@ pub enum CustomCursorBuilder {
}
impl CustomCursorBuilder {
pub fn build<T>(self, window_target: &EventLoopWindowTarget<T>) -> Arc<CustomCursor> {
Lazy::force(&DROP_HANDLER);
match self {
Self::Image(image) => ImageState::from_rgba(
window_target.runner.window(),
window_target.runner.document().clone(),
&image,
),
Self::Url {
url,
hotspot_x,
hotspot_y,
} => ImageState::from_url(url, hotspot_x, hotspot_y),
}
}
}
#[derive(Debug)]
pub struct CustomCursor(Option<ThreadSafe<RefCell<ImageState>>>);
static DROP_HANDLER: Lazy<AsyncSender<ThreadSafe<RefCell<ImageState>>>> = Lazy::new(|| {
let (sender, receiver) = r#async::channel();
wasm_bindgen_futures::spawn_local(async move { while receiver.next().await.is_ok() {} });
sender
});
impl CustomCursor {
pub fn from_rgba(
rgba: Vec<u8>,
width: u16,
@ -75,9 +48,60 @@ impl CustomCursor {
rgba, width, height, hotspot_x, hotspot_y,
)?))
}
}
#[derive(Clone, Debug)]
pub struct CustomCursor(Arc<Inner>);
impl Hash for CustomCursor {
fn hash<H: Hasher>(&self, state: &mut H) {
Arc::as_ptr(&self.0).hash(state);
}
}
impl PartialEq for CustomCursor {
fn eq(&self, other: &Self) -> bool {
Arc::ptr_eq(&self.0, &other.0)
}
}
impl Eq for CustomCursor {}
impl CustomCursor {
pub(crate) fn build<T>(
builder: CustomCursorBuilder,
window_target: &EventLoopWindowTarget<T>,
) -> Self {
Lazy::force(&DROP_HANDLER);
Self(match builder {
CustomCursorBuilder::Image(image) => ImageState::from_rgba(
window_target.runner.window(),
window_target.runner.document().clone(),
&image,
),
CustomCursorBuilder::Url {
url,
hotspot_x,
hotspot_y,
} => ImageState::from_url(url, hotspot_x, hotspot_y),
})
}
}
#[derive(Debug)]
struct Inner(Option<ThreadSafe<RefCell<ImageState>>>);
static DROP_HANDLER: Lazy<AsyncSender<ThreadSafe<RefCell<ImageState>>>> = Lazy::new(|| {
let (sender, receiver) = r#async::channel();
wasm_bindgen_futures::spawn_local(async move { while receiver.next().await.is_ok() {} });
sender
});
impl Inner {
fn new() -> Arc<Self> {
Arc::new(Self(Some(ThreadSafe::new(RefCell::new(
Arc::new(Inner(Some(ThreadSafe::new(RefCell::new(
ImageState::Loading(None),
)))))
}
@ -90,7 +114,7 @@ impl CustomCursor {
}
}
impl Drop for CustomCursor {
impl Drop for Inner {
fn drop(&mut self) {
let value = self
.0
@ -130,13 +154,13 @@ impl CursorState {
this.set_style();
}
pub fn set_custom_cursor(&self, cursor: Arc<CustomCursor>) {
pub(crate) fn set_custom_cursor(&self, cursor: CustomCursor) {
let mut this = self.0.borrow_mut();
match cursor.get().borrow_mut().deref_mut() {
match cursor.0.get().borrow_mut().deref_mut() {
ImageState::Loading(state) => {
this.cursor = SelectedCursor::ImageLoading {
state: cursor.clone(),
state: cursor.0.clone(),
previous: mem::take(&mut this.cursor).into(),
};
*state = Some(Rc::downgrade(&self.0));
@ -187,7 +211,7 @@ impl State {
enum SelectedCursor {
Named(CursorIcon),
ImageLoading {
state: Arc<CustomCursor>,
state: Arc<Inner>,
previous: Previous,
},
ImageReady(Rc<Image>),
@ -241,7 +265,7 @@ enum ImageState {
}
impl ImageState {
fn from_rgba(window: &Window, document: Document, image: &CursorImage) -> Arc<CustomCursor> {
fn from_rgba(window: &Window, document: Document, image: &CursorImage) -> Arc<Inner> {
// 1. Create an `ImageData` from the RGBA data.
// 2. Create an `ImageBitmap` from the `ImageData`.
// 3. Draw `ImageBitmap` on an `HTMLCanvasElement`.
@ -293,7 +317,7 @@ impl ImageState {
.expect("unexpected exception in `createImageBitmap()`"),
);
let this = CustomCursor::new();
let this = Inner::new();
wasm_bindgen_futures::spawn_local({
let weak = Arc::downgrade(&this);
@ -406,8 +430,8 @@ impl ImageState {
this
}
fn from_url(url: String, hotspot_x: u16, hotspot_y: u16) -> Arc<CustomCursor> {
let this = CustomCursor::new();
fn from_url(url: String, hotspot_x: u16, hotspot_y: u16) -> Arc<Inner> {
let this = Inner::new();
wasm_bindgen_futures::spawn_local(Self::decode(
Arc::downgrade(&this),
url,
@ -420,7 +444,7 @@ impl ImageState {
}
async fn decode(
weak: sync::Weak<CustomCursor>,
weak: sync::Weak<Inner>,
url: String,
object: bool,
hotspot_x: u16,

View file

@ -16,7 +16,6 @@ use web_sys::HtmlCanvasElement;
use std::cell::RefCell;
use std::collections::VecDeque;
use std::rc::Rc;
use std::sync::Arc;
pub struct Window {
inner: Dispatcher<Inner>,
@ -218,7 +217,7 @@ impl Inner {
}
#[inline]
pub(crate) fn set_custom_cursor(&self, cursor: Arc<PlatformCustomCursor>) {
pub(crate) fn set_custom_cursor(&self, cursor: PlatformCustomCursor) {
self.cursor.set_custom_cursor(cursor)
}