mirror of
https://github.com/servo/servo.git
synced 2025-08-05 13:40:08 +01:00
layout: Store scroll offsets in the ScrollTree
(#37428)
There are currently five places that scroll offsets are stored: - DOM: A set of scroll offsets used for script. - Layout: An array of scroll offsets that is used for tracking layout-side scroll offsets. - Layout: The scroll offsets stored in the `ScrollTree`. These are currently unset and unused. - Compositor: The scroll offsets stored in the `ScrollTree` mirrored from layout. - WebRender: The scrolled offsets stored in the WebRender spatial tree. This change is the first step in combining the first three into the layout `ScrollTree`. It eliminates the extra array of scroll offsets stored in layout in favor of the storing them in the `ScrollTree`. A followup change will eliminate the ones stored in the DOM. - In addition the `ScrollState` data structure is eliminated as these are now stored in a `HashMap` everywhere when passing them via IPC. - The offsests stored in layout can now never scroll past the boundaries of the scrolled content. Testing: This should not change behavior and is thus covered by existing WPT tests. Signed-off-by: Martin Robinson <mrobinson@igalia.com> Co-authored-by: stevennovaryo <steven.novaryo@gmail.com>
This commit is contained in:
parent
6cac782fb1
commit
f451dccd0b
11 changed files with 182 additions and 122 deletions
|
@ -4,6 +4,8 @@
|
|||
|
||||
//! Defines data structures which are consumed by the Compositor.
|
||||
|
||||
use std::collections::HashMap;
|
||||
|
||||
use base::id::ScrollTreeNodeId;
|
||||
use bitflags::bitflags;
|
||||
use embedder_traits::Cursor;
|
||||
|
@ -338,7 +340,7 @@ impl ScrollTree {
|
|||
|
||||
/// Given an [`ExternalScrollId`] and an offset, update the scroll offset of the scroll node
|
||||
/// with the given id.
|
||||
pub fn set_scroll_offsets_for_node_with_external_scroll_id(
|
||||
pub fn set_scroll_offset_for_node_with_external_scroll_id(
|
||||
&mut self,
|
||||
external_scroll_id: ExternalScrollId,
|
||||
offset: LayoutVector2D,
|
||||
|
@ -353,6 +355,29 @@ impl ScrollTree {
|
|||
_ => None,
|
||||
})
|
||||
}
|
||||
|
||||
/// Given a set of all scroll offsets coming from the Servo renderer, update all of the offsets
|
||||
/// for nodes that actually exist in this tree.
|
||||
pub fn set_all_scroll_offsets(&mut self, offsets: &HashMap<ExternalScrollId, LayoutVector2D>) {
|
||||
for node in self.nodes.iter_mut() {
|
||||
if let SpatialTreeNodeInfo::Scroll(ref mut scroll_info) = node.info {
|
||||
if let Some(offset) = offsets.get(&scroll_info.external_id) {
|
||||
scroll_info.offset = *offset;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Collect all of the scroll offsets of the scrolling nodes of this tree into a
|
||||
/// [`HashMap`] which can be applied to another tree.
|
||||
pub fn scroll_offsets(&self) -> HashMap<ExternalScrollId, LayoutVector2D> {
|
||||
HashMap::from_iter(self.nodes.iter().filter_map(|node| match node.info {
|
||||
SpatialTreeNodeInfo::Scroll(ref scroll_info) => {
|
||||
Some((scroll_info.external_id, scroll_info.offset))
|
||||
},
|
||||
_ => None,
|
||||
}))
|
||||
}
|
||||
}
|
||||
|
||||
/// A data structure which stores compositor-side information about
|
||||
|
|
|
@ -35,7 +35,7 @@ use ipc_channel::ipc::{self, IpcSharedMemory};
|
|||
use profile_traits::mem::{OpaqueSender, ReportsChan};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use servo_geometry::{DeviceIndependentIntRect, DeviceIndependentIntSize};
|
||||
use webrender_api::units::{DevicePoint, LayoutPoint, TexelRect};
|
||||
use webrender_api::units::{DevicePoint, LayoutVector2D, TexelRect};
|
||||
use webrender_api::{
|
||||
BuiltDisplayList, BuiltDisplayListDescriptor, ExternalImage, ExternalImageData,
|
||||
ExternalImageHandler, ExternalImageId, ExternalImageSource, ExternalScrollId,
|
||||
|
@ -124,7 +124,7 @@ pub enum CompositorMsg {
|
|||
SendScrollNode(
|
||||
WebViewId,
|
||||
WebRenderPipelineId,
|
||||
LayoutPoint,
|
||||
LayoutVector2D,
|
||||
ExternalScrollId,
|
||||
),
|
||||
/// Inform WebRender of a new display list for the given pipeline.
|
||||
|
@ -232,7 +232,7 @@ impl CrossProcessCompositorApi {
|
|||
&self,
|
||||
webview_id: WebViewId,
|
||||
pipeline_id: WebRenderPipelineId,
|
||||
point: LayoutPoint,
|
||||
point: LayoutVector2D,
|
||||
scroll_id: ExternalScrollId,
|
||||
) {
|
||||
if let Err(e) = self.0.send(CompositorMsg::SendScrollNode(
|
||||
|
|
|
@ -22,7 +22,6 @@ use embedder_traits::{
|
|||
CompositorHitTestResult, Cursor, InputEvent, JavaScriptEvaluationId, MediaSessionActionType,
|
||||
Theme, ViewportDetails, WebDriverCommandMsg,
|
||||
};
|
||||
use euclid::Vector2D;
|
||||
pub use from_script_message::*;
|
||||
use ipc_channel::ipc::IpcSender;
|
||||
use malloc_size_of_derive::MallocSizeOf;
|
||||
|
@ -32,7 +31,7 @@ use servo_url::{ImmutableOrigin, ServoUrl};
|
|||
pub use structured_data::*;
|
||||
use strum_macros::IntoStaticStr;
|
||||
use webrender_api::ExternalScrollId;
|
||||
use webrender_api::units::LayoutPixel;
|
||||
use webrender_api::units::LayoutVector2D;
|
||||
|
||||
/// Messages to the Constellation from the embedding layer, whether from `ServoRenderer` or
|
||||
/// from `libservo` itself.
|
||||
|
@ -90,7 +89,7 @@ pub enum EmbedderToConstellationMessage {
|
|||
SetWebViewThrottled(WebViewId, bool),
|
||||
/// The Servo renderer scrolled and is updating the scroll states of the nodes in the
|
||||
/// given pipeline via the constellation.
|
||||
SetScrollStates(PipelineId, Vec<ScrollState>),
|
||||
SetScrollStates(PipelineId, HashMap<ExternalScrollId, LayoutVector2D>),
|
||||
/// Notify the constellation that a particular paint metric event has happened for the given pipeline.
|
||||
PaintMetric(PipelineId, PaintMetricEvent),
|
||||
/// Evaluate a JavaScript string in the context of a `WebView`. When execution is complete or an
|
||||
|
@ -136,15 +135,6 @@ pub enum WindowSizeType {
|
|||
Resize,
|
||||
}
|
||||
|
||||
/// The scroll state of a stacking context.
|
||||
#[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize)]
|
||||
pub struct ScrollState {
|
||||
/// The ID of the scroll root.
|
||||
pub scroll_id: ExternalScrollId,
|
||||
/// The scrolling offset of this stacking context.
|
||||
pub scroll_offset: Vector2D<f32, LayoutPixel>,
|
||||
}
|
||||
|
||||
/// The direction of a history traversal
|
||||
#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, PartialEq, Serialize)]
|
||||
pub enum TraversalDirection {
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
#![deny(missing_docs)]
|
||||
#![deny(unsafe_code)]
|
||||
|
||||
use std::collections::HashMap;
|
||||
use std::fmt;
|
||||
use std::sync::Arc;
|
||||
|
||||
|
@ -20,8 +21,8 @@ use bluetooth_traits::BluetoothRequest;
|
|||
use canvas_traits::webgl::WebGLPipeline;
|
||||
use compositing_traits::CrossProcessCompositorApi;
|
||||
use constellation_traits::{
|
||||
LoadData, NavigationHistoryBehavior, ScriptToConstellationChan, ScrollState,
|
||||
StructuredSerializedData, WindowSizeType,
|
||||
LoadData, NavigationHistoryBehavior, ScriptToConstellationChan, StructuredSerializedData,
|
||||
WindowSizeType,
|
||||
};
|
||||
use crossbeam_channel::{RecvTimeoutError, Sender};
|
||||
use devtools_traits::ScriptToDevtoolsControlMsg;
|
||||
|
@ -47,8 +48,8 @@ use style_traits::{CSSPixel, SpeculativePainter};
|
|||
use stylo_atoms::Atom;
|
||||
#[cfg(feature = "webgpu")]
|
||||
use webgpu_traits::WebGPUMsg;
|
||||
use webrender_api::ImageKey;
|
||||
use webrender_api::units::DevicePixel;
|
||||
use webrender_api::units::{DevicePixel, LayoutVector2D};
|
||||
use webrender_api::{ExternalScrollId, ImageKey};
|
||||
|
||||
/// The initial data required to create a new layout attached to an existing script thread.
|
||||
#[derive(Debug, Deserialize, Serialize)]
|
||||
|
@ -246,7 +247,7 @@ pub enum ScriptThreadMessage {
|
|||
SetWebGPUPort(IpcReceiver<WebGPUMsg>),
|
||||
/// The compositor scrolled and is updating the scroll states of the nodes in the given
|
||||
/// pipeline via the Constellation.
|
||||
SetScrollStates(PipelineId, Vec<ScrollState>),
|
||||
SetScrollStates(PipelineId, HashMap<ExternalScrollId, LayoutVector2D>),
|
||||
/// Evaluate the given JavaScript and return a result via a corresponding message
|
||||
/// to the Constellation.
|
||||
EvaluateJavaScript(PipelineId, JavaScriptEvaluationId, String),
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
pub mod wrapper_traits;
|
||||
|
||||
use std::any::Any;
|
||||
use std::collections::HashMap;
|
||||
use std::sync::Arc;
|
||||
use std::sync::atomic::{AtomicIsize, AtomicU64, Ordering};
|
||||
|
||||
|
@ -19,7 +20,7 @@ use atomic_refcell::AtomicRefCell;
|
|||
use base::Epoch;
|
||||
use base::id::{BrowsingContextId, PipelineId, WebViewId};
|
||||
use compositing_traits::CrossProcessCompositorApi;
|
||||
use constellation_traits::{LoadData, ScrollState};
|
||||
use constellation_traits::LoadData;
|
||||
use embedder_traits::{Theme, UntrustedNodeAddress, ViewportDetails};
|
||||
use euclid::default::{Point2D, Rect};
|
||||
use fnv::FnvHashMap;
|
||||
|
@ -48,8 +49,8 @@ use style::properties::PropertyId;
|
|||
use style::properties::style_structs::Font;
|
||||
use style::selector_parser::{PseudoElement, RestyleDamage, Snapshot};
|
||||
use style::stylesheets::Stylesheet;
|
||||
use webrender_api::ImageKey;
|
||||
use webrender_api::units::DeviceIntSize;
|
||||
use webrender_api::units::{DeviceIntSize, LayoutVector2D};
|
||||
use webrender_api::{ExternalScrollId, ImageKey};
|
||||
|
||||
pub trait GenericLayoutDataTrait: Any + MallocSizeOfTrait {
|
||||
fn as_any(&self) -> &dyn Any;
|
||||
|
@ -245,7 +246,10 @@ pub trait Layout {
|
|||
);
|
||||
|
||||
/// Set the scroll states of this layout after a compositor scroll.
|
||||
fn set_scroll_offsets(&mut self, scroll_states: &[ScrollState]);
|
||||
fn set_scroll_offsets_from_renderer(
|
||||
&mut self,
|
||||
scroll_states: &HashMap<ExternalScrollId, LayoutVector2D>,
|
||||
);
|
||||
|
||||
fn query_content_box(&self, node: TrustedNodeAddress) -> Option<Rect<Au>>;
|
||||
fn query_content_boxes(&self, node: TrustedNodeAddress) -> Vec<Rect<Au>>;
|
||||
|
@ -333,7 +337,7 @@ pub enum ReflowGoal {
|
|||
|
||||
/// Tells layout about a single new scrolling offset from the script. The rest will
|
||||
/// remain untouched and layout won't forward this back to script.
|
||||
UpdateScrollNode(ScrollState),
|
||||
UpdateScrollNode(ExternalScrollId, LayoutVector2D),
|
||||
}
|
||||
|
||||
impl ReflowGoal {
|
||||
|
@ -341,7 +345,7 @@ impl ReflowGoal {
|
|||
/// be present or false if it only needs stacking-relative positions.
|
||||
pub fn needs_display_list(&self) -> bool {
|
||||
match *self {
|
||||
ReflowGoal::UpdateTheRendering | ReflowGoal::UpdateScrollNode(_) => true,
|
||||
ReflowGoal::UpdateTheRendering | ReflowGoal::UpdateScrollNode(..) => true,
|
||||
ReflowGoal::LayoutQuery(ref querymsg) => match *querymsg {
|
||||
QueryMsg::ElementInnerOuterTextQuery |
|
||||
QueryMsg::InnerWindowDimensionsQuery |
|
||||
|
@ -363,7 +367,7 @@ impl ReflowGoal {
|
|||
/// false if a layout_thread display list is sufficient.
|
||||
pub fn needs_display(&self) -> bool {
|
||||
match *self {
|
||||
ReflowGoal::UpdateTheRendering | ReflowGoal::UpdateScrollNode(_) => true,
|
||||
ReflowGoal::UpdateTheRendering | ReflowGoal::UpdateScrollNode(..) => true,
|
||||
ReflowGoal::LayoutQuery(ref querymsg) => match *querymsg {
|
||||
QueryMsg::NodesFromPointQuery |
|
||||
QueryMsg::TextIndexQuery |
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue