From 8068d4ba322e84cc11081d04a94a5c0366bf7fc1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=9B=B7=E7=94=B5=E8=8A=BD=E8=A1=A3?= Date: Fri, 8 May 2026 13:36:15 -0400 Subject: [PATCH] Stabilize PRD site rendering refresh --- crates/ely_app/src/shell/mod.rs | 1 + crates/ely_app/src/shell/web_surface.rs | 88 +++++++++++-------- crates/ely_app/src/shell/web_surface_image.rs | 28 ++++++ 3 files changed, 80 insertions(+), 37 deletions(-) create mode 100644 crates/ely_app/src/shell/web_surface_image.rs diff --git a/crates/ely_app/src/shell/mod.rs b/crates/ely_app/src/shell/mod.rs index 339acfe..b24cef8 100644 --- a/crates/ely_app/src/shell/mod.rs +++ b/crates/ely_app/src/shell/mod.rs @@ -15,6 +15,7 @@ mod splits; mod tab_groups; mod tab_lifecycle; mod web_surface; +mod web_surface_image; use ely_browser_core::{BrowserCore, InitialBrowserConfig}; use ely_domain::{ diff --git a/crates/ely_app/src/shell/web_surface.rs b/crates/ely_app/src/shell/web_surface.rs index 77686da..e8bac9f 100644 --- a/crates/ely_app/src/shell/web_surface.rs +++ b/crates/ely_app/src/shell/web_surface.rs @@ -7,20 +7,19 @@ use gpui::{ rgb, }; use gpui_component::StyledExt; -use image::{ImageBuffer, Rgba, imageops::FilterType}; +use image::{ImageBuffer, Rgba}; use thiserror::Error; use crate::services::servo_sidecar::{ ServoSidecarClient, ServoSidecarError, SidecarSnapshot, SidecarSnapshotRequest, }; -use super::ElyShell; +use super::{ElyShell, web_surface_image::renderable_image_buffer}; use ely_design_system::{colors, spacing}; -const WEB_SURFACE_IMAGE_MAX_EDGE: u32 = 1024; - pub(super) struct WebSurfaceStore { client: WebSurfaceClient, + pending_viewport_sizes: BTreeMap, viewport_sizes: BTreeMap, states: BTreeMap, } @@ -29,6 +28,7 @@ impl WebSurfaceStore { pub(super) fn new() -> Self { Self { client: WebSurfaceClient::new(), + pending_viewport_sizes: BTreeMap::new(), viewport_sizes: BTreeMap::new(), states: BTreeMap::new(), } @@ -65,7 +65,11 @@ impl WebSurfaceStore { self.states.insert( tab.id().clone(), - WebSurfaceState::Loading { requested_url: requested_url.clone(), size }, + WebSurfaceState::Loading { + requested_url: requested_url.clone(), + size, + previous_frame: self.previous_ready_frame(tab.id(), requested_url.as_str()), + }, ); Some(WebSurfaceRequest { @@ -83,9 +87,11 @@ impl WebSurfaceStore { fn has_current_state(&self, tab_id: &TabId, requested_url: &str, size: WebSurfaceSize) -> bool { match self.states.get(tab_id) { - Some(WebSurfaceState::Loading { requested_url: current_url, size: current_size }) => { - current_url == requested_url && *current_size == size - } + Some(WebSurfaceState::Loading { + requested_url: current_url, + size: current_size, + .. + }) => current_url == requested_url && *current_size == size, Some(WebSurfaceState::Ready(frame)) => { frame.requested_url == requested_url && frame.size() == size } @@ -101,7 +107,11 @@ impl WebSurfaceStore { fn is_loading(&self, tab_id: &TabId, requested_url: &str, size: WebSurfaceSize) -> bool { matches!( self.states.get(tab_id), - Some(WebSurfaceState::Loading { requested_url: current_url, size: current_size }) + Some(WebSurfaceState::Loading { + requested_url: current_url, + size: current_size, + .. + }) if current_url == requested_url && *current_size == size ) } @@ -114,6 +124,18 @@ impl WebSurfaceStore { ) } + fn previous_ready_frame(&self, tab_id: &TabId, requested_url: &str) -> Option { + match self.states.get(tab_id) { + Some(WebSurfaceState::Ready(frame)) if frame.requested_url == requested_url => { + Some(frame.clone()) + } + Some(WebSurfaceState::Loading { + requested_url: current_url, previous_frame, .. + }) if current_url == requested_url => previous_frame.clone(), + _ => None, + } + } + fn finish(&mut self, tab_id: TabId, state: WebSurfaceState) { self.states.insert(tab_id, state); } @@ -123,10 +145,23 @@ impl WebSurfaceStore { return false; }; - if self.viewport_sizes.get(tab_id) == Some(&size) { + let Some(current_size) = self.viewport_sizes.get(tab_id).copied() else { + self.viewport_sizes.insert(tab_id.clone(), size); + self.pending_viewport_sizes.remove(tab_id); + return true; + }; + + if current_size == size { + self.pending_viewport_sizes.remove(tab_id); return false; } + if self.pending_viewport_sizes.get(tab_id) != Some(&size) { + self.pending_viewport_sizes.insert(tab_id.clone(), size); + return false; + } + + self.pending_viewport_sizes.remove(tab_id); self.viewport_sizes.insert(tab_id.clone(), size); true } @@ -155,7 +190,7 @@ struct WebSurfaceRequest { } enum WebSurfaceState { - Loading { requested_url: String, size: WebSurfaceSize }, + Loading { requested_url: String, size: WebSurfaceSize, previous_frame: Option }, Ready(WebSurfaceFrame), Failed { requested_url: String, size: WebSurfaceSize, message: String }, } @@ -175,6 +210,7 @@ impl WebSurfaceSize { } } +#[derive(Clone)] struct WebSurfaceFrame { requested_url: String, loaded_url: Option, @@ -246,7 +282,10 @@ impl ElyShell { Some(WebSurfaceState::Failed { message, .. }) => { render_failed_web_surface(tab, message.as_str(), state_entity) } - Some(WebSurfaceState::Loading { .. }) | None => { + Some(WebSurfaceState::Loading { previous_frame: Some(frame), .. }) => { + render_ready_web_surface(frame, tab, state_entity) + } + Some(WebSurfaceState::Loading { previous_frame: None, .. }) | None => { render_loading_web_surface(tab, state_entity) } } @@ -454,31 +493,6 @@ fn viewport_dimension(pixels: Pixels) -> Option { Some(value as u32) } -fn renderable_image_buffer( - buffer: ImageBuffer, Vec>, -) -> ImageBuffer, Vec> { - let largest_edge = buffer.width().max(buffer.height()); - if largest_edge <= WEB_SURFACE_IMAGE_MAX_EDGE { - return buffer; - } - - image::imageops::resize( - &buffer, - scaled_image_dimension(buffer.width(), largest_edge), - scaled_image_dimension(buffer.height(), largest_edge), - FilterType::Triangle, - ) -} - -fn scaled_image_dimension(dimension: u32, largest_edge: u32) -> u32 { - let numerator = u64::from(dimension) * u64::from(WEB_SURFACE_IMAGE_MAX_EDGE); - let rounded = (numerator + u64::from(largest_edge / 2)) / u64::from(largest_edge); - match u32::try_from(rounded.max(1)) { - Ok(value) => value, - Err(_) => WEB_SURFACE_IMAGE_MAX_EDGE, - } -} - pub(super) fn is_external_web_url(url: &str) -> bool { url.starts_with("https://") || url.starts_with("http://") } diff --git a/crates/ely_app/src/shell/web_surface_image.rs b/crates/ely_app/src/shell/web_surface_image.rs new file mode 100644 index 0000000..22a8cb5 --- /dev/null +++ b/crates/ely_app/src/shell/web_surface_image.rs @@ -0,0 +1,28 @@ +use image::{ImageBuffer, Rgba, imageops::FilterType}; + +const WEB_SURFACE_IMAGE_MAX_EDGE: u32 = 1024; + +pub(super) fn renderable_image_buffer( + buffer: ImageBuffer, Vec>, +) -> ImageBuffer, Vec> { + let largest_edge = buffer.width().max(buffer.height()); + if largest_edge <= WEB_SURFACE_IMAGE_MAX_EDGE { + return buffer; + } + + image::imageops::resize( + &buffer, + scaled_image_dimension(buffer.width(), largest_edge), + scaled_image_dimension(buffer.height(), largest_edge), + FilterType::Triangle, + ) +} + +fn scaled_image_dimension(dimension: u32, largest_edge: u32) -> u32 { + let numerator = u64::from(dimension) * u64::from(WEB_SURFACE_IMAGE_MAX_EDGE); + let rounded = (numerator + u64::from(largest_edge / 2)) / u64::from(largest_edge); + match u32::try_from(rounded.max(1)) { + Ok(value) => value, + Err(_) => WEB_SURFACE_IMAGE_MAX_EDGE, + } +}