mirror of
https://github.com/servo/servo.git
synced 2025-06-06 16:45:39 +00:00
libservo: Make zooming and HiDPI scaling work per-WebView
(#36419)
libservo: Make zooming and HiDPI scaling work per-`WebView` This change moves all zooming and HiDPI scaling to work per-`WebView` in both libservo and Compositor. This means that you can pinch zoom one `WebView` and it should now work independently of other `WebView`s. This is accomplished by making each `WebView` in the WebRender scene have its own scaling reference frame. All WebViews are now expected to manage their HiDPI scaling factor and this can be set independently of other WebViews. Perhaps in the future this will become a Servo-wide setting. This allows full removal of the `WindowMethods` trait from Servo. Testing: There are not yet any tests for the WebView API, but I hope to add those soon. Co-authored-by: Shubham Gupta <shubham13297@gmail.com> Signed-off-by: Martin Robinson <mrobinson@igalia.com> Signed-off-by: Martin Robinson <mrobinson@igalia.com> Co-authored-by: Shubham Gupta <shubham13297@gmail.com>
This commit is contained in:
parent
f1417c4e75
commit
c6dc7c83a8
17 changed files with 415 additions and 385 deletions
|
@ -21,16 +21,14 @@ use compositing_traits::rendering_context::RenderingContext;
|
|||
use compositing_traits::{
|
||||
CompositionPipeline, CompositorMsg, ImageUpdate, RendererWebView, SendableFrameTree,
|
||||
};
|
||||
use constellation_traits::{
|
||||
AnimationTickType, EmbedderToConstellationMessage, PaintMetricEvent, WindowSizeType,
|
||||
};
|
||||
use constellation_traits::{AnimationTickType, EmbedderToConstellationMessage, PaintMetricEvent};
|
||||
use crossbeam_channel::Sender;
|
||||
use dpi::PhysicalSize;
|
||||
use embedder_traits::{
|
||||
AnimationState, CompositorHitTestResult, Cursor, InputEvent, MouseButtonEvent, MouseMoveEvent,
|
||||
ScreenGeometry, ShutdownState, TouchEventType, UntrustedNodeAddress, ViewportDetails,
|
||||
ShutdownState, TouchEventType, UntrustedNodeAddress, ViewportDetails,
|
||||
};
|
||||
use euclid::{Box2D, Point2D, Rect, Scale, Size2D, Transform3D};
|
||||
use euclid::{Point2D, Rect, Scale, Size2D, Transform3D};
|
||||
use fnv::FnvHashMap;
|
||||
use ipc_channel::ipc::{self, IpcReceiver, IpcSharedMemory};
|
||||
use libc::c_void;
|
||||
|
@ -40,7 +38,7 @@ use profile_traits::time::{self as profile_time, ProfilerCategory};
|
|||
use profile_traits::time_profile;
|
||||
use servo_config::opts;
|
||||
use servo_geometry::DeviceIndependentPixel;
|
||||
use style_traits::{CSSPixel, PinchZoomFactor};
|
||||
use style_traits::CSSPixel;
|
||||
use webrender::{CaptureBits, RenderApi, Transaction};
|
||||
use webrender_api::units::{
|
||||
DeviceIntPoint, DeviceIntRect, DevicePixel, DevicePoint, DeviceRect, LayoutPoint, LayoutRect,
|
||||
|
@ -57,7 +55,7 @@ use webrender_api::{
|
|||
use crate::InitialCompositorState;
|
||||
use crate::webview::{UnknownWebView, WebView};
|
||||
use crate::webview_manager::WebViewManager;
|
||||
use crate::windowing::{WebRenderDebugOption, WindowMethods};
|
||||
use crate::windowing::WebRenderDebugOption;
|
||||
|
||||
#[derive(Debug, PartialEq)]
|
||||
enum UnableToComposite {
|
||||
|
@ -71,10 +69,6 @@ enum NotReadyToPaint {
|
|||
WaitingOnConstellation,
|
||||
}
|
||||
|
||||
// Default viewport constraints
|
||||
const MAX_ZOOM: f32 = 8.0;
|
||||
const MIN_ZOOM: f32 = 0.1;
|
||||
|
||||
/// Holds the state when running reftests that determines when it is
|
||||
/// safe to save the output image.
|
||||
#[derive(Clone, Copy, Debug, PartialEq)]
|
||||
|
@ -134,19 +128,6 @@ pub struct IOCompositor {
|
|||
/// Our top-level browsing contexts.
|
||||
webviews: WebViewManager<WebView>,
|
||||
|
||||
/// The application window.
|
||||
pub window: Rc<dyn WindowMethods>,
|
||||
|
||||
/// "Mobile-style" zoom that does not reflow the page.
|
||||
viewport_zoom: PinchZoomFactor,
|
||||
|
||||
/// Viewport zoom constraints provided by @viewport.
|
||||
min_viewport_zoom: Option<PinchZoomFactor>,
|
||||
max_viewport_zoom: Option<PinchZoomFactor>,
|
||||
|
||||
/// "Desktop-style" zoom that resizes the viewport to fit the window.
|
||||
page_zoom: Scale<f32, CSSPixel, DeviceIndependentPixel>,
|
||||
|
||||
/// Tracks whether or not the view needs to be repainted.
|
||||
needs_repaint: Cell<RepaintReason>,
|
||||
|
||||
|
@ -160,10 +141,6 @@ pub struct IOCompositor {
|
|||
/// The surfman instance that webrender targets
|
||||
rendering_context: Rc<dyn RenderingContext>,
|
||||
|
||||
/// The HighDPI factor of the native window, its view and the screen.
|
||||
/// TODO: Eventually this should be a property of the `WebView`.
|
||||
hidpi_factor: Scale<f32, DeviceIndependentPixel, DevicePixel>,
|
||||
|
||||
/// The number of frames pending to receive from WebRender.
|
||||
pending_frames: usize,
|
||||
|
||||
|
@ -413,11 +390,7 @@ impl ServoRenderer {
|
|||
}
|
||||
|
||||
impl IOCompositor {
|
||||
pub fn new(
|
||||
window: Rc<dyn WindowMethods>,
|
||||
state: InitialCompositorState,
|
||||
convert_mouse_to_touch: bool,
|
||||
) -> Self {
|
||||
pub fn new(state: InitialCompositorState, convert_mouse_to_touch: bool) -> Self {
|
||||
let compositor = IOCompositor {
|
||||
global: Rc::new(RefCell::new(ServoRenderer {
|
||||
shutdown_state: state.shutdown_state,
|
||||
|
@ -435,13 +408,7 @@ impl IOCompositor {
|
|||
cursor_pos: DevicePoint::new(0.0, 0.0),
|
||||
})),
|
||||
webviews: WebViewManager::default(),
|
||||
hidpi_factor: window.hidpi_factor(),
|
||||
window,
|
||||
needs_repaint: Cell::default(),
|
||||
page_zoom: Scale::new(1.0),
|
||||
viewport_zoom: PinchZoomFactor::new(1.0),
|
||||
min_viewport_zoom: Some(PinchZoomFactor::new(1.0)),
|
||||
max_viewport_zoom: None,
|
||||
ready_to_save_state: ReadyState::Unknown,
|
||||
webrender: Some(state.webrender),
|
||||
rendering_context: state.rendering_context,
|
||||
|
@ -467,15 +434,8 @@ impl IOCompositor {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn default_webview_viewport_details(&self) -> ViewportDetails {
|
||||
// The division by 1 represents the page's default zoom of 100%,
|
||||
// and gives us the appropriate CSSPixel type for the viewport.
|
||||
let hidpi_scale_factor = self.window.hidpi_factor();
|
||||
let scaled_viewport_size = self.rendering_context.size2d().to_f32() / hidpi_scale_factor;
|
||||
ViewportDetails {
|
||||
size: scaled_viewport_size / Scale::new(1.0),
|
||||
hidpi_scale_factor: Scale::new(hidpi_scale_factor.0),
|
||||
}
|
||||
pub fn rendering_context_size(&self) -> Size2D<u32, DevicePixel> {
|
||||
self.rendering_context.size2d()
|
||||
}
|
||||
|
||||
pub fn webxr_running(&self) -> bool {
|
||||
|
@ -577,8 +537,8 @@ impl IOCompositor {
|
|||
webview.on_touch_event_processed(result);
|
||||
},
|
||||
|
||||
CompositorMsg::CreatePng(page_rect, reply) => {
|
||||
let res = self.render_to_shared_memory(page_rect);
|
||||
CompositorMsg::CreatePng(webview_id, page_rect, reply) => {
|
||||
let res = self.render_to_shared_memory(webview_id, page_rect);
|
||||
if let Err(ref e) = res {
|
||||
info!("Error retrieving PNG: {:?}", e);
|
||||
}
|
||||
|
@ -646,12 +606,12 @@ impl IOCompositor {
|
|||
},
|
||||
|
||||
CompositorMsg::WebDriverMouseButtonEvent(webview_id, action, button, x, y) => {
|
||||
let dppx = self.device_pixels_per_page_pixel();
|
||||
let point = dppx.transform_point(Point2D::new(x, y));
|
||||
let Some(webview) = self.webviews.get_mut(webview_id) else {
|
||||
warn!("Handling input event for unknown webview: {webview_id}");
|
||||
return;
|
||||
};
|
||||
let dppx = webview.device_pixels_per_page_pixel();
|
||||
let point = dppx.transform_point(Point2D::new(x, y));
|
||||
webview.dispatch_input_event(InputEvent::MouseButton(MouseButtonEvent {
|
||||
point,
|
||||
action,
|
||||
|
@ -660,12 +620,12 @@ impl IOCompositor {
|
|||
},
|
||||
|
||||
CompositorMsg::WebDriverMouseMoveEvent(webview_id, x, y) => {
|
||||
let dppx = self.device_pixels_per_page_pixel();
|
||||
let point = dppx.transform_point(Point2D::new(x, y));
|
||||
let Some(webview) = self.webviews.get_mut(webview_id) else {
|
||||
warn!("Handling input event for unknown webview: {webview_id}");
|
||||
return;
|
||||
};
|
||||
let dppx = webview.device_pixels_per_page_pixel();
|
||||
let point = dppx.transform_point(Point2D::new(x, y));
|
||||
webview.dispatch_input_event(InputEvent::MouseMove(MouseMoveEvent { point }));
|
||||
},
|
||||
|
||||
|
@ -897,45 +857,38 @@ impl IOCompositor {
|
|||
let _ = result_sender.send((font_keys, font_instance_keys));
|
||||
},
|
||||
CompositorMsg::GetClientWindowRect(webview_id, response_sender) => {
|
||||
let screen_geometry = self.webview_screen_geometry(webview_id);
|
||||
let rect = DeviceIntRect::from_origin_and_size(
|
||||
screen_geometry.offset,
|
||||
self.rendering_context.size2d().to_i32(),
|
||||
)
|
||||
.to_f32() /
|
||||
self.hidpi_factor;
|
||||
|
||||
if let Err(error) = response_sender.send(rect.to_i32()) {
|
||||
let client_window_rect = self
|
||||
.webviews
|
||||
.get(webview_id)
|
||||
.map(|webview| webview.client_window_rect(self.rendering_context.size2d()))
|
||||
.unwrap_or_default();
|
||||
if let Err(error) = response_sender.send(client_window_rect) {
|
||||
warn!("Sending response to get client window failed ({error:?}).");
|
||||
}
|
||||
},
|
||||
CompositorMsg::GetScreenSize(webview_id, response_sender) => {
|
||||
let screen_geometry = self.webview_screen_geometry(webview_id);
|
||||
let screen_size = screen_geometry.size.to_f32() / self.hidpi_factor;
|
||||
|
||||
if let Err(error) = response_sender.send(screen_size.to_i32()) {
|
||||
let screen_size = self
|
||||
.webviews
|
||||
.get(webview_id)
|
||||
.map(WebView::screen_size)
|
||||
.unwrap_or_default();
|
||||
if let Err(error) = response_sender.send(screen_size) {
|
||||
warn!("Sending response to get screen size failed ({error:?}).");
|
||||
}
|
||||
},
|
||||
CompositorMsg::GetAvailableScreenSize(webview_id, response_sender) => {
|
||||
let screen_geometry = self.webview_screen_geometry(webview_id);
|
||||
let available_screen_size =
|
||||
screen_geometry.available_size.to_f32() / self.hidpi_factor;
|
||||
|
||||
if let Err(error) = response_sender.send(available_screen_size.to_i32()) {
|
||||
let available_screen_size = self
|
||||
.webviews
|
||||
.get(webview_id)
|
||||
.map(WebView::available_screen_size)
|
||||
.unwrap_or_default();
|
||||
if let Err(error) = response_sender.send(available_screen_size) {
|
||||
warn!("Sending response to get screen size failed ({error:?}).");
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
fn webview_screen_geometry(&self, webview_id: WebViewId) -> ScreenGeometry {
|
||||
self.webviews
|
||||
.get(webview_id)
|
||||
.and_then(|webview| webview.renderer_webview.screen_geometry())
|
||||
.unwrap_or_default()
|
||||
}
|
||||
|
||||
/// Handle messages sent to the compositor during the shutdown process. In general,
|
||||
/// the things the compositor can do in this state are limited. It's very important to
|
||||
/// answer any synchronous messages though as other threads might be waiting on the
|
||||
|
@ -1035,43 +988,50 @@ impl IOCompositor {
|
|||
let mut builder = webrender_api::DisplayListBuilder::new(root_pipeline);
|
||||
builder.begin();
|
||||
|
||||
let zoom_factor = self.device_pixels_per_page_pixel().0;
|
||||
let zoom_reference_frame = builder.push_reference_frame(
|
||||
let root_reference_frame = SpatialId::root_reference_frame(root_pipeline);
|
||||
|
||||
let viewport_size = self.rendering_context.size2d().to_f32().to_untyped();
|
||||
let viewport_rect = LayoutRect::from_origin_and_size(
|
||||
LayoutPoint::zero(),
|
||||
SpatialId::root_reference_frame(root_pipeline),
|
||||
TransformStyle::Flat,
|
||||
PropertyBinding::Value(Transform3D::scale(zoom_factor, zoom_factor, 1.)),
|
||||
ReferenceFrameKind::Transform {
|
||||
is_2d_scale_translation: true,
|
||||
should_snap: true,
|
||||
paired_with_perspective: false,
|
||||
},
|
||||
SpatialTreeItemKey::new(0, 0),
|
||||
LayoutSize::from_untyped(viewport_size),
|
||||
);
|
||||
|
||||
let scaled_viewport_size =
|
||||
self.rendering_context.size2d().to_f32().to_untyped() / zoom_factor;
|
||||
let scaled_viewport_rect = LayoutRect::from_origin_and_size(
|
||||
LayoutPoint::zero(),
|
||||
LayoutSize::from_untyped(scaled_viewport_size),
|
||||
);
|
||||
|
||||
let root_clip_id = builder.define_clip_rect(zoom_reference_frame, scaled_viewport_rect);
|
||||
let root_clip_id = builder.define_clip_rect(root_reference_frame, viewport_rect);
|
||||
let clip_chain_id = builder.define_clip_chain(None, [root_clip_id]);
|
||||
for (_, webview) in self.webviews.painting_order() {
|
||||
if let Some(pipeline_id) = webview.root_pipeline_id {
|
||||
let scaled_webview_rect = webview.rect / zoom_factor;
|
||||
builder.push_iframe(
|
||||
LayoutRect::from_untyped(&scaled_webview_rect.to_untyped()),
|
||||
LayoutRect::from_untyped(&scaled_webview_rect.to_untyped()),
|
||||
&SpaceAndClipInfo {
|
||||
spatial_id: zoom_reference_frame,
|
||||
clip_chain_id,
|
||||
},
|
||||
pipeline_id.into(),
|
||||
true,
|
||||
);
|
||||
}
|
||||
let Some(pipeline_id) = webview.root_pipeline_id else {
|
||||
continue;
|
||||
};
|
||||
|
||||
let device_pixels_per_page_pixel = webview.device_pixels_per_page_pixel().0;
|
||||
let webview_reference_frame = builder.push_reference_frame(
|
||||
LayoutPoint::zero(),
|
||||
root_reference_frame,
|
||||
TransformStyle::Flat,
|
||||
PropertyBinding::Value(Transform3D::scale(
|
||||
device_pixels_per_page_pixel,
|
||||
device_pixels_per_page_pixel,
|
||||
1.,
|
||||
)),
|
||||
ReferenceFrameKind::Transform {
|
||||
is_2d_scale_translation: true,
|
||||
should_snap: true,
|
||||
paired_with_perspective: false,
|
||||
},
|
||||
SpatialTreeItemKey::new(0, 0),
|
||||
);
|
||||
|
||||
let scaled_webview_rect = webview.rect / device_pixels_per_page_pixel;
|
||||
builder.push_iframe(
|
||||
LayoutRect::from_untyped(&scaled_webview_rect.to_untyped()),
|
||||
LayoutRect::from_untyped(&scaled_webview_rect.to_untyped()),
|
||||
&SpaceAndClipInfo {
|
||||
spatial_id: webview_reference_frame,
|
||||
clip_chain_id,
|
||||
},
|
||||
pipeline_id.into(),
|
||||
true,
|
||||
);
|
||||
}
|
||||
|
||||
let built_display_list = builder.end();
|
||||
|
@ -1113,12 +1073,15 @@ impl IOCompositor {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn add_webview(&mut self, webview: Box<dyn RendererWebView>) {
|
||||
let size = self.rendering_context.size2d().to_f32();
|
||||
pub fn add_webview(
|
||||
&mut self,
|
||||
webview: Box<dyn RendererWebView>,
|
||||
viewport_details: ViewportDetails,
|
||||
) {
|
||||
self.webviews.entry(webview.id()).or_insert(WebView::new(
|
||||
webview,
|
||||
Box2D::from_origin_and_size(Point2D::origin(), size),
|
||||
self.global.clone(),
|
||||
webview,
|
||||
viewport_details,
|
||||
));
|
||||
}
|
||||
|
||||
|
@ -1147,31 +1110,6 @@ impl IOCompositor {
|
|||
self.send_root_pipeline_display_list();
|
||||
}
|
||||
|
||||
pub fn move_resize_webview(&mut self, webview_id: WebViewId, rect: DeviceRect) {
|
||||
debug!("{webview_id}: Moving and/or resizing webview; rect={rect:?}");
|
||||
let rect_changed;
|
||||
let size_changed;
|
||||
match self.webviews.get_mut(webview_id) {
|
||||
Some(webview) => {
|
||||
rect_changed = rect != webview.rect;
|
||||
size_changed = rect.size() != webview.rect.size();
|
||||
webview.rect = rect;
|
||||
},
|
||||
None => {
|
||||
warn!("{webview_id}: MoveResizeWebView on unknown webview id");
|
||||
return;
|
||||
},
|
||||
};
|
||||
|
||||
if rect_changed {
|
||||
if size_changed {
|
||||
self.send_window_size_message_for_top_level_browser_context(rect, webview_id);
|
||||
}
|
||||
|
||||
self.send_root_pipeline_display_list();
|
||||
}
|
||||
}
|
||||
|
||||
pub fn show_webview(
|
||||
&mut self,
|
||||
webview_id: WebViewId,
|
||||
|
@ -1228,37 +1166,46 @@ impl IOCompositor {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
fn send_window_size_message_for_top_level_browser_context(
|
||||
&self,
|
||||
rect: DeviceRect,
|
||||
webview_id: WebViewId,
|
||||
) {
|
||||
// The device pixel ratio used by the style system should include the scale from page pixels
|
||||
// to device pixels, but not including any pinch zoom.
|
||||
let hidpi_scale_factor = self.device_pixels_per_page_pixel_not_including_page_zoom();
|
||||
let size = rect.size().to_f32() / hidpi_scale_factor;
|
||||
let msg = EmbedderToConstellationMessage::ChangeViewportDetails(
|
||||
webview_id,
|
||||
ViewportDetails {
|
||||
size,
|
||||
hidpi_scale_factor,
|
||||
},
|
||||
WindowSizeType::Resize,
|
||||
);
|
||||
if let Err(e) = self.global.borrow().constellation_sender.send(msg) {
|
||||
warn!("Sending window resize to constellation failed ({:?}).", e);
|
||||
pub fn move_resize_webview(&mut self, webview_id: WebViewId, rect: DeviceRect) {
|
||||
if self.global.borrow().shutdown_state() != ShutdownState::NotShuttingDown {
|
||||
return;
|
||||
}
|
||||
let Some(webview) = self.webviews.get_mut(webview_id) else {
|
||||
return;
|
||||
};
|
||||
if !webview.set_rect(rect) {
|
||||
return;
|
||||
}
|
||||
|
||||
self.send_root_pipeline_display_list();
|
||||
self.set_needs_repaint(RepaintReason::Resize);
|
||||
}
|
||||
|
||||
pub fn resize_rendering_context(&mut self, new_size: PhysicalSize<u32>) -> bool {
|
||||
pub fn set_hidpi_scale_factor(
|
||||
&mut self,
|
||||
webview_id: WebViewId,
|
||||
new_scale_factor: Scale<f32, DeviceIndependentPixel, DevicePixel>,
|
||||
) {
|
||||
if self.global.borrow().shutdown_state() != ShutdownState::NotShuttingDown {
|
||||
return false;
|
||||
return;
|
||||
}
|
||||
let Some(webview) = self.webviews.get_mut(webview_id) else {
|
||||
return;
|
||||
};
|
||||
if !webview.set_hidpi_scale_factor(new_scale_factor) {
|
||||
return;
|
||||
}
|
||||
|
||||
let old_hidpi_factor = self.hidpi_factor;
|
||||
self.hidpi_factor = self.window.hidpi_factor();
|
||||
if self.hidpi_factor == old_hidpi_factor && self.rendering_context.size() == new_size {
|
||||
return false;
|
||||
self.send_root_pipeline_display_list();
|
||||
self.set_needs_repaint(RepaintReason::Resize);
|
||||
}
|
||||
|
||||
pub fn resize_rendering_context(&mut self, new_size: PhysicalSize<u32>) {
|
||||
if self.global.borrow().shutdown_state() != ShutdownState::NotShuttingDown {
|
||||
return;
|
||||
}
|
||||
if self.rendering_context.size() == new_size {
|
||||
return;
|
||||
}
|
||||
|
||||
self.rendering_context.resize(new_size);
|
||||
|
@ -1271,9 +1218,8 @@ impl IOCompositor {
|
|||
transaction.set_document_view(output_region);
|
||||
self.global.borrow_mut().send_transaction(transaction);
|
||||
|
||||
self.update_after_zoom_or_hidpi_change();
|
||||
self.send_root_pipeline_display_list();
|
||||
self.set_needs_repaint(RepaintReason::Resize);
|
||||
true
|
||||
}
|
||||
|
||||
/// If there are any animations running, dispatches appropriate messages to the constellation.
|
||||
|
@ -1294,41 +1240,25 @@ impl IOCompositor {
|
|||
}
|
||||
}
|
||||
|
||||
pub(crate) fn device_pixels_per_page_pixel(&self) -> Scale<f32, CSSPixel, DevicePixel> {
|
||||
self.device_pixels_per_page_pixel_not_including_page_zoom() * self.pinch_zoom_level()
|
||||
}
|
||||
|
||||
fn device_pixels_per_page_pixel_not_including_page_zoom(
|
||||
&self,
|
||||
) -> Scale<f32, CSSPixel, DevicePixel> {
|
||||
self.page_zoom * self.hidpi_factor
|
||||
}
|
||||
|
||||
pub fn on_zoom_reset_window_event(&mut self) {
|
||||
pub fn on_zoom_reset_window_event(&mut self, webview_id: WebViewId) {
|
||||
if self.global.borrow().shutdown_state() != ShutdownState::NotShuttingDown {
|
||||
return;
|
||||
}
|
||||
|
||||
self.page_zoom = Scale::new(1.0);
|
||||
self.update_after_zoom_or_hidpi_change();
|
||||
if let Some(webview) = self.webviews.get_mut(webview_id) {
|
||||
webview.set_page_zoom(1.0);
|
||||
}
|
||||
self.send_root_pipeline_display_list();
|
||||
}
|
||||
|
||||
pub fn on_zoom_window_event(&mut self, magnification: f32) {
|
||||
pub fn on_zoom_window_event(&mut self, webview_id: WebViewId, magnification: f32) {
|
||||
if self.global.borrow().shutdown_state() != ShutdownState::NotShuttingDown {
|
||||
return;
|
||||
}
|
||||
|
||||
self.page_zoom =
|
||||
Scale::new((self.page_zoom.get() * magnification).clamp(MIN_ZOOM, MAX_ZOOM));
|
||||
self.update_after_zoom_or_hidpi_change();
|
||||
}
|
||||
|
||||
fn update_after_zoom_or_hidpi_change(&mut self) {
|
||||
for (webview_id, webview) in self.webviews.painting_order() {
|
||||
self.send_window_size_message_for_top_level_browser_context(webview.rect, *webview_id);
|
||||
if let Some(webview) = self.webviews.get_mut(webview_id) {
|
||||
webview.set_page_zoom(magnification);
|
||||
}
|
||||
|
||||
// Update the root transform in WebRender to reflect the new zoom.
|
||||
self.send_root_pipeline_display_list();
|
||||
}
|
||||
|
||||
|
@ -1428,13 +1358,19 @@ impl IOCompositor {
|
|||
/// [`IOCompositor`]. If succesful return the output image in shared memory.
|
||||
fn render_to_shared_memory(
|
||||
&mut self,
|
||||
webview_id: WebViewId,
|
||||
page_rect: Option<Rect<f32, CSSPixel>>,
|
||||
) -> Result<Option<Image>, UnableToComposite> {
|
||||
self.render_inner()?;
|
||||
|
||||
let size = self.rendering_context.size2d().to_i32();
|
||||
let rect = if let Some(rect) = page_rect {
|
||||
let rect = self.device_pixels_per_page_pixel().transform_rect(&rect);
|
||||
let scale = self
|
||||
.webviews
|
||||
.get(webview_id)
|
||||
.map(WebView::device_pixels_per_page_pixel)
|
||||
.unwrap_or_else(|| Scale::new(1.0));
|
||||
let rect = scale.transform_rect(&rect);
|
||||
|
||||
let x = rect.origin.x as i32;
|
||||
// We need to convert to the bottom-left origin coordinate
|
||||
|
@ -1676,22 +1612,6 @@ impl IOCompositor {
|
|||
self.global.borrow().shutdown_state() != ShutdownState::FinishedShuttingDown
|
||||
}
|
||||
|
||||
pub fn pinch_zoom_level(&self) -> Scale<f32, DevicePixel, DevicePixel> {
|
||||
Scale::new(self.viewport_zoom.get())
|
||||
}
|
||||
|
||||
pub(crate) fn set_pinch_zoom_level(&mut self, mut zoom: f32) -> bool {
|
||||
if let Some(min) = self.min_viewport_zoom {
|
||||
zoom = f32::max(min.get(), zoom);
|
||||
}
|
||||
if let Some(max) = self.max_viewport_zoom {
|
||||
zoom = f32::min(max.get(), zoom);
|
||||
}
|
||||
|
||||
let old_zoom = std::mem::replace(&mut self.viewport_zoom, PinchZoomFactor::new(zoom));
|
||||
old_zoom != self.viewport_zoom
|
||||
}
|
||||
|
||||
pub fn toggle_webrender_debug(&mut self, option: WebRenderDebugOption) {
|
||||
let Some(webrender) = self.webrender.as_mut() else {
|
||||
return;
|
||||
|
|
|
@ -9,17 +9,21 @@ use std::rc::Rc;
|
|||
|
||||
use base::id::{PipelineId, WebViewId};
|
||||
use compositing_traits::{RendererWebView, SendableFrameTree};
|
||||
use constellation_traits::{EmbedderToConstellationMessage, ScrollState};
|
||||
use constellation_traits::{EmbedderToConstellationMessage, ScrollState, WindowSizeType};
|
||||
use embedder_traits::{
|
||||
AnimationState, CompositorHitTestResult, InputEvent, MouseButton, MouseButtonAction,
|
||||
MouseButtonEvent, MouseMoveEvent, ShutdownState, TouchEvent, TouchEventResult, TouchEventType,
|
||||
TouchId,
|
||||
TouchId, ViewportDetails,
|
||||
};
|
||||
use euclid::{Point2D, Scale, Vector2D};
|
||||
use euclid::{Box2D, Point2D, Scale, Size2D, Vector2D};
|
||||
use fnv::FnvHashSet;
|
||||
use log::{debug, warn};
|
||||
use servo_geometry::DeviceIndependentPixel;
|
||||
use style_traits::{CSSPixel, PinchZoomFactor};
|
||||
use webrender::Transaction;
|
||||
use webrender_api::units::{DeviceIntPoint, DevicePoint, DeviceRect, LayoutVector2D};
|
||||
use webrender_api::units::{
|
||||
DeviceIntPoint, DeviceIntRect, DevicePixel, DevicePoint, DeviceRect, LayoutVector2D,
|
||||
};
|
||||
use webrender_api::{
|
||||
ExternalScrollId, HitTestFlags, RenderReasons, SampledScrollOffset, ScrollLocation,
|
||||
};
|
||||
|
@ -28,6 +32,10 @@ use crate::IOCompositor;
|
|||
use crate::compositor::{PipelineDetails, ServoRenderer};
|
||||
use crate::touch::{TouchHandler, TouchMoveAction, TouchMoveAllowed, TouchSequenceState};
|
||||
|
||||
// Default viewport constraints
|
||||
const MAX_ZOOM: f32 = 8.0;
|
||||
const MIN_ZOOM: f32 = 0.1;
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
struct ScrollEvent {
|
||||
/// Scroll by this offset, or to Start or End
|
||||
|
@ -65,6 +73,16 @@ pub(crate) struct WebView {
|
|||
pending_scroll_zoom_events: Vec<ScrollZoomEvent>,
|
||||
/// Touch input state machine
|
||||
touch_handler: TouchHandler,
|
||||
/// "Desktop-style" zoom that resizes the viewport to fit the window.
|
||||
pub page_zoom: Scale<f32, CSSPixel, DeviceIndependentPixel>,
|
||||
/// "Mobile-style" zoom that does not reflow the page.
|
||||
viewport_zoom: PinchZoomFactor,
|
||||
/// Viewport zoom constraints provided by @viewport.
|
||||
min_viewport_zoom: Option<PinchZoomFactor>,
|
||||
max_viewport_zoom: Option<PinchZoomFactor>,
|
||||
/// The HiDPI scale factor for the `WebView` associated with this renderer. This is controlled
|
||||
/// by the embedding layer.
|
||||
hidpi_scale_factor: Scale<f32, DeviceIndependentPixel, DevicePixel>,
|
||||
}
|
||||
|
||||
impl Drop for WebView {
|
||||
|
@ -78,19 +96,26 @@ impl Drop for WebView {
|
|||
|
||||
impl WebView {
|
||||
pub(crate) fn new(
|
||||
renderer_webview: Box<dyn RendererWebView>,
|
||||
rect: DeviceRect,
|
||||
global: Rc<RefCell<ServoRenderer>>,
|
||||
renderer_webview: Box<dyn RendererWebView>,
|
||||
viewport_details: ViewportDetails,
|
||||
) -> Self {
|
||||
let hidpi_scale_factor = viewport_details.hidpi_scale_factor;
|
||||
let size = viewport_details.size * viewport_details.hidpi_scale_factor;
|
||||
Self {
|
||||
id: renderer_webview.id(),
|
||||
renderer_webview,
|
||||
root_pipeline_id: None,
|
||||
rect,
|
||||
rect: DeviceRect::from_origin_and_size(DevicePoint::origin(), size),
|
||||
pipelines: Default::default(),
|
||||
touch_handler: TouchHandler::new(),
|
||||
global,
|
||||
pending_scroll_zoom_events: Default::default(),
|
||||
page_zoom: Scale::new(1.0),
|
||||
viewport_zoom: PinchZoomFactor::new(1.0),
|
||||
min_viewport_zoom: Some(PinchZoomFactor::new(1.0)),
|
||||
max_viewport_zoom: None,
|
||||
hidpi_scale_factor: Scale::new(hidpi_scale_factor.0),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -265,7 +290,7 @@ impl WebView {
|
|||
}
|
||||
|
||||
/// On a Window refresh tick (e.g. vsync)
|
||||
pub fn on_vsync(&mut self) {
|
||||
pub(crate) fn on_vsync(&mut self) {
|
||||
if let Some(fling_action) = self.touch_handler.on_vsync() {
|
||||
self.on_scroll_window_event(
|
||||
ScrollLocation::Delta(fling_action.delta),
|
||||
|
@ -300,7 +325,7 @@ impl WebView {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn notify_input_event(&mut self, event: InputEvent) {
|
||||
pub(crate) fn notify_input_event(&mut self, event: InputEvent) {
|
||||
if self.global.borrow().shutdown_state() != ShutdownState::NotShuttingDown {
|
||||
return;
|
||||
}
|
||||
|
@ -365,7 +390,7 @@ impl WebView {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn on_touch_event(&mut self, event: TouchEvent) {
|
||||
pub(crate) fn on_touch_event(&mut self, event: TouchEvent) {
|
||||
if self.global.borrow().shutdown_state() != ShutdownState::NotShuttingDown {
|
||||
return;
|
||||
}
|
||||
|
@ -644,7 +669,7 @@ impl WebView {
|
|||
}));
|
||||
}
|
||||
|
||||
pub fn notify_scroll_event(
|
||||
pub(crate) fn notify_scroll_event(
|
||||
&mut self,
|
||||
scroll_location: ScrollLocation,
|
||||
cursor: DeviceIntPoint,
|
||||
|
@ -727,13 +752,12 @@ impl WebView {
|
|||
}
|
||||
}
|
||||
|
||||
let zoom_changed = compositor
|
||||
.set_pinch_zoom_level(compositor.pinch_zoom_level().get() * combined_magnification);
|
||||
let zoom_changed =
|
||||
self.set_pinch_zoom_level(self.pinch_zoom_level().get() * combined_magnification);
|
||||
let scroll_result = combined_scroll_event.and_then(|combined_event| {
|
||||
self.scroll_node_at_device_point(
|
||||
combined_event.cursor.to_f32(),
|
||||
combined_event.scroll_location,
|
||||
compositor,
|
||||
)
|
||||
});
|
||||
if !zoom_changed && scroll_result.is_none() {
|
||||
|
@ -769,11 +793,10 @@ impl WebView {
|
|||
&mut self,
|
||||
cursor: DevicePoint,
|
||||
scroll_location: ScrollLocation,
|
||||
compositor: &mut IOCompositor,
|
||||
) -> Option<(PipelineId, ExternalScrollId, LayoutVector2D)> {
|
||||
let scroll_location = match scroll_location {
|
||||
ScrollLocation::Delta(delta) => {
|
||||
let device_pixels_per_page = compositor.device_pixels_per_page_pixel();
|
||||
let device_pixels_per_page = self.device_pixels_per_page_pixel();
|
||||
let scaled_delta = (Vector2D::from_untyped(delta.to_untyped()) /
|
||||
device_pixels_per_page)
|
||||
.to_untyped();
|
||||
|
@ -818,8 +841,39 @@ impl WebView {
|
|||
None
|
||||
}
|
||||
|
||||
pub(crate) fn pinch_zoom_level(&self) -> Scale<f32, DevicePixel, DevicePixel> {
|
||||
Scale::new(self.viewport_zoom.get())
|
||||
}
|
||||
|
||||
fn set_pinch_zoom_level(&mut self, mut zoom: f32) -> bool {
|
||||
if let Some(min) = self.min_viewport_zoom {
|
||||
zoom = f32::max(min.get(), zoom);
|
||||
}
|
||||
if let Some(max) = self.max_viewport_zoom {
|
||||
zoom = f32::min(max.get(), zoom);
|
||||
}
|
||||
|
||||
let old_zoom = std::mem::replace(&mut self.viewport_zoom, PinchZoomFactor::new(zoom));
|
||||
old_zoom != self.viewport_zoom
|
||||
}
|
||||
|
||||
pub(crate) fn set_page_zoom(&mut self, magnification: f32) {
|
||||
self.page_zoom =
|
||||
Scale::new((self.page_zoom.get() * magnification).clamp(MIN_ZOOM, MAX_ZOOM));
|
||||
}
|
||||
|
||||
pub(crate) fn device_pixels_per_page_pixel(&self) -> Scale<f32, CSSPixel, DevicePixel> {
|
||||
self.page_zoom * self.hidpi_scale_factor * self.pinch_zoom_level()
|
||||
}
|
||||
|
||||
pub(crate) fn device_pixels_per_page_pixel_not_including_pinch_zoom(
|
||||
&self,
|
||||
) -> Scale<f32, CSSPixel, DevicePixel> {
|
||||
self.page_zoom * self.hidpi_scale_factor
|
||||
}
|
||||
|
||||
/// Simulate a pinch zoom
|
||||
pub fn set_pinch_zoom(&mut self, magnification: f32) {
|
||||
pub(crate) fn set_pinch_zoom(&mut self, magnification: f32) {
|
||||
if self.global.borrow().shutdown_state() != ShutdownState::NotShuttingDown {
|
||||
return;
|
||||
}
|
||||
|
@ -828,6 +882,71 @@ impl WebView {
|
|||
self.pending_scroll_zoom_events
|
||||
.push(ScrollZoomEvent::PinchZoom(magnification));
|
||||
}
|
||||
|
||||
fn send_window_size_message(&self) {
|
||||
// The device pixel ratio used by the style system should include the scale from page pixels
|
||||
// to device pixels, but not including any pinch zoom.
|
||||
let device_pixel_ratio = self.device_pixels_per_page_pixel_not_including_pinch_zoom();
|
||||
let initial_viewport = self.rect.size().to_f32() / device_pixel_ratio;
|
||||
let msg = EmbedderToConstellationMessage::ChangeViewportDetails(
|
||||
self.id,
|
||||
ViewportDetails {
|
||||
hidpi_scale_factor: device_pixel_ratio,
|
||||
size: initial_viewport,
|
||||
},
|
||||
WindowSizeType::Resize,
|
||||
);
|
||||
if let Err(e) = self.global.borrow().constellation_sender.send(msg) {
|
||||
warn!("Sending window resize to constellation failed ({:?}).", e);
|
||||
}
|
||||
}
|
||||
|
||||
/// Set the `hidpi_scale_factor` for this renderer, returning `true` if the value actually changed.
|
||||
pub(crate) fn set_hidpi_scale_factor(
|
||||
&mut self,
|
||||
new_scale: Scale<f32, DeviceIndependentPixel, DevicePixel>,
|
||||
) -> bool {
|
||||
let old_scale_factor = std::mem::replace(&mut self.hidpi_scale_factor, new_scale);
|
||||
if self.hidpi_scale_factor == old_scale_factor {
|
||||
return false;
|
||||
}
|
||||
|
||||
self.send_window_size_message();
|
||||
true
|
||||
}
|
||||
|
||||
/// Set the `rect` for this renderer, returning `true` if the value actually changed.
|
||||
pub(crate) fn set_rect(&mut self, new_rect: DeviceRect) -> bool {
|
||||
let old_rect = std::mem::replace(&mut self.rect, new_rect);
|
||||
if old_rect.size() != self.rect.size() {
|
||||
self.send_window_size_message();
|
||||
}
|
||||
old_rect != self.rect
|
||||
}
|
||||
|
||||
pub(crate) fn client_window_rect(
|
||||
&self,
|
||||
rendering_context_size: Size2D<u32, DevicePixel>,
|
||||
) -> Box2D<i32, DeviceIndependentPixel> {
|
||||
let screen_geometry = self.renderer_webview.screen_geometry().unwrap_or_default();
|
||||
let rect = DeviceIntRect::from_origin_and_size(
|
||||
screen_geometry.offset,
|
||||
rendering_context_size.to_i32(),
|
||||
)
|
||||
.to_f32() /
|
||||
self.hidpi_scale_factor;
|
||||
rect.to_i32()
|
||||
}
|
||||
|
||||
pub(crate) fn screen_size(&self) -> Size2D<i32, DeviceIndependentPixel> {
|
||||
let screen_geometry = self.renderer_webview.screen_geometry().unwrap_or_default();
|
||||
(screen_geometry.size.to_f32() / self.hidpi_scale_factor).to_i32()
|
||||
}
|
||||
|
||||
pub(crate) fn available_screen_size(&self) -> Size2D<i32, DeviceIndependentPixel> {
|
||||
let screen_geometry = self.renderer_webview.screen_geometry().unwrap_or_default();
|
||||
(screen_geometry.available_size.to_f32() / self.hidpi_scale_factor).to_i32()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, PartialEq)]
|
||||
|
|
|
@ -5,10 +5,8 @@
|
|||
//! Abstract windowing methods. The concrete implementations of these can be found in `platform/`.
|
||||
|
||||
use embedder_traits::{EventLoopWaker, MouseButton};
|
||||
use euclid::Scale;
|
||||
use net::protocols::ProtocolRegistry;
|
||||
use servo_geometry::DeviceIndependentPixel;
|
||||
use webrender_api::units::{DevicePixel, DevicePoint};
|
||||
use webrender_api::units::DevicePoint;
|
||||
|
||||
#[derive(Clone)]
|
||||
pub enum MouseWindowEvent {
|
||||
|
@ -25,15 +23,6 @@ pub enum WebRenderDebugOption {
|
|||
RenderTargetDebug,
|
||||
}
|
||||
|
||||
// TODO: this trait assumes that the window is responsible
|
||||
// for creating the GL context, making it current, buffer
|
||||
// swapping, etc. Really that should all be done by surfman.
|
||||
pub trait WindowMethods {
|
||||
/// Get the HighDPI factor of the native window, the screen and the framebuffer.
|
||||
/// TODO(martin): Move this to `RendererWebView` when possible.
|
||||
fn hidpi_factor(&self) -> Scale<f32, DeviceIndependentPixel, DevicePixel>;
|
||||
}
|
||||
|
||||
pub trait EmbedderMethods {
|
||||
/// Returns a thread-safe object to wake up the window's event loop.
|
||||
fn create_event_loop_waker(&mut self) -> Box<dyn EventLoopWaker>;
|
||||
|
|
|
@ -4588,9 +4588,12 @@ where
|
|||
self.compositor_proxy
|
||||
.send(CompositorMsg::WebDriverMouseMoveEvent(webview_id, x, y));
|
||||
},
|
||||
WebDriverCommandMsg::TakeScreenshot(_, rect, response_sender) => {
|
||||
self.compositor_proxy
|
||||
.send(CompositorMsg::CreatePng(rect, response_sender));
|
||||
WebDriverCommandMsg::TakeScreenshot(webview_id, rect, response_sender) => {
|
||||
self.compositor_proxy.send(CompositorMsg::CreatePng(
|
||||
webview_id,
|
||||
rect,
|
||||
response_sender,
|
||||
));
|
||||
},
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,18 +5,17 @@ use std::cell::RefCell;
|
|||
use std::error::Error;
|
||||
use std::rc::Rc;
|
||||
|
||||
use compositing::windowing::{EmbedderMethods, WindowMethods};
|
||||
use euclid::{Point2D, Scale, Size2D};
|
||||
use compositing::windowing::EmbedderMethods;
|
||||
use euclid::{Scale, Size2D};
|
||||
use servo::{
|
||||
RenderingContext, Servo, TouchEventType, WebView, WebViewBuilder, WindowRenderingContext,
|
||||
};
|
||||
use servo_geometry::DeviceIndependentPixel;
|
||||
use tracing::warn;
|
||||
use url::Url;
|
||||
use webrender_api::ScrollLocation;
|
||||
use webrender_api::units::{DeviceIntPoint, DevicePixel, LayoutVector2D};
|
||||
use winit::application::ApplicationHandler;
|
||||
use winit::dpi::{PhysicalPosition, PhysicalSize};
|
||||
use winit::dpi::PhysicalSize;
|
||||
use winit::event::{MouseScrollDelta, WindowEvent};
|
||||
use winit::event_loop::EventLoop;
|
||||
use winit::raw_window_handle::{HasDisplayHandle, HasWindowHandle};
|
||||
|
@ -43,7 +42,7 @@ fn main() -> Result<(), Box<dyn Error>> {
|
|||
}
|
||||
|
||||
struct AppState {
|
||||
window_delegate: Rc<WindowDelegate>,
|
||||
window: Window,
|
||||
servo: Servo,
|
||||
rendering_context: Rc<WindowRenderingContext>,
|
||||
webviews: RefCell<Vec<WebView>>,
|
||||
|
@ -51,15 +50,17 @@ struct AppState {
|
|||
|
||||
impl ::servo::WebViewDelegate for AppState {
|
||||
fn notify_new_frame_ready(&self, _: WebView) {
|
||||
self.window_delegate.window.request_redraw();
|
||||
self.window.request_redraw();
|
||||
}
|
||||
|
||||
fn request_open_auxiliary_webview(&self, parent_webview: WebView) -> Option<WebView> {
|
||||
let webview = WebViewBuilder::new_auxiliary(&self.servo)
|
||||
.hidpi_scale_factor(Scale::new(self.window.scale_factor() as f32))
|
||||
.delegate(parent_webview.delegate())
|
||||
.build();
|
||||
webview.focus();
|
||||
webview.raise_to_top(true);
|
||||
|
||||
self.webviews.borrow_mut().push(webview.clone());
|
||||
Some(webview)
|
||||
}
|
||||
|
@ -91,7 +92,6 @@ impl ApplicationHandler<WakerEvent> for App {
|
|||
WindowRenderingContext::new(display_handle, window_handle, window.inner_size())
|
||||
.expect("Could not create RenderingContext for window."),
|
||||
);
|
||||
let window_delegate = Rc::new(WindowDelegate::new(window));
|
||||
|
||||
let _ = rendering_context.make_current();
|
||||
|
||||
|
@ -102,13 +102,12 @@ impl ApplicationHandler<WakerEvent> for App {
|
|||
Box::new(EmbedderDelegate {
|
||||
waker: waker.clone(),
|
||||
}),
|
||||
window_delegate.clone(),
|
||||
Default::default(),
|
||||
);
|
||||
servo.setup_logging();
|
||||
|
||||
let app_state = Rc::new(AppState {
|
||||
window_delegate,
|
||||
window,
|
||||
servo,
|
||||
rendering_context,
|
||||
webviews: Default::default(),
|
||||
|
@ -120,8 +119,10 @@ impl ApplicationHandler<WakerEvent> for App {
|
|||
|
||||
let webview = WebViewBuilder::new(&app_state.servo)
|
||||
.url(url)
|
||||
.hidpi_scale_factor(Scale::new(app_state.window.scale_factor() as f32))
|
||||
.delegate(app_state.clone())
|
||||
.build();
|
||||
|
||||
webview.focus();
|
||||
webview.raise_to_top(true);
|
||||
|
||||
|
@ -239,26 +240,6 @@ impl embedder_traits::EventLoopWaker for Waker {
|
|||
}
|
||||
}
|
||||
|
||||
struct WindowDelegate {
|
||||
window: Window,
|
||||
}
|
||||
|
||||
impl WindowDelegate {
|
||||
fn new(window: Window) -> Self {
|
||||
Self { window }
|
||||
}
|
||||
}
|
||||
|
||||
impl WindowMethods for WindowDelegate {
|
||||
fn hidpi_factor(&self) -> Scale<f32, DeviceIndependentPixel, DevicePixel> {
|
||||
Scale::new(self.window.scale_factor() as f32)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn winit_size_to_euclid_size<T>(size: PhysicalSize<T>) -> Size2D<T, DevicePixel> {
|
||||
Size2D::new(size.width, size.height)
|
||||
}
|
||||
|
||||
pub fn winit_position_to_euclid_point<T>(position: PhysicalPosition<T>) -> Point2D<T, DevicePixel> {
|
||||
Point2D::new(position.x, position.y)
|
||||
}
|
||||
|
|
|
@ -42,7 +42,7 @@ use canvas::WebGLComm;
|
|||
use canvas::canvas_paint_thread::CanvasPaintThread;
|
||||
use canvas_traits::webgl::{GlType, WebGLThreads};
|
||||
use clipboard_delegate::StringRequest;
|
||||
use compositing::windowing::{EmbedderMethods, WindowMethods};
|
||||
use compositing::windowing::EmbedderMethods;
|
||||
use compositing::{IOCompositor, InitialCompositorState};
|
||||
pub use compositing_traits::rendering_context::{
|
||||
OffscreenRenderingContext, RenderingContext, SoftwareRenderingContext, WindowRenderingContext,
|
||||
|
@ -186,11 +186,8 @@ mod media_platform {
|
|||
/// orchestrating the interaction between JavaScript, CSS layout,
|
||||
/// rendering, and the client window.
|
||||
///
|
||||
/// Clients create a `Servo` instance for a given reference-counted type
|
||||
/// implementing `WindowMethods`, which is the bridge to whatever
|
||||
/// application Servo is embedded in. Clients then create an event
|
||||
/// loop to pump messages between the embedding application and
|
||||
/// various browser components.
|
||||
// Clients create an event loop to pump messages between the embedding
|
||||
// application and various browser components.
|
||||
pub struct Servo {
|
||||
delegate: RefCell<Rc<dyn ServoDelegate>>,
|
||||
compositor: Rc<RefCell<IOCompositor>>,
|
||||
|
@ -250,7 +247,7 @@ impl Servo {
|
|||
#[cfg_attr(
|
||||
feature = "tracing",
|
||||
tracing::instrument(
|
||||
skip(preferences, rendering_context, embedder, window),
|
||||
skip(preferences, rendering_context, embedder),
|
||||
fields(servo_profiling = true),
|
||||
level = "trace",
|
||||
)
|
||||
|
@ -260,7 +257,6 @@ impl Servo {
|
|||
preferences: Preferences,
|
||||
rendering_context: Rc<dyn RenderingContext>,
|
||||
mut embedder: Box<dyn EmbedderMethods>,
|
||||
window: Rc<dyn WindowMethods>,
|
||||
user_content_manager: UserContentManager,
|
||||
) -> Self {
|
||||
// Global configuration options, parsed from the command line.
|
||||
|
@ -484,7 +480,6 @@ impl Servo {
|
|||
// rendered page and display it somewhere.
|
||||
let shutdown_state = Rc::new(Cell::new(ShutdownState::NotShuttingDown));
|
||||
let compositor = IOCompositor::new(
|
||||
window,
|
||||
InitialCompositorState {
|
||||
sender: compositor_proxy,
|
||||
receiver: compositor_receiver,
|
||||
|
@ -625,10 +620,6 @@ impl Servo {
|
|||
.retain(|_webview_id, webview| webview.strong_count() > 0);
|
||||
}
|
||||
|
||||
pub fn pinch_zoom_level(&self) -> f32 {
|
||||
self.compositor.borrow_mut().pinch_zoom_level().get()
|
||||
}
|
||||
|
||||
pub fn setup_logging(&self) {
|
||||
let constellation_chan = self.constellation_proxy.sender();
|
||||
let env = env_logger::Env::default();
|
||||
|
@ -724,15 +715,7 @@ impl Servo {
|
|||
let webview_id_and_viewport_details = webview
|
||||
.delegate()
|
||||
.request_open_auxiliary_webview(webview)
|
||||
.map(|webview| {
|
||||
let mut viewport =
|
||||
self.compositor.borrow().default_webview_viewport_details();
|
||||
let rect = webview.rect();
|
||||
if !rect.is_empty() {
|
||||
viewport.size = rect.size() / viewport.hidpi_scale_factor;
|
||||
}
|
||||
(webview.id(), viewport)
|
||||
});
|
||||
.map(|webview| (webview.id(), webview.viewport_details()));
|
||||
let _ = response_sender.send(webview_id_and_viewport_details);
|
||||
}
|
||||
},
|
||||
|
|
|
@ -7,14 +7,12 @@ use std::sync::Arc;
|
|||
use std::sync::atomic::{AtomicBool, Ordering};
|
||||
use std::time::Duration;
|
||||
|
||||
use compositing::windowing::{EmbedderMethods, WindowMethods};
|
||||
use compositing::windowing::EmbedderMethods;
|
||||
use compositing_traits::rendering_context::{RenderingContext, SoftwareRenderingContext};
|
||||
use dpi::PhysicalSize;
|
||||
use embedder_traits::EventLoopWaker;
|
||||
use euclid::Scale;
|
||||
use servo::Servo;
|
||||
use servo_geometry::DeviceIndependentPixel;
|
||||
use webrender_api::units::DevicePixel;
|
||||
|
||||
pub struct ServoTest {
|
||||
servo: Servo,
|
||||
|
@ -39,13 +37,6 @@ impl ServoTest {
|
|||
}
|
||||
}
|
||||
|
||||
struct WindowMethodsImpl;
|
||||
impl WindowMethods for WindowMethodsImpl {
|
||||
fn hidpi_factor(&self) -> Scale<f32, DeviceIndependentPixel, DevicePixel> {
|
||||
Scale::new(1.0)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
struct EventLoopWakerImpl(Arc<AtomicBool>);
|
||||
impl EventLoopWaker for EventLoopWakerImpl {
|
||||
|
@ -64,7 +55,6 @@ impl ServoTest {
|
|||
Default::default(),
|
||||
rendering_context.clone(),
|
||||
Box::new(EmbedderMethodsImpl(user_event_triggered)),
|
||||
Rc::new(WindowMethodsImpl),
|
||||
Default::default(),
|
||||
);
|
||||
Self { servo }
|
||||
|
|
|
@ -15,10 +15,13 @@ use constellation_traits::{EmbedderToConstellationMessage, TraversalDirection};
|
|||
use dpi::PhysicalSize;
|
||||
use embedder_traits::{
|
||||
Cursor, InputEvent, LoadStatus, MediaSessionActionType, ScreenGeometry, Theme, TouchEventType,
|
||||
ViewportDetails,
|
||||
};
|
||||
use euclid::{Point2D, Scale, Size2D};
|
||||
use servo_geometry::DeviceIndependentPixel;
|
||||
use url::Url;
|
||||
use webrender_api::ScrollLocation;
|
||||
use webrender_api::units::{DeviceIntPoint, DeviceRect};
|
||||
use webrender_api::units::{DeviceIntPoint, DevicePixel, DeviceRect};
|
||||
|
||||
use crate::clipboard_delegate::{ClipboardDelegate, DefaultClipboardDelegate};
|
||||
use crate::webview_delegate::{DefaultWebViewDelegate, WebViewDelegate};
|
||||
|
@ -75,6 +78,7 @@ pub(crate) struct WebViewInner {
|
|||
pub(crate) clipboard_delegate: Rc<dyn ClipboardDelegate>,
|
||||
|
||||
rect: DeviceRect,
|
||||
hidpi_scale_factor: Scale<f32, DeviceIndependentPixel, DevicePixel>,
|
||||
load_status: LoadStatus,
|
||||
url: Option<Url>,
|
||||
status_text: Option<String>,
|
||||
|
@ -96,6 +100,17 @@ impl WebView {
|
|||
pub(crate) fn new(builder: WebViewBuilder) -> Self {
|
||||
let id = WebViewId::new();
|
||||
let servo = builder.servo;
|
||||
let size = builder.size.map_or_else(
|
||||
|| {
|
||||
builder
|
||||
.servo
|
||||
.compositor
|
||||
.borrow()
|
||||
.rendering_context_size()
|
||||
.to_f32()
|
||||
},
|
||||
|size| Size2D::new(size.width as f32, size.height as f32),
|
||||
);
|
||||
|
||||
let webview = Self(Rc::new(RefCell::new(WebViewInner {
|
||||
id,
|
||||
|
@ -103,7 +118,8 @@ impl WebView {
|
|||
compositor: servo.compositor.clone(),
|
||||
delegate: builder.delegate,
|
||||
clipboard_delegate: Rc::new(DefaultClipboardDelegate),
|
||||
rect: DeviceRect::zero(),
|
||||
rect: DeviceRect::from_origin_and_size(Point2D::origin(), size),
|
||||
hidpi_scale_factor: builder.hidpi_scale_factor,
|
||||
load_status: LoadStatus::Complete,
|
||||
url: None,
|
||||
status_text: None,
|
||||
|
@ -114,14 +130,14 @@ impl WebView {
|
|||
cursor: Cursor::Pointer,
|
||||
})));
|
||||
|
||||
builder
|
||||
.servo
|
||||
.compositor
|
||||
.borrow_mut()
|
||||
.add_webview(Box::new(ServoRendererWebView {
|
||||
let viewport_details = webview.viewport_details();
|
||||
servo.compositor.borrow_mut().add_webview(
|
||||
Box::new(ServoRendererWebView {
|
||||
weak_handle: webview.weak_handle(),
|
||||
id,
|
||||
}));
|
||||
}),
|
||||
viewport_details,
|
||||
);
|
||||
|
||||
servo
|
||||
.webviews
|
||||
|
@ -133,8 +149,8 @@ impl WebView {
|
|||
Url::parse("about:blank").expect("Should always be able to parse 'about:blank'."),
|
||||
);
|
||||
|
||||
let viewport_details = servo.compositor.borrow().default_webview_viewport_details();
|
||||
servo
|
||||
builder
|
||||
.servo
|
||||
.constellation_proxy
|
||||
.send(EmbedderToConstellationMessage::NewWebView(
|
||||
url.into(),
|
||||
|
@ -154,6 +170,17 @@ impl WebView {
|
|||
self.0.borrow_mut()
|
||||
}
|
||||
|
||||
pub(crate) fn viewport_details(&self) -> ViewportDetails {
|
||||
// The division by 1 represents the page's default zoom of 100%,
|
||||
// and gives us the appropriate CSSPixel type for the viewport.
|
||||
let inner = self.inner();
|
||||
let scaled_viewport_size = inner.rect.size() / inner.hidpi_scale_factor;
|
||||
ViewportDetails {
|
||||
size: scaled_viewport_size / Scale::new(1.0),
|
||||
hidpi_scale_factor: Scale::new(inner.hidpi_scale_factor.0),
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn from_weak_handle(inner: &Weak<RefCell<WebViewInner>>) -> Option<Self> {
|
||||
inner.upgrade().map(WebView)
|
||||
}
|
||||
|
@ -320,6 +347,25 @@ impl WebView {
|
|||
.move_resize_webview(self.id(), rect);
|
||||
}
|
||||
|
||||
pub fn hidpi_scale_factor(&self) -> Scale<f32, DeviceIndependentPixel, DevicePixel> {
|
||||
self.inner().hidpi_scale_factor
|
||||
}
|
||||
|
||||
pub fn set_hidpi_scale_factor(
|
||||
&self,
|
||||
new_scale_factor: Scale<f32, DeviceIndependentPixel, DevicePixel>,
|
||||
) {
|
||||
if self.inner().hidpi_scale_factor == new_scale_factor {
|
||||
return;
|
||||
}
|
||||
|
||||
self.inner_mut().hidpi_scale_factor = new_scale_factor;
|
||||
self.inner()
|
||||
.compositor
|
||||
.borrow_mut()
|
||||
.set_hidpi_scale_factor(self.id(), new_scale_factor);
|
||||
}
|
||||
|
||||
pub fn show(&self, hide_others: bool) {
|
||||
self.inner()
|
||||
.compositor
|
||||
|
@ -437,14 +483,14 @@ impl WebView {
|
|||
self.inner()
|
||||
.compositor
|
||||
.borrow_mut()
|
||||
.on_zoom_window_event(new_zoom);
|
||||
.on_zoom_window_event(self.id(), new_zoom);
|
||||
}
|
||||
|
||||
pub fn reset_zoom(&self) {
|
||||
self.inner()
|
||||
.compositor
|
||||
.borrow_mut()
|
||||
.on_zoom_reset_window_event();
|
||||
.on_zoom_reset_window_event(self.id());
|
||||
}
|
||||
|
||||
pub fn set_pinch_zoom(&self, new_pinch_zoom: f32) {
|
||||
|
@ -535,6 +581,8 @@ pub struct WebViewBuilder<'servo> {
|
|||
delegate: Rc<dyn WebViewDelegate>,
|
||||
auxiliary: bool,
|
||||
url: Option<Url>,
|
||||
size: Option<PhysicalSize<u32>>,
|
||||
hidpi_scale_factor: Scale<f32, DeviceIndependentPixel, DevicePixel>,
|
||||
}
|
||||
|
||||
impl<'servo> WebViewBuilder<'servo> {
|
||||
|
@ -543,6 +591,8 @@ impl<'servo> WebViewBuilder<'servo> {
|
|||
servo,
|
||||
auxiliary: false,
|
||||
url: None,
|
||||
size: None,
|
||||
hidpi_scale_factor: Scale::new(1.0),
|
||||
delegate: Rc::new(DefaultWebViewDelegate),
|
||||
}
|
||||
}
|
||||
|
@ -563,6 +613,19 @@ impl<'servo> WebViewBuilder<'servo> {
|
|||
self
|
||||
}
|
||||
|
||||
pub fn size(mut self, size: PhysicalSize<u32>) -> Self {
|
||||
self.size = Some(size);
|
||||
self
|
||||
}
|
||||
|
||||
pub fn hidpi_scale_factor(
|
||||
mut self,
|
||||
hidpi_scale_factor: Scale<f32, DeviceIndependentPixel, DevicePixel>,
|
||||
) -> Self {
|
||||
self.hidpi_scale_factor = hidpi_scale_factor;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn build(self) -> WebView {
|
||||
WebView::new(self)
|
||||
}
|
||||
|
|
|
@ -70,7 +70,11 @@ pub enum CompositorMsg {
|
|||
/// Script has handled a touch event, and either prevented or allowed default actions.
|
||||
TouchEventProcessed(WebViewId, TouchEventResult),
|
||||
/// Composite to a PNG file and return the Image over a passed channel.
|
||||
CreatePng(Option<Rect<f32, CSSPixel>>, IpcSender<Option<Image>>),
|
||||
CreatePng(
|
||||
WebViewId,
|
||||
Option<Rect<f32, CSSPixel>>,
|
||||
IpcSender<Option<Image>>,
|
||||
),
|
||||
/// A reply to the compositor asking if the output image is stable.
|
||||
IsReadyToSaveImageReply(bool),
|
||||
/// Set whether to use less resources by stopping animations.
|
||||
|
|
|
@ -11,16 +11,12 @@ use std::rc::Rc;
|
|||
use std::time::Instant;
|
||||
use std::{env, fs};
|
||||
|
||||
use euclid::Scale;
|
||||
use log::{info, trace, warn};
|
||||
use servo::compositing::windowing::WindowMethods;
|
||||
use servo::config::opts::Opts;
|
||||
use servo::config::prefs::Preferences;
|
||||
use servo::servo_config::pref;
|
||||
use servo::servo_geometry::DeviceIndependentPixel;
|
||||
use servo::servo_url::ServoUrl;
|
||||
use servo::user_content_manager::{UserContentManager, UserScript};
|
||||
use servo::webrender_api::units::DevicePixel;
|
||||
use servo::webxr::glwindow::GlWindowDiscovery;
|
||||
#[cfg(target_os = "windows")]
|
||||
use servo::webxr::openxr::{AppInfo, OpenXrDiscovery};
|
||||
|
@ -139,15 +135,6 @@ impl App {
|
|||
// Implements embedder methods, used by libservo and constellation.
|
||||
let embedder = Box::new(EmbedderCallbacks::new(self.waker.clone(), xr_discovery));
|
||||
|
||||
// TODO: Remove this once dyn upcasting coercion stabilises
|
||||
// <https://github.com/rust-lang/rust/issues/65991>
|
||||
struct UpcastedWindow(Rc<dyn WindowPortsMethods>);
|
||||
impl WindowMethods for UpcastedWindow {
|
||||
fn hidpi_factor(&self) -> Scale<f32, DeviceIndependentPixel, DevicePixel> {
|
||||
self.0.hidpi_factor()
|
||||
}
|
||||
}
|
||||
|
||||
let mut user_content_manager = UserContentManager::new();
|
||||
for script in load_userscripts(self.servoshell_preferences.userscripts_directory.as_deref())
|
||||
.expect("Loading userscripts failed")
|
||||
|
@ -160,7 +147,6 @@ impl App {
|
|||
self.preferences.clone(),
|
||||
window.rendering_context(),
|
||||
embedder,
|
||||
Rc::new(UpcastedWindow(window.clone())),
|
||||
user_content_manager,
|
||||
);
|
||||
servo.setup_logging();
|
||||
|
@ -358,7 +344,7 @@ impl ApplicationHandler<WakerEvent> for App {
|
|||
// Intercept any ScaleFactorChanged events away from EguiGlow::on_window_event, so
|
||||
// we can use our own logic for calculating the scale factor and set egui’s
|
||||
// scale factor to that value manually.
|
||||
let desired_scale_factor = window.hidpi_factor().get();
|
||||
let desired_scale_factor = window.hidpi_scale_factor().get();
|
||||
let effective_egui_zoom_factor = desired_scale_factor / scale_factor as f32;
|
||||
|
||||
info!(
|
||||
|
@ -371,6 +357,8 @@ impl ApplicationHandler<WakerEvent> for App {
|
|||
.egui_ctx
|
||||
.set_zoom_factor(effective_egui_zoom_factor);
|
||||
|
||||
state.hidpi_scale_factor_changed();
|
||||
|
||||
// Request a winit redraw event, so we can recomposite, update and paint
|
||||
// the minibrowser, and present the new frame.
|
||||
window.winit_window().unwrap().request_redraw();
|
||||
|
|
|
@ -109,6 +109,7 @@ impl RunningAppState {
|
|||
pub(crate) fn new_toplevel_webview(self: &Rc<Self>, url: Url) {
|
||||
let webview = WebViewBuilder::new(self.servo())
|
||||
.url(url)
|
||||
.hidpi_scale_factor(self.inner().window.hidpi_scale_factor())
|
||||
.delegate(self.clone())
|
||||
.build();
|
||||
|
||||
|
@ -130,6 +131,14 @@ impl RunningAppState {
|
|||
&self.servo
|
||||
}
|
||||
|
||||
pub(crate) fn hidpi_scale_factor_changed(&self) {
|
||||
let inner = self.inner();
|
||||
let new_scale_factor = inner.window.hidpi_scale_factor();
|
||||
for webview in inner.webviews.values() {
|
||||
webview.set_hidpi_scale_factor(new_scale_factor);
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn save_output_image_if_necessary(&self) {
|
||||
let Some(output_path) = self.servoshell_preferences.output_image_path.as_ref() else {
|
||||
return;
|
||||
|
@ -462,6 +471,7 @@ impl WebViewDelegate for RunningAppState {
|
|||
parent_webview: servo::WebView,
|
||||
) -> Option<servo::WebView> {
|
||||
let webview = WebViewBuilder::new_auxiliary(&self.servo)
|
||||
.hidpi_scale_factor(self.inner().window.hidpi_scale_factor())
|
||||
.delegate(parent_webview.delegate())
|
||||
.build();
|
||||
|
||||
|
|
|
@ -14,7 +14,7 @@ use euclid::{Angle, Length, Point2D, Rotation3D, Scale, Size2D, UnknownUnit, Vec
|
|||
use keyboard_types::{Modifiers, ShortcutMatcher};
|
||||
use log::{debug, info};
|
||||
use raw_window_handle::{HasDisplayHandle, HasWindowHandle, RawWindowHandle};
|
||||
use servo::compositing::windowing::{WebRenderDebugOption, WindowMethods};
|
||||
use servo::compositing::windowing::WebRenderDebugOption;
|
||||
use servo::servo_config::pref;
|
||||
use servo::servo_geometry::DeviceIndependentPixel;
|
||||
use servo::webrender_api::ScrollLocation;
|
||||
|
@ -252,7 +252,7 @@ impl Window {
|
|||
|
||||
/// Helper function to handle a click
|
||||
fn handle_mouse(&self, webview: &WebView, button: MouseButton, action: ElementState) {
|
||||
let max_pixel_dist = 10.0 * self.hidpi_factor().get();
|
||||
let max_pixel_dist = 10.0 * self.hidpi_scale_factor().get();
|
||||
let mouse_button = match &button {
|
||||
MouseButton::Left => ServoMouseButton::Left,
|
||||
MouseButton::Right => ServoMouseButton::Right,
|
||||
|
@ -443,8 +443,11 @@ impl Window {
|
|||
|
||||
impl WindowPortsMethods for Window {
|
||||
fn screen_geometry(&self) -> ScreenGeometry {
|
||||
let hidpi_factor = self.hidpi_factor();
|
||||
let toolbar_size = Size2D::new(0.0, (self.toolbar_height.get() * self.hidpi_factor()).0);
|
||||
let hidpi_factor = self.hidpi_scale_factor();
|
||||
let toolbar_size = Size2D::new(
|
||||
0.0,
|
||||
(self.toolbar_height.get() * self.hidpi_scale_factor()).0,
|
||||
);
|
||||
|
||||
let screen_size = self.screen_size.to_f32() * hidpi_factor;
|
||||
let available_screen_size = screen_size - toolbar_size;
|
||||
|
@ -462,18 +465,18 @@ impl WindowPortsMethods for Window {
|
|||
}
|
||||
}
|
||||
|
||||
fn device_hidpi_factor(&self) -> Scale<f32, DeviceIndependentPixel, DevicePixel> {
|
||||
fn device_hidpi_scale_factor(&self) -> Scale<f32, DeviceIndependentPixel, DevicePixel> {
|
||||
Scale::new(self.winit_window.scale_factor() as f32)
|
||||
}
|
||||
|
||||
fn device_pixel_ratio_override(
|
||||
&self,
|
||||
) -> Option<Scale<f32, DeviceIndependentPixel, DevicePixel>> {
|
||||
self.device_pixel_ratio_override.map(Scale::new)
|
||||
fn hidpi_scale_factor(&self) -> Scale<f32, DeviceIndependentPixel, DevicePixel> {
|
||||
self.device_pixel_ratio_override
|
||||
.map(Scale::new)
|
||||
.unwrap_or_else(|| self.device_hidpi_scale_factor())
|
||||
}
|
||||
|
||||
fn page_height(&self) -> f32 {
|
||||
let dpr = self.hidpi_factor();
|
||||
let dpr = self.hidpi_scale_factor();
|
||||
let size = self.winit_window.inner_size();
|
||||
size.height as f32 * dpr.get()
|
||||
}
|
||||
|
@ -483,7 +486,7 @@ impl WindowPortsMethods for Window {
|
|||
}
|
||||
|
||||
fn request_resize(&self, _: &WebView, size: DeviceIntSize) -> Option<DeviceIntSize> {
|
||||
let toolbar_height = self.toolbar_height() * self.hidpi_factor();
|
||||
let toolbar_height = self.toolbar_height() * self.hidpi_scale_factor();
|
||||
let toolbar_height = toolbar_height.get().ceil() as i32;
|
||||
let total_size = PhysicalSize::new(size.width, size.height + toolbar_height);
|
||||
self.winit_window
|
||||
|
@ -587,7 +590,7 @@ impl WindowPortsMethods for Window {
|
|||
},
|
||||
WindowEvent::CursorMoved { position, .. } => {
|
||||
let mut point = winit_position_to_euclid_point(position).to_f32();
|
||||
point.y -= (self.toolbar_height() * self.hidpi_factor()).0;
|
||||
point.y -= (self.toolbar_height() * self.hidpi_scale_factor()).0;
|
||||
|
||||
self.webview_relative_mouse_point.set(point);
|
||||
webview.notify_input_event(InputEvent::MouseMove(MouseMoveEvent { point }));
|
||||
|
@ -598,7 +601,7 @@ impl WindowPortsMethods for Window {
|
|||
(dx as f64, (dy * LINE_HEIGHT) as f64, WheelMode::DeltaLine)
|
||||
},
|
||||
MouseScrollDelta::PixelDelta(position) => {
|
||||
let scale_factor = self.device_hidpi_factor().inverse().get() as f64;
|
||||
let scale_factor = self.device_hidpi_scale_factor().inverse().get() as f64;
|
||||
let position = position.to_logical(scale_factor);
|
||||
(position.x, position.y, WheelMode::DeltaPixel)
|
||||
},
|
||||
|
@ -728,7 +731,7 @@ impl WindowPortsMethods for Window {
|
|||
// this prevents a crash in the compositor due to invalid surface size
|
||||
self.winit_window.set_min_inner_size(Some(PhysicalSize::new(
|
||||
1.0,
|
||||
1.0 + (self.toolbar_height() * self.hidpi_factor()).0,
|
||||
1.0 + (self.toolbar_height() * self.hidpi_scale_factor()).0,
|
||||
)));
|
||||
}
|
||||
|
||||
|
@ -761,13 +764,6 @@ impl WindowPortsMethods for Window {
|
|||
}
|
||||
}
|
||||
|
||||
impl WindowMethods for Window {
|
||||
fn hidpi_factor(&self) -> Scale<f32, DeviceIndependentPixel, DevicePixel> {
|
||||
self.device_pixel_ratio_override()
|
||||
.unwrap_or_else(|| self.device_hidpi_factor())
|
||||
}
|
||||
}
|
||||
|
||||
fn winit_phase_to_touch_event_type(phase: TouchPhase) -> TouchEventType {
|
||||
match phase {
|
||||
TouchPhase::Started => TouchEventType::Down,
|
||||
|
|
|
@ -9,7 +9,6 @@ use std::rc::Rc;
|
|||
|
||||
use euclid::num::Zero;
|
||||
use euclid::{Length, Scale, Size2D};
|
||||
use servo::compositing::windowing::WindowMethods;
|
||||
use servo::servo_geometry::DeviceIndependentPixel;
|
||||
use servo::webrender_api::units::{DeviceIntSize, DevicePixel};
|
||||
use servo::{RenderingContext, ScreenGeometry, SoftwareRenderingContext};
|
||||
|
@ -94,19 +93,18 @@ impl WindowPortsMethods for Window {
|
|||
Some(new_size)
|
||||
}
|
||||
|
||||
fn device_hidpi_factor(&self) -> Scale<f32, DeviceIndependentPixel, DevicePixel> {
|
||||
fn device_hidpi_scale_factor(&self) -> Scale<f32, DeviceIndependentPixel, DevicePixel> {
|
||||
Scale::new(1.0)
|
||||
}
|
||||
|
||||
fn device_pixel_ratio_override(
|
||||
&self,
|
||||
) -> Option<Scale<f32, DeviceIndependentPixel, DevicePixel>> {
|
||||
fn hidpi_scale_factor(&self) -> Scale<f32, DeviceIndependentPixel, DevicePixel> {
|
||||
self.device_pixel_ratio_override
|
||||
.unwrap_or_else(|| self.device_hidpi_scale_factor())
|
||||
}
|
||||
|
||||
fn page_height(&self) -> f32 {
|
||||
let height = self.inner_size.get().height;
|
||||
let dpr = self.hidpi_factor();
|
||||
let dpr = self.hidpi_scale_factor();
|
||||
height as f32 * dpr.get()
|
||||
}
|
||||
|
||||
|
@ -145,10 +143,3 @@ impl WindowPortsMethods for Window {
|
|||
self.rendering_context.clone()
|
||||
}
|
||||
}
|
||||
|
||||
impl WindowMethods for Window {
|
||||
fn hidpi_factor(&self) -> Scale<f32, DeviceIndependentPixel, DevicePixel> {
|
||||
self.device_pixel_ratio_override()
|
||||
.unwrap_or_else(|| self.device_hidpi_factor())
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,7 +8,6 @@
|
|||
use std::rc::Rc;
|
||||
|
||||
use euclid::{Length, Scale};
|
||||
use servo::compositing::windowing::WindowMethods;
|
||||
use servo::servo_geometry::DeviceIndependentPixel;
|
||||
use servo::webrender_api::units::{DeviceIntPoint, DeviceIntSize, DevicePixel};
|
||||
use servo::{Cursor, RenderingContext, ScreenGeometry, WebView};
|
||||
|
@ -18,13 +17,11 @@ use super::app_state::RunningAppState;
|
|||
// This should vary by zoom level and maybe actual text size (focused or under cursor)
|
||||
pub const LINE_HEIGHT: f32 = 38.0;
|
||||
|
||||
pub trait WindowPortsMethods: WindowMethods {
|
||||
pub trait WindowPortsMethods {
|
||||
fn id(&self) -> winit::window::WindowId;
|
||||
fn screen_geometry(&self) -> ScreenGeometry;
|
||||
fn device_hidpi_factor(&self) -> Scale<f32, DeviceIndependentPixel, DevicePixel>;
|
||||
fn device_pixel_ratio_override(
|
||||
&self,
|
||||
) -> Option<Scale<f32, DeviceIndependentPixel, DevicePixel>>;
|
||||
fn device_hidpi_scale_factor(&self) -> Scale<f32, DeviceIndependentPixel, DevicePixel>;
|
||||
fn hidpi_scale_factor(&self) -> Scale<f32, DeviceIndependentPixel, DevicePixel>;
|
||||
fn page_height(&self) -> f32;
|
||||
fn get_fullscreen(&self) -> bool;
|
||||
fn handle_winit_event(&self, state: Rc<RunningAppState>, event: winit::event::WindowEvent);
|
||||
|
|
|
@ -83,7 +83,6 @@ pub fn init(
|
|||
let window_callbacks = Rc::new(ServoWindowCallbacks::new(
|
||||
callbacks,
|
||||
RefCell::new(init_opts.coordinates),
|
||||
init_opts.density,
|
||||
));
|
||||
|
||||
let embedder_callbacks = Box::new(ServoEmbedderCallbacks::new(
|
||||
|
@ -97,13 +96,13 @@ pub fn init(
|
|||
preferences,
|
||||
rendering_context.clone(),
|
||||
embedder_callbacks,
|
||||
window_callbacks.clone(),
|
||||
Default::default(),
|
||||
);
|
||||
|
||||
APP.with(|app| {
|
||||
let app_state = RunningAppState::new(
|
||||
init_opts.url,
|
||||
init_opts.density,
|
||||
rendering_context,
|
||||
servo,
|
||||
window_callbacks,
|
||||
|
|
|
@ -11,7 +11,7 @@ use keyboard_types::{CompositionEvent, CompositionState};
|
|||
use log::{debug, error, info, warn};
|
||||
use raw_window_handle::{RawWindowHandle, WindowHandle};
|
||||
use servo::base::id::WebViewId;
|
||||
use servo::compositing::windowing::{EmbedderMethods, WindowMethods};
|
||||
use servo::compositing::windowing::EmbedderMethods;
|
||||
use servo::euclid::{Point2D, Rect, Scale, Size2D, Vector2D};
|
||||
use servo::servo_geometry::DeviceIndependentPixel;
|
||||
use servo::webrender_api::ScrollLocation;
|
||||
|
@ -45,19 +45,16 @@ impl Coordinates {
|
|||
pub(super) struct ServoWindowCallbacks {
|
||||
host_callbacks: Box<dyn HostTrait>,
|
||||
coordinates: RefCell<Coordinates>,
|
||||
hidpi_factor: Scale<f32, DeviceIndependentPixel, DevicePixel>,
|
||||
}
|
||||
|
||||
impl ServoWindowCallbacks {
|
||||
pub(super) fn new(
|
||||
host_callbacks: Box<dyn HostTrait>,
|
||||
coordinates: RefCell<Coordinates>,
|
||||
hidpi_factor: f32,
|
||||
) -> Self {
|
||||
Self {
|
||||
host_callbacks,
|
||||
coordinates,
|
||||
hidpi_factor: Scale::new(hidpi_factor),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -90,6 +87,9 @@ struct RunningAppStateInner {
|
|||
/// Whether or not the animation state has changed. This is used to trigger
|
||||
/// host callbacks indicating that animation state has changed.
|
||||
animating_state_changed: Rc<Cell<bool>>,
|
||||
|
||||
/// The HiDPI scaling factor to use for the display of [`WebView`]s.
|
||||
hidpi_scale_factor: Scale<f32, DeviceIndependentPixel, DevicePixel>,
|
||||
}
|
||||
|
||||
struct ServoShellServoDelegate {
|
||||
|
@ -115,7 +115,7 @@ impl ServoDelegate for ServoShellServoDelegate {
|
|||
}
|
||||
|
||||
impl WebViewDelegate for RunningAppState {
|
||||
fn screen_geometry(&self, webview: WebView) -> Option<ScreenGeometry> {
|
||||
fn screen_geometry(&self, _webview: WebView) -> Option<ScreenGeometry> {
|
||||
let coord = self.callbacks.coordinates.borrow();
|
||||
let screen_size = DeviceIntSize::new(coord.viewport.size.width, coord.viewport.size.height);
|
||||
Some(ScreenGeometry {
|
||||
|
@ -214,6 +214,7 @@ impl WebViewDelegate for RunningAppState {
|
|||
fn request_open_auxiliary_webview(&self, parent_webview: WebView) -> Option<WebView> {
|
||||
let webview = WebViewBuilder::new_auxiliary(&self.servo)
|
||||
.delegate(parent_webview.delegate())
|
||||
.hidpi_scale_factor(self.inner().hidpi_scale_factor)
|
||||
.build();
|
||||
self.add(webview.clone());
|
||||
Some(webview)
|
||||
|
@ -275,6 +276,7 @@ impl WebViewDelegate for RunningAppState {
|
|||
impl RunningAppState {
|
||||
pub(super) fn new(
|
||||
initial_url: Option<String>,
|
||||
hidpi_scale_factor: f32,
|
||||
rendering_context: Rc<WindowRenderingContext>,
|
||||
servo: Servo,
|
||||
callbacks: Rc<ServoWindowCallbacks>,
|
||||
|
@ -303,6 +305,7 @@ impl RunningAppState {
|
|||
creation_order: vec![],
|
||||
focused_webview_id: None,
|
||||
animating_state_changed,
|
||||
hidpi_scale_factor: Scale::new(hidpi_scale_factor),
|
||||
}),
|
||||
});
|
||||
|
||||
|
@ -313,6 +316,7 @@ impl RunningAppState {
|
|||
pub(crate) fn new_toplevel_webview(self: &Rc<Self>, url: Url) {
|
||||
let webview = WebViewBuilder::new(&self.servo)
|
||||
.url(url)
|
||||
.hidpi_scale_factor(self.inner().hidpi_scale_factor)
|
||||
.delegate(self.clone())
|
||||
.build();
|
||||
|
||||
|
@ -715,9 +719,3 @@ impl EmbedderMethods for ServoEmbedderCallbacks {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl WindowMethods for ServoWindowCallbacks {
|
||||
fn hidpi_factor(&self) -> Scale<f32, DeviceIndependentPixel, DevicePixel> {
|
||||
self.hidpi_factor
|
||||
}
|
||||
}
|
||||
|
|
|
@ -124,7 +124,6 @@ pub fn init(
|
|||
let window_callbacks = Rc::new(ServoWindowCallbacks::new(
|
||||
callbacks,
|
||||
RefCell::new(coordinates),
|
||||
options.display_density as f32,
|
||||
));
|
||||
|
||||
let embedder_callbacks = Box::new(ServoEmbedderCallbacks::new(
|
||||
|
@ -138,12 +137,12 @@ pub fn init(
|
|||
preferences,
|
||||
rendering_context.clone(),
|
||||
embedder_callbacks,
|
||||
window_callbacks.clone(),
|
||||
Default::default(),
|
||||
);
|
||||
|
||||
let app_state = RunningAppState::new(
|
||||
Some(options.url),
|
||||
options.display_density as f32,
|
||||
rendering_context,
|
||||
servo,
|
||||
window_callbacks,
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue