mirror of
https://github.com/servo/servo.git
synced 2025-06-21 07:38:59 +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
|
@ -30,7 +30,6 @@ use embedder_traits::{
|
||||||
TouchEventType, UntrustedNodeAddress, ViewportDetails, WheelDelta, WheelEvent, WheelMode,
|
TouchEventType, UntrustedNodeAddress, ViewportDetails, WheelDelta, WheelEvent, WheelMode,
|
||||||
};
|
};
|
||||||
use euclid::{Point2D, Rect, Scale, Size2D, Transform3D, Vector2D};
|
use euclid::{Point2D, Rect, Scale, Size2D, Transform3D, Vector2D};
|
||||||
use fnv::FnvHashMap;
|
|
||||||
use ipc_channel::ipc::{self, IpcSharedMemory};
|
use ipc_channel::ipc::{self, IpcSharedMemory};
|
||||||
use libc::c_void;
|
use libc::c_void;
|
||||||
use log::{debug, info, trace, warn};
|
use log::{debug, info, trace, warn};
|
||||||
|
@ -48,10 +47,10 @@ use webrender_api::units::{
|
||||||
};
|
};
|
||||||
use webrender_api::{
|
use webrender_api::{
|
||||||
self, BuiltDisplayList, DirtyRect, DisplayListPayload, DocumentId, Epoch as WebRenderEpoch,
|
self, BuiltDisplayList, DirtyRect, DisplayListPayload, DocumentId, Epoch as WebRenderEpoch,
|
||||||
ExternalScrollId, FontInstanceFlags, FontInstanceKey, FontInstanceOptions, FontKey,
|
FontInstanceFlags, FontInstanceKey, FontInstanceOptions, FontKey, HitTestFlags,
|
||||||
HitTestFlags, PipelineId as WebRenderPipelineId, PropertyBinding, ReferenceFrameKind,
|
PipelineId as WebRenderPipelineId, PropertyBinding, ReferenceFrameKind, RenderReasons,
|
||||||
RenderReasons, SampledScrollOffset, ScrollLocation, SpaceAndClipInfo, SpatialId,
|
SampledScrollOffset, ScrollLocation, SpaceAndClipInfo, SpatialId, SpatialTreeItemKey,
|
||||||
SpatialTreeItemKey, TransformStyle,
|
TransformStyle,
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::InitialCompositorState;
|
use crate::InitialCompositorState;
|
||||||
|
@ -260,26 +259,9 @@ impl PipelineDetails {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn install_new_scroll_tree(&mut self, new_scroll_tree: ScrollTree) {
|
fn install_new_scroll_tree(&mut self, new_scroll_tree: ScrollTree) {
|
||||||
let old_scroll_offsets: FnvHashMap<ExternalScrollId, LayoutVector2D> = self
|
let old_scroll_offsets = self.scroll_tree.scroll_offsets();
|
||||||
.scroll_tree
|
|
||||||
.nodes
|
|
||||||
.drain(..)
|
|
||||||
.filter_map(|node| match (node.external_id(), node.offset()) {
|
|
||||||
(Some(external_id), Some(offset)) => Some((external_id, offset)),
|
|
||||||
_ => None,
|
|
||||||
})
|
|
||||||
.collect();
|
|
||||||
|
|
||||||
self.scroll_tree = new_scroll_tree;
|
self.scroll_tree = new_scroll_tree;
|
||||||
for node in self.scroll_tree.nodes.iter_mut() {
|
self.scroll_tree.set_all_scroll_offsets(&old_scroll_offsets);
|
||||||
match node.external_id() {
|
|
||||||
Some(external_id) => match old_scroll_offsets.get(&external_id) {
|
|
||||||
Some(new_offset) => node.set_offset(*new_offset),
|
|
||||||
None => continue,
|
|
||||||
},
|
|
||||||
_ => continue,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -728,7 +710,7 @@ impl IOCompositor {
|
||||||
self.global.borrow_mut().send_transaction(txn);
|
self.global.borrow_mut().send_transaction(txn);
|
||||||
},
|
},
|
||||||
|
|
||||||
CompositorMsg::SendScrollNode(webview_id, pipeline_id, point, external_scroll_id) => {
|
CompositorMsg::SendScrollNode(webview_id, pipeline_id, offset, external_scroll_id) => {
|
||||||
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;
|
return;
|
||||||
};
|
};
|
||||||
|
@ -739,15 +721,17 @@ impl IOCompositor {
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
|
|
||||||
let offset = LayoutVector2D::new(point.x, point.y);
|
|
||||||
let Some(offset) = pipeline_details
|
let Some(offset) = pipeline_details
|
||||||
.scroll_tree
|
.scroll_tree
|
||||||
.set_scroll_offsets_for_node_with_external_scroll_id(
|
.set_scroll_offset_for_node_with_external_scroll_id(
|
||||||
external_scroll_id,
|
external_scroll_id,
|
||||||
-offset,
|
offset,
|
||||||
ScrollType::Script,
|
ScrollType::Script,
|
||||||
)
|
)
|
||||||
else {
|
else {
|
||||||
|
// The renderer should be fully up-to-date with script at this point and script
|
||||||
|
// should never try to scroll to an invalid location.
|
||||||
|
warn!("Could not scroll node with id: {external_scroll_id:?}");
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -13,7 +13,7 @@ use compositing_traits::viewport_description::{
|
||||||
DEFAULT_ZOOM, MAX_ZOOM, MIN_ZOOM, ViewportDescription,
|
DEFAULT_ZOOM, MAX_ZOOM, MIN_ZOOM, ViewportDescription,
|
||||||
};
|
};
|
||||||
use compositing_traits::{SendableFrameTree, WebViewTrait};
|
use compositing_traits::{SendableFrameTree, WebViewTrait};
|
||||||
use constellation_traits::{EmbedderToConstellationMessage, ScrollState, WindowSizeType};
|
use constellation_traits::{EmbedderToConstellationMessage, WindowSizeType};
|
||||||
use embedder_traits::{
|
use embedder_traits::{
|
||||||
AnimationState, CompositorHitTestResult, InputEvent, MouseButton, MouseButtonAction,
|
AnimationState, CompositorHitTestResult, InputEvent, MouseButton, MouseButtonAction,
|
||||||
MouseButtonEvent, MouseMoveEvent, ShutdownState, TouchEvent, TouchEventResult, TouchEventType,
|
MouseButtonEvent, MouseMoveEvent, ShutdownState, TouchEvent, TouchEventResult, TouchEventType,
|
||||||
|
@ -204,18 +204,18 @@ impl WebViewRenderer {
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut scroll_states = Vec::new();
|
let scroll_offsets = details.scroll_tree.scroll_offsets();
|
||||||
details.scroll_tree.nodes.iter().for_each(|node| {
|
|
||||||
if let (Some(scroll_id), Some(scroll_offset)) = (node.external_id(), node.offset()) {
|
// This might be true if we have not received a display list from the layout
|
||||||
scroll_states.push(ScrollState {
|
// associated with this pipeline yet. In that case, the layout is not ready to
|
||||||
scroll_id,
|
// receive scroll offsets anyway, so just save time and prevent other issues by
|
||||||
scroll_offset,
|
// not sending them.
|
||||||
});
|
if scroll_offsets.is_empty() {
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
});
|
|
||||||
|
|
||||||
let _ = self.global.borrow().constellation_sender.send(
|
let _ = self.global.borrow().constellation_sender.send(
|
||||||
EmbedderToConstellationMessage::SetScrollStates(pipeline_id, scroll_states),
|
EmbedderToConstellationMessage::SetScrollStates(pipeline_id, scroll_offsets),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -116,9 +116,8 @@ use constellation_traits::{
|
||||||
EmbedderToConstellationMessage, IFrameLoadInfo, IFrameLoadInfoWithData, IFrameSandboxState,
|
EmbedderToConstellationMessage, IFrameLoadInfo, IFrameLoadInfoWithData, IFrameSandboxState,
|
||||||
IFrameSizeMsg, Job, LoadData, LoadOrigin, LogEntry, MessagePortMsg, NavigationHistoryBehavior,
|
IFrameSizeMsg, Job, LoadData, LoadOrigin, LogEntry, MessagePortMsg, NavigationHistoryBehavior,
|
||||||
PaintMetricEvent, PortMessageTask, PortTransferInfo, SWManagerMsg, SWManagerSenders,
|
PaintMetricEvent, PortMessageTask, PortTransferInfo, SWManagerMsg, SWManagerSenders,
|
||||||
ScriptToConstellationChan, ScriptToConstellationMessage, ScrollState,
|
ScriptToConstellationChan, ScriptToConstellationMessage, ServiceWorkerManagerFactory,
|
||||||
ServiceWorkerManagerFactory, ServiceWorkerMsg, StructuredSerializedData, TraversalDirection,
|
ServiceWorkerMsg, StructuredSerializedData, TraversalDirection, WindowSizeType,
|
||||||
WindowSizeType,
|
|
||||||
};
|
};
|
||||||
use crossbeam_channel::{Receiver, Select, Sender, unbounded};
|
use crossbeam_channel::{Receiver, Select, Sender, unbounded};
|
||||||
use devtools_traits::{
|
use devtools_traits::{
|
||||||
|
@ -167,7 +166,8 @@ use webgpu_traits::{WebGPU, WebGPURequest};
|
||||||
#[cfg(feature = "webgpu")]
|
#[cfg(feature = "webgpu")]
|
||||||
use webrender::RenderApi;
|
use webrender::RenderApi;
|
||||||
use webrender::RenderApiSender;
|
use webrender::RenderApiSender;
|
||||||
use webrender_api::{DocumentId, ImageKey};
|
use webrender_api::units::LayoutVector2D;
|
||||||
|
use webrender_api::{DocumentId, ExternalScrollId, ImageKey};
|
||||||
|
|
||||||
use crate::browsingcontext::{
|
use crate::browsingcontext::{
|
||||||
AllBrowsingContextsIterator, BrowsingContext, FullyActiveBrowsingContextsIterator,
|
AllBrowsingContextsIterator, BrowsingContext, FullyActiveBrowsingContextsIterator,
|
||||||
|
@ -6051,7 +6051,11 @@ where
|
||||||
feature = "tracing",
|
feature = "tracing",
|
||||||
tracing::instrument(skip_all, fields(servo_profiling = true), level = "trace")
|
tracing::instrument(skip_all, fields(servo_profiling = true), level = "trace")
|
||||||
)]
|
)]
|
||||||
fn handle_set_scroll_states(&self, pipeline_id: PipelineId, scroll_states: Vec<ScrollState>) {
|
fn handle_set_scroll_states(
|
||||||
|
&self,
|
||||||
|
pipeline_id: PipelineId,
|
||||||
|
scroll_states: HashMap<ExternalScrollId, LayoutVector2D>,
|
||||||
|
) {
|
||||||
let Some(pipeline) = self.pipelines.get(&pipeline_id) else {
|
let Some(pipeline) = self.pipelines.get(&pipeline_id) else {
|
||||||
warn!("Discarding scroll offset update for unknown pipeline");
|
warn!("Discarding scroll offset update for unknown pipeline");
|
||||||
return;
|
return;
|
||||||
|
|
|
@ -15,16 +15,16 @@ use app_units::Au;
|
||||||
use base::Epoch;
|
use base::Epoch;
|
||||||
use base::id::{PipelineId, WebViewId};
|
use base::id::{PipelineId, WebViewId};
|
||||||
use compositing_traits::CrossProcessCompositorApi;
|
use compositing_traits::CrossProcessCompositorApi;
|
||||||
use constellation_traits::ScrollState;
|
use compositing_traits::display_list::ScrollType;
|
||||||
use embedder_traits::{Theme, UntrustedNodeAddress, ViewportDetails};
|
use embedder_traits::{Theme, UntrustedNodeAddress, ViewportDetails};
|
||||||
use euclid::default::{Point2D as UntypedPoint2D, Rect as UntypedRect};
|
use euclid::default::{Point2D as UntypedPoint2D, Rect as UntypedRect};
|
||||||
use euclid::{Point2D, Scale, Size2D, Vector2D};
|
use euclid::{Point2D, Scale, Size2D};
|
||||||
use fnv::FnvHashMap;
|
use fnv::FnvHashMap;
|
||||||
use fonts::{FontContext, FontContextWebFontMethods};
|
use fonts::{FontContext, FontContextWebFontMethods};
|
||||||
use fonts_traits::StylesheetWebFontLoadFinishedCallback;
|
use fonts_traits::StylesheetWebFontLoadFinishedCallback;
|
||||||
use fxhash::FxHashMap;
|
use fxhash::FxHashMap;
|
||||||
use ipc_channel::ipc::IpcSender;
|
use ipc_channel::ipc::IpcSender;
|
||||||
use log::{debug, error};
|
use log::{debug, error, warn};
|
||||||
use malloc_size_of::{MallocConditionalSizeOf, MallocSizeOf, MallocSizeOfOps};
|
use malloc_size_of::{MallocConditionalSizeOf, MallocSizeOf, MallocSizeOfOps};
|
||||||
use net_traits::image_cache::{ImageCache, UsePlaceholder};
|
use net_traits::image_cache::{ImageCache, UsePlaceholder};
|
||||||
use parking_lot::{Mutex, RwLock};
|
use parking_lot::{Mutex, RwLock};
|
||||||
|
@ -74,7 +74,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, LayoutPixel, LayoutPoint, LayoutSize};
|
use webrender_api::units::{DevicePixel, DevicePoint, LayoutSize, LayoutVector2D};
|
||||||
use webrender_api::{ExternalScrollId, HitTestFlags};
|
use webrender_api::{ExternalScrollId, HitTestFlags};
|
||||||
|
|
||||||
use crate::context::{CachedImageOrError, LayoutContext};
|
use crate::context::{CachedImageOrError, LayoutContext};
|
||||||
|
@ -149,6 +149,12 @@ pub struct LayoutThread {
|
||||||
/// layout trees remain the same.
|
/// layout trees remain the same.
|
||||||
need_new_display_list: Cell<bool>,
|
need_new_display_list: Cell<bool>,
|
||||||
|
|
||||||
|
/// Whether or not the existing stacking context tree is dirty and needs to be
|
||||||
|
/// rebuilt. This happens after a relayout or overflow update. The reason that we
|
||||||
|
/// don't simply clear the stacking context tree when it becomes dirty is that we need
|
||||||
|
/// to preserve scroll offsets from the old tree to the new one.
|
||||||
|
need_new_stacking_context_tree: Cell<bool>,
|
||||||
|
|
||||||
/// The box tree.
|
/// The box tree.
|
||||||
box_tree: RefCell<Option<Arc<BoxTree>>>,
|
box_tree: RefCell<Option<Arc<BoxTree>>>,
|
||||||
|
|
||||||
|
@ -161,9 +167,6 @@ pub struct LayoutThread {
|
||||||
/// A counter for epoch messages
|
/// A counter for epoch messages
|
||||||
epoch: Cell<Epoch>,
|
epoch: Cell<Epoch>,
|
||||||
|
|
||||||
/// Scroll offsets of nodes that scroll.
|
|
||||||
scroll_offsets: RefCell<HashMap<ExternalScrollId, Vector2D<f32, LayoutPixel>>>,
|
|
||||||
|
|
||||||
// A cache that maps image resources specified in CSS (e.g as the `url()` value
|
// A cache that maps image resources specified in CSS (e.g as the `url()` value
|
||||||
// for `background-image` or `content` properties) to either the final resolved
|
// for `background-image` or `content` properties) to either the final resolved
|
||||||
// image data, or an error if the image cache failed to load/decode the image.
|
// image data, or an error if the image cache failed to load/decode the image.
|
||||||
|
@ -485,11 +488,20 @@ impl Layout for LayoutThread {
|
||||||
) {
|
) {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn set_scroll_offsets(&mut self, scroll_states: &[ScrollState]) {
|
fn set_scroll_offsets_from_renderer(
|
||||||
*self.scroll_offsets.borrow_mut() = scroll_states
|
&mut self,
|
||||||
.iter()
|
scroll_states: &HashMap<ExternalScrollId, LayoutVector2D>,
|
||||||
.map(|scroll_state| (scroll_state.scroll_id, scroll_state.scroll_offset))
|
) {
|
||||||
.collect();
|
let mut stacking_context_tree = self.stacking_context_tree.borrow_mut();
|
||||||
|
let Some(stacking_context_tree) = stacking_context_tree.as_mut() else {
|
||||||
|
warn!("Received scroll offsets before finishing layout.");
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
|
||||||
|
stacking_context_tree
|
||||||
|
.compositor_info
|
||||||
|
.scroll_tree
|
||||||
|
.set_all_scroll_offsets(scroll_states);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -533,13 +545,13 @@ impl LayoutThread {
|
||||||
have_added_user_agent_stylesheets: false,
|
have_added_user_agent_stylesheets: false,
|
||||||
have_ever_generated_display_list: Cell::new(false),
|
have_ever_generated_display_list: Cell::new(false),
|
||||||
need_new_display_list: Cell::new(false),
|
need_new_display_list: Cell::new(false),
|
||||||
|
need_new_stacking_context_tree: Cell::new(false),
|
||||||
box_tree: Default::default(),
|
box_tree: Default::default(),
|
||||||
fragment_tree: Default::default(),
|
fragment_tree: Default::default(),
|
||||||
stacking_context_tree: Default::default(),
|
stacking_context_tree: Default::default(),
|
||||||
// Epoch starts at 1 because of the initial display list for epoch 0 that we send to WR
|
// Epoch starts at 1 because of the initial display list for epoch 0 that we send to WR
|
||||||
epoch: Cell::new(Epoch(1)),
|
epoch: Cell::new(Epoch(1)),
|
||||||
compositor_api: config.compositor_api,
|
compositor_api: config.compositor_api,
|
||||||
scroll_offsets: Default::default(),
|
|
||||||
stylist: Stylist::new(device, QuirksMode::NoQuirks),
|
stylist: Stylist::new(device, QuirksMode::NoQuirks),
|
||||||
resolved_images_cache: Default::default(),
|
resolved_images_cache: Default::default(),
|
||||||
debug: opts::get().debug.clone(),
|
debug: opts::get().debug.clone(),
|
||||||
|
@ -674,8 +686,9 @@ impl LayoutThread {
|
||||||
let built_display_list =
|
let built_display_list =
|
||||||
self.build_display_list(&reflow_request, damage, &mut layout_context);
|
self.build_display_list(&reflow_request, damage, &mut layout_context);
|
||||||
|
|
||||||
if let ReflowGoal::UpdateScrollNode(scroll_state) = reflow_request.reflow_goal {
|
if let ReflowGoal::UpdateScrollNode(external_scroll_id, offset) = reflow_request.reflow_goal
|
||||||
self.update_scroll_node_state(&scroll_state);
|
{
|
||||||
|
self.set_scroll_offset_from_script(external_scroll_id, offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
let pending_images = std::mem::take(&mut *layout_context.pending_images.lock());
|
let pending_images = std::mem::take(&mut *layout_context.pending_images.lock());
|
||||||
|
@ -828,12 +841,10 @@ impl LayoutThread {
|
||||||
|
|
||||||
*self.fragment_tree.borrow_mut() = Some(fragment_tree);
|
*self.fragment_tree.borrow_mut() = Some(fragment_tree);
|
||||||
|
|
||||||
// The FragmentTree has been updated, so any existing StackingContext tree that layout
|
// Changes to layout require us to generate a new stacking context tree and display
|
||||||
// had is now out of date and should be rebuilt.
|
// list the next time one is requested.
|
||||||
*self.stacking_context_tree.borrow_mut() = None;
|
|
||||||
|
|
||||||
// Force display list generation as layout has changed.
|
|
||||||
self.need_new_display_list.set(true);
|
self.need_new_display_list.set(true);
|
||||||
|
self.need_new_stacking_context_tree.set(true);
|
||||||
|
|
||||||
if self.debug.dump_style_tree {
|
if self.debug.dump_style_tree {
|
||||||
println!(
|
println!(
|
||||||
|
@ -866,6 +877,11 @@ impl LayoutThread {
|
||||||
fragment_tree.print();
|
fragment_tree.print();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Changes to overflow require us to generate a new stacking context tree and
|
||||||
|
// display list the next time one is requested.
|
||||||
|
self.need_new_display_list.set(true);
|
||||||
|
self.need_new_stacking_context_tree.set(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn build_stacking_context_tree(&self, reflow_request: &ReflowRequest, damage: RestyleDamage) {
|
fn build_stacking_context_tree(&self, reflow_request: &ReflowRequest, damage: RestyleDamage) {
|
||||||
|
@ -878,7 +894,7 @@ impl LayoutThread {
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
if !damage.contains(RestyleDamage::REBUILD_STACKING_CONTEXT) &&
|
if !damage.contains(RestyleDamage::REBUILD_STACKING_CONTEXT) &&
|
||||||
self.stacking_context_tree.borrow().is_some()
|
!self.need_new_stacking_context_tree.get()
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -889,19 +905,39 @@ impl LayoutThread {
|
||||||
viewport_size.height.to_f32_px(),
|
viewport_size.height.to_f32_px(),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
let mut stacking_context_tree = self.stacking_context_tree.borrow_mut();
|
||||||
|
let old_scroll_offsets = stacking_context_tree
|
||||||
|
.as_ref()
|
||||||
|
.map(|tree| tree.compositor_info.scroll_tree.scroll_offsets());
|
||||||
|
|
||||||
// Build the StackingContextTree. This turns the `FragmentTree` into a
|
// Build the StackingContextTree. This turns the `FragmentTree` into a
|
||||||
// tree of fragments in CSS painting order and also creates all
|
// tree of fragments in CSS painting order and also creates all
|
||||||
// applicable spatial and clip nodes.
|
// applicable spatial and clip nodes.
|
||||||
*self.stacking_context_tree.borrow_mut() = Some(StackingContextTree::new(
|
let mut new_stacking_context_tree = StackingContextTree::new(
|
||||||
fragment_tree,
|
fragment_tree,
|
||||||
viewport_size,
|
viewport_size,
|
||||||
self.id.into(),
|
self.id.into(),
|
||||||
!self.have_ever_generated_display_list.get(),
|
!self.have_ever_generated_display_list.get(),
|
||||||
&self.debug,
|
&self.debug,
|
||||||
));
|
);
|
||||||
|
|
||||||
|
// When a new StackingContextTree is built, it contains a freshly built
|
||||||
|
// ScrollTree. We want to preserve any existing scroll offsets in that tree,
|
||||||
|
// adjusted by any new scroll constraints.
|
||||||
|
if let Some(old_scroll_offsets) = old_scroll_offsets {
|
||||||
|
new_stacking_context_tree
|
||||||
|
.compositor_info
|
||||||
|
.scroll_tree
|
||||||
|
.set_all_scroll_offsets(&old_scroll_offsets);
|
||||||
|
}
|
||||||
|
|
||||||
|
*stacking_context_tree = Some(new_stacking_context_tree);
|
||||||
|
|
||||||
// Force display list generation as layout has changed.
|
// Force display list generation as layout has changed.
|
||||||
self.need_new_display_list.set(true);
|
self.need_new_display_list.set(true);
|
||||||
|
|
||||||
|
// The stacking context tree is up-to-date again.
|
||||||
|
self.need_new_stacking_context_tree.set(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Build the display list for the current layout and send it to the renderer. If no display
|
/// Build the display list for the current layout and send it to the renderer. If no display
|
||||||
|
@ -959,18 +995,33 @@ impl LayoutThread {
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
fn update_scroll_node_state(&self, state: &ScrollState) {
|
fn set_scroll_offset_from_script(
|
||||||
self.scroll_offsets
|
&self,
|
||||||
.borrow_mut()
|
external_scroll_id: ExternalScrollId,
|
||||||
.insert(state.scroll_id, state.scroll_offset);
|
offset: LayoutVector2D,
|
||||||
let point = Point2D::new(-state.scroll_offset.x, -state.scroll_offset.y);
|
) {
|
||||||
|
let mut stacking_context_tree = self.stacking_context_tree.borrow_mut();
|
||||||
|
let Some(stacking_context_tree) = stacking_context_tree.as_mut() else {
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
|
||||||
|
if let Some(offset) = stacking_context_tree
|
||||||
|
.compositor_info
|
||||||
|
.scroll_tree
|
||||||
|
.set_scroll_offset_for_node_with_external_scroll_id(
|
||||||
|
external_scroll_id,
|
||||||
|
offset,
|
||||||
|
ScrollType::Script,
|
||||||
|
)
|
||||||
|
{
|
||||||
self.compositor_api.send_scroll_node(
|
self.compositor_api.send_scroll_node(
|
||||||
self.webview_id,
|
self.webview_id,
|
||||||
self.id.into(),
|
self.id.into(),
|
||||||
LayoutPoint::from_untyped(point),
|
offset,
|
||||||
state.scroll_id,
|
external_scroll_id,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Returns profiling information which is passed to the time profiler.
|
/// Returns profiling information which is passed to the time profiler.
|
||||||
fn profiler_metadata(&self) -> Option<TimerMetadata> {
|
fn profiler_metadata(&self) -> Option<TimerMetadata> {
|
||||||
|
|
|
@ -24,7 +24,7 @@ use canvas_traits::webgl::WebGLChan;
|
||||||
use compositing_traits::CrossProcessCompositorApi;
|
use compositing_traits::CrossProcessCompositorApi;
|
||||||
use constellation_traits::{
|
use constellation_traits::{
|
||||||
DocumentState, LoadData, LoadOrigin, NavigationHistoryBehavior, ScriptToConstellationChan,
|
DocumentState, LoadData, LoadOrigin, NavigationHistoryBehavior, ScriptToConstellationChan,
|
||||||
ScriptToConstellationMessage, ScrollState, StructuredSerializedData, WindowSizeType,
|
ScriptToConstellationMessage, StructuredSerializedData, WindowSizeType,
|
||||||
};
|
};
|
||||||
use crossbeam_channel::{Sender, unbounded};
|
use crossbeam_channel::{Sender, unbounded};
|
||||||
use cssparser::SourceLocation;
|
use cssparser::SourceLocation;
|
||||||
|
@ -2097,10 +2097,7 @@ impl Window {
|
||||||
// TODO(mrobinson, #18709): Add smooth scrolling support to WebRender so that we can
|
// TODO(mrobinson, #18709): Add smooth scrolling support to WebRender so that we can
|
||||||
// properly process ScrollBehavior here.
|
// properly process ScrollBehavior here.
|
||||||
self.reflow(
|
self.reflow(
|
||||||
ReflowGoal::UpdateScrollNode(ScrollState {
|
ReflowGoal::UpdateScrollNode(scroll_id, Vector2D::new(-x, -y)),
|
||||||
scroll_id,
|
|
||||||
scroll_offset: Vector2D::new(-x, -y),
|
|
||||||
}),
|
|
||||||
can_gc,
|
can_gc,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -3234,7 +3231,7 @@ fn should_move_clip_rect(clip_rect: UntypedRect<Au>, new_viewport: UntypedRect<f
|
||||||
fn debug_reflow_events(id: PipelineId, reflow_goal: &ReflowGoal) {
|
fn debug_reflow_events(id: PipelineId, reflow_goal: &ReflowGoal) {
|
||||||
let goal_string = match *reflow_goal {
|
let goal_string = match *reflow_goal {
|
||||||
ReflowGoal::UpdateTheRendering => "\tFull",
|
ReflowGoal::UpdateTheRendering => "\tFull",
|
||||||
ReflowGoal::UpdateScrollNode(_) => "\tUpdateScrollNode",
|
ReflowGoal::UpdateScrollNode(..) => "\tUpdateScrollNode",
|
||||||
ReflowGoal::LayoutQuery(ref query_msg) => match *query_msg {
|
ReflowGoal::LayoutQuery(ref query_msg) => match *query_msg {
|
||||||
QueryMsg::ContentBox => "\tContentBoxQuery",
|
QueryMsg::ContentBox => "\tContentBoxQuery",
|
||||||
QueryMsg::ContentBoxes => "\tContentBoxesQuery",
|
QueryMsg::ContentBoxes => "\tContentBoxesQuery",
|
||||||
|
|
|
@ -39,7 +39,7 @@ use chrono::{DateTime, Local};
|
||||||
use compositing_traits::CrossProcessCompositorApi;
|
use compositing_traits::CrossProcessCompositorApi;
|
||||||
use constellation_traits::{
|
use constellation_traits::{
|
||||||
JsEvalResult, LoadData, LoadOrigin, NavigationHistoryBehavior, ScriptToConstellationChan,
|
JsEvalResult, LoadData, LoadOrigin, NavigationHistoryBehavior, ScriptToConstellationChan,
|
||||||
ScriptToConstellationMessage, ScrollState, StructuredSerializedData, WindowSizeType,
|
ScriptToConstellationMessage, StructuredSerializedData, WindowSizeType,
|
||||||
};
|
};
|
||||||
use content_security_policy::{self as csp};
|
use content_security_policy::{self as csp};
|
||||||
use crossbeam_channel::unbounded;
|
use crossbeam_channel::unbounded;
|
||||||
|
@ -99,7 +99,8 @@ use timers::{TimerEventRequest, TimerId, TimerScheduler};
|
||||||
use url::Position;
|
use url::Position;
|
||||||
#[cfg(feature = "webgpu")]
|
#[cfg(feature = "webgpu")]
|
||||||
use webgpu_traits::{WebGPUDevice, WebGPUMsg};
|
use webgpu_traits::{WebGPUDevice, WebGPUMsg};
|
||||||
use webrender_api::units::DevicePixel;
|
use webrender_api::ExternalScrollId;
|
||||||
|
use webrender_api::units::{DevicePixel, LayoutVector2D};
|
||||||
|
|
||||||
use crate::document_collection::DocumentCollection;
|
use crate::document_collection::DocumentCollection;
|
||||||
use crate::document_loader::DocumentLoader;
|
use crate::document_loader::DocumentLoader;
|
||||||
|
@ -2010,7 +2011,11 @@ impl ScriptThread {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn handle_set_scroll_states(&self, pipeline_id: PipelineId, scroll_states: Vec<ScrollState>) {
|
fn handle_set_scroll_states(
|
||||||
|
&self,
|
||||||
|
pipeline_id: PipelineId,
|
||||||
|
scroll_states: HashMap<ExternalScrollId, LayoutVector2D>,
|
||||||
|
) {
|
||||||
let Some(window) = self.documents.borrow().find_window(pipeline_id) else {
|
let Some(window) = self.documents.borrow().find_window(pipeline_id) else {
|
||||||
warn!("Received scroll states for closed pipeline {pipeline_id}");
|
warn!("Received scroll states for closed pipeline {pipeline_id}");
|
||||||
return;
|
return;
|
||||||
|
@ -2020,16 +2025,15 @@ impl ScriptThread {
|
||||||
ScriptThreadEventCategory::SetScrollState,
|
ScriptThreadEventCategory::SetScrollState,
|
||||||
Some(pipeline_id),
|
Some(pipeline_id),
|
||||||
|| {
|
|| {
|
||||||
window.layout_mut().set_scroll_offsets(&scroll_states);
|
window
|
||||||
|
.layout_mut()
|
||||||
|
.set_scroll_offsets_from_renderer(&scroll_states);
|
||||||
|
|
||||||
let mut scroll_offsets = HashMap::new();
|
let mut scroll_offsets = HashMap::new();
|
||||||
for scroll_state in scroll_states.into_iter() {
|
for (scroll_id, scroll_offset) in scroll_states.into_iter() {
|
||||||
let scroll_offset = scroll_state.scroll_offset;
|
if scroll_id.is_root() {
|
||||||
if scroll_state.scroll_id.is_root() {
|
|
||||||
window.update_viewport_for_scroll(-scroll_offset.x, -scroll_offset.y);
|
window.update_viewport_for_scroll(-scroll_offset.x, -scroll_offset.y);
|
||||||
} else if let Some(node_id) =
|
} else if let Some(node_id) = node_id_from_scroll_id(scroll_id.0 as usize) {
|
||||||
node_id_from_scroll_id(scroll_state.scroll_id.0 as usize)
|
|
||||||
{
|
|
||||||
scroll_offsets.insert(OpaqueNode(node_id), -scroll_offset);
|
scroll_offsets.insert(OpaqueNode(node_id), -scroll_offset);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,6 +4,8 @@
|
||||||
|
|
||||||
//! Defines data structures which are consumed by the Compositor.
|
//! Defines data structures which are consumed by the Compositor.
|
||||||
|
|
||||||
|
use std::collections::HashMap;
|
||||||
|
|
||||||
use base::id::ScrollTreeNodeId;
|
use base::id::ScrollTreeNodeId;
|
||||||
use bitflags::bitflags;
|
use bitflags::bitflags;
|
||||||
use embedder_traits::Cursor;
|
use embedder_traits::Cursor;
|
||||||
|
@ -338,7 +340,7 @@ impl ScrollTree {
|
||||||
|
|
||||||
/// Given an [`ExternalScrollId`] and an offset, update the scroll offset of the scroll node
|
/// Given an [`ExternalScrollId`] and an offset, update the scroll offset of the scroll node
|
||||||
/// with the given id.
|
/// 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,
|
&mut self,
|
||||||
external_scroll_id: ExternalScrollId,
|
external_scroll_id: ExternalScrollId,
|
||||||
offset: LayoutVector2D,
|
offset: LayoutVector2D,
|
||||||
|
@ -353,6 +355,29 @@ impl ScrollTree {
|
||||||
_ => None,
|
_ => 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
|
/// 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 profile_traits::mem::{OpaqueSender, ReportsChan};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use servo_geometry::{DeviceIndependentIntRect, DeviceIndependentIntSize};
|
use servo_geometry::{DeviceIndependentIntRect, DeviceIndependentIntSize};
|
||||||
use webrender_api::units::{DevicePoint, LayoutPoint, TexelRect};
|
use webrender_api::units::{DevicePoint, LayoutVector2D, TexelRect};
|
||||||
use webrender_api::{
|
use webrender_api::{
|
||||||
BuiltDisplayList, BuiltDisplayListDescriptor, ExternalImage, ExternalImageData,
|
BuiltDisplayList, BuiltDisplayListDescriptor, ExternalImage, ExternalImageData,
|
||||||
ExternalImageHandler, ExternalImageId, ExternalImageSource, ExternalScrollId,
|
ExternalImageHandler, ExternalImageId, ExternalImageSource, ExternalScrollId,
|
||||||
|
@ -124,7 +124,7 @@ pub enum CompositorMsg {
|
||||||
SendScrollNode(
|
SendScrollNode(
|
||||||
WebViewId,
|
WebViewId,
|
||||||
WebRenderPipelineId,
|
WebRenderPipelineId,
|
||||||
LayoutPoint,
|
LayoutVector2D,
|
||||||
ExternalScrollId,
|
ExternalScrollId,
|
||||||
),
|
),
|
||||||
/// Inform WebRender of a new display list for the given pipeline.
|
/// Inform WebRender of a new display list for the given pipeline.
|
||||||
|
@ -232,7 +232,7 @@ impl CrossProcessCompositorApi {
|
||||||
&self,
|
&self,
|
||||||
webview_id: WebViewId,
|
webview_id: WebViewId,
|
||||||
pipeline_id: WebRenderPipelineId,
|
pipeline_id: WebRenderPipelineId,
|
||||||
point: LayoutPoint,
|
point: LayoutVector2D,
|
||||||
scroll_id: ExternalScrollId,
|
scroll_id: ExternalScrollId,
|
||||||
) {
|
) {
|
||||||
if let Err(e) = self.0.send(CompositorMsg::SendScrollNode(
|
if let Err(e) = self.0.send(CompositorMsg::SendScrollNode(
|
||||||
|
|
|
@ -22,7 +22,6 @@ use embedder_traits::{
|
||||||
CompositorHitTestResult, Cursor, InputEvent, JavaScriptEvaluationId, MediaSessionActionType,
|
CompositorHitTestResult, Cursor, InputEvent, JavaScriptEvaluationId, MediaSessionActionType,
|
||||||
Theme, ViewportDetails, WebDriverCommandMsg,
|
Theme, ViewportDetails, WebDriverCommandMsg,
|
||||||
};
|
};
|
||||||
use euclid::Vector2D;
|
|
||||||
pub use from_script_message::*;
|
pub use from_script_message::*;
|
||||||
use ipc_channel::ipc::IpcSender;
|
use ipc_channel::ipc::IpcSender;
|
||||||
use malloc_size_of_derive::MallocSizeOf;
|
use malloc_size_of_derive::MallocSizeOf;
|
||||||
|
@ -32,7 +31,7 @@ use servo_url::{ImmutableOrigin, ServoUrl};
|
||||||
pub use structured_data::*;
|
pub use structured_data::*;
|
||||||
use strum_macros::IntoStaticStr;
|
use strum_macros::IntoStaticStr;
|
||||||
use webrender_api::ExternalScrollId;
|
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
|
/// Messages to the Constellation from the embedding layer, whether from `ServoRenderer` or
|
||||||
/// from `libservo` itself.
|
/// from `libservo` itself.
|
||||||
|
@ -90,7 +89,7 @@ pub enum EmbedderToConstellationMessage {
|
||||||
SetWebViewThrottled(WebViewId, bool),
|
SetWebViewThrottled(WebViewId, bool),
|
||||||
/// The Servo renderer scrolled and is updating the scroll states of the nodes in the
|
/// The Servo renderer scrolled and is updating the scroll states of the nodes in the
|
||||||
/// given pipeline via the constellation.
|
/// 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.
|
/// Notify the constellation that a particular paint metric event has happened for the given pipeline.
|
||||||
PaintMetric(PipelineId, PaintMetricEvent),
|
PaintMetric(PipelineId, PaintMetricEvent),
|
||||||
/// Evaluate a JavaScript string in the context of a `WebView`. When execution is complete or an
|
/// Evaluate a JavaScript string in the context of a `WebView`. When execution is complete or an
|
||||||
|
@ -136,15 +135,6 @@ pub enum WindowSizeType {
|
||||||
Resize,
|
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
|
/// The direction of a history traversal
|
||||||
#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, PartialEq, Serialize)]
|
#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, PartialEq, Serialize)]
|
||||||
pub enum TraversalDirection {
|
pub enum TraversalDirection {
|
||||||
|
|
|
@ -9,6 +9,7 @@
|
||||||
#![deny(missing_docs)]
|
#![deny(missing_docs)]
|
||||||
#![deny(unsafe_code)]
|
#![deny(unsafe_code)]
|
||||||
|
|
||||||
|
use std::collections::HashMap;
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
|
@ -20,8 +21,8 @@ use bluetooth_traits::BluetoothRequest;
|
||||||
use canvas_traits::webgl::WebGLPipeline;
|
use canvas_traits::webgl::WebGLPipeline;
|
||||||
use compositing_traits::CrossProcessCompositorApi;
|
use compositing_traits::CrossProcessCompositorApi;
|
||||||
use constellation_traits::{
|
use constellation_traits::{
|
||||||
LoadData, NavigationHistoryBehavior, ScriptToConstellationChan, ScrollState,
|
LoadData, NavigationHistoryBehavior, ScriptToConstellationChan, StructuredSerializedData,
|
||||||
StructuredSerializedData, WindowSizeType,
|
WindowSizeType,
|
||||||
};
|
};
|
||||||
use crossbeam_channel::{RecvTimeoutError, Sender};
|
use crossbeam_channel::{RecvTimeoutError, Sender};
|
||||||
use devtools_traits::ScriptToDevtoolsControlMsg;
|
use devtools_traits::ScriptToDevtoolsControlMsg;
|
||||||
|
@ -47,8 +48,8 @@ use style_traits::{CSSPixel, SpeculativePainter};
|
||||||
use stylo_atoms::Atom;
|
use stylo_atoms::Atom;
|
||||||
#[cfg(feature = "webgpu")]
|
#[cfg(feature = "webgpu")]
|
||||||
use webgpu_traits::WebGPUMsg;
|
use webgpu_traits::WebGPUMsg;
|
||||||
use webrender_api::ImageKey;
|
use webrender_api::units::{DevicePixel, LayoutVector2D};
|
||||||
use webrender_api::units::DevicePixel;
|
use webrender_api::{ExternalScrollId, ImageKey};
|
||||||
|
|
||||||
/// The initial data required to create a new layout attached to an existing script thread.
|
/// The initial data required to create a new layout attached to an existing script thread.
|
||||||
#[derive(Debug, Deserialize, Serialize)]
|
#[derive(Debug, Deserialize, Serialize)]
|
||||||
|
@ -246,7 +247,7 @@ pub enum ScriptThreadMessage {
|
||||||
SetWebGPUPort(IpcReceiver<WebGPUMsg>),
|
SetWebGPUPort(IpcReceiver<WebGPUMsg>),
|
||||||
/// The compositor scrolled and is updating the scroll states of the nodes in the given
|
/// The compositor scrolled and is updating the scroll states of the nodes in the given
|
||||||
/// pipeline via the Constellation.
|
/// 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
|
/// Evaluate the given JavaScript and return a result via a corresponding message
|
||||||
/// to the Constellation.
|
/// to the Constellation.
|
||||||
EvaluateJavaScript(PipelineId, JavaScriptEvaluationId, String),
|
EvaluateJavaScript(PipelineId, JavaScriptEvaluationId, String),
|
||||||
|
|
|
@ -11,6 +11,7 @@
|
||||||
pub mod wrapper_traits;
|
pub mod wrapper_traits;
|
||||||
|
|
||||||
use std::any::Any;
|
use std::any::Any;
|
||||||
|
use std::collections::HashMap;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use std::sync::atomic::{AtomicIsize, AtomicU64, Ordering};
|
use std::sync::atomic::{AtomicIsize, AtomicU64, Ordering};
|
||||||
|
|
||||||
|
@ -19,7 +20,7 @@ use atomic_refcell::AtomicRefCell;
|
||||||
use base::Epoch;
|
use base::Epoch;
|
||||||
use base::id::{BrowsingContextId, PipelineId, WebViewId};
|
use base::id::{BrowsingContextId, PipelineId, WebViewId};
|
||||||
use compositing_traits::CrossProcessCompositorApi;
|
use compositing_traits::CrossProcessCompositorApi;
|
||||||
use constellation_traits::{LoadData, ScrollState};
|
use constellation_traits::LoadData;
|
||||||
use embedder_traits::{Theme, UntrustedNodeAddress, ViewportDetails};
|
use embedder_traits::{Theme, UntrustedNodeAddress, ViewportDetails};
|
||||||
use euclid::default::{Point2D, Rect};
|
use euclid::default::{Point2D, Rect};
|
||||||
use fnv::FnvHashMap;
|
use fnv::FnvHashMap;
|
||||||
|
@ -48,8 +49,8 @@ use style::properties::PropertyId;
|
||||||
use style::properties::style_structs::Font;
|
use style::properties::style_structs::Font;
|
||||||
use style::selector_parser::{PseudoElement, RestyleDamage, Snapshot};
|
use style::selector_parser::{PseudoElement, RestyleDamage, Snapshot};
|
||||||
use style::stylesheets::Stylesheet;
|
use style::stylesheets::Stylesheet;
|
||||||
use webrender_api::ImageKey;
|
use webrender_api::units::{DeviceIntSize, LayoutVector2D};
|
||||||
use webrender_api::units::DeviceIntSize;
|
use webrender_api::{ExternalScrollId, ImageKey};
|
||||||
|
|
||||||
pub trait GenericLayoutDataTrait: Any + MallocSizeOfTrait {
|
pub trait GenericLayoutDataTrait: Any + MallocSizeOfTrait {
|
||||||
fn as_any(&self) -> &dyn Any;
|
fn as_any(&self) -> &dyn Any;
|
||||||
|
@ -245,7 +246,10 @@ pub trait Layout {
|
||||||
);
|
);
|
||||||
|
|
||||||
/// Set the scroll states of this layout after a compositor scroll.
|
/// 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_box(&self, node: TrustedNodeAddress) -> Option<Rect<Au>>;
|
||||||
fn query_content_boxes(&self, node: TrustedNodeAddress) -> Vec<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
|
/// 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.
|
/// remain untouched and layout won't forward this back to script.
|
||||||
UpdateScrollNode(ScrollState),
|
UpdateScrollNode(ExternalScrollId, LayoutVector2D),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ReflowGoal {
|
impl ReflowGoal {
|
||||||
|
@ -341,7 +345,7 @@ impl ReflowGoal {
|
||||||
/// be present or false if it only needs stacking-relative positions.
|
/// be present or false if it only needs stacking-relative positions.
|
||||||
pub fn needs_display_list(&self) -> bool {
|
pub fn needs_display_list(&self) -> bool {
|
||||||
match *self {
|
match *self {
|
||||||
ReflowGoal::UpdateTheRendering | ReflowGoal::UpdateScrollNode(_) => true,
|
ReflowGoal::UpdateTheRendering | ReflowGoal::UpdateScrollNode(..) => true,
|
||||||
ReflowGoal::LayoutQuery(ref querymsg) => match *querymsg {
|
ReflowGoal::LayoutQuery(ref querymsg) => match *querymsg {
|
||||||
QueryMsg::ElementInnerOuterTextQuery |
|
QueryMsg::ElementInnerOuterTextQuery |
|
||||||
QueryMsg::InnerWindowDimensionsQuery |
|
QueryMsg::InnerWindowDimensionsQuery |
|
||||||
|
@ -363,7 +367,7 @@ impl ReflowGoal {
|
||||||
/// false if a layout_thread display list is sufficient.
|
/// false if a layout_thread display list is sufficient.
|
||||||
pub fn needs_display(&self) -> bool {
|
pub fn needs_display(&self) -> bool {
|
||||||
match *self {
|
match *self {
|
||||||
ReflowGoal::UpdateTheRendering | ReflowGoal::UpdateScrollNode(_) => true,
|
ReflowGoal::UpdateTheRendering | ReflowGoal::UpdateScrollNode(..) => true,
|
||||||
ReflowGoal::LayoutQuery(ref querymsg) => match *querymsg {
|
ReflowGoal::LayoutQuery(ref querymsg) => match *querymsg {
|
||||||
QueryMsg::NodesFromPointQuery |
|
QueryMsg::NodesFromPointQuery |
|
||||||
QueryMsg::TextIndexQuery |
|
QueryMsg::TextIndexQuery |
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue