2020-08-30 21:15:44 +08:00
|
|
|
use super::super::ScaleChangeArgs;
|
2020-09-21 06:42:07 +08:00
|
|
|
use super::media_query_handle::MediaQueryListHandle;
|
2020-08-30 21:15:44 +08:00
|
|
|
|
|
|
|
|
use std::{cell::RefCell, rc::Rc};
|
2020-09-21 06:42:07 +08:00
|
|
|
use wasm_bindgen::prelude::Closure;
|
|
|
|
|
use web_sys::MediaQueryListEvent;
|
2020-08-30 21:15:44 +08:00
|
|
|
|
|
|
|
|
pub struct ScaleChangeDetector(Rc<RefCell<ScaleChangeDetectorInternal>>);
|
|
|
|
|
|
|
|
|
|
impl ScaleChangeDetector {
|
|
|
|
|
pub(crate) fn new<F>(handler: F) -> Self
|
|
|
|
|
where
|
|
|
|
|
F: 'static + FnMut(ScaleChangeArgs),
|
|
|
|
|
{
|
|
|
|
|
Self(ScaleChangeDetectorInternal::new(handler))
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// This is a helper type to help manage the `MediaQueryList` used for detecting
|
|
|
|
|
/// changes of the `devicePixelRatio`.
|
|
|
|
|
struct ScaleChangeDetectorInternal {
|
|
|
|
|
callback: Box<dyn FnMut(ScaleChangeArgs)>,
|
2020-09-21 06:42:07 +08:00
|
|
|
mql: Option<MediaQueryListHandle>,
|
2020-08-30 21:15:44 +08:00
|
|
|
last_scale: f64,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl ScaleChangeDetectorInternal {
|
|
|
|
|
fn new<F>(handler: F) -> Rc<RefCell<Self>>
|
|
|
|
|
where
|
|
|
|
|
F: 'static + FnMut(ScaleChangeArgs),
|
|
|
|
|
{
|
|
|
|
|
let current_scale = super::scale_factor();
|
|
|
|
|
let new_self = Rc::new(RefCell::new(Self {
|
|
|
|
|
callback: Box::new(handler),
|
|
|
|
|
mql: None,
|
|
|
|
|
last_scale: current_scale,
|
|
|
|
|
}));
|
|
|
|
|
|
2020-09-21 06:42:07 +08:00
|
|
|
let weak_self = Rc::downgrade(&new_self);
|
2020-08-30 21:15:44 +08:00
|
|
|
let closure = Closure::wrap(Box::new(move |event: MediaQueryListEvent| {
|
2020-09-21 06:42:07 +08:00
|
|
|
if let Some(rc_self) = weak_self.upgrade() {
|
|
|
|
|
rc_self.borrow_mut().handler(event);
|
|
|
|
|
}
|
2020-08-30 21:15:44 +08:00
|
|
|
}) as Box<dyn FnMut(_)>);
|
|
|
|
|
|
2020-09-21 06:42:07 +08:00
|
|
|
let mql = Self::create_mql(closure);
|
2020-08-30 21:15:44 +08:00
|
|
|
{
|
|
|
|
|
let mut borrowed_self = new_self.borrow_mut();
|
|
|
|
|
borrowed_self.mql = mql;
|
|
|
|
|
}
|
|
|
|
|
new_self
|
|
|
|
|
}
|
|
|
|
|
|
2020-09-21 06:42:07 +08:00
|
|
|
fn create_mql(
|
|
|
|
|
closure: Closure<dyn FnMut(MediaQueryListEvent)>,
|
|
|
|
|
) -> Option<MediaQueryListHandle> {
|
2020-08-30 21:15:44 +08:00
|
|
|
let current_scale = super::scale_factor();
|
|
|
|
|
// This media query initially matches the current `devicePixelRatio`.
|
|
|
|
|
// We add 0.0001 to the lower and upper bounds such that it won't fail
|
|
|
|
|
// due to floating point precision limitations.
|
|
|
|
|
let media_query = format!(
|
2020-10-10 06:31:51 +02:00
|
|
|
"(min-resolution: {min_scale:.4}dppx) and (max-resolution: {max_scale:.4}dppx),
|
|
|
|
|
(-webkit-min-device-pixel-ratio: {min_scale:.4}) and (-webkit-max-device-pixel-ratio: {max_scale:.4})",
|
|
|
|
|
min_scale = current_scale - 0.0001, max_scale= current_scale + 0.0001,
|
2020-08-30 21:15:44 +08:00
|
|
|
);
|
2020-09-21 06:42:07 +08:00
|
|
|
let mql = MediaQueryListHandle::new(&media_query, closure);
|
|
|
|
|
if let Some(mql) = &mql {
|
2022-06-10 13:43:33 +03:00
|
|
|
assert!(mql.mql().matches());
|
2020-09-21 06:42:07 +08:00
|
|
|
}
|
|
|
|
|
mql
|
2020-08-30 21:15:44 +08:00
|
|
|
}
|
|
|
|
|
|
2022-12-23 14:19:25 +01:00
|
|
|
fn handler(&mut self, _event: MediaQueryListEvent) {
|
2020-08-30 21:15:44 +08:00
|
|
|
let mql = self
|
|
|
|
|
.mql
|
|
|
|
|
.take()
|
|
|
|
|
.expect("DevicePixelRatioChangeDetector::mql should not be None");
|
2020-09-21 06:42:07 +08:00
|
|
|
let closure = mql.remove();
|
2020-08-30 21:15:44 +08:00
|
|
|
let new_scale = super::scale_factor();
|
|
|
|
|
(self.callback)(ScaleChangeArgs {
|
|
|
|
|
old_scale: self.last_scale,
|
|
|
|
|
new_scale,
|
|
|
|
|
});
|
|
|
|
|
let new_mql = Self::create_mql(closure);
|
|
|
|
|
self.mql = new_mql;
|
|
|
|
|
self.last_scale = new_scale;
|
|
|
|
|
}
|
|
|
|
|
}
|