Stabilize PRD site rendering refresh

This commit is contained in:
2026-05-08 13:36:15 -04:00
parent 8e12d6690b
commit 8068d4ba32
3 changed files with 80 additions and 37 deletions
+1
View File
@@ -15,6 +15,7 @@ mod splits;
mod tab_groups; mod tab_groups;
mod tab_lifecycle; mod tab_lifecycle;
mod web_surface; mod web_surface;
mod web_surface_image;
use ely_browser_core::{BrowserCore, InitialBrowserConfig}; use ely_browser_core::{BrowserCore, InitialBrowserConfig};
use ely_domain::{ use ely_domain::{
+51 -37
View File
@@ -7,20 +7,19 @@ use gpui::{
rgb, rgb,
}; };
use gpui_component::StyledExt; use gpui_component::StyledExt;
use image::{ImageBuffer, Rgba, imageops::FilterType}; use image::{ImageBuffer, Rgba};
use thiserror::Error; use thiserror::Error;
use crate::services::servo_sidecar::{ use crate::services::servo_sidecar::{
ServoSidecarClient, ServoSidecarError, SidecarSnapshot, SidecarSnapshotRequest, ServoSidecarClient, ServoSidecarError, SidecarSnapshot, SidecarSnapshotRequest,
}; };
use super::ElyShell; use super::{ElyShell, web_surface_image::renderable_image_buffer};
use ely_design_system::{colors, spacing}; use ely_design_system::{colors, spacing};
const WEB_SURFACE_IMAGE_MAX_EDGE: u32 = 1024;
pub(super) struct WebSurfaceStore { pub(super) struct WebSurfaceStore {
client: WebSurfaceClient, client: WebSurfaceClient,
pending_viewport_sizes: BTreeMap<TabId, WebSurfaceSize>,
viewport_sizes: BTreeMap<TabId, WebSurfaceSize>, viewport_sizes: BTreeMap<TabId, WebSurfaceSize>,
states: BTreeMap<TabId, WebSurfaceState>, states: BTreeMap<TabId, WebSurfaceState>,
} }
@@ -29,6 +28,7 @@ impl WebSurfaceStore {
pub(super) fn new() -> Self { pub(super) fn new() -> Self {
Self { Self {
client: WebSurfaceClient::new(), client: WebSurfaceClient::new(),
pending_viewport_sizes: BTreeMap::new(),
viewport_sizes: BTreeMap::new(), viewport_sizes: BTreeMap::new(),
states: BTreeMap::new(), states: BTreeMap::new(),
} }
@@ -65,7 +65,11 @@ impl WebSurfaceStore {
self.states.insert( self.states.insert(
tab.id().clone(), 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 { Some(WebSurfaceRequest {
@@ -83,9 +87,11 @@ impl WebSurfaceStore {
fn has_current_state(&self, tab_id: &TabId, requested_url: &str, size: WebSurfaceSize) -> bool { fn has_current_state(&self, tab_id: &TabId, requested_url: &str, size: WebSurfaceSize) -> bool {
match self.states.get(tab_id) { match self.states.get(tab_id) {
Some(WebSurfaceState::Loading { requested_url: current_url, size: current_size }) => { Some(WebSurfaceState::Loading {
current_url == requested_url && *current_size == size requested_url: current_url,
} size: current_size,
..
}) => current_url == requested_url && *current_size == size,
Some(WebSurfaceState::Ready(frame)) => { Some(WebSurfaceState::Ready(frame)) => {
frame.requested_url == requested_url && frame.size() == size 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 { fn is_loading(&self, tab_id: &TabId, requested_url: &str, size: WebSurfaceSize) -> bool {
matches!( matches!(
self.states.get(tab_id), 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 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<WebSurfaceFrame> {
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) { fn finish(&mut self, tab_id: TabId, state: WebSurfaceState) {
self.states.insert(tab_id, state); self.states.insert(tab_id, state);
} }
@@ -123,10 +145,23 @@ impl WebSurfaceStore {
return false; 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; 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); self.viewport_sizes.insert(tab_id.clone(), size);
true true
} }
@@ -155,7 +190,7 @@ struct WebSurfaceRequest {
} }
enum WebSurfaceState { enum WebSurfaceState {
Loading { requested_url: String, size: WebSurfaceSize }, Loading { requested_url: String, size: WebSurfaceSize, previous_frame: Option<WebSurfaceFrame> },
Ready(WebSurfaceFrame), Ready(WebSurfaceFrame),
Failed { requested_url: String, size: WebSurfaceSize, message: String }, Failed { requested_url: String, size: WebSurfaceSize, message: String },
} }
@@ -175,6 +210,7 @@ impl WebSurfaceSize {
} }
} }
#[derive(Clone)]
struct WebSurfaceFrame { struct WebSurfaceFrame {
requested_url: String, requested_url: String,
loaded_url: Option<String>, loaded_url: Option<String>,
@@ -246,7 +282,10 @@ impl ElyShell {
Some(WebSurfaceState::Failed { message, .. }) => { Some(WebSurfaceState::Failed { message, .. }) => {
render_failed_web_surface(tab, message.as_str(), state_entity) 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) render_loading_web_surface(tab, state_entity)
} }
} }
@@ -454,31 +493,6 @@ fn viewport_dimension(pixels: Pixels) -> Option<u32> {
Some(value as u32) Some(value as u32)
} }
fn renderable_image_buffer(
buffer: ImageBuffer<Rgba<u8>, Vec<u8>>,
) -> ImageBuffer<Rgba<u8>, Vec<u8>> {
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 { pub(super) fn is_external_web_url(url: &str) -> bool {
url.starts_with("https://") || url.starts_with("http://") url.starts_with("https://") || url.starts_with("http://")
} }
@@ -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<Rgba<u8>, Vec<u8>>,
) -> ImageBuffer<Rgba<u8>, Vec<u8>> {
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,
}
}