mirror of
https://github.com/servo/servo.git
synced 2025-08-04 13:10:20 +01:00
compositor: Request reflow when doing a page zooming (#38166)
Request a reflow when doing page zoom and only modify the scaling of the WebView scene after the first root pipeline display list with the new zoom is ready. In addition: - store zoom limits in `Scale` types - send `ViewportDetails` along with the display list so that we can detect when the root pipeline scale is ready. Testing: This is quite hard to test as it requires verification that contents are zoomed appropriately at the right time. Fixes: #38091. Signed-off-by: Martin Robinson <mrobinson@igalia.com>
This commit is contained in:
parent
3d2f0d1be5
commit
8d5faa9bf9
10 changed files with 111 additions and 44 deletions
1
Cargo.lock
generated
1
Cargo.lock
generated
|
@ -1426,6 +1426,7 @@ dependencies = [
|
||||||
"profile_traits",
|
"profile_traits",
|
||||||
"raw-window-handle",
|
"raw-window-handle",
|
||||||
"serde",
|
"serde",
|
||||||
|
"servo_geometry",
|
||||||
"servo_malloc_size_of",
|
"servo_malloc_size_of",
|
||||||
"smallvec",
|
"smallvec",
|
||||||
"strum_macros",
|
"strum_macros",
|
||||||
|
|
|
@ -227,6 +227,11 @@ pub(crate) struct PipelineDetails {
|
||||||
/// The paint metric status of the first contentful paint.
|
/// The paint metric status of the first contentful paint.
|
||||||
pub first_contentful_paint_metric: PaintMetricState,
|
pub first_contentful_paint_metric: PaintMetricState,
|
||||||
|
|
||||||
|
/// The CSS pixel to device pixel scale of the viewport of this pipeline, including
|
||||||
|
/// page zoom, but not including any pinch zoom amount. This is used to detect
|
||||||
|
/// situations where the current display list is for an old scale.
|
||||||
|
pub viewport_scale: Option<Scale<f32, CSSPixel, DevicePixel>>,
|
||||||
|
|
||||||
/// Which parts of Servo have reported that this `Pipeline` has exited. Only when all
|
/// Which parts of Servo have reported that this `Pipeline` has exited. Only when all
|
||||||
/// have done so will it be discarded.
|
/// have done so will it be discarded.
|
||||||
pub exited: PipelineExitSource,
|
pub exited: PipelineExitSource,
|
||||||
|
@ -248,6 +253,7 @@ impl PipelineDetails {
|
||||||
pipeline: None,
|
pipeline: None,
|
||||||
parent_pipeline_id: None,
|
parent_pipeline_id: None,
|
||||||
most_recent_display_list_epoch: None,
|
most_recent_display_list_epoch: None,
|
||||||
|
viewport_scale: None,
|
||||||
animations_running: false,
|
animations_running: false,
|
||||||
animation_callbacks_running: false,
|
animation_callbacks_running: false,
|
||||||
throttled: false,
|
throttled: false,
|
||||||
|
@ -761,14 +767,18 @@ impl IOCompositor {
|
||||||
let Some(webview_renderer) = self.webview_renderers.get_mut(webview_id) else {
|
let Some(webview_renderer) = self.webview_renderers.get_mut(webview_id) else {
|
||||||
return warn!("Could not find WebView for incoming display list");
|
return warn!("Could not find WebView for incoming display list");
|
||||||
};
|
};
|
||||||
|
|
||||||
// WebRender is not ready until we receive "NewWebRenderFrameReady"
|
// WebRender is not ready until we receive "NewWebRenderFrameReady"
|
||||||
webview_renderer.webrender_frame_ready.set(false);
|
webview_renderer.webrender_frame_ready.set(false);
|
||||||
|
let old_scale = webview_renderer.device_pixels_per_page_pixel();
|
||||||
|
|
||||||
let pipeline_id = display_list_info.pipeline_id;
|
let pipeline_id = display_list_info.pipeline_id;
|
||||||
let details = webview_renderer.ensure_pipeline_details(pipeline_id.into());
|
let details = webview_renderer.ensure_pipeline_details(pipeline_id.into());
|
||||||
details.most_recent_display_list_epoch = Some(display_list_info.epoch);
|
details.most_recent_display_list_epoch = Some(display_list_info.epoch);
|
||||||
details.hit_test_items = display_list_info.hit_test_info;
|
details.hit_test_items = display_list_info.hit_test_info;
|
||||||
details.install_new_scroll_tree(display_list_info.scroll_tree);
|
details.install_new_scroll_tree(display_list_info.scroll_tree);
|
||||||
|
details.viewport_scale =
|
||||||
|
Some(display_list_info.viewport_details.hidpi_scale_factor);
|
||||||
|
|
||||||
let epoch = display_list_info.epoch;
|
let epoch = display_list_info.epoch;
|
||||||
let first_reflow = display_list_info.first_reflow;
|
let first_reflow = display_list_info.first_reflow;
|
||||||
|
@ -783,6 +793,14 @@ impl IOCompositor {
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut transaction = Transaction::new();
|
let mut transaction = Transaction::new();
|
||||||
|
|
||||||
|
let is_root_pipeline =
|
||||||
|
Some(pipeline_id.into()) == webview_renderer.root_pipeline_id;
|
||||||
|
if is_root_pipeline && old_scale != webview_renderer.device_pixels_per_page_pixel()
|
||||||
|
{
|
||||||
|
self.send_root_pipeline_display_list_in_transaction(&mut transaction);
|
||||||
|
}
|
||||||
|
|
||||||
transaction
|
transaction
|
||||||
.set_display_list(display_list_info.epoch, (pipeline_id, built_display_list));
|
.set_display_list(display_list_info.epoch, (pipeline_id, built_display_list));
|
||||||
self.update_transaction_with_all_scroll_offsets(&mut transaction);
|
self.update_transaction_with_all_scroll_offsets(&mut transaction);
|
||||||
|
@ -1227,9 +1245,8 @@ impl IOCompositor {
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(webview_renderer) = self.webview_renderers.get_mut(webview_id) {
|
if let Some(webview_renderer) = self.webview_renderers.get_mut(webview_id) {
|
||||||
webview_renderer.set_page_zoom(1.0);
|
webview_renderer.set_page_zoom(Scale::new(1.0));
|
||||||
}
|
}
|
||||||
self.send_root_pipeline_display_list();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn on_zoom_window_event(&mut self, webview_id: WebViewId, magnification: f32) {
|
pub fn on_zoom_window_event(&mut self, webview_id: WebViewId, magnification: f32) {
|
||||||
|
@ -1238,9 +1255,9 @@ impl IOCompositor {
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(webview_renderer) = self.webview_renderers.get_mut(webview_id) {
|
if let Some(webview_renderer) = self.webview_renderers.get_mut(webview_id) {
|
||||||
webview_renderer.set_page_zoom(magnification);
|
let current_page_zoom = webview_renderer.page_zoom();
|
||||||
|
webview_renderer.set_page_zoom(current_page_zoom * Scale::new(magnification));
|
||||||
}
|
}
|
||||||
self.send_root_pipeline_display_list();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn details_for_pipeline(&self, pipeline_id: PipelineId) -> Option<&PipelineDetails> {
|
fn details_for_pipeline(&self, pipeline_id: PipelineId) -> Option<&PipelineDetails> {
|
||||||
|
|
|
@ -10,7 +10,7 @@ use std::rc::Rc;
|
||||||
use base::id::{PipelineId, WebViewId};
|
use base::id::{PipelineId, WebViewId};
|
||||||
use compositing_traits::display_list::ScrollType;
|
use compositing_traits::display_list::ScrollType;
|
||||||
use compositing_traits::viewport_description::{
|
use compositing_traits::viewport_description::{
|
||||||
DEFAULT_ZOOM, MAX_ZOOM, MIN_ZOOM, ViewportDescription,
|
DEFAULT_PAGE_ZOOM, MAX_PAGE_ZOOM, MIN_PAGE_ZOOM, ViewportDescription,
|
||||||
};
|
};
|
||||||
use compositing_traits::{PipelineExitSource, SendableFrameTree, WebViewTrait};
|
use compositing_traits::{PipelineExitSource, SendableFrameTree, WebViewTrait};
|
||||||
use constellation_traits::{EmbedderToConstellationMessage, WindowSizeType};
|
use constellation_traits::{EmbedderToConstellationMessage, WindowSizeType};
|
||||||
|
@ -100,7 +100,8 @@ pub(crate) struct WebViewRenderer {
|
||||||
pending_point_input_events: RefCell<VecDeque<InputEvent>>,
|
pending_point_input_events: RefCell<VecDeque<InputEvent>>,
|
||||||
/// WebRender is not ready between `SendDisplayList` and `WebRenderFrameReady` messages.
|
/// WebRender is not ready between `SendDisplayList` and `WebRenderFrameReady` messages.
|
||||||
pub webrender_frame_ready: Cell<bool>,
|
pub webrender_frame_ready: Cell<bool>,
|
||||||
/// Viewport Description
|
/// A [`ViewportDescription`] for this [`WebViewRenderer`], which contains the limitations
|
||||||
|
/// and initial values for zoom derived from the `viewport` meta tag in web content.
|
||||||
viewport_description: Option<ViewportDescription>,
|
viewport_description: Option<ViewportDescription>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -130,8 +131,8 @@ impl WebViewRenderer {
|
||||||
touch_handler: TouchHandler::new(),
|
touch_handler: TouchHandler::new(),
|
||||||
global,
|
global,
|
||||||
pending_scroll_zoom_events: Default::default(),
|
pending_scroll_zoom_events: Default::default(),
|
||||||
page_zoom: Scale::new(DEFAULT_ZOOM),
|
page_zoom: DEFAULT_PAGE_ZOOM,
|
||||||
pinch_zoom: PinchZoomFactor::new(DEFAULT_ZOOM),
|
pinch_zoom: PinchZoomFactor::new(1.0),
|
||||||
hidpi_scale_factor: Scale::new(hidpi_scale_factor.0),
|
hidpi_scale_factor: Scale::new(hidpi_scale_factor.0),
|
||||||
animating: false,
|
animating: false,
|
||||||
pending_point_input_events: Default::default(),
|
pending_point_input_events: Default::default(),
|
||||||
|
@ -964,15 +965,39 @@ impl WebViewRenderer {
|
||||||
old_zoom != self.pinch_zoom
|
old_zoom != self.pinch_zoom
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn set_page_zoom(&mut self, magnification: f32) {
|
pub(crate) fn page_zoom(&mut self) -> Scale<f32, CSSPixel, DeviceIndependentPixel> {
|
||||||
self.page_zoom =
|
self.page_zoom
|
||||||
Scale::new((self.page_zoom.get() * magnification).clamp(MIN_ZOOM, MAX_ZOOM));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(crate) fn set_page_zoom(
|
||||||
|
&mut self,
|
||||||
|
new_page_zoom: Scale<f32, CSSPixel, DeviceIndependentPixel>,
|
||||||
|
) {
|
||||||
|
let new_page_zoom = new_page_zoom.clamp(MIN_PAGE_ZOOM, MAX_PAGE_ZOOM);
|
||||||
|
let old_zoom = std::mem::replace(&mut self.page_zoom, new_page_zoom);
|
||||||
|
if old_zoom != self.page_zoom {
|
||||||
|
self.send_window_size_message();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The scale to use when displaying this [`WebViewRenderer`] in WebRender
|
||||||
|
/// including both viewport scale (page zoom and hidpi scale) as well as any
|
||||||
|
/// pinch zoom applied. This is based on the latest display list received,
|
||||||
|
/// as page zoom changes are applied asynchronously and the rendered view
|
||||||
|
/// should reflect the latest display list.
|
||||||
pub(crate) fn device_pixels_per_page_pixel(&self) -> Scale<f32, CSSPixel, DevicePixel> {
|
pub(crate) fn device_pixels_per_page_pixel(&self) -> Scale<f32, CSSPixel, DevicePixel> {
|
||||||
self.page_zoom * self.hidpi_scale_factor * self.pinch_zoom_level()
|
let viewport_scale = self
|
||||||
|
.root_pipeline_id
|
||||||
|
.and_then(|pipeline_id| self.pipelines.get(&pipeline_id))
|
||||||
|
.and_then(|pipeline| pipeline.viewport_scale)
|
||||||
|
.unwrap_or_else(|| self.page_zoom * self.hidpi_scale_factor);
|
||||||
|
viewport_scale * self.pinch_zoom_level()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The current viewport scale (hidpi scale and page zoom and not pinch
|
||||||
|
/// zoom) based on the current setting of the WebView. Note that this may
|
||||||
|
/// not be the rendered viewport zoom as that is based on the latest display
|
||||||
|
/// list and zoom changes are applied asynchronously.
|
||||||
pub(crate) fn device_pixels_per_page_pixel_not_including_pinch_zoom(
|
pub(crate) fn device_pixels_per_page_pixel_not_including_pinch_zoom(
|
||||||
&self,
|
&self,
|
||||||
) -> Scale<f32, CSSPixel, DevicePixel> {
|
) -> Scale<f32, CSSPixel, DevicePixel> {
|
||||||
|
|
|
@ -65,7 +65,11 @@ impl<'a> BackgroundPainter<'a> {
|
||||||
if &BackgroundAttachment::Fixed ==
|
if &BackgroundAttachment::Fixed ==
|
||||||
get_cyclic(&background.background_attachment.0, layer_index)
|
get_cyclic(&background.background_attachment.0, layer_index)
|
||||||
{
|
{
|
||||||
return builder.compositor_info.viewport_size.into();
|
return builder
|
||||||
|
.compositor_info
|
||||||
|
.viewport_details
|
||||||
|
.layout_size()
|
||||||
|
.into();
|
||||||
}
|
}
|
||||||
|
|
||||||
match get_cyclic(&background.background_clip.0, layer_index) {
|
match get_cyclic(&background.background_clip.0, layer_index) {
|
||||||
|
@ -149,7 +153,11 @@ impl<'a> BackgroundPainter<'a> {
|
||||||
Origin::PaddingBox => *fragment_builder.padding_rect(),
|
Origin::PaddingBox => *fragment_builder.padding_rect(),
|
||||||
Origin::BorderBox => fragment_builder.border_rect,
|
Origin::BorderBox => fragment_builder.border_rect,
|
||||||
},
|
},
|
||||||
BackgroundAttachment::Fixed => builder.compositor_info.viewport_size.into(),
|
BackgroundAttachment::Fixed => builder
|
||||||
|
.compositor_info
|
||||||
|
.viewport_details
|
||||||
|
.layout_size()
|
||||||
|
.into(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,6 +14,7 @@ use compositing_traits::display_list::{
|
||||||
AxesScrollSensitivity, CompositorDisplayListInfo, ReferenceFrameNodeInfo, ScrollableNodeInfo,
|
AxesScrollSensitivity, CompositorDisplayListInfo, ReferenceFrameNodeInfo, ScrollableNodeInfo,
|
||||||
SpatialTreeNodeInfo, StickyNodeInfo,
|
SpatialTreeNodeInfo, StickyNodeInfo,
|
||||||
};
|
};
|
||||||
|
use embedder_traits::ViewportDetails;
|
||||||
use euclid::SideOffsets2D;
|
use euclid::SideOffsets2D;
|
||||||
use euclid::default::{Point2D, Rect, Size2D};
|
use euclid::default::{Point2D, Rect, Size2D};
|
||||||
use log::warn;
|
use log::warn;
|
||||||
|
@ -120,7 +121,7 @@ impl StackingContextTree {
|
||||||
/// pipeline id.
|
/// pipeline id.
|
||||||
pub fn new(
|
pub fn new(
|
||||||
fragment_tree: &FragmentTree,
|
fragment_tree: &FragmentTree,
|
||||||
viewport_size: LayoutSize,
|
viewport_details: ViewportDetails,
|
||||||
pipeline_id: wr::PipelineId,
|
pipeline_id: wr::PipelineId,
|
||||||
first_reflow: bool,
|
first_reflow: bool,
|
||||||
debug: &DebugOptions,
|
debug: &DebugOptions,
|
||||||
|
@ -131,8 +132,9 @@ impl StackingContextTree {
|
||||||
scrollable_overflow.size.height.to_f32_px(),
|
scrollable_overflow.size.height.to_f32_px(),
|
||||||
));
|
));
|
||||||
|
|
||||||
|
let viewport_size = viewport_details.layout_size();
|
||||||
let compositor_info = CompositorDisplayListInfo::new(
|
let compositor_info = CompositorDisplayListInfo::new(
|
||||||
viewport_size,
|
viewport_details,
|
||||||
scrollable_overflow,
|
scrollable_overflow,
|
||||||
pipeline_id,
|
pipeline_id,
|
||||||
// This epoch is set when the WebRender display list is built. For now use a dummy value.
|
// This epoch is set when the WebRender display list is built. For now use a dummy value.
|
||||||
|
@ -145,7 +147,7 @@ impl StackingContextTree {
|
||||||
let cb_for_non_fixed_descendants = ContainingBlock::new(
|
let cb_for_non_fixed_descendants = ContainingBlock::new(
|
||||||
fragment_tree.initial_containing_block,
|
fragment_tree.initial_containing_block,
|
||||||
root_scroll_node_id,
|
root_scroll_node_id,
|
||||||
Some(compositor_info.viewport_size),
|
Some(viewport_size),
|
||||||
ClipId::INVALID,
|
ClipId::INVALID,
|
||||||
);
|
);
|
||||||
let cb_for_fixed_descendants = ContainingBlock::new(
|
let cb_for_fixed_descendants = ContainingBlock::new(
|
||||||
|
@ -1504,7 +1506,10 @@ impl BoxFragment {
|
||||||
Some(size) => size,
|
Some(size) => size,
|
||||||
None => {
|
None => {
|
||||||
// This is a direct descendant of a reference frame.
|
// This is a direct descendant of a reference frame.
|
||||||
&stacking_context_tree.compositor_info.viewport_size
|
&stacking_context_tree
|
||||||
|
.compositor_info
|
||||||
|
.viewport_details
|
||||||
|
.layout_size()
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -75,7 +75,7 @@ use style::{Zero, driver};
|
||||||
use style_traits::{CSSPixel, SpeculativePainter};
|
use style_traits::{CSSPixel, SpeculativePainter};
|
||||||
use stylo_atoms::Atom;
|
use stylo_atoms::Atom;
|
||||||
use url::Url;
|
use url::Url;
|
||||||
use webrender_api::units::{DevicePixel, DevicePoint, LayoutSize, LayoutVector2D};
|
use webrender_api::units::{DevicePixel, DevicePoint, LayoutVector2D};
|
||||||
use webrender_api::{ExternalScrollId, HitTestFlags};
|
use webrender_api::{ExternalScrollId, HitTestFlags};
|
||||||
|
|
||||||
use crate::context::{CachedImageOrError, ImageResolver, LayoutContext};
|
use crate::context::{CachedImageOrError, ImageResolver, LayoutContext};
|
||||||
|
@ -960,12 +960,6 @@ impl LayoutThread {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
let viewport_size = self.stylist.device().au_viewport_size();
|
|
||||||
let viewport_size = LayoutSize::new(
|
|
||||||
viewport_size.width.to_f32_px(),
|
|
||||||
viewport_size.height.to_f32_px(),
|
|
||||||
);
|
|
||||||
|
|
||||||
let mut stacking_context_tree = self.stacking_context_tree.borrow_mut();
|
let mut stacking_context_tree = self.stacking_context_tree.borrow_mut();
|
||||||
let old_scroll_offsets = stacking_context_tree
|
let old_scroll_offsets = stacking_context_tree
|
||||||
.as_ref()
|
.as_ref()
|
||||||
|
@ -976,7 +970,7 @@ impl LayoutThread {
|
||||||
// applicable spatial and clip nodes.
|
// applicable spatial and clip nodes.
|
||||||
let mut new_stacking_context_tree = StackingContextTree::new(
|
let mut new_stacking_context_tree = StackingContextTree::new(
|
||||||
fragment_tree,
|
fragment_tree,
|
||||||
viewport_size,
|
reflow_request.viewport_details,
|
||||||
self.id.into(),
|
self.id.into(),
|
||||||
!self.have_ever_generated_display_list.get(),
|
!self.have_ever_generated_display_list.get(),
|
||||||
&self.debug,
|
&self.debug,
|
||||||
|
|
|
@ -32,6 +32,7 @@ malloc_size_of_derive = { workspace = true }
|
||||||
profile_traits = { path = '../profile' }
|
profile_traits = { path = '../profile' }
|
||||||
raw-window-handle = { version = "0.6" }
|
raw-window-handle = { version = "0.6" }
|
||||||
serde = { workspace = true }
|
serde = { workspace = true }
|
||||||
|
servo_geometry = { path = "../../geometry" }
|
||||||
smallvec = { workspace = true }
|
smallvec = { workspace = true }
|
||||||
strum_macros = { workspace = true }
|
strum_macros = { workspace = true }
|
||||||
stylo = { workspace = true }
|
stylo = { workspace = true }
|
||||||
|
|
|
@ -9,7 +9,7 @@ use std::collections::HashMap;
|
||||||
use base::id::ScrollTreeNodeId;
|
use base::id::ScrollTreeNodeId;
|
||||||
use base::print_tree::PrintTree;
|
use base::print_tree::PrintTree;
|
||||||
use bitflags::bitflags;
|
use bitflags::bitflags;
|
||||||
use embedder_traits::Cursor;
|
use embedder_traits::{Cursor, ViewportDetails};
|
||||||
use euclid::SideOffsets2D;
|
use euclid::SideOffsets2D;
|
||||||
use malloc_size_of_derive::MallocSizeOf;
|
use malloc_size_of_derive::MallocSizeOf;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
@ -486,8 +486,9 @@ pub struct CompositorDisplayListInfo {
|
||||||
/// The WebRender [PipelineId] of this display list.
|
/// The WebRender [PipelineId] of this display list.
|
||||||
pub pipeline_id: PipelineId,
|
pub pipeline_id: PipelineId,
|
||||||
|
|
||||||
/// The size of the viewport that this display list renders into.
|
/// The [`ViewportDetails`] that describe the viewport in the script/layout thread at
|
||||||
pub viewport_size: LayoutSize,
|
/// the time this display list was created.
|
||||||
|
pub viewport_details: ViewportDetails,
|
||||||
|
|
||||||
/// The size of this display list's content.
|
/// The size of this display list's content.
|
||||||
pub content_size: LayoutSize,
|
pub content_size: LayoutSize,
|
||||||
|
@ -526,7 +527,7 @@ impl CompositorDisplayListInfo {
|
||||||
/// Create a new CompositorDisplayListInfo with the root reference frame
|
/// Create a new CompositorDisplayListInfo with the root reference frame
|
||||||
/// and scroll frame already added to the scroll tree.
|
/// and scroll frame already added to the scroll tree.
|
||||||
pub fn new(
|
pub fn new(
|
||||||
viewport_size: LayoutSize,
|
viewport_details: ViewportDetails,
|
||||||
content_size: LayoutSize,
|
content_size: LayoutSize,
|
||||||
pipeline_id: PipelineId,
|
pipeline_id: PipelineId,
|
||||||
epoch: Epoch,
|
epoch: Epoch,
|
||||||
|
@ -548,7 +549,10 @@ impl CompositorDisplayListInfo {
|
||||||
SpatialTreeNodeInfo::Scroll(ScrollableNodeInfo {
|
SpatialTreeNodeInfo::Scroll(ScrollableNodeInfo {
|
||||||
external_id: ExternalScrollId(0, pipeline_id),
|
external_id: ExternalScrollId(0, pipeline_id),
|
||||||
content_rect: LayoutRect::from_origin_and_size(LayoutPoint::zero(), content_size),
|
content_rect: LayoutRect::from_origin_and_size(LayoutPoint::zero(), content_size),
|
||||||
clip_rect: LayoutRect::from_origin_and_size(LayoutPoint::zero(), viewport_size),
|
clip_rect: LayoutRect::from_origin_and_size(
|
||||||
|
LayoutPoint::zero(),
|
||||||
|
viewport_details.layout_size(),
|
||||||
|
),
|
||||||
scroll_sensitivity: viewport_scroll_sensitivity,
|
scroll_sensitivity: viewport_scroll_sensitivity,
|
||||||
offset: LayoutVector2D::zero(),
|
offset: LayoutVector2D::zero(),
|
||||||
}),
|
}),
|
||||||
|
@ -556,7 +560,7 @@ impl CompositorDisplayListInfo {
|
||||||
|
|
||||||
CompositorDisplayListInfo {
|
CompositorDisplayListInfo {
|
||||||
pipeline_id,
|
pipeline_id,
|
||||||
viewport_size,
|
viewport_details,
|
||||||
content_size,
|
content_size,
|
||||||
epoch,
|
epoch,
|
||||||
hit_test_info: Default::default(),
|
hit_test_info: Default::default(),
|
||||||
|
|
|
@ -7,17 +7,19 @@
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
|
|
||||||
use euclid::default::Scale;
|
use euclid::Scale;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
use servo_geometry::DeviceIndependentPixel;
|
||||||
|
use style_traits::CSSPixel;
|
||||||
|
|
||||||
/// Default viewport constraints
|
/// Default viewport constraints
|
||||||
///
|
///
|
||||||
/// <https://developer.mozilla.org/en-US/docs/Web/HTML/Viewport_meta_tag#initial-scale>
|
/// <https://developer.mozilla.org/en-US/docs/Web/HTML/Viewport_meta_tag#initial-scale>
|
||||||
pub const MIN_ZOOM: f32 = 0.1;
|
pub const MIN_PAGE_ZOOM: Scale<f32, CSSPixel, DeviceIndependentPixel> = Scale::new(0.1);
|
||||||
/// <https://developer.mozilla.org/en-US/docs/Web/HTML/Viewport_meta_tag#initial-scale>
|
/// <https://developer.mozilla.org/en-US/docs/Web/HTML/Viewport_meta_tag#initial-scale>
|
||||||
pub const MAX_ZOOM: f32 = 10.0;
|
pub const MAX_PAGE_ZOOM: Scale<f32, CSSPixel, DeviceIndependentPixel> = Scale::new(10.0);
|
||||||
/// <https://developer.mozilla.org/en-US/docs/Web/HTML/Viewport_meta_tag#initial-scale>
|
/// <https://developer.mozilla.org/en-US/docs/Web/HTML/Viewport_meta_tag#initial-scale>
|
||||||
pub const DEFAULT_ZOOM: f32 = 1.0;
|
pub const DEFAULT_PAGE_ZOOM: Scale<f32, CSSPixel, DeviceIndependentPixel> = Scale::new(1.0);
|
||||||
|
|
||||||
/// <https://drafts.csswg.org/css-viewport/#parsing-algorithm>
|
/// <https://drafts.csswg.org/css-viewport/#parsing-algorithm>
|
||||||
const SEPARATORS: [char; 2] = [',', ';']; // Comma (0x2c) and Semicolon (0x3b)
|
const SEPARATORS: [char; 2] = [',', ';']; // Comma (0x2c) and Semicolon (0x3b)
|
||||||
|
@ -35,15 +37,15 @@ pub struct ViewportDescription {
|
||||||
// TODO: height Needs to be implemented
|
// TODO: height Needs to be implemented
|
||||||
/// <https://developer.mozilla.org/en-US/docs/Web/HTML/Viewport_meta_tag#initial-scale>
|
/// <https://developer.mozilla.org/en-US/docs/Web/HTML/Viewport_meta_tag#initial-scale>
|
||||||
/// the zoom level when the page is first loaded
|
/// the zoom level when the page is first loaded
|
||||||
pub initial_scale: Scale<f32>,
|
pub initial_scale: Scale<f32, CSSPixel, DeviceIndependentPixel>,
|
||||||
|
|
||||||
/// <https://developer.mozilla.org/en-US/docs/Web/HTML/Viewport_meta_tag#minimum_scale>
|
/// <https://developer.mozilla.org/en-US/docs/Web/HTML/Viewport_meta_tag#minimum_scale>
|
||||||
/// how much zoom out is allowed on the page.
|
/// how much zoom out is allowed on the page.
|
||||||
pub minimum_scale: Scale<f32>,
|
pub minimum_scale: Scale<f32, CSSPixel, DeviceIndependentPixel>,
|
||||||
|
|
||||||
/// <https://developer.mozilla.org/en-US/docs/Web/HTML/Viewport_meta_tag#maximum_scale>
|
/// <https://developer.mozilla.org/en-US/docs/Web/HTML/Viewport_meta_tag#maximum_scale>
|
||||||
/// how much zoom in is allowed on the page
|
/// how much zoom in is allowed on the page
|
||||||
pub maximum_scale: Scale<f32>,
|
pub maximum_scale: Scale<f32, CSSPixel, DeviceIndependentPixel>,
|
||||||
|
|
||||||
/// <https://developer.mozilla.org/en-US/docs/Web/HTML/Viewport_meta_tag#user_scalable>
|
/// <https://developer.mozilla.org/en-US/docs/Web/HTML/Viewport_meta_tag#user_scalable>
|
||||||
/// whether zoom in and zoom out actions are allowed on the page
|
/// whether zoom in and zoom out actions are allowed on the page
|
||||||
|
@ -85,9 +87,9 @@ impl TryFrom<&str> for UserScalable {
|
||||||
impl Default for ViewportDescription {
|
impl Default for ViewportDescription {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
ViewportDescription {
|
ViewportDescription {
|
||||||
initial_scale: Scale::new(DEFAULT_ZOOM),
|
initial_scale: DEFAULT_PAGE_ZOOM,
|
||||||
minimum_scale: Scale::new(MIN_ZOOM),
|
minimum_scale: MIN_PAGE_ZOOM,
|
||||||
maximum_scale: Scale::new(MAX_ZOOM),
|
maximum_scale: MAX_PAGE_ZOOM,
|
||||||
user_scalable: UserScalable::Yes,
|
user_scalable: UserScalable::Yes,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -126,7 +128,9 @@ impl ViewportDescription {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Parses a viewport zoom value.
|
/// Parses a viewport zoom value.
|
||||||
fn parse_viewport_value_as_zoom(value: &str) -> Option<Scale<f32>> {
|
fn parse_viewport_value_as_zoom(
|
||||||
|
value: &str,
|
||||||
|
) -> Option<Scale<f32, CSSPixel, DeviceIndependentPixel>> {
|
||||||
value
|
value
|
||||||
.to_lowercase()
|
.to_lowercase()
|
||||||
.as_str()
|
.as_str()
|
||||||
|
|
|
@ -38,7 +38,7 @@ use style::queries::values::PrefersColorScheme;
|
||||||
use style_traits::CSSPixel;
|
use style_traits::CSSPixel;
|
||||||
use url::Url;
|
use url::Url;
|
||||||
use uuid::Uuid;
|
use uuid::Uuid;
|
||||||
use webrender_api::units::{DeviceIntPoint, DeviceIntRect, DeviceIntSize, DevicePixel};
|
use webrender_api::units::{DeviceIntPoint, DeviceIntRect, DeviceIntSize, DevicePixel, LayoutSize};
|
||||||
|
|
||||||
pub use crate::input_events::*;
|
pub use crate::input_events::*;
|
||||||
pub use crate::webdriver::*;
|
pub use crate::webdriver::*;
|
||||||
|
@ -319,6 +319,14 @@ pub struct ViewportDetails {
|
||||||
pub hidpi_scale_factor: Scale<f32, CSSPixel, DevicePixel>,
|
pub hidpi_scale_factor: Scale<f32, CSSPixel, DevicePixel>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl ViewportDetails {
|
||||||
|
/// Convert this [`ViewportDetails`] size to a [`LayoutSize`]. This is the same numerical
|
||||||
|
/// value as [`Self::size`], because a `LayoutPixel` is the same as a `CSSPixel`.
|
||||||
|
pub fn layout_size(&self) -> LayoutSize {
|
||||||
|
Size2D::from_untyped(self.size.to_untyped())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Unlike [`ScreenGeometry`], the data is in device-independent pixels
|
/// Unlike [`ScreenGeometry`], the data is in device-independent pixels
|
||||||
/// to be used by DOM APIs
|
/// to be used by DOM APIs
|
||||||
#[derive(Default, Deserialize, Serialize)]
|
#[derive(Default, Deserialize, Serialize)]
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue