Stabilize PRD site rendering refresh
This commit is contained in:
@@ -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::{
|
||||||
|
|||||||
@@ -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,
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user