Desktop: Add support for UI scaling (#3310)

* desktop support ui scaling

* fix some warnings

* use browser zoom if needed

* fix infinite footprint size

* fix web canvas scale

* always set zoom

* use only zoom for scaling

* prevent user zoom

* remove mouse position scaling
This commit is contained in:
Timon
2025-11-08 12:32:04 +01:00
committed by GitHub
parent 7254c470ef
commit f02f834097
25 changed files with 286 additions and 162 deletions
+69 -32
View File
@@ -38,8 +38,8 @@ use texture_import::SharedTextureHandle;
pub(crate) use context::{CefContext, CefContextBuilder, InitError};
pub(crate) trait CefEventHandler: Clone + Send + Sync + 'static {
fn window_size(&self) -> WindowSize;
pub(crate) trait CefEventHandler: Send + Sync + 'static {
fn view_info(&self) -> ViewInfo;
fn draw<'a>(&self, frame_buffer: FrameBufferRef<'a>);
#[cfg(feature = "accelerated_paint")]
fn draw_gpu(&self, shared_texture: SharedTextureHandle);
@@ -50,24 +50,54 @@ pub(crate) trait CefEventHandler: Clone + Send + Sync + 'static {
fn schedule_cef_message_loop_work(&self, scheduled_time: Instant);
fn initialized_web_communication(&self);
fn receive_web_message(&self, message: &[u8]);
fn duplicate(&self) -> Self
where
Self: Sized;
}
#[derive(Clone, Copy)]
pub(crate) struct WindowSize {
pub(crate) width: usize,
pub(crate) height: usize,
pub(crate) struct ViewInfo {
width: usize,
height: usize,
scale: f64,
}
impl WindowSize {
pub(crate) fn new(width: usize, height: usize) -> Self {
Self { width, height }
impl ViewInfo {
pub(crate) fn new() -> Self {
Self { width: 1, height: 1, scale: 1. }
}
pub(crate) fn apply_update(&mut self, update: ViewInfoUpdate) {
match update {
ViewInfoUpdate::Size { width, height } if width > 0 && height > 0 => {
self.width = width;
self.height = height;
}
ViewInfoUpdate::Scale(scale) if scale > 0. => {
self.scale = scale;
}
_ => {}
}
}
pub(crate) fn zoom(&self) -> f64 {
self.scale.ln() / 1.2_f64.ln()
}
pub(crate) fn width(&self) -> usize {
self.width
}
pub(crate) fn height(&self) -> usize {
self.height
}
}
impl From<winit::dpi::PhysicalSize<u32>> for WindowSize {
fn from(size: winit::dpi::PhysicalSize<u32>) -> Self {
Self::new(size.width as usize, size.height as usize)
impl Default for ViewInfo {
fn default() -> Self {
Self::new()
}
}
pub(crate) enum ViewInfoUpdate {
Size { width: usize, height: usize },
Scale(f64),
}
#[derive(Clone)]
pub(crate) struct Resource {
pub(crate) reader: ResourceReader,
@@ -89,34 +119,33 @@ impl Read for ResourceReader {
}
}
#[derive(Clone)]
pub(crate) struct CefHandler {
wgpu_context: WgpuContext,
app_event_scheduler: AppEventScheduler,
window_size_receiver: Arc<Mutex<WindowSizeReceiver>>,
view_info_receiver: Arc<Mutex<ViewInfoReceiver>>,
}
impl CefHandler {
pub(crate) fn new(wgpu_context: WgpuContext, app_event_scheduler: AppEventScheduler, window_size_receiver: Receiver<WindowSize>) -> Self {
pub(crate) fn new(wgpu_context: WgpuContext, app_event_scheduler: AppEventScheduler, view_info_receiver: Receiver<ViewInfoUpdate>) -> Self {
Self {
wgpu_context,
app_event_scheduler,
window_size_receiver: Arc::new(Mutex::new(WindowSizeReceiver::new(window_size_receiver))),
view_info_receiver: Arc::new(Mutex::new(ViewInfoReceiver::new(view_info_receiver))),
}
}
}
impl CefEventHandler for CefHandler {
fn window_size(&self) -> WindowSize {
let Ok(mut guard) = self.window_size_receiver.lock() else {
tracing::error!("Failed to lock window_size_receiver");
return WindowSize::new(1, 1);
fn view_info(&self) -> ViewInfo {
let Ok(mut guard) = self.view_info_receiver.lock() else {
tracing::error!("Failed to lock view_info_receiver");
return ViewInfo::new();
};
let WindowSizeReceiver { receiver, window_size } = &mut *guard;
for new_window_size in receiver.try_iter() {
*window_size = new_window_size;
let ViewInfoReceiver { receiver, view_info } = &mut *guard;
for update in receiver.try_iter() {
view_info.apply_update(update);
}
*window_size
*view_info
}
fn draw<'a>(&self, frame_buffer: FrameBufferRef<'a>) {
let width = frame_buffer.width() as u32;
@@ -244,17 +273,25 @@ impl CefEventHandler for CefHandler {
};
self.app_event_scheduler.schedule(AppEvent::DesktopWrapperMessage(desktop_wrapper_message));
}
}
struct WindowSizeReceiver {
window_size: WindowSize,
receiver: Receiver<WindowSize>,
}
impl WindowSizeReceiver {
fn new(window_size_receiver: Receiver<WindowSize>) -> Self {
fn duplicate(&self) -> Self
where
Self: Sized,
{
Self {
window_size: WindowSize { width: 1, height: 1 },
receiver: window_size_receiver,
wgpu_context: self.wgpu_context.clone(),
app_event_scheduler: self.app_event_scheduler.clone(),
view_info_receiver: self.view_info_receiver.clone(),
}
}
}
struct ViewInfoReceiver {
view_info: ViewInfo,
receiver: Receiver<ViewInfoUpdate>,
}
impl ViewInfoReceiver {
fn new(receiver: Receiver<ViewInfoUpdate>) -> Self {
Self { view_info: ViewInfo::new(), receiver }
}
}