Add Servo page zoom support
This commit is contained in:
@@ -36,6 +36,7 @@ actions!(
|
||||
OpenTaskManager,
|
||||
Quit,
|
||||
RestoreClosedTab,
|
||||
ResetZoom,
|
||||
SelectNextSpace,
|
||||
SelectNextTab,
|
||||
SelectPreviousSpace,
|
||||
@@ -44,6 +45,8 @@ actions!(
|
||||
ToggleFavoriteTab,
|
||||
TogglePinnedTab,
|
||||
ToggleSidebar,
|
||||
ZoomIn,
|
||||
ZoomOut,
|
||||
]
|
||||
);
|
||||
|
||||
@@ -78,6 +81,10 @@ fn main() {
|
||||
MenuItem::action("Command Mode", FocusCommandMode),
|
||||
MenuItem::action("Toggle Sidebar", ToggleSidebar),
|
||||
MenuItem::separator(),
|
||||
MenuItem::action("Zoom In", ZoomIn),
|
||||
MenuItem::action("Zoom Out", ZoomOut),
|
||||
MenuItem::action("Reset Zoom", ResetZoom),
|
||||
MenuItem::separator(),
|
||||
MenuItem::action("Close Tab", CloseCurrentTab),
|
||||
MenuItem::separator(),
|
||||
MenuItem::action("Restore Closed Tab", RestoreClosedTab),
|
||||
|
||||
@@ -165,7 +165,9 @@ fn append_snapshot_args(
|
||||
.arg("--scroll-x")
|
||||
.arg(request.scroll_x.to_string())
|
||||
.arg("--scroll-y")
|
||||
.arg(request.scroll_y.to_string());
|
||||
.arg(request.scroll_y.to_string())
|
||||
.arg("--page-zoom-percent")
|
||||
.arg(request.page_zoom_percent.to_string());
|
||||
}
|
||||
|
||||
impl SidecarSnapshotRequest {
|
||||
|
||||
@@ -1,4 +1,7 @@
|
||||
use ely_domain::{ProfileId, SiteOrigin, SitePermissionDecision, SitePermissionFeature, UrlText};
|
||||
use ely_domain::{
|
||||
DEFAULT_ZOOM_PERCENT, ProfileId, SiteOrigin, SitePermissionDecision, SitePermissionFeature,
|
||||
UrlText,
|
||||
};
|
||||
|
||||
use super::ProfileDataMode;
|
||||
|
||||
@@ -11,6 +14,7 @@ pub struct SidecarSnapshotRequest {
|
||||
pub(in crate::services) height: u32,
|
||||
pub(in crate::services) scroll_x: i32,
|
||||
pub(in crate::services) scroll_y: i32,
|
||||
pub(in crate::services) page_zoom_percent: u16,
|
||||
pub(in crate::services) click_point: Option<SidecarClickPoint>,
|
||||
pub(in crate::services) typed_text: Option<String>,
|
||||
pub(in crate::services) site_permissions: Vec<SidecarSitePermission>,
|
||||
@@ -27,6 +31,7 @@ impl SidecarSnapshotRequest {
|
||||
height,
|
||||
scroll_x: 0,
|
||||
scroll_y: 0,
|
||||
page_zoom_percent: DEFAULT_ZOOM_PERCENT,
|
||||
click_point: None,
|
||||
typed_text: None,
|
||||
site_permissions: Vec::new(),
|
||||
@@ -46,6 +51,12 @@ impl SidecarSnapshotRequest {
|
||||
self
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn with_page_zoom_percent(mut self, page_zoom_percent: u16) -> Self {
|
||||
self.page_zoom_percent = page_zoom_percent;
|
||||
self
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn with_click_point(mut self, x: u32, y: u32) -> Self {
|
||||
self.click_point = Some(SidecarClickPoint { x, y });
|
||||
@@ -78,6 +89,11 @@ impl SidecarSnapshotRequest {
|
||||
pub(crate) fn profile_data_mode_for_test(&self) -> ProfileDataMode {
|
||||
self.profile_data_mode
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
pub(crate) fn page_zoom_percent_for_test(&self) -> u16 {
|
||||
self.page_zoom_percent
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
|
||||
@@ -45,8 +45,8 @@ use web_surface::WebSurfaceStore;
|
||||
|
||||
use crate::{
|
||||
CloseCurrentTab, FocusAddressBar, FocusCommandMode, OpenDownloads, OpenHistory, OpenNewTab,
|
||||
OpenSettings, OpenTaskManager, RestoreClosedTab, SelectNextTab, SelectPreviousTab,
|
||||
ToggleFavoriteTab, TogglePinnedTab,
|
||||
OpenSettings, OpenTaskManager, ResetZoom, RestoreClosedTab, SelectNextTab, SelectPreviousTab,
|
||||
ToggleFavoriteTab, TogglePinnedTab, ZoomIn, ZoomOut,
|
||||
};
|
||||
|
||||
enum ShellState {
|
||||
@@ -284,6 +284,30 @@ impl ElyShell {
|
||||
}
|
||||
}
|
||||
|
||||
fn zoom_active_tab_in(&mut self, cx: &mut Context<Self>) {
|
||||
if let ShellState::Ready(core) = &mut self.state
|
||||
&& core.zoom_active_tab_in().is_ok()
|
||||
{
|
||||
cx.notify();
|
||||
}
|
||||
}
|
||||
|
||||
fn zoom_active_tab_out(&mut self, cx: &mut Context<Self>) {
|
||||
if let ShellState::Ready(core) = &mut self.state
|
||||
&& core.zoom_active_tab_out().is_ok()
|
||||
{
|
||||
cx.notify();
|
||||
}
|
||||
}
|
||||
|
||||
fn reset_active_tab_zoom(&mut self, cx: &mut Context<Self>) {
|
||||
if let ShellState::Ready(core) = &mut self.state
|
||||
&& core.reset_active_tab_zoom().is_ok()
|
||||
{
|
||||
cx.notify();
|
||||
}
|
||||
}
|
||||
|
||||
fn on_close_current_tab(
|
||||
&mut self,
|
||||
_: &CloseCurrentTab,
|
||||
@@ -350,6 +374,10 @@ impl ElyShell {
|
||||
self.restore_closed_tab(window, cx);
|
||||
}
|
||||
|
||||
fn on_reset_zoom(&mut self, _: &ResetZoom, _: &mut Window, cx: &mut Context<Self>) {
|
||||
self.reset_active_tab_zoom(cx);
|
||||
}
|
||||
|
||||
fn on_select_next_tab(
|
||||
&mut self,
|
||||
_: &SelectNextTab,
|
||||
@@ -385,4 +413,12 @@ impl ElyShell {
|
||||
) {
|
||||
self.toggle_active_tab_pinned(cx);
|
||||
}
|
||||
|
||||
fn on_zoom_in(&mut self, _: &ZoomIn, _: &mut Window, cx: &mut Context<Self>) {
|
||||
self.zoom_active_tab_in(cx);
|
||||
}
|
||||
|
||||
fn on_zoom_out(&mut self, _: &ZoomOut, _: &mut Window, cx: &mut Context<Self>) {
|
||||
self.zoom_active_tab_out(cx);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -51,6 +51,7 @@ impl ElyShell {
|
||||
.on_action(cx.listener(Self::on_open_new_tab))
|
||||
.on_action(cx.listener(Self::on_open_settings))
|
||||
.on_action(cx.listener(Self::on_open_task_manager))
|
||||
.on_action(cx.listener(Self::on_reset_zoom))
|
||||
.on_action(cx.listener(Self::on_restore_closed_tab))
|
||||
.on_action(cx.listener(Self::on_select_next_space))
|
||||
.on_action(cx.listener(Self::on_select_next_tab))
|
||||
@@ -60,6 +61,8 @@ impl ElyShell {
|
||||
.on_action(cx.listener(Self::on_toggle_favorite_tab))
|
||||
.on_action(cx.listener(Self::on_toggle_pinned_tab))
|
||||
.on_action(cx.listener(Self::on_toggle_sidebar))
|
||||
.on_action(cx.listener(Self::on_zoom_in))
|
||||
.on_action(cx.listener(Self::on_zoom_out))
|
||||
.bg(rgb(ELY_THEME.canvas))
|
||||
.text_color(rgb(ELY_THEME.ink))
|
||||
.flex()
|
||||
|
||||
@@ -12,7 +12,7 @@ use super::{
|
||||
},
|
||||
web_surface_state::{
|
||||
WebSurfaceClickState, WebSurfaceClient, WebSurfaceKeyboardFocusState, WebSurfaceRequest,
|
||||
WebSurfaceScrollState, WebSurfaceState, WebSurfaceTextInputState,
|
||||
WebSurfaceScrollState, WebSurfaceState, WebSurfaceStateKey, WebSurfaceTextInputState,
|
||||
},
|
||||
};
|
||||
|
||||
@@ -59,20 +59,22 @@ impl WebSurfaceStore {
|
||||
let size = self.viewport_sizes.get(tab.id()).copied()?;
|
||||
let requested_url = tab.url().as_str().to_string();
|
||||
let scroll_offset = self.scroll_offset_for(tab.id(), requested_url.as_str());
|
||||
let zoom_percent = tab.zoom_percent();
|
||||
let click_point = self.click_point_for(tab.id(), requested_url.as_str(), scroll_offset);
|
||||
let typed_text =
|
||||
self.typed_text_for(tab.id(), requested_url.as_str(), scroll_offset, click_point);
|
||||
if self.is_loading_requested_url(tab.id(), requested_url.as_str()) {
|
||||
return None;
|
||||
}
|
||||
if self.has_current_state(
|
||||
tab.id(),
|
||||
&requested_url,
|
||||
let state_key = WebSurfaceStateKey {
|
||||
requested_url: &requested_url,
|
||||
size,
|
||||
scroll_offset,
|
||||
zoom_percent,
|
||||
click_point,
|
||||
typed_text.as_deref(),
|
||||
) {
|
||||
typed_text: typed_text.as_deref(),
|
||||
};
|
||||
if self.has_current_state(tab.id(), state_key) {
|
||||
return None;
|
||||
}
|
||||
|
||||
@@ -85,6 +87,7 @@ impl WebSurfaceStore {
|
||||
requested_url,
|
||||
size,
|
||||
scroll_offset,
|
||||
zoom_percent,
|
||||
click_point,
|
||||
typed_text: typed_text.clone(),
|
||||
message: message.clone(),
|
||||
@@ -100,9 +103,14 @@ impl WebSurfaceStore {
|
||||
requested_url: requested_url.clone(),
|
||||
size,
|
||||
scroll_offset,
|
||||
zoom_percent,
|
||||
click_point,
|
||||
typed_text: typed_text.clone(),
|
||||
previous_frame: self.previous_ready_frame(tab.id(), requested_url.as_str()),
|
||||
previous_frame: self.previous_ready_frame(
|
||||
tab.id(),
|
||||
requested_url.as_str(),
|
||||
zoom_percent,
|
||||
),
|
||||
},
|
||||
);
|
||||
|
||||
@@ -113,7 +121,8 @@ impl WebSurfaceStore {
|
||||
size.height,
|
||||
)
|
||||
.with_profile_data_mode(profile_data_mode)
|
||||
.with_scroll_offset(scroll_offset.x(), scroll_offset.y());
|
||||
.with_scroll_offset(scroll_offset.x(), scroll_offset.y())
|
||||
.with_page_zoom_percent(zoom_percent);
|
||||
if let Some(click_point) = click_point {
|
||||
snapshot_request = snapshot_request.with_click_point(click_point.x(), click_point.y());
|
||||
}
|
||||
@@ -126,6 +135,7 @@ impl WebSurfaceStore {
|
||||
requested_url,
|
||||
size,
|
||||
scroll_offset,
|
||||
zoom_percent,
|
||||
click_point,
|
||||
typed_text,
|
||||
client,
|
||||
@@ -133,79 +143,70 @@ impl WebSurfaceStore {
|
||||
})
|
||||
}
|
||||
|
||||
fn has_current_state(
|
||||
&self,
|
||||
tab_id: &TabId,
|
||||
requested_url: &str,
|
||||
size: WebSurfaceSize,
|
||||
scroll_offset: WebSurfaceScrollOffset,
|
||||
click_point: Option<WebSurfaceClickPoint>,
|
||||
typed_text: Option<&str>,
|
||||
) -> bool {
|
||||
fn has_current_state(&self, tab_id: &TabId, key: WebSurfaceStateKey<'_>) -> bool {
|
||||
match self.states.get(tab_id) {
|
||||
Some(WebSurfaceState::Loading {
|
||||
requested_url: current_url,
|
||||
size: current_size,
|
||||
scroll_offset: current_scroll_offset,
|
||||
zoom_percent: current_zoom_percent,
|
||||
click_point: current_click_point,
|
||||
typed_text: current_typed_text,
|
||||
..
|
||||
}) => {
|
||||
current_url == requested_url
|
||||
&& *current_size == size
|
||||
&& *current_scroll_offset == scroll_offset
|
||||
&& *current_click_point == click_point
|
||||
&& current_typed_text.as_deref() == typed_text
|
||||
current_url == key.requested_url
|
||||
&& *current_size == key.size
|
||||
&& *current_scroll_offset == key.scroll_offset
|
||||
&& *current_zoom_percent == key.zoom_percent
|
||||
&& *current_click_point == key.click_point
|
||||
&& current_typed_text.as_deref() == key.typed_text
|
||||
}
|
||||
Some(WebSurfaceState::Ready(frame)) => {
|
||||
frame.requested_url == requested_url
|
||||
&& frame.size() == size
|
||||
&& frame.scroll_offset() == scroll_offset
|
||||
&& frame.click_point() == click_point
|
||||
&& frame.typed_text() == typed_text
|
||||
frame.requested_url == key.requested_url
|
||||
&& frame.size() == key.size
|
||||
&& frame.scroll_offset() == key.scroll_offset
|
||||
&& frame.zoom_percent() == key.zoom_percent
|
||||
&& frame.click_point() == key.click_point
|
||||
&& frame.typed_text() == key.typed_text
|
||||
}
|
||||
Some(WebSurfaceState::Failed {
|
||||
requested_url: current_url,
|
||||
size: current_size,
|
||||
scroll_offset: current_scroll_offset,
|
||||
zoom_percent: current_zoom_percent,
|
||||
click_point: current_click_point,
|
||||
typed_text: current_typed_text,
|
||||
..
|
||||
}) => {
|
||||
current_url == requested_url
|
||||
&& *current_size == size
|
||||
&& *current_scroll_offset == scroll_offset
|
||||
&& *current_click_point == click_point
|
||||
&& current_typed_text.as_deref() == typed_text
|
||||
current_url == key.requested_url
|
||||
&& *current_size == key.size
|
||||
&& *current_scroll_offset == key.scroll_offset
|
||||
&& *current_zoom_percent == key.zoom_percent
|
||||
&& *current_click_point == key.click_point
|
||||
&& current_typed_text.as_deref() == key.typed_text
|
||||
}
|
||||
None => false,
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) fn is_loading(
|
||||
&self,
|
||||
tab_id: &TabId,
|
||||
requested_url: &str,
|
||||
size: WebSurfaceSize,
|
||||
scroll_offset: WebSurfaceScrollOffset,
|
||||
click_point: Option<WebSurfaceClickPoint>,
|
||||
typed_text: Option<&str>,
|
||||
) -> bool {
|
||||
pub(super) fn is_loading(&self, tab_id: &TabId, key: WebSurfaceStateKey<'_>) -> bool {
|
||||
matches!(
|
||||
self.states.get(tab_id),
|
||||
Some(WebSurfaceState::Loading {
|
||||
requested_url: current_url,
|
||||
size: current_size,
|
||||
scroll_offset: current_scroll_offset,
|
||||
zoom_percent: current_zoom_percent,
|
||||
click_point: current_click_point,
|
||||
typed_text: current_typed_text,
|
||||
..
|
||||
})
|
||||
if current_url == requested_url
|
||||
&& *current_size == size
|
||||
&& *current_scroll_offset == scroll_offset
|
||||
&& *current_click_point == click_point
|
||||
&& current_typed_text.as_deref() == typed_text
|
||||
if current_url == key.requested_url
|
||||
&& *current_size == key.size
|
||||
&& *current_scroll_offset == key.scroll_offset
|
||||
&& *current_zoom_percent == key.zoom_percent
|
||||
&& *current_click_point == key.click_point
|
||||
&& current_typed_text.as_deref() == key.typed_text
|
||||
)
|
||||
}
|
||||
|
||||
@@ -217,14 +218,24 @@ impl WebSurfaceStore {
|
||||
)
|
||||
}
|
||||
|
||||
fn previous_ready_frame(&self, tab_id: &TabId, requested_url: &str) -> Option<WebSurfaceFrame> {
|
||||
fn previous_ready_frame(
|
||||
&self,
|
||||
tab_id: &TabId,
|
||||
requested_url: &str,
|
||||
zoom_percent: u16,
|
||||
) -> Option<WebSurfaceFrame> {
|
||||
match self.states.get(tab_id) {
|
||||
Some(WebSurfaceState::Ready(frame)) if frame.requested_url == requested_url => {
|
||||
Some(WebSurfaceState::Ready(frame))
|
||||
if frame.requested_url == requested_url && frame.zoom_percent() == zoom_percent =>
|
||||
{
|
||||
Some(frame.clone())
|
||||
}
|
||||
Some(WebSurfaceState::Loading {
|
||||
requested_url: current_url, previous_frame, ..
|
||||
}) if current_url == requested_url => previous_frame.clone(),
|
||||
}) if current_url == requested_url => previous_frame
|
||||
.as_ref()
|
||||
.filter(|frame| frame.zoom_percent() == zoom_percent)
|
||||
.cloned(),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
@@ -409,68 +420,8 @@ pub(super) fn is_external_web_url(url: &str) -> bool {
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use std::error::Error;
|
||||
|
||||
use ely_domain::{BrowserTab, ProfileId, SpaceId, TabId, UrlText};
|
||||
use gpui::{Bounds, point, px, size};
|
||||
|
||||
use super::{ProfileDataMode, WebSurfaceStore};
|
||||
|
||||
#[test]
|
||||
fn typed_text_enters_snapshot_request_after_clicked_viewport() -> Result<(), Box<dyn Error>> {
|
||||
let mut store = WebSurfaceStore::new();
|
||||
let tab = web_tab("https://example.com/form")?;
|
||||
|
||||
let bounds = Bounds::new(point(px(0.0), px(0.0)), size(px(640.0), px(480.0)));
|
||||
assert!(store.record_viewport_size(tab.id(), bounds));
|
||||
assert!(store.record_click_point(
|
||||
tab.id(),
|
||||
tab.url().as_str(),
|
||||
point(px(160.0), px(120.0))
|
||||
));
|
||||
assert!(store.record_typed_text(tab.id(), tab.url().as_str(), "e"));
|
||||
assert!(store.record_typed_text(tab.id(), tab.url().as_str(), "l"));
|
||||
|
||||
let request = store
|
||||
.prepare_request(&tab, ProfileDataMode::Persistent)
|
||||
.ok_or("missing web surface request")?;
|
||||
|
||||
assert_eq!(request.typed_text.as_deref(), Some("el"));
|
||||
assert_eq!(request.snapshot_request.typed_text_for_test(), Some("el"));
|
||||
assert_eq!(request.snapshot_request.profile_id_for_test(), tab.profile_id());
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn private_profile_enters_transient_snapshot_request() -> Result<(), Box<dyn Error>> {
|
||||
let mut store = WebSurfaceStore::new();
|
||||
let tab = web_tab("https://example.com/private")?;
|
||||
|
||||
let bounds = Bounds::new(point(px(0.0), px(0.0)), size(px(640.0), px(480.0)));
|
||||
assert!(store.record_viewport_size(tab.id(), bounds));
|
||||
|
||||
let request = store
|
||||
.prepare_request(&tab, ProfileDataMode::Transient)
|
||||
.ok_or("missing web surface request")?;
|
||||
|
||||
assert_eq!(
|
||||
request.snapshot_request.profile_data_mode_for_test(),
|
||||
ProfileDataMode::Transient
|
||||
);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn web_tab(url: &str) -> Result<BrowserTab, Box<dyn Error>> {
|
||||
Ok(BrowserTab::new(
|
||||
TabId::new(),
|
||||
SpaceId::new(),
|
||||
ProfileId::new(),
|
||||
"Web",
|
||||
UrlText::parse(url)?,
|
||||
))
|
||||
}
|
||||
}
|
||||
#[path = "web_surface_tests.rs"]
|
||||
mod tests;
|
||||
|
||||
#[cfg(all(test, feature = "live-site-smoke"))]
|
||||
#[path = "web_surface_live_site_tests.rs"]
|
||||
|
||||
@@ -12,7 +12,7 @@ use super::{
|
||||
web_surface_frame::WebSurfaceFrame,
|
||||
web_surface_geometry::{WebSurfaceClickPoint, WebSurfaceScrollOffset, WebSurfaceSize},
|
||||
web_surface_permissions::sidecar_site_permissions_for_tab,
|
||||
web_surface_state::{WebSurfaceRequest, WebSurfaceState},
|
||||
web_surface_state::{WebSurfaceRequest, WebSurfaceState, WebSurfaceStateKey},
|
||||
web_surface_view::{
|
||||
render_failed_web_surface, render_loading_web_surface, render_ready_web_surface,
|
||||
},
|
||||
@@ -23,6 +23,7 @@ struct PendingWebSurfaceFrame {
|
||||
requested_url: String,
|
||||
size: WebSurfaceSize,
|
||||
scroll_offset: WebSurfaceScrollOffset,
|
||||
zoom_percent: u16,
|
||||
click_point: Option<WebSurfaceClickPoint>,
|
||||
typed_text: Option<String>,
|
||||
}
|
||||
@@ -74,6 +75,7 @@ impl ElyShell {
|
||||
requested_url,
|
||||
size,
|
||||
scroll_offset,
|
||||
zoom_percent,
|
||||
click_point,
|
||||
typed_text,
|
||||
client,
|
||||
@@ -85,6 +87,7 @@ impl ElyShell {
|
||||
requested_url,
|
||||
size,
|
||||
scroll_offset,
|
||||
zoom_percent,
|
||||
click_point,
|
||||
typed_text,
|
||||
};
|
||||
@@ -112,17 +115,19 @@ impl ElyShell {
|
||||
requested_url,
|
||||
size,
|
||||
scroll_offset,
|
||||
zoom_percent,
|
||||
click_point,
|
||||
typed_text,
|
||||
} = pending_frame;
|
||||
if !self.web_surfaces.is_loading(
|
||||
&tab_id,
|
||||
requested_url.as_str(),
|
||||
let state_key = WebSurfaceStateKey {
|
||||
requested_url: requested_url.as_str(),
|
||||
size,
|
||||
scroll_offset,
|
||||
zoom_percent,
|
||||
click_point,
|
||||
typed_text.as_deref(),
|
||||
) {
|
||||
typed_text: typed_text.as_deref(),
|
||||
};
|
||||
if !self.web_surfaces.is_loading(&tab_id, state_key) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -130,6 +135,7 @@ impl ElyShell {
|
||||
Ok(snapshot) => match WebSurfaceFrame::from_snapshot(
|
||||
requested_url.clone(),
|
||||
scroll_offset,
|
||||
zoom_percent,
|
||||
click_point,
|
||||
typed_text.clone(),
|
||||
snapshot,
|
||||
@@ -139,6 +145,7 @@ impl ElyShell {
|
||||
requested_url,
|
||||
size,
|
||||
scroll_offset,
|
||||
zoom_percent,
|
||||
click_point,
|
||||
typed_text,
|
||||
message: error.to_string(),
|
||||
@@ -148,6 +155,7 @@ impl ElyShell {
|
||||
requested_url,
|
||||
size,
|
||||
scroll_offset,
|
||||
zoom_percent,
|
||||
click_point,
|
||||
typed_text,
|
||||
message: error.to_string(),
|
||||
|
||||
@@ -20,6 +20,7 @@ pub(super) struct WebSurfaceFrame {
|
||||
width: u32,
|
||||
height: u32,
|
||||
scroll_offset: WebSurfaceScrollOffset,
|
||||
zoom_percent: u16,
|
||||
click_point: Option<WebSurfaceClickPoint>,
|
||||
typed_text: Option<String>,
|
||||
#[cfg(all(test, feature = "live-site-smoke"))]
|
||||
@@ -35,6 +36,7 @@ impl WebSurfaceFrame {
|
||||
pub(super) fn from_snapshot(
|
||||
requested_url: String,
|
||||
scroll_offset: WebSurfaceScrollOffset,
|
||||
zoom_percent: u16,
|
||||
click_point: Option<WebSurfaceClickPoint>,
|
||||
typed_text: Option<String>,
|
||||
snapshot: SidecarSnapshot,
|
||||
@@ -66,6 +68,7 @@ impl WebSurfaceFrame {
|
||||
width,
|
||||
height,
|
||||
scroll_offset,
|
||||
zoom_percent,
|
||||
click_point,
|
||||
typed_text,
|
||||
#[cfg(all(test, feature = "live-site-smoke"))]
|
||||
@@ -89,6 +92,9 @@ impl WebSurfaceFrame {
|
||||
pub(super) fn detail_label(&self) -> String {
|
||||
let mut detail =
|
||||
format!("{} {}", self.render_state(), self.scroll_offset.detail_label(self.size()));
|
||||
if self.zoom_percent != ely_domain::DEFAULT_ZOOM_PERCENT {
|
||||
detail = format!("{detail} zoom={}%", self.zoom_percent);
|
||||
}
|
||||
if let Some(click_point) = self.click_point {
|
||||
detail = format!("{detail} {}", click_point.detail_label());
|
||||
}
|
||||
@@ -110,6 +116,10 @@ impl WebSurfaceFrame {
|
||||
self.scroll_offset
|
||||
}
|
||||
|
||||
pub(super) fn zoom_percent(&self) -> u16 {
|
||||
self.zoom_percent
|
||||
}
|
||||
|
||||
pub(super) fn click_point(&self) -> Option<WebSurfaceClickPoint> {
|
||||
self.click_point
|
||||
}
|
||||
|
||||
@@ -61,6 +61,7 @@ fn render_web_surface_frame(case: &LiveSiteCase) -> Result<WebSurfaceFrame, Box<
|
||||
let frame = WebSurfaceFrame::from_snapshot(
|
||||
request.requested_url,
|
||||
request.scroll_offset,
|
||||
request.zoom_percent,
|
||||
request.click_point,
|
||||
request.typed_text,
|
||||
snapshot,
|
||||
|
||||
@@ -40,6 +40,16 @@ pub(super) struct WebSurfaceTextInputState {
|
||||
pub(super) text: String,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
pub(super) struct WebSurfaceStateKey<'a> {
|
||||
pub(super) requested_url: &'a str,
|
||||
pub(super) size: WebSurfaceSize,
|
||||
pub(super) scroll_offset: WebSurfaceScrollOffset,
|
||||
pub(super) zoom_percent: u16,
|
||||
pub(super) click_point: Option<WebSurfaceClickPoint>,
|
||||
pub(super) typed_text: Option<&'a str>,
|
||||
}
|
||||
|
||||
pub(super) enum WebSurfaceClient {
|
||||
Ready(ServoSidecarClient),
|
||||
Unavailable(String),
|
||||
@@ -59,6 +69,7 @@ pub(super) struct WebSurfaceRequest {
|
||||
pub(super) requested_url: String,
|
||||
pub(super) size: WebSurfaceSize,
|
||||
pub(super) scroll_offset: WebSurfaceScrollOffset,
|
||||
pub(super) zoom_percent: u16,
|
||||
pub(super) click_point: Option<WebSurfaceClickPoint>,
|
||||
pub(super) typed_text: Option<String>,
|
||||
pub(super) client: ServoSidecarClient,
|
||||
@@ -70,6 +81,7 @@ pub(super) enum WebSurfaceState {
|
||||
requested_url: String,
|
||||
size: WebSurfaceSize,
|
||||
scroll_offset: WebSurfaceScrollOffset,
|
||||
zoom_percent: u16,
|
||||
click_point: Option<WebSurfaceClickPoint>,
|
||||
typed_text: Option<String>,
|
||||
previous_frame: Option<WebSurfaceFrame>,
|
||||
@@ -79,6 +91,7 @@ pub(super) enum WebSurfaceState {
|
||||
requested_url: String,
|
||||
size: WebSurfaceSize,
|
||||
scroll_offset: WebSurfaceScrollOffset,
|
||||
zoom_percent: u16,
|
||||
click_point: Option<WebSurfaceClickPoint>,
|
||||
typed_text: Option<String>,
|
||||
message: String,
|
||||
|
||||
@@ -0,0 +1,70 @@
|
||||
use std::error::Error;
|
||||
|
||||
use ely_domain::{BrowserTab, ProfileId, SpaceId, TabId, UrlText};
|
||||
use gpui::{Bounds, point, px, size};
|
||||
|
||||
use super::{ProfileDataMode, WebSurfaceStore};
|
||||
|
||||
#[test]
|
||||
fn typed_text_enters_snapshot_request_after_clicked_viewport() -> Result<(), Box<dyn Error>> {
|
||||
let mut store = WebSurfaceStore::new();
|
||||
let tab = web_tab("https://example.com/form")?;
|
||||
|
||||
let bounds = Bounds::new(point(px(0.0), px(0.0)), size(px(640.0), px(480.0)));
|
||||
assert!(store.record_viewport_size(tab.id(), bounds));
|
||||
assert!(store.record_click_point(tab.id(), tab.url().as_str(), point(px(160.0), px(120.0))));
|
||||
assert!(store.record_typed_text(tab.id(), tab.url().as_str(), "e"));
|
||||
assert!(store.record_typed_text(tab.id(), tab.url().as_str(), "l"));
|
||||
|
||||
let request = store
|
||||
.prepare_request(&tab, ProfileDataMode::Persistent)
|
||||
.ok_or("missing web surface request")?;
|
||||
|
||||
assert_eq!(request.typed_text.as_deref(), Some("el"));
|
||||
assert_eq!(request.snapshot_request.typed_text_for_test(), Some("el"));
|
||||
assert_eq!(request.snapshot_request.profile_id_for_test(), tab.profile_id());
|
||||
assert_eq!(request.zoom_percent, ely_domain::DEFAULT_ZOOM_PERCENT);
|
||||
assert_eq!(
|
||||
request.snapshot_request.page_zoom_percent_for_test(),
|
||||
ely_domain::DEFAULT_ZOOM_PERCENT
|
||||
);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn private_profile_enters_transient_snapshot_request() -> Result<(), Box<dyn Error>> {
|
||||
let mut store = WebSurfaceStore::new();
|
||||
let tab = web_tab("https://example.com/private")?;
|
||||
|
||||
let bounds = Bounds::new(point(px(0.0), px(0.0)), size(px(640.0), px(480.0)));
|
||||
assert!(store.record_viewport_size(tab.id(), bounds));
|
||||
|
||||
let request = store
|
||||
.prepare_request(&tab, ProfileDataMode::Transient)
|
||||
.ok_or("missing web surface request")?;
|
||||
|
||||
assert_eq!(request.snapshot_request.profile_data_mode_for_test(), ProfileDataMode::Transient);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn tab_zoom_enters_snapshot_request() -> Result<(), Box<dyn Error>> {
|
||||
let mut store = WebSurfaceStore::new();
|
||||
let mut tab = web_tab("https://example.com/zoom")?;
|
||||
tab.set_zoom_percent(125)?;
|
||||
|
||||
let bounds = Bounds::new(point(px(0.0), px(0.0)), size(px(640.0), px(480.0)));
|
||||
assert!(store.record_viewport_size(tab.id(), bounds));
|
||||
|
||||
let request = store
|
||||
.prepare_request(&tab, ProfileDataMode::Persistent)
|
||||
.ok_or("missing web surface request")?;
|
||||
|
||||
assert_eq!(request.zoom_percent, 125);
|
||||
assert_eq!(request.snapshot_request.page_zoom_percent_for_test(), 125);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn web_tab(url: &str) -> Result<BrowserTab, Box<dyn Error>> {
|
||||
Ok(BrowserTab::new(TabId::new(), SpaceId::new(), ProfileId::new(), "Web", UrlText::parse(url)?))
|
||||
}
|
||||
@@ -10,9 +10,9 @@ pub(crate) use profile::{
|
||||
|
||||
use crate::{
|
||||
CloseCurrentTab, FocusAddressBar, FocusCommandMode, OpenDownloads, OpenHistory, OpenNewTab,
|
||||
OpenPrivateWindow, OpenSettings, OpenTaskManager, Quit, RestoreClosedTab, SelectNextSpace,
|
||||
SelectNextTab, SelectPreviousSpace, SelectPreviousTab, SplitRight, ToggleFavoriteTab,
|
||||
ToggleSidebar,
|
||||
OpenPrivateWindow, OpenSettings, OpenTaskManager, Quit, ResetZoom, RestoreClosedTab,
|
||||
SelectNextSpace, SelectNextTab, SelectPreviousSpace, SelectPreviousTab, SplitRight,
|
||||
ToggleFavoriteTab, ToggleSidebar, ZoomIn, ZoomOut,
|
||||
};
|
||||
|
||||
#[derive(Clone, Copy, Debug, Deserialize, Eq, Ord, PartialEq, PartialOrd, Serialize)]
|
||||
@@ -47,6 +47,9 @@ pub(crate) enum ShortcutAction {
|
||||
SplitRight,
|
||||
ToggleSidebar,
|
||||
ToggleFavoriteTab,
|
||||
ZoomIn,
|
||||
ZoomOut,
|
||||
ResetZoom,
|
||||
OpenDownloads,
|
||||
OpenHistory,
|
||||
OpenSettings,
|
||||
@@ -70,6 +73,9 @@ impl ShortcutAction {
|
||||
Self::SplitRight => "Split Right",
|
||||
Self::ToggleSidebar => "Toggle Sidebar",
|
||||
Self::ToggleFavoriteTab => "Toggle Favorite",
|
||||
Self::ZoomIn => "Zoom In",
|
||||
Self::ZoomOut => "Zoom Out",
|
||||
Self::ResetZoom => "Reset Zoom",
|
||||
Self::OpenDownloads => "Open Downloads",
|
||||
Self::OpenHistory => "Open History",
|
||||
Self::OpenSettings => "Open Settings",
|
||||
@@ -91,7 +97,10 @@ impl ShortcutAction {
|
||||
| Self::SelectPreviousTab
|
||||
| Self::SplitRight
|
||||
| Self::ToggleSidebar
|
||||
| Self::ToggleFavoriteTab => "Tabs",
|
||||
| Self::ToggleFavoriteTab
|
||||
| Self::ZoomIn
|
||||
| Self::ZoomOut
|
||||
| Self::ResetZoom => "Tabs",
|
||||
Self::OpenDownloads | Self::OpenHistory => "Library",
|
||||
Self::OpenSettings | Self::OpenTaskManager => "System",
|
||||
Self::Quit => "Application",
|
||||
@@ -113,6 +122,9 @@ impl ShortcutAction {
|
||||
Self::SplitRight => Some(">split-right"),
|
||||
Self::ToggleSidebar => None,
|
||||
Self::ToggleFavoriteTab => Some(">favorite"),
|
||||
Self::ZoomIn => Some(">zoom-in"),
|
||||
Self::ZoomOut => Some(">zoom-out"),
|
||||
Self::ResetZoom => Some(">reset-zoom"),
|
||||
Self::OpenDownloads => Some(">open-downloads"),
|
||||
Self::OpenHistory => Some(">open-history"),
|
||||
Self::OpenSettings => Some(">open-settings"),
|
||||
@@ -164,6 +176,9 @@ pub(crate) const SHORTCUT_ACTIONS: &[ShortcutAction] = &[
|
||||
ShortcutAction::SplitRight,
|
||||
ShortcutAction::ToggleSidebar,
|
||||
ShortcutAction::ToggleFavoriteTab,
|
||||
ShortcutAction::ZoomIn,
|
||||
ShortcutAction::ZoomOut,
|
||||
ShortcutAction::ResetZoom,
|
||||
ShortcutAction::OpenDownloads,
|
||||
ShortcutAction::OpenHistory,
|
||||
ShortcutAction::OpenSettings,
|
||||
@@ -196,6 +211,12 @@ pub(crate) const SHORTCUT_BINDINGS: &[ShortcutBinding] = &[
|
||||
shortcut(ShortcutAction::RestoreClosedTab, ShortcutPlatform::WindowsLinux, "ctrl-shift-t"),
|
||||
shortcut(ShortcutAction::ToggleFavoriteTab, ShortcutPlatform::Macos, "cmd-shift-f"),
|
||||
shortcut(ShortcutAction::ToggleFavoriteTab, ShortcutPlatform::WindowsLinux, "ctrl-shift-f"),
|
||||
shortcut(ShortcutAction::ZoomIn, ShortcutPlatform::Macos, "cmd-="),
|
||||
shortcut(ShortcutAction::ZoomIn, ShortcutPlatform::WindowsLinux, "ctrl-="),
|
||||
shortcut(ShortcutAction::ZoomOut, ShortcutPlatform::Macos, "cmd--"),
|
||||
shortcut(ShortcutAction::ZoomOut, ShortcutPlatform::WindowsLinux, "ctrl--"),
|
||||
shortcut(ShortcutAction::ResetZoom, ShortcutPlatform::Macos, "cmd-0"),
|
||||
shortcut(ShortcutAction::ResetZoom, ShortcutPlatform::WindowsLinux, "ctrl-0"),
|
||||
shortcut(ShortcutAction::FocusCommandMode, ShortcutPlatform::Macos, "cmd-shift-p"),
|
||||
shortcut(ShortcutAction::FocusCommandMode, ShortcutPlatform::WindowsLinux, "ctrl-shift-p"),
|
||||
shortcut(ShortcutAction::SelectNextSpace, ShortcutPlatform::Macos, "cmd-alt-right"),
|
||||
@@ -243,6 +264,7 @@ pub(crate) fn key_binding_for_action(action: ShortcutAction, keystroke: &str) ->
|
||||
ShortcutAction::OpenSettings => KeyBinding::new(keystroke, OpenSettings, None),
|
||||
ShortcutAction::OpenTaskManager => KeyBinding::new(keystroke, OpenTaskManager, None),
|
||||
ShortcutAction::Quit => KeyBinding::new(keystroke, Quit, None),
|
||||
ShortcutAction::ResetZoom => KeyBinding::new(keystroke, ResetZoom, None),
|
||||
ShortcutAction::RestoreClosedTab => KeyBinding::new(keystroke, RestoreClosedTab, None),
|
||||
ShortcutAction::SelectNextSpace => KeyBinding::new(keystroke, SelectNextSpace, None),
|
||||
ShortcutAction::SelectNextTab => KeyBinding::new(keystroke, SelectNextTab, None),
|
||||
@@ -253,6 +275,8 @@ pub(crate) fn key_binding_for_action(action: ShortcutAction, keystroke: &str) ->
|
||||
ShortcutAction::SplitRight => KeyBinding::new(keystroke, SplitRight, None),
|
||||
ShortcutAction::ToggleFavoriteTab => KeyBinding::new(keystroke, ToggleFavoriteTab, None),
|
||||
ShortcutAction::ToggleSidebar => KeyBinding::new(keystroke, ToggleSidebar, None),
|
||||
ShortcutAction::ZoomIn => KeyBinding::new(keystroke, ZoomIn, None),
|
||||
ShortcutAction::ZoomOut => KeyBinding::new(keystroke, ZoomOut, None),
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user