diff options
author | Martin Robinson <mrobinson@igalia.com> | 2024-03-29 17:25:47 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2024-03-29 16:25:47 +0000 |
commit | b7d089930ea075a580a20bede881c677a0ba0fb0 (patch) | |
tree | c85d7bf011d80d5f3c47a2a5b5df2948134ec1b8 | |
parent | 07391e346b0ff3e89485ddc7e8f3c448ef1de4f4 (diff) | |
download | servo-b7d089930ea075a580a20bede881c677a0ba0fb0.tar.gz servo-b7d089930ea075a580a20bede881c677a0ba0fb0.zip |
layout: Remove LayoutRPC and query layout via the `Layout` trait (#31937)
Instead of the tricky `LayoutRPC` interface, query layout using the
`Layout` trait. This means that now queries will requires calling layout
and then running the query. During layout an enum is used to indicate
what kind of layout is necessary.
This change also removes the mutex-locked `rw_data` from both layout
threads. It's no longer necessary since layout runs synchronously. The
one downside here is that for resolved style queries, we now have to
create two StyleContexts. One for layout and one for the query itself.
The creation of this context should not be very expensive though.
`LayoutRPC` used to be necessary because layout used to run
asynchronously from script, but that no longer happens. With this
change, it becomes possible to safely pass nodes to layout from script
-- a cleanup that can happen in a followup change.
-rw-r--r-- | components/layout/query.rs | 190 | ||||
-rw-r--r-- | components/layout_2020/query.rs | 192 | ||||
-rw-r--r-- | components/layout_thread/lib.rs | 576 | ||||
-rw-r--r-- | components/layout_thread_2020/lib.rs | 519 | ||||
-rw-r--r-- | components/script/dom/documentorshadowroot.rs | 11 | ||||
-rw-r--r-- | components/script/dom/htmlelement.rs | 9 | ||||
-rwxr-xr-x | components/script/dom/htmlinputelement.rs | 4 | ||||
-rw-r--r-- | components/script/dom/window.rs | 119 | ||||
-rw-r--r-- | components/shared/msg/constellation_msg.rs | 1 | ||||
-rw-r--r-- | components/shared/script_layout/lib.rs | 58 | ||||
-rw-r--r-- | components/shared/script_layout/message.rs | 87 | ||||
-rw-r--r-- | components/shared/script_layout/rpc.rs | 75 |
12 files changed, 667 insertions, 1174 deletions
diff --git a/components/layout/query.rs b/components/layout/query.rs index 4225c170b42..d8dd633e8c3 100644 --- a/components/layout/query.rs +++ b/components/layout/query.rs @@ -6,22 +6,14 @@ use std::cmp::{max, min}; use std::ops::Deref; -use std::sync::{Arc, Mutex}; use app_units::Au; use euclid::default::{Box2D, Point2D, Rect, Size2D, Vector2D}; -use euclid::Size2D as TypedSize2D; -use ipc_channel::ipc::IpcSender; use msg::constellation_msg::PipelineId; -use script_layout_interface::rpc::{ - ContentBoxResponse, ContentBoxesResponse, LayoutRPC, NodeGeometryResponse, - NodeScrollIdResponse, OffsetParentResponse, ResolvedStyleResponse, TextIndexResponse, -}; use script_layout_interface::wrapper_traits::{ LayoutNode, ThreadSafeLayoutElement, ThreadSafeLayoutNode, }; -use script_layout_interface::{LayoutElementType, LayoutNodeType}; -use script_traits::{LayoutMsg as ConstellationMsg, UntrustedNodeAddress}; +use script_layout_interface::{LayoutElementType, LayoutNodeType, OffsetParentResponse}; use servo_arc::Arc as ServoArc; use servo_url::ServoUrl; use style::computed_values::display::T as Display; @@ -33,17 +25,16 @@ use style::logical_geometry::{BlockFlowDirection, InlineBaseDirection, WritingMo use style::properties::style_structs::{self, Font}; use style::properties::{ parse_one_declaration_into, ComputedValues, Importance, LonghandId, PropertyDeclarationBlock, - PropertyDeclarationId, PropertyId, SourcePropertyDeclaration, + PropertyDeclarationId, PropertyId, ShorthandId, SourcePropertyDeclaration, }; use style::selector_parser::PseudoElement; use style::shared_lock::SharedRwLock; use style::stylesheets::{CssRuleType, Origin, UrlExtraData}; -use style_traits::{CSSPixel, ParsingMode, ToCss}; +use style_traits::{ParsingMode, ToCss}; use webrender_api::ExternalScrollId; use crate::construct::ConstructionResult; -use crate::context::LayoutContext; -use crate::display_list::items::{DisplayList, OpaqueNode, ScrollOffsetMap}; +use crate::display_list::items::OpaqueNode; use crate::display_list::IndexableText; use crate::flow::{Flow, GetBaseFlow}; use crate::fragment::{Fragment, FragmentBorderBoxIterator, FragmentFlags, SpecificFragmentInfo}; @@ -51,60 +42,6 @@ use crate::inline::InlineFragmentNodeFlags; use crate::sequential; use crate::wrapper::LayoutNodeLayoutData; -/// Mutable data belonging to the LayoutThread. -/// -/// This needs to be protected by a mutex so we can do fast RPCs. -pub struct LayoutThreadData { - /// The channel on which messages can be sent to the constellation. - pub constellation_chan: IpcSender<ConstellationMsg>, - - /// The root stacking context. - pub display_list: Option<DisplayList>, - - pub indexable_text: IndexableText, - - /// A queued response for the union of the content boxes of a node. - pub content_box_response: Option<Rect<Au>>, - - /// A queued response for the content boxes of a node. - pub content_boxes_response: Vec<Rect<Au>>, - - /// A queued response for the client {top, left, width, height} of a node in pixels. - pub client_rect_response: Rect<i32>, - - /// A queued response for the scroll id for a given node. - pub scroll_id_response: Option<ExternalScrollId>, - - /// A queued response for the scroll {top, left, width, height} of a node in pixels. - pub scrolling_area_response: Rect<i32>, - - /// A queued response for the resolved style property of an element. - pub resolved_style_response: String, - - /// A queued response for the resolved font style for canvas. - pub resolved_font_style_response: Option<ServoArc<Font>>, - - /// A queued response for the offset parent/rect of a node. - pub offset_parent_response: OffsetParentResponse, - - /// Scroll offsets of scrolling regions. - pub scroll_offsets: ScrollOffsetMap, - - /// Index in a text fragment. We need this do determine the insertion point. - pub text_index_response: TextIndexResponse, - - /// A queued response for the list of nodes at a given point. - pub nodes_from_point_response: Vec<UntrustedNodeAddress>, - - /// A queued response for the inner text of a given element. - pub element_inner_text_response: String, - - /// A queued response for the viewport dimensions for a given browsing context. - pub inner_window_dimensions_response: Option<TypedSize2D<f32, CSSPixel>>, -} - -pub struct LayoutRPCImpl(pub Arc<Mutex<LayoutThreadData>>); - // https://drafts.csswg.org/cssom-view/#overflow-directions fn overflow_direction(writing_mode: &WritingMode) -> OverflowDirection { match ( @@ -128,90 +65,6 @@ fn overflow_direction(writing_mode: &WritingMode) -> OverflowDirection { } } -impl LayoutRPC for LayoutRPCImpl { - // The neat thing here is that in order to answer the following two queries we only - // need to compare nodes for equality. Thus we can safely work only with `OpaqueNode`. - fn content_box(&self) -> ContentBoxResponse { - let LayoutRPCImpl(rw_data) = self; - let rw_data = rw_data.lock().unwrap(); - ContentBoxResponse(rw_data.content_box_response) - } - - /// Requests the dimensions of all the content boxes, as in the `getClientRects()` call. - fn content_boxes(&self) -> ContentBoxesResponse { - let LayoutRPCImpl(rw_data) = self; - let rw_data = rw_data.lock().unwrap(); - ContentBoxesResponse(rw_data.content_boxes_response.clone()) - } - - fn nodes_from_point_response(&self) -> Vec<UntrustedNodeAddress> { - let LayoutRPCImpl(rw_data) = self; - let rw_data = rw_data.lock().unwrap(); - rw_data.nodes_from_point_response.clone() - } - - fn node_geometry(&self) -> NodeGeometryResponse { - let LayoutRPCImpl(rw_data) = self; - let rw_data = rw_data.lock().unwrap(); - NodeGeometryResponse { - client_rect: rw_data.client_rect_response, - } - } - - fn scrolling_area(&self) -> NodeGeometryResponse { - NodeGeometryResponse { - client_rect: self.0.lock().unwrap().scrolling_area_response, - } - } - - fn node_scroll_id(&self) -> NodeScrollIdResponse { - NodeScrollIdResponse( - self.0 - .lock() - .unwrap() - .scroll_id_response - .expect("scroll id is not correctly fetched"), - ) - } - - /// Retrieves the resolved value for a CSS style property. - fn resolved_style(&self) -> ResolvedStyleResponse { - let LayoutRPCImpl(rw_data) = self; - let rw_data = rw_data.lock().unwrap(); - ResolvedStyleResponse(rw_data.resolved_style_response.clone()) - } - - fn resolved_font_style(&self) -> Option<ServoArc<Font>> { - let LayoutRPCImpl(rw_data) = self; - let rw_data = rw_data.lock().unwrap(); - rw_data.resolved_font_style_response.clone() - } - - fn offset_parent(&self) -> OffsetParentResponse { - let LayoutRPCImpl(rw_data) = self; - let rw_data = rw_data.lock().unwrap(); - rw_data.offset_parent_response.clone() - } - - fn text_index(&self) -> TextIndexResponse { - let LayoutRPCImpl(rw_data) = self; - let rw_data = rw_data.lock().unwrap(); - rw_data.text_index_response.clone() - } - - fn element_inner_text(&self) -> String { - let LayoutRPCImpl(rw_data) = self; - let rw_data = rw_data.lock().unwrap(); - rw_data.element_inner_text_response.clone() - } - - fn inner_window_dimensions(&self) -> Option<TypedSize2D<f32, CSSPixel>> { - let LayoutRPCImpl(rw_data) = self; - let rw_data = rw_data.lock().unwrap(); - rw_data.inner_window_dimensions_response - } -} - struct UnioningFragmentBorderBoxIterator { node_address: OpaqueNode, rect: Option<Rect<Au>>, @@ -788,14 +641,13 @@ pub fn process_scrolling_area_request( fn create_font_declaration( value: &str, - property: &PropertyId, url_data: &ServoUrl, quirks_mode: QuirksMode, ) -> Option<PropertyDeclarationBlock> { let mut declarations = SourcePropertyDeclaration::default(); let result = parse_one_declaration_into( &mut declarations, - property.clone(), + PropertyId::Shorthand(ShorthandId::Font), value, Origin::Author, &UrlExtraData(url_data.get_arc()), @@ -839,10 +691,9 @@ where } pub fn process_resolved_font_style_request<'dom, E>( - context: &LayoutContext, + context: &SharedStyleContext, node: E, value: &str, - property: &PropertyId, url_data: ServoUrl, shared_lock: &SharedRwLock, ) -> Option<ServoArc<Font>> @@ -853,8 +704,8 @@ where use style::traversal::resolve_style; // 1. Parse the given font property value - let quirks_mode = context.style_context.quirks_mode(); - let declarations = create_font_declaration(value, property, &url_data, quirks_mode)?; + let quirks_mode = context.quirks_mode(); + let declarations = create_font_declaration(value, &url_data, quirks_mode)?; // TODO: Reject 'inherit' and 'initial' values for the font property. @@ -866,7 +717,7 @@ where } else { let mut tlc = ThreadLocalStyleContext::new(); let mut context = StyleContext { - shared: &context.style_context, + shared: context, thread_local: &mut tlc, }; let styles = resolve_style(&mut context, element, RuleInclusion::All, None, None); @@ -874,22 +725,13 @@ where } } else { let default_declarations = - create_font_declaration("10px sans-serif", property, &url_data, quirks_mode).unwrap(); - resolve_for_declarations::<E>( - &context.style_context, - None, - default_declarations, - shared_lock, - ) + create_font_declaration("10px sans-serif", &url_data, quirks_mode).unwrap(); + resolve_for_declarations::<E>(context, None, default_declarations, shared_lock) }; // 3. Resolve the parsed value with resolved styles of the parent element - let computed_values = resolve_for_declarations::<E>( - &context.style_context, - Some(&*parent_style), - declarations, - shared_lock, - ); + let computed_values = + resolve_for_declarations::<E>(context, Some(&*parent_style), declarations, shared_lock); Some(computed_values.clone_font()) } @@ -897,7 +739,7 @@ where /// Return the resolved value of property for a given (pseudo)element. /// <https://drafts.csswg.org/cssom/#resolved-value> pub fn process_resolved_style_request<'dom>( - context: &LayoutContext, + context: &SharedStyleContext, node: impl LayoutNode<'dom>, pseudo: &Option<PseudoElement>, property: &PropertyId, @@ -921,7 +763,7 @@ pub fn process_resolved_style_request<'dom>( let mut tlc = ThreadLocalStyleContext::new(); let mut context = StyleContext { - shared: &context.style_context, + shared: context, thread_local: &mut tlc, }; @@ -1112,7 +954,7 @@ pub fn process_offset_parent_query( rect: Rect::new(origin, size), } }, - _ => OffsetParentResponse::empty(), + _ => OffsetParentResponse::default(), } } diff --git a/components/layout_2020/query.rs b/components/layout_2020/query.rs index 9dfd573493b..2702fe52117 100644 --- a/components/layout_2020/query.rs +++ b/components/layout_2020/query.rs @@ -3,22 +3,17 @@ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ //! Utilities for querying the layout, as needed by layout. -use std::collections::HashMap; -use std::sync::{Arc, Mutex}; +use std::sync::Arc; use app_units::Au; use euclid::default::{Point2D, Rect}; use euclid::{SideOffsets2D, Size2D, Vector2D}; use log::warn; use msg::constellation_msg::PipelineId; -use script_layout_interface::rpc::{ - ContentBoxResponse, ContentBoxesResponse, LayoutRPC, NodeGeometryResponse, - NodeScrollIdResponse, OffsetParentResponse, ResolvedStyleResponse, TextIndexResponse, -}; use script_layout_interface::wrapper_traits::{ LayoutNode, ThreadSafeLayoutElement, ThreadSafeLayoutNode, }; -use script_traits::UntrustedNodeAddress; +use script_layout_interface::OffsetParentResponse; use servo_arc::Arc as ServoArc; use servo_url::ServoUrl; use style::computed_values::position::T as Position; @@ -27,7 +22,7 @@ use style::dom::{OpaqueNode, TElement}; use style::properties::style_structs::Font; use style::properties::{ parse_one_declaration_into, ComputedValues, Importance, LonghandId, PropertyDeclarationBlock, - PropertyDeclarationId, PropertyId, SourcePropertyDeclaration, + PropertyDeclarationId, PropertyId, ShorthandId, SourcePropertyDeclaration, }; use style::selector_parser::PseudoElement; use style::shared_lock::SharedRwLock; @@ -35,146 +30,11 @@ use style::stylesheets::{CssRuleType, Origin, UrlExtraData}; use style::stylist::RuleInclusion; use style::traversal::resolve_style; use style::values::generics::text::LineHeight; -use style_traits::{CSSPixel, ParsingMode, ToCss}; -use webrender_api::units::LayoutPixel; -use webrender_api::{DisplayListBuilder, ExternalScrollId}; +use style_traits::{ParsingMode, ToCss}; +use webrender_api::ExternalScrollId; -use crate::context::LayoutContext; use crate::fragment_tree::{Fragment, FragmentFlags, FragmentTree, Tag}; -/// Mutable data belonging to the LayoutThread. -/// -/// This needs to be protected by a mutex so we can do fast RPCs. -pub struct LayoutThreadData { - /// The root stacking context. - pub display_list: Option<DisplayListBuilder>, - - /// A queued response for the union of the content boxes of a node. - pub content_box_response: Option<Rect<Au>>, - - /// A queued response for the content boxes of a node. - pub content_boxes_response: Vec<Rect<Au>>, - - /// A queued response for the client {top, left, width, height} of a node in pixels. - pub client_rect_response: Rect<i32>, - - /// A queued response for the scroll id for a given node. - pub scroll_id_response: Option<ExternalScrollId>, - - /// A queued response for the scroll {top, left, width, height} of a node in pixels. - pub scrolling_area_response: Rect<i32>, - - /// A queued response for the resolved style property of an element. - pub resolved_style_response: String, - - /// A queued response for the resolved font style for canvas. - pub resolved_font_style_response: Option<ServoArc<Font>>, - - /// A queued response for the offset parent/rect of a node. - pub offset_parent_response: OffsetParentResponse, - - /// Scroll offsets of scrolling regions. - pub scroll_offsets: HashMap<ExternalScrollId, Vector2D<f32, LayoutPixel>>, - - /// Index in a text fragment. We need this do determine the insertion point. - pub text_index_response: TextIndexResponse, - - /// A queued response for the list of nodes at a given point. - pub nodes_from_point_response: Vec<UntrustedNodeAddress>, - - /// A queued response for the inner text of a given element. - pub element_inner_text_response: String, - - /// A queued response for the viewport dimensions for a given browsing context. - pub inner_window_dimensions_response: Option<Size2D<f32, CSSPixel>>, -} - -pub struct LayoutRPCImpl(pub Arc<Mutex<LayoutThreadData>>); - -impl LayoutRPC for LayoutRPCImpl { - // The neat thing here is that in order to answer the following two queries we only - // need to compare nodes for equality. Thus we can safely work only with `OpaqueNode`. - fn content_box(&self) -> ContentBoxResponse { - let LayoutRPCImpl(rw_data) = self; - let rw_data = rw_data.lock().unwrap(); - ContentBoxResponse(rw_data.content_box_response) - } - - /// Requests the dimensions of all the content boxes, as in the `getClientRects()` call. - fn content_boxes(&self) -> ContentBoxesResponse { - let LayoutRPCImpl(rw_data) = self; - let rw_data = rw_data.lock().unwrap(); - ContentBoxesResponse(rw_data.content_boxes_response.clone()) - } - - fn nodes_from_point_response(&self) -> Vec<UntrustedNodeAddress> { - let LayoutRPCImpl(rw_data) = self; - let rw_data = rw_data.lock().unwrap(); - rw_data.nodes_from_point_response.clone() - } - - fn node_geometry(&self) -> NodeGeometryResponse { - let LayoutRPCImpl(rw_data) = self; - let rw_data = rw_data.lock().unwrap(); - NodeGeometryResponse { - client_rect: rw_data.client_rect_response, - } - } - - fn scrolling_area(&self) -> NodeGeometryResponse { - NodeGeometryResponse { - client_rect: self.0.lock().unwrap().scrolling_area_response, - } - } - - fn node_scroll_id(&self) -> NodeScrollIdResponse { - NodeScrollIdResponse( - self.0 - .lock() - .unwrap() - .scroll_id_response - .expect("scroll id is not correctly fetched"), - ) - } - - /// Retrieves the resolved value for a CSS style property. - fn resolved_style(&self) -> ResolvedStyleResponse { - let LayoutRPCImpl(rw_data) = self; - let rw_data = rw_data.lock().unwrap(); - ResolvedStyleResponse(rw_data.resolved_style_response.clone()) - } - - fn resolved_font_style(&self) -> Option<ServoArc<Font>> { - let LayoutRPCImpl(rw_data) = self; - let rw_data = rw_data.lock().unwrap(); - rw_data.resolved_font_style_response.clone() - } - - fn offset_parent(&self) -> OffsetParentResponse { - let LayoutRPCImpl(rw_data) = self; - let rw_data = rw_data.lock().unwrap(); - rw_data.offset_parent_response.clone() - } - - fn text_index(&self) -> TextIndexResponse { - let LayoutRPCImpl(rw_data) = self; - let rw_data = rw_data.lock().unwrap(); - rw_data.text_index_response.clone() - } - - fn element_inner_text(&self) -> String { - let LayoutRPCImpl(rw_data) = self; - let rw_data = rw_data.lock().unwrap(); - rw_data.element_inner_text_response.clone() - } - - fn inner_window_dimensions(&self) -> Option<Size2D<f32, CSSPixel>> { - let LayoutRPCImpl(rw_data) = self; - let rw_data = rw_data.lock().unwrap(); - rw_data.inner_window_dimensions_response - } -} - pub fn process_content_box_request( requested_node: OpaqueNode, fragment_tree: Option<Arc<FragmentTree>>, @@ -242,7 +102,7 @@ pub fn process_node_scroll_area_request( /// Return the resolved value of property for a given (pseudo)element. /// <https://drafts.csswg.org/cssom/#resolved-value> pub fn process_resolved_style_request<'dom>( - context: &LayoutContext, + context: &SharedStyleContext, node: impl LayoutNode<'dom>, pseudo: &Option<PseudoElement>, property: &PropertyId, @@ -386,7 +246,7 @@ pub fn process_resolved_style_request<'dom>( } pub fn process_resolved_style_request_for_unstyled_node<'dom>( - context: &LayoutContext, + context: &SharedStyleContext, node: impl LayoutNode<'dom>, pseudo: &Option<PseudoElement>, property: &PropertyId, @@ -398,7 +258,7 @@ pub fn process_resolved_style_request_for_unstyled_node<'dom>( let mut tlc = ThreadLocalStyleContext::new(); let mut context = StyleContext { - shared: &context.style_context, + shared: context, thread_local: &mut tlc, }; @@ -449,8 +309,7 @@ pub fn process_offset_parent_query( node: OpaqueNode, fragment_tree: Option<Arc<FragmentTree>>, ) -> OffsetParentResponse { - process_offset_parent_query_inner(node, fragment_tree) - .unwrap_or_else(OffsetParentResponse::empty) + process_offset_parent_query_inner(node, fragment_tree).unwrap_or_default() } #[inline] @@ -656,14 +515,13 @@ pub fn process_element_inner_text_query<'dom>(_node: impl LayoutNode<'dom>) -> S "".to_owned() } -pub fn process_text_index_request(_node: OpaqueNode, _point: Point2D<Au>) -> TextIndexResponse { - TextIndexResponse(None) +pub fn process_text_index_request(_node: OpaqueNode, _point: Point2D<Au>) -> Option<usize> { + None } pub fn process_resolved_font_style_query<'dom, E>( - context: &LayoutContext, + context: &SharedStyleContext, node: E, - property: &PropertyId, value: &str, url_data: ServoUrl, shared_lock: &SharedRwLock, @@ -673,14 +531,13 @@ where { fn create_font_declaration( value: &str, - property: &PropertyId, url_data: &ServoUrl, quirks_mode: QuirksMode, ) -> Option<PropertyDeclarationBlock> { let mut declarations = SourcePropertyDeclaration::default(); let result = parse_one_declaration_into( &mut declarations, - property.clone(), + PropertyId::Shorthand(ShorthandId::Font), value, Origin::Author, &UrlExtraData(url_data.get_arc()), @@ -724,8 +581,8 @@ where // https://html.spec.whatwg.org/multipage/#dom-context-2d-font // 1. Parse the given font property value - let quirks_mode = context.style_context.quirks_mode(); - let declarations = create_font_declaration(value, property, &url_data, quirks_mode)?; + let quirks_mode = context.quirks_mode(); + let declarations = create_font_declaration(value, &url_data, quirks_mode)?; // TODO: Reject 'inherit' and 'initial' values for the font property. @@ -737,7 +594,7 @@ where } else { let mut tlc = ThreadLocalStyleContext::new(); let mut context = StyleContext { - shared: &context.style_context, + shared: context, thread_local: &mut tlc, }; let styles = resolve_style(&mut context, element, RuleInclusion::All, None, None); @@ -745,22 +602,13 @@ where } } else { let default_declarations = - create_font_declaration("10px sans-serif", property, &url_data, quirks_mode).unwrap(); - resolve_for_declarations::<E>( - &context.style_context, - None, - default_declarations, - shared_lock, - ) + create_font_declaration("10px sans-serif", &url_data, quirks_mode).unwrap(); + resolve_for_declarations::<E>(context, None, default_declarations, shared_lock) }; // 3. Resolve the parsed value with resolved styles of the parent element - let computed_values = resolve_for_declarations::<E>( - &context.style_context, - Some(&*parent_style), - declarations, - shared_lock, - ); + let computed_values = + resolve_for_declarations::<E>(context, Some(&*parent_style), declarations, shared_lock); Some(computed_values.clone_font()) } diff --git a/components/layout_thread/lib.rs b/components/layout_thread/lib.rs index c54d65700b0..beeb30ae9cf 100644 --- a/components/layout_thread/lib.rs +++ b/components/layout_thread/lib.rs @@ -14,11 +14,11 @@ use std::collections::HashMap; use std::ops::{Deref, DerefMut}; use std::process; use std::sync::atomic::{AtomicUsize, Ordering}; -use std::sync::{Arc, Mutex, MutexGuard}; +use std::sync::{Arc, Mutex}; use app_units::Au; use embedder_traits::resources::{self, Resource}; -use euclid::default::Size2D as UntypedSize2D; +use euclid::default::{Point2D as UntypedPoint2D, Rect as UntypedRect, Size2D as UntypedSize2D}; use euclid::{Point2D, Rect, Scale, Size2D}; use fnv::FnvHashMap; use fxhash::{FxHashMap, FxHashSet}; @@ -32,7 +32,7 @@ use layout::construct::ConstructionResult; use layout::context::{ malloc_size_of_persistent_local_context, LayoutContext, RegisteredPainter, RegisteredPainters, }; -use layout::display_list::items::WebRenderImageInfo; +use layout::display_list::items::{DisplayList, ScrollOffsetMap, WebRenderImageInfo}; use layout::display_list::{IndexableText, ToLayout}; use layout::flow::{Flow, FlowFlags, GetBaseFlow, ImmutableFlowUtils, MutableOwnedFlowUtils}; use layout::flow_ref::FlowRef; @@ -41,7 +41,7 @@ use layout::query::{ process_client_rect_query, process_content_box_request, process_content_boxes_request, process_element_inner_text_query, process_node_scroll_id_request, process_offset_parent_query, process_resolved_font_style_request, process_resolved_style_request, - process_scrolling_area_request, LayoutRPCImpl, LayoutThreadData, + process_scrolling_area_request, }; use layout::traversal::{ construct_flows_at_ancestors, ComputeStackingRelativePositions, PreorderFlowTraversal, @@ -63,11 +63,12 @@ use profile_traits::time::{ }; use script::layout_dom::{ServoLayoutDocument, ServoLayoutElement, ServoLayoutNode}; use script_layout_interface::message::{ - Msg, NodesFromPointQueryType, QueryMsg, Reflow, ReflowComplete, ReflowGoal, ScriptReflow, + Msg, NodesFromPointQueryType, Reflow, ReflowComplete, ReflowGoal, ScriptReflow, }; -use script_layout_interface::rpc::{LayoutRPC, OffsetParentResponse, TextIndexResponse}; use script_layout_interface::wrapper_traits::LayoutNode; -use script_layout_interface::{Layout, LayoutConfig, LayoutFactory}; +use script_layout_interface::{ + Layout, LayoutConfig, LayoutFactory, OffsetParentResponse, TrustedNodeAddress, +}; use script_traits::{ ConstellationControlMsg, DrawAPaintImageResult, IFrameSizeMsg, LayoutControlMsg, LayoutMsg as ConstellationMsg, PaintWorkletError, Painter, ScrollState, UntrustedNodeAddress, @@ -81,13 +82,14 @@ use style::animation::{AnimationSetKey, DocumentAnimationSet, ElementAnimationSe use style::context::{ QuirksMode, RegisteredSpeculativePainter, RegisteredSpeculativePainters, SharedStyleContext, }; -use style::dom::{ShowSubtree, ShowSubtreeDataAndPrimaryValues, TElement, TNode}; +use style::dom::{OpaqueNode, ShowSubtree, ShowSubtreeDataAndPrimaryValues, TElement, TNode}; use style::driver; use style::error_reporting::RustLogReporter; use style::global_style_data::{GLOBAL_STYLE_DATA, STYLE_THREAD_POOL}; use style::invalidation::element::restyle_hints::RestyleHint; use style::logical_geometry::LogicalPoint; use style::media_queries::{Device, MediaList, MediaType}; +use style::properties::style_structs::Font; use style::properties::PropertyId; use style::selector_parser::{PseudoElement, SnapshotMap}; use style::servo::restyle_damage::ServoRestyleDamage; @@ -158,11 +160,14 @@ pub struct LayoutThread { /// constraints. viewport_size: UntypedSize2D<Au>, - /// A mutex to allow for fast, read-only RPC of layout's internal data - /// structures, while still letting the LayoutThread modify them. - /// - /// All the other elements of this struct are read-only. - rw_data: Arc<Mutex<LayoutThreadData>>, + /// The root stacking context. + display_list: RefCell<Option<DisplayList>>, + + /// A map that stores all of the indexable text in this layout. + indexable_text: RefCell<IndexableText>, + + /// Scroll offsets of scrolling regions. + scroll_offsets: RefCell<ScrollOffsetMap>, webrender_image_cache: Arc<RwLock<FnvHashMap<(ServoUrl, UsePlaceholder), WebRenderImageInfo>>>, @@ -245,56 +250,6 @@ impl Drop for ScriptReflowResult { } } -/// The `LayoutThread` `rw_data` lock must remain locked until the first reflow, -/// as RPC calls don't make sense until then. Use this in combination with -/// `LayoutThread::lock_rw_data` and `LayoutThread::return_rw_data`. -pub enum RWGuard<'a> { - /// If the lock was previously held, from when the thread started. - Held(MutexGuard<'a, LayoutThreadData>), - /// If the lock was just used, and has been returned since there has been - /// a reflow already. - Used(MutexGuard<'a, LayoutThreadData>), -} - -impl<'a> Deref for RWGuard<'a> { - type Target = LayoutThreadData; - fn deref(&self) -> &LayoutThreadData { - match *self { - RWGuard::Held(ref x) => &**x, - RWGuard::Used(ref x) => &**x, - } - } -} - -impl<'a> DerefMut for RWGuard<'a> { - fn deref_mut(&mut self) -> &mut LayoutThreadData { - match *self { - RWGuard::Held(ref mut x) => &mut **x, - RWGuard::Used(ref mut x) => &mut **x, - } - } -} - -struct RwData<'a, 'b: 'a> { - rw_data: &'b Arc<Mutex<LayoutThreadData>>, - possibly_locked_rw_data: &'a mut Option<MutexGuard<'b, LayoutThreadData>>, -} - -impl<'a, 'b: 'a> RwData<'a, 'b> { - /// If no reflow has happened yet, this will just return the lock in - /// `possibly_locked_rw_data`. Otherwise, it will acquire the `rw_data` lock. - /// - /// If you do not wish RPCs to remain blocked, just drop the `RWGuard` - /// returned from this function. If you _do_ wish for them to remain blocked, - /// use `block`. - fn lock(&mut self) -> RWGuard<'b> { - match self.possibly_locked_rw_data.take() { - None => RWGuard::Used(self.rw_data.lock().unwrap()), - Some(x) => RWGuard::Held(x), - } - } -} - impl Layout for LayoutThread { fn process(&mut self, msg: script_layout_interface::message::Msg) { self.handle_request(Request::FromScript(msg)); @@ -308,10 +263,6 @@ impl Layout for LayoutThread { self.handle_request(Request::FromFontCache); } - fn rpc(&self) -> Box<dyn script_layout_interface::rpc::LayoutRPC> { - Box::new(LayoutRPCImpl(self.rw_data.clone())) as Box<dyn LayoutRPC> - } - fn waiting_for_web_fonts_to_load(&self) -> bool { self.outstanding_web_fonts.load(Ordering::SeqCst) != 0 } @@ -350,6 +301,178 @@ impl Layout for LayoutThread { self.stylist .remove_stylesheet(DocumentStyleSheet(stylesheet.clone()), &guard); } + + fn query_content_box(&self, node: OpaqueNode) -> Option<UntypedRect<Au>> { + let Some(mut root_flow) = self.root_flow_for_query() else { + return None; + }; + + let root_flow_ref = FlowRef::deref_mut(&mut root_flow); + process_content_box_request(node, root_flow_ref) + } + + fn query_content_boxes(&self, node: OpaqueNode) -> Vec<UntypedRect<Au>> { + let Some(mut root_flow) = self.root_flow_for_query() else { + return vec![]; + }; + let root_flow_ref = FlowRef::deref_mut(&mut root_flow); + process_content_boxes_request(node, root_flow_ref) + } + + fn query_client_rect(&self, node: OpaqueNode) -> UntypedRect<i32> { + let Some(mut root_flow) = self.root_flow_for_query() else { + return UntypedRect::zero(); + }; + let root_flow_ref = FlowRef::deref_mut(&mut root_flow); + process_client_rect_query(node, root_flow_ref) + } + + fn query_element_inner_text( + &self, + node: script_layout_interface::TrustedNodeAddress, + ) -> String { + let node: ServoLayoutNode<LayoutData> = unsafe { ServoLayoutNode::new(&node) }; + process_element_inner_text_query(node, &self.indexable_text.borrow()) + } + + fn query_inner_window_dimension( + &self, + browsing_context_id: BrowsingContextId, + ) -> Option<Size2D<f32, CSSPixel>> { + self.last_iframe_sizes + .borrow() + .get(&browsing_context_id) + .cloned() + } + + fn query_nodes_from_point( + &self, + point: UntypedPoint2D<f32>, + query_type: NodesFromPointQueryType, + ) -> Vec<UntrustedNodeAddress> { + let mut flags = match query_type { + NodesFromPointQueryType::Topmost => HitTestFlags::empty(), + NodesFromPointQueryType::All => HitTestFlags::FIND_ALL, + }; + + // The point we get is not relative to the entire WebRender scene, but to this + // particular pipeline, so we need to tell WebRender about that. + flags.insert(HitTestFlags::POINT_RELATIVE_TO_PIPELINE_VIEWPORT); + + let client_point = units::DevicePoint::from_untyped(point); + let results = + self.webrender_api + .hit_test(Some(self.id.to_webrender()), client_point, flags); + + results.iter().map(|result| result.node).collect() + } + + fn query_offset_parent(&self, node: OpaqueNode) -> OffsetParentResponse { + let Some(mut root_flow) = self.root_flow_for_query() else { + return OffsetParentResponse::default(); + }; + let root_flow_ref = FlowRef::deref_mut(&mut root_flow); + process_offset_parent_query(node, root_flow_ref) + } + + fn query_resolved_style( + &self, + node: TrustedNodeAddress, + pseudo: Option<PseudoElement>, + property_id: PropertyId, + animations: DocumentAnimationSet, + animation_timeline_value: f64, + ) -> String { + let node: ServoLayoutNode<LayoutData> = unsafe { ServoLayoutNode::new(&node) }; + let document = node.owner_doc(); + let document_shared_lock = document.style_shared_lock(); + let guards = StylesheetGuards { + author: &document_shared_lock.read(), + ua_or_user: &UA_STYLESHEETS.shared_lock.read(), + }; + let snapshot_map = SnapshotMap::new(); + + let shared_style_context = self.build_shared_style_context( + guards, + &snapshot_map, + animation_timeline_value, + &animations, + TraversalFlags::empty(), + ); + + let Some(mut root_flow) = self.root_flow_for_query() else { + return String::new(); + }; + let root_flow_ref = FlowRef::deref_mut(&mut root_flow); + + process_resolved_style_request( + &shared_style_context, + node, + &pseudo, + &property_id, + root_flow_ref, + ) + } + + fn query_resolved_font_style( + &self, + node: TrustedNodeAddress, + value: &str, + animations: DocumentAnimationSet, + animation_timeline_value: f64, + ) -> Option<ServoArc<Font>> { + let node: ServoLayoutNode<LayoutData> = unsafe { ServoLayoutNode::new(&node) }; + let document = node.owner_doc(); + let document_shared_lock = document.style_shared_lock(); + let guards = StylesheetGuards { + author: &document_shared_lock.read(), + ua_or_user: &UA_STYLESHEETS.shared_lock.read(), + }; + let snapshot_map = SnapshotMap::new(); + let shared_style_context = self.build_shared_style_context( + guards, + &snapshot_map, + animation_timeline_value, + &animations, + TraversalFlags::empty(), + ); + + process_resolved_font_style_request( + &shared_style_context, + node, + value, + self.url.clone(), + document_shared_lock, + ) + } + + fn query_scroll_id( + &self, + node: script_layout_interface::TrustedNodeAddress, + ) -> webrender_api::ExternalScrollId { + let node: ServoLayoutNode<LayoutData> = unsafe { ServoLayoutNode::new(&node) }; + process_node_scroll_id_request(self.id, node) + } + + fn query_scrolling_area(&self, node: Option<OpaqueNode>) -> UntypedRect<i32> { + let Some(mut root_flow) = self.root_flow_for_query() else { + return UntypedRect::zero(); + }; + let root_flow_ref = FlowRef::deref_mut(&mut root_flow); + process_scrolling_area_request(node, root_flow_ref) + } + + fn query_text_indext( + &self, + node: OpaqueNode, + point_in_node: UntypedPoint2D<f32>, + ) -> Option<usize> { + let point_in_node = Point2D::new( + Au::from_f32_px(point_in_node.x), + Au::from_f32_px(point_in_node.y), + ); + self.indexable_text.borrow().text_index(node, point_in_node) + } } enum Request { FromPipeline(LayoutControlMsg), @@ -358,6 +481,10 @@ enum Request { } impl LayoutThread { + fn root_flow_for_query(&self) -> Option<FlowRef> { + self.root_flow.borrow().clone() + } + fn new( id: PipelineId, url: ServoUrl, @@ -397,7 +524,7 @@ impl LayoutThread { url, is_iframe, script_chan, - constellation_chan: constellation_chan.clone(), + constellation_chan, time_profiler_chan, registered_painters: RegisteredPaintersImpl(Default::default()), image_cache, @@ -416,24 +543,9 @@ impl LayoutThread { ), webrender_api, stylist: Stylist::new(device, QuirksMode::NoQuirks), - rw_data: Arc::new(Mutex::new(LayoutThreadData { - constellation_chan, - display_list: None, - indexable_text: IndexableText::default(), - content_box_response: None, - content_boxes_response: Vec::new(), - client_rect_response: Rect::zero(), - scroll_id_response: None, - scrolling_area_response: Rect::zero(), - resolved_style_response: String::new(), - resolved_font_style_response: None, - offset_parent_response: OffsetParentResponse::empty(), - scroll_offsets: HashMap::new(), - text_index_response: TextIndexResponse(None), - nodes_from_point_response: vec![], - element_inner_text_response: String::new(), - inner_window_dimensions_response: None, - })), + display_list: Default::default(), + indexable_text: Default::default(), + scroll_offsets: Default::default(), webrender_image_cache: Arc::new(RwLock::new(FnvHashMap::default())), paint_time_metrics, layout_query_waiting_time: Histogram::new(), @@ -443,6 +555,27 @@ impl LayoutThread { } } + fn build_shared_style_context<'a>( + &'a self, + guards: StylesheetGuards<'a>, + snapshot_map: &'a SnapshotMap, + animation_timeline_value: f64, + animations: &DocumentAnimationSet, + traversal_flags: TraversalFlags, + ) -> SharedStyleContext<'a> { + SharedStyleContext { + stylist: &self.stylist, + options: GLOBAL_STYLE_DATA.options.clone(), + guards, + visited_styles_enabled: false, + animations: animations.clone(), + registered_speculative_painters: &self.registered_painters, + current_time_for_animations: animation_timeline_value, + traversal_flags, + snapshot_map, + } + } + // Create a layout context for use in building display lists, hit testing, &c. fn build_layout_context<'a>( &'a self, @@ -461,17 +594,13 @@ impl LayoutThread { LayoutContext { id: self.id, origin, - style_context: SharedStyleContext { - stylist: &self.stylist, - options: GLOBAL_STYLE_DATA.options.clone(), + style_context: self.build_shared_style_context( guards, - visited_styles_enabled: false, - animations: animations.clone(), - registered_speculative_painters: &self.registered_painters, - current_time_for_animations: animation_timeline_value, - traversal_flags, snapshot_map, - }, + animation_timeline_value, + animations, + traversal_flags, + ), image_cache: self.image_cache.clone(), font_cache_thread: Mutex::new(self.font_cache_thread.clone()), webrender_image_cache: self.webrender_image_cache.clone(), @@ -482,26 +611,18 @@ impl LayoutThread { /// Receives and dispatches messages from the script and constellation threads fn handle_request<'a, 'b>(&mut self, request: Request) { - let rw_data = self.rw_data.clone(); - let mut possibly_locked_rw_data = Some(rw_data.lock().unwrap()); - let mut rw_data = RwData { - rw_data: &rw_data, - possibly_locked_rw_data: &mut possibly_locked_rw_data, - }; - match request { Request::FromPipeline(LayoutControlMsg::SetScrollStates(new_scroll_states)) => { - self.handle_request_helper(Msg::SetScrollStates(new_scroll_states), &mut rw_data) + self.handle_request_helper(Msg::SetScrollStates(new_scroll_states)) }, Request::FromPipeline(LayoutControlMsg::ExitNow) => { - self.handle_request_helper(Msg::ExitNow, &mut rw_data); + self.handle_request_helper(Msg::ExitNow); }, Request::FromPipeline(LayoutControlMsg::PaintMetric(epoch, paint_time)) => { self.paint_time_metrics.maybe_set_metric(epoch, paint_time); }, - Request::FromScript(msg) => self.handle_request_helper(msg, &mut rw_data), + Request::FromScript(msg) => self.handle_request_helper(msg), Request::FromFontCache => { - let _rw_data = rw_data.lock(); self.outstanding_web_fonts.fetch_sub(1, Ordering::SeqCst); self.handle_web_font_loaded(); }, @@ -509,32 +630,23 @@ impl LayoutThread { } /// Receives and dispatches messages from other threads. - fn handle_request_helper( - &mut self, - request: Msg, - possibly_locked_rw_data: &mut RwData<'_, '_>, - ) { + fn handle_request_helper(&mut self, request: Msg) { match request { Msg::SetQuirksMode(mode) => self.handle_set_quirks_mode(mode), - Msg::GetRPC(response_chan) => { - response_chan - .send(Box::new(LayoutRPCImpl(self.rw_data.clone())) as Box<dyn LayoutRPC + Send>) - .unwrap(); - }, Msg::Reflow(data) => { let mut data = ScriptReflowResult::new(data); profile( profile_time::ProfilerCategory::LayoutPerform, self.profiler_metadata(), self.time_profiler_chan.clone(), - || self.handle_reflow(&mut data, possibly_locked_rw_data), + || self.handle_reflow(&mut data), ); }, Msg::SetScrollStates(new_scroll_states) => { - self.set_scroll_states(new_scroll_states, possibly_locked_rw_data); + self.set_scroll_states(new_scroll_states); }, Msg::CollectReports(reports_chan) => { - self.collect_reports(reports_chan, possibly_locked_rw_data); + self.collect_reports(reports_chan); }, Msg::RegisterPaint(name, mut properties, painter) => { debug!("Registering the painter"); @@ -561,24 +673,20 @@ impl LayoutThread { } } - fn collect_reports( - &self, - reports_chan: ReportsChan, - possibly_locked_rw_data: &mut RwData<'_, '_>, - ) { + fn collect_reports(&self, reports_chan: ReportsChan) { let mut reports = vec![]; // Servo uses vanilla jemalloc, which doesn't have a // malloc_enclosing_size_of function. let mut ops = MallocSizeOfOps::new(servo_allocator::usable_size, None, None); // FIXME(njn): Just measuring the display tree for now. - let rw_data = possibly_locked_rw_data.lock(); - let display_list = rw_data.display_list.as_ref(); + let display_list = self.display_list.borrow(); + let display_list_ref = display_list.as_ref(); let formatted_url = &format!("url({})", self.url); reports.push(Report { path: path![formatted_url, "layout-thread", "display-list"], kind: ReportKind::ExplicitJemallocHeapSize, - size: display_list.map_or(0, |sc| sc.size_of(&mut ops)), + size: display_list_ref.map_or(0, |sc| sc.size_of(&mut ops)), }); reports.push(Report { @@ -768,7 +876,6 @@ impl LayoutThread { document: Option<&ServoLayoutDocument<LayoutData>>, layout_root: &mut dyn Flow, layout_context: &mut LayoutContext, - rw_data: &mut LayoutThreadData, ) { let writing_mode = layout_root.base().writing_mode; let (metadata, sender) = (self.profiler_metadata(), self.time_profiler_chan.clone()); @@ -791,7 +898,7 @@ impl LayoutThread { .base() .restyle_damage .contains(ServoRestyleDamage::REPAINT) || - rw_data.display_list.is_none() + self.display_list.borrow().is_none() { if reflow_goal.needs_display_list() { let background_color = get_root_flow_background_color(layout_root); @@ -817,8 +924,9 @@ impl LayoutThread { let iframe_sizes = std::mem::take(&mut build_state.iframe_sizes); self.update_iframe_sizes(iframe_sizes); - rw_data.indexable_text = std::mem::take(&mut build_state.indexable_text); - rw_data.display_list = Some(build_state.to_display_list()); + *self.indexable_text.borrow_mut() = + std::mem::take(&mut build_state.indexable_text); + *self.display_list.borrow_mut() = Some(build_state.to_display_list()); } } @@ -836,8 +944,8 @@ impl LayoutThread { document.will_paint(); } - let display_list = rw_data.display_list.as_mut().unwrap(); - + let mut display_list = self.display_list.borrow_mut(); + let display_list = display_list.as_mut().unwrap(); if self.debug.dump_display_list { display_list.print(); } @@ -873,11 +981,7 @@ impl LayoutThread { } /// The high-level routine that performs layout. - fn handle_reflow( - &mut self, - data: &mut ScriptReflowResult, - possibly_locked_rw_data: &mut RwData<'_, '_>, - ) { + fn handle_reflow(&mut self, data: &mut ScriptReflowResult) { let document = unsafe { ServoLayoutNode::new(&data.document) }; let document = document.as_document().unwrap(); @@ -888,8 +992,6 @@ impl LayoutThread { debug!("Number of objects in DOM: {}", data.dom_count); debug!("layout: parallel? {}", self.parallel_flag); - let mut rw_data = possibly_locked_rw_data.lock(); - // Record the time that layout query has been waited. let now = time::precise_time_ns(); if let ReflowGoal::LayoutQuery(_, timestamp) = data.reflow_goal { @@ -898,57 +1000,9 @@ impl LayoutThread { .expect("layout: wrong layout query timestamp"); }; - let root_element = match document.root_element() { - None => { - // Since we cannot compute anything, give spec-required placeholders. - debug!("layout: No root node: bailing"); - match data.reflow_goal { - ReflowGoal::LayoutQuery(ref query_msg, _) => match query_msg { - &QueryMsg::ContentBoxQuery(_) => { - rw_data.content_box_response = None; - }, - &QueryMsg::ContentBoxesQuery(_) => { - rw_data.content_boxes_response = Vec::new(); - }, - &QueryMsg::NodesFromPointQuery(..) => { - rw_data.nodes_from_point_response = Vec::new(); - }, - &QueryMsg::ClientRectQuery(_) => { - rw_data.client_rect_response = Rect::zero(); - }, - &QueryMsg::ScrollingAreaQuery(_) => { - rw_data.scrolling_area_response = Rect::zero(); - }, - &QueryMsg::NodeScrollIdQuery(_) => { - rw_data.scroll_id_response = None; - }, - &QueryMsg::ResolvedStyleQuery(_, _, _) => { - rw_data.resolved_style_response = String::new(); - }, - &QueryMsg::OffsetParentQuery(_) => { - rw_data.offset_parent_response = OffsetParentResponse::empty(); - }, - &QueryMsg::StyleQuery => {}, - &QueryMsg::TextIndexQuery(..) => { - rw_data.text_index_response = TextIndexResponse(None); - }, - &QueryMsg::ElementInnerTextQuery(_) => { - rw_data.element_inner_text_response = String::new(); - }, - &QueryMsg::ResolvedFontStyleQuery(..) => { - rw_data.resolved_font_style_response = None; - }, - &QueryMsg::InnerWindowDimensionsQuery(_) => { - rw_data.inner_window_dimensions_response = None; - }, - }, - ReflowGoal::Full | - ReflowGoal::TickAnimations | - ReflowGoal::UpdateScrollNode(_) => {}, - } - return; - }, - Some(x) => x, + let Some(root_element) = document.root_element() else { + debug!("layout: No root node: bailing"); + return; }; debug!( @@ -1156,129 +1210,24 @@ impl LayoutThread { &data.reflow_info, &data.reflow_goal, Some(&document), - &mut rw_data, &mut layout_context, thread_pool, ); } self.first_reflow.set(false); - self.respond_to_query_if_necessary( - &data.reflow_goal, - &mut *rw_data, - &mut layout_context, - data.result.borrow_mut().as_mut().unwrap(), - document_shared_lock, - ); - } - fn respond_to_query_if_necessary( - &self, - reflow_goal: &ReflowGoal, - rw_data: &mut LayoutThreadData, - context: &mut LayoutContext, - reflow_result: &mut ReflowComplete, - shared_lock: &SharedRwLock, - ) { - reflow_result.pending_images = std::mem::take(&mut *context.pending_images.lock().unwrap()); + data.result.borrow_mut().as_mut().unwrap().pending_images = + std::mem::take(&mut *layout_context.pending_images.lock().unwrap()); - let mut root_flow = match self.root_flow.borrow().clone() { - Some(root_flow) => root_flow, - None => return, - }; - let root_flow = FlowRef::deref_mut(&mut root_flow); - match *reflow_goal { - ReflowGoal::LayoutQuery(ref querymsg, _) => match querymsg { - &QueryMsg::ContentBoxQuery(node) => { - rw_data.content_box_response = process_content_box_request(node, root_flow); - }, - &QueryMsg::ContentBoxesQuery(node) => { - rw_data.content_boxes_response = process_content_boxes_request(node, root_flow); - }, - &QueryMsg::TextIndexQuery(node, point_in_node) => { - let point_in_node = Point2D::new( - Au::from_f32_px(point_in_node.x), - Au::from_f32_px(point_in_node.y), - ); - rw_data.text_index_response = - TextIndexResponse(rw_data.indexable_text.text_index(node, point_in_node)); - }, - &QueryMsg::ClientRectQuery(node) => { - rw_data.client_rect_response = process_client_rect_query(node, root_flow); - }, - &QueryMsg::ScrollingAreaQuery(node) => { - rw_data.scrolling_area_response = - process_scrolling_area_request(node, root_flow); - }, - &QueryMsg::NodeScrollIdQuery(node) => { - let node: ServoLayoutNode<LayoutData> = unsafe { ServoLayoutNode::new(&node) }; - rw_data.scroll_id_response = - Some(process_node_scroll_id_request(self.id, node)); - }, - &QueryMsg::ResolvedStyleQuery(node, ref pseudo, ref property) => { - let node: ServoLayoutNode<LayoutData> = unsafe { ServoLayoutNode::new(&node) }; - rw_data.resolved_style_response = - process_resolved_style_request(context, node, pseudo, property, root_flow); - }, - &QueryMsg::ResolvedFontStyleQuery(node, ref property, ref value) => { - let node: ServoLayoutNode<LayoutData> = unsafe { ServoLayoutNode::new(&node) }; - let url = self.url.clone(); - rw_data.resolved_font_style_response = process_resolved_font_style_request( - context, - node, - value, - property, - url, - shared_lock, - ); - }, - &QueryMsg::OffsetParentQuery(node) => { - rw_data.offset_parent_response = process_offset_parent_query(node, root_flow); - }, - &QueryMsg::StyleQuery => {}, - &QueryMsg::NodesFromPointQuery(client_point, ref reflow_goal) => { - let mut flags = match reflow_goal { - &NodesFromPointQueryType::Topmost => HitTestFlags::empty(), - &NodesFromPointQueryType::All => HitTestFlags::FIND_ALL, - }; - - // The point we get is not relative to the entire WebRender scene, but to this - // particular pipeline, so we need to tell WebRender about that. - flags.insert(HitTestFlags::POINT_RELATIVE_TO_PIPELINE_VIEWPORT); - - let client_point = units::DevicePoint::from_untyped(client_point); - let results = self.webrender_api.hit_test( - Some(self.id.to_webrender()), - client_point, - flags, - ); - - rw_data.nodes_from_point_response = - results.iter().map(|result| result.node).collect() - }, - &QueryMsg::ElementInnerTextQuery(node) => { - let node: ServoLayoutNode<LayoutData> = unsafe { ServoLayoutNode::new(&node) }; - rw_data.element_inner_text_response = - process_element_inner_text_query(node, &rw_data.indexable_text); - }, - &QueryMsg::InnerWindowDimensionsQuery(browsing_context_id) => { - rw_data.inner_window_dimensions_response = self - .last_iframe_sizes - .borrow() - .get(&browsing_context_id) - .cloned(); - }, - }, - ReflowGoal::UpdateScrollNode(scroll_state) => { - self.update_scroll_node_state(&scroll_state, rw_data); - }, - ReflowGoal::Full | ReflowGoal::TickAnimations => {}, + if let ReflowGoal::UpdateScrollNode(scroll_state) = data.reflow_goal { + self.update_scroll_node_state(&scroll_state); } } - fn update_scroll_node_state(&self, state: &ScrollState, rw_data: &mut LayoutThreadData) { - rw_data - .scroll_offsets + fn update_scroll_node_state(&self, state: &ScrollState) { + self.scroll_offsets + .borrow_mut() .insert(state.scroll_id, state.scroll_offset); let point = Point2D::new(-state.scroll_offset.x, -state.scroll_offset.y); @@ -1289,12 +1238,7 @@ impl LayoutThread { ); } - fn set_scroll_states( - &mut self, - new_scroll_states: Vec<ScrollState>, - possibly_locked_rw_data: &mut RwData<'_, '_>, - ) { - let mut rw_data = possibly_locked_rw_data.lock(); + fn set_scroll_states(&mut self, new_scroll_states: Vec<ScrollState>) { let mut script_scroll_states = vec![]; let mut layout_scroll_states = HashMap::new(); for new_state in &new_scroll_states { @@ -1313,7 +1257,7 @@ impl LayoutThread { self.id, script_scroll_states, )); - rw_data.scroll_offsets = layout_scroll_states + *self.scroll_offsets.borrow_mut() = layout_scroll_states } /// Cancel animations for any nodes which have been removed from flow tree. @@ -1363,7 +1307,6 @@ impl LayoutThread { data: &Reflow, reflow_goal: &ReflowGoal, document: Option<&ServoLayoutDocument<LayoutData>>, - rw_data: &mut LayoutThreadData, context: &mut LayoutContext, thread_pool: Option<&rayon::ThreadPool>, ) { @@ -1449,14 +1392,7 @@ impl LayoutThread { }, ); - self.perform_post_main_layout_passes( - data, - root_flow, - reflow_goal, - document, - rw_data, - context, - ); + self.perform_post_main_layout_passes(data, root_flow, reflow_goal, document, context); } fn perform_post_main_layout_passes( @@ -1465,7 +1401,6 @@ impl LayoutThread { mut root_flow: &mut FlowRef, reflow_goal: &ReflowGoal, document: Option<&ServoLayoutDocument<LayoutData>>, - rw_data: &mut LayoutThreadData, layout_context: &mut LayoutContext, ) { // Build the display list if necessary, and send it to the painter. @@ -1475,7 +1410,6 @@ impl LayoutThread { document, FlowRef::deref_mut(&mut root_flow), &mut *layout_context, - rw_data, ); if self.debug.trace_layout { diff --git a/components/layout_thread_2020/lib.rs b/components/layout_thread_2020/lib.rs index 760bdc85240..b5d9c97b171 100644 --- a/components/layout_thread_2020/lib.rs +++ b/components/layout_thread_2020/lib.rs @@ -13,12 +13,12 @@ use std::collections::HashMap; use std::ops::{Deref, DerefMut}; use std::process; use std::sync::atomic::{AtomicUsize, Ordering}; -use std::sync::{Arc, Mutex, MutexGuard}; +use std::sync::{Arc, Mutex}; use app_units::Au; use embedder_traits::resources::{self, Resource}; -use euclid::default::Size2D as UntypedSize2D; -use euclid::{Point2D, Rect, Scale, Size2D}; +use euclid::default::{Point2D as UntypedPoint2D, Rect as UntypedRect, Size2D as UntypedSize2D}; +use euclid::{Point2D, Scale, Size2D, Vector2D}; use fnv::FnvHashMap; use fxhash::FxHashMap; use gfx::font_cache_thread::FontCacheThread; @@ -33,7 +33,7 @@ use layout::query::{ process_content_box_request, process_content_boxes_request, process_element_inner_text_query, process_node_geometry_request, process_node_scroll_area_request, process_node_scroll_id_request, process_offset_parent_query, process_resolved_font_style_query, - process_resolved_style_request, process_text_index_request, LayoutRPCImpl, LayoutThreadData, + process_resolved_style_request, process_text_index_request, }; use layout::traversal::RecalcStyle; use layout::{layout_debug, BoxTree, FragmentTree}; @@ -51,10 +51,11 @@ use profile_traits::time::{ }; use script::layout_dom::{ServoLayoutDocument, ServoLayoutElement, ServoLayoutNode}; use script_layout_interface::message::{ - Msg, NodesFromPointQueryType, QueryMsg, ReflowComplete, ReflowGoal, ScriptReflow, + Msg, NodesFromPointQueryType, ReflowComplete, ReflowGoal, ScriptReflow, +}; +use script_layout_interface::{ + Layout, LayoutConfig, LayoutFactory, OffsetParentResponse, TrustedNodeAddress, }; -use script_layout_interface::rpc::{LayoutRPC, OffsetParentResponse, TextIndexResponse}; -use script_layout_interface::{Layout, LayoutConfig, LayoutFactory}; use script_traits::{ ConstellationControlMsg, DrawAPaintImageResult, IFrameSizeMsg, LayoutControlMsg, LayoutMsg as ConstellationMsg, PaintWorkletError, Painter, ScrollState, UntrustedNodeAddress, @@ -68,14 +69,15 @@ use style::animation::DocumentAnimationSet; use style::context::{ QuirksMode, RegisteredSpeculativePainter, RegisteredSpeculativePainters, SharedStyleContext, }; -use style::dom::{TElement, TNode}; +use style::dom::{OpaqueNode, TElement, TNode}; use style::driver; use style::error_reporting::RustLogReporter; use style::global_style_data::{GLOBAL_STYLE_DATA, STYLE_THREAD_POOL}; use style::invalidation::element::restyle_hints::RestyleHint; use style::media_queries::{Device, MediaList, MediaType}; +use style::properties::style_structs::Font; use style::properties::PropertyId; -use style::selector_parser::SnapshotMap; +use style::selector_parser::{PseudoElement, SnapshotMap}; use style::shared_lock::{SharedRwLock, SharedRwLockReadGuard, StylesheetGuards}; use style::stylesheets::{ DocumentStyleSheet, Origin, Stylesheet, StylesheetInDocument, UrlExtraData, @@ -86,7 +88,8 @@ use style::traversal::DomTraversal; use style::traversal_flags::TraversalFlags; use style_traits::{CSSPixel, DevicePixel, SpeculativePainter}; use url::Url; -use webrender_api::{units, HitTestFlags}; +use webrender_api::units::LayoutPixel; +use webrender_api::{units, ExternalScrollId, HitTestFlags}; /// Information needed by layout. pub struct LayoutThread { @@ -143,11 +146,8 @@ pub struct LayoutThread { /// constraints. viewport_size: UntypedSize2D<Au>, - /// A mutex to allow for fast, read-only RPC of layout's internal data - /// structures, while still letting the LayoutThread modify them. - /// - /// All the other elements of this struct are read-only. - rw_data: Arc<Mutex<LayoutThreadData>>, + /// Scroll offsets of nodes that scroll. + scroll_offsets: RefCell<HashMap<ExternalScrollId, Vector2D<f32, LayoutPixel>>>, webrender_image_cache: Arc<RwLock<FnvHashMap<(ServoUrl, UsePlaceholder), WebRenderImageInfo>>>, @@ -224,56 +224,6 @@ impl Drop for ScriptReflowResult { } } -/// The `LayoutThread` `rw_data` lock must remain locked until the first reflow, -/// as RPC calls don't make sense until then. Use this in combination with -/// `LayoutThread::lock_rw_data` and `LayoutThread::return_rw_data`. -pub enum RWGuard<'a> { - /// If the lock was previously held, from when the thread started. - Held(MutexGuard<'a, LayoutThreadData>), - /// If the lock was just used, and has been returned since there has been - /// a reflow already. - Used(MutexGuard<'a, LayoutThreadData>), -} - -impl<'a> Deref for RWGuard<'a> { - type Target = LayoutThreadData; - fn deref(&self) -> &LayoutThreadData { - match *self { - RWGuard::Held(ref x) => &**x, - RWGuard::Used(ref x) => &**x, - } - } -} - -impl<'a> DerefMut for RWGuard<'a> { - fn deref_mut(&mut self) -> &mut LayoutThreadData { - match *self { - RWGuard::Held(ref mut x) => &mut **x, - RWGuard::Used(ref mut x) => &mut **x, - } - } -} - -struct RwData<'a, 'b: 'a> { - rw_data: &'b Arc<Mutex<LayoutThreadData>>, - possibly_locked_rw_data: &'a mut Option<MutexGuard<'b, LayoutThreadData>>, -} - -impl<'a, 'b: 'a> RwData<'a, 'b> { - /// If no reflow has happened yet, this will just return the lock in - /// `possibly_locked_rw_data`. Otherwise, it will acquire the `rw_data` lock. - /// - /// If you do not wish RPCs to remain blocked, just drop the `RWGuard` - /// returned from this function. If you _do_ wish for them to remain blocked, - /// use `block`. - fn lock(&mut self) -> RWGuard<'b> { - match self.possibly_locked_rw_data.take() { - None => RWGuard::Used(self.rw_data.lock().unwrap()), - Some(x) => RWGuard::Held(x), - } - } -} - impl Layout for LayoutThread { fn process(&mut self, msg: script_layout_interface::message::Msg) { self.handle_request(Request::FromScript(msg)); @@ -287,10 +237,6 @@ impl Layout for LayoutThread { self.handle_request(Request::FromFontCache); } - fn rpc(&self) -> Box<dyn script_layout_interface::rpc::LayoutRPC> { - Box::new(LayoutRPCImpl(self.rw_data.clone())) as Box<dyn LayoutRPC> - } - fn waiting_for_web_fonts_to_load(&self) -> bool { self.outstanding_web_fonts.load(Ordering::SeqCst) != 0 } @@ -330,6 +276,152 @@ impl Layout for LayoutThread { self.stylist .remove_stylesheet(DocumentStyleSheet(stylesheet.clone()), &guard); } + + fn query_content_box(&self, node: OpaqueNode) -> Option<UntypedRect<Au>> { + process_content_box_request(node, self.fragment_tree.borrow().clone()) + } + + fn query_content_boxes(&self, node: OpaqueNode) -> Vec<UntypedRect<Au>> { + process_content_boxes_request(node, self.fragment_tree.borrow().clone()) + } + + fn query_client_rect(&self, node: OpaqueNode) -> UntypedRect<i32> { + process_node_geometry_request(node, self.fragment_tree.borrow().clone()) + } + + fn query_element_inner_text( + &self, + node: script_layout_interface::TrustedNodeAddress, + ) -> String { + let node = unsafe { ServoLayoutNode::<DOMLayoutData>::new(&node) }; + process_element_inner_text_query(node) + } + + fn query_inner_window_dimension( + &self, + _context: BrowsingContextId, + ) -> Option<Size2D<f32, CSSPixel>> { + // TODO(jdm): port the iframe sizing code from layout2013's display + // builder in order to support query iframe sizing. + None + } + + fn query_nodes_from_point( + &self, + point: UntypedPoint2D<f32>, + query_type: NodesFromPointQueryType, + ) -> Vec<UntrustedNodeAddress> { + let mut flags = match query_type { + NodesFromPointQueryType::Topmost => HitTestFlags::empty(), + NodesFromPointQueryType::All => HitTestFlags::FIND_ALL, + }; + + // The point we get is not relative to the entire WebRender scene, but to this + // particular pipeline, so we need to tell WebRender about that. + flags.insert(HitTestFlags::POINT_RELATIVE_TO_PIPELINE_VIEWPORT); + + let client_point = units::DevicePoint::from_untyped(point); + let results = + self.webrender_api + .hit_test(Some(self.id.to_webrender()), client_point, flags); + + results.iter().map(|result| result.node).collect() + } + + fn query_offset_parent(&self, node: OpaqueNode) -> OffsetParentResponse { + process_offset_parent_query(node, self.fragment_tree.borrow().clone()) + } + + fn query_resolved_style( + &self, + node: TrustedNodeAddress, + pseudo: Option<PseudoElement>, + property_id: PropertyId, + animations: DocumentAnimationSet, + animation_timeline_value: f64, + ) -> String { + let node: ServoLayoutNode<DOMLayoutData> = unsafe { ServoLayoutNode::new(&node) }; + let document = node.owner_doc(); + let document_shared_lock = document.style_shared_lock(); + let guards = StylesheetGuards { + author: &document_shared_lock.read(), + ua_or_user: &UA_STYLESHEETS.shared_lock.read(), + }; + let snapshot_map = SnapshotMap::new(); + + let shared_style_context = self.build_shared_style_context( + guards, + &snapshot_map, + animation_timeline_value, + &animations, + TraversalFlags::empty(), + ); + + let fragment_tree = self.fragment_tree.borrow().clone(); + process_resolved_style_request( + &shared_style_context, + node, + &pseudo, + &property_id, + fragment_tree, + ) + } + + fn query_resolved_font_style( + &self, + node: TrustedNodeAddress, + value: &str, + animations: DocumentAnimationSet, + animation_timeline_value: f64, + ) -> Option<ServoArc<Font>> { + let node: ServoLayoutNode<DOMLayoutData> = unsafe { ServoLayoutNode::new(&node) }; + let document = node.owner_doc(); + let document_shared_lock = document.style_shared_lock(); + let guards = StylesheetGuards { + author: &document_shared_lock.read(), + ua_or_user: &UA_STYLESHEETS.shared_lock.read(), + }; + let snapshot_map = SnapshotMap::new(); + let shared_style_context = self.build_shared_style_context( + guards, + &snapshot_map, + animation_timeline_value, + &animations, + TraversalFlags::empty(), + ); + + process_resolved_font_style_query( + &shared_style_context, + node, + value, + self.url.clone(), + document_shared_lock, + ) + } + + fn query_scroll_id( + &self, + node: script_layout_interface::TrustedNodeAddress, + ) -> ExternalScrollId { + let node = unsafe { ServoLayoutNode::<DOMLayoutData>::new(&node) }; + process_node_scroll_id_request(self.id, node) + } + + fn query_scrolling_area(&self, node: Option<OpaqueNode>) -> UntypedRect<i32> { + process_node_scroll_area_request(node, self.fragment_tree.borrow().clone()) + } + + fn query_text_indext( + &self, + node: OpaqueNode, + point_in_node: UntypedPoint2D<f32>, + ) -> Option<usize> { + let point_in_node = Point2D::new( + Au::from_f32_px(point_in_node.x), + Au::from_f32_px(point_in_node.y), + ); + process_text_index_request(node, point_in_node) + } } enum Request { @@ -398,23 +490,8 @@ impl LayoutThread { Au::from_f32_px(window_size.initial_viewport.height), ), webrender_api: webrender_api_sender, + scroll_offsets: Default::default(), stylist: Stylist::new(device, QuirksMode::NoQuirks), - rw_data: Arc::new(Mutex::new(LayoutThreadData { - display_list: None, - content_box_response: None, - content_boxes_response: Vec::new(), - client_rect_response: Rect::zero(), - scroll_id_response: None, - scrolling_area_response: Rect::zero(), - resolved_style_response: String::new(), - resolved_font_style_response: None, - offset_parent_response: OffsetParentResponse::empty(), - scroll_offsets: HashMap::new(), - text_index_response: TextIndexResponse(None), - nodes_from_point_response: vec![], - element_inner_text_response: String::new(), - inner_window_dimensions_response: None, - })), webrender_image_cache: Default::default(), paint_time_metrics, last_iframe_sizes: Default::default(), @@ -422,6 +499,27 @@ impl LayoutThread { } } + fn build_shared_style_context<'a>( + &'a self, + guards: StylesheetGuards<'a>, + snapshot_map: &'a SnapshotMap, + animation_timeline_value: f64, + animations: &DocumentAnimationSet, + traversal_flags: TraversalFlags, + ) -> SharedStyleContext<'a> { + SharedStyleContext { + stylist: &self.stylist, + options: GLOBAL_STYLE_DATA.options.clone(), + guards, + visited_styles_enabled: false, + animations: animations.clone(), + registered_speculative_painters: &self.registered_painters, + current_time_for_animations: animation_timeline_value, + traversal_flags, + snapshot_map, + } + } + // Create a layout context for use in building display lists, hit testing, &c. fn build_layout_context<'a>( &'a self, @@ -441,17 +539,13 @@ impl LayoutThread { LayoutContext { id: self.id, origin, - style_context: SharedStyleContext { - stylist: &self.stylist, - options: GLOBAL_STYLE_DATA.options.clone(), + style_context: self.build_shared_style_context( guards, - visited_styles_enabled: false, - animations: animations.clone(), - registered_speculative_painters: &self.registered_painters, - current_time_for_animations: animation_timeline_value, - traversal_flags, snapshot_map, - }, + animation_timeline_value, + animations, + traversal_flags, + ), image_cache: self.image_cache.clone(), font_cache_thread: Mutex::new(self.font_cache_thread.clone()), webrender_image_cache: self.webrender_image_cache.clone(), @@ -462,26 +556,18 @@ impl LayoutThread { /// Receives and dispatches messages from the script and constellation threads fn handle_request<'a, 'b>(&mut self, request: Request) { - let rw_data = self.rw_data.clone(); - let mut possibly_locked_rw_data = Some(rw_data.lock().unwrap()); - let mut rw_data = RwData { - rw_data: &rw_data, - possibly_locked_rw_data: &mut possibly_locked_rw_data, - }; - match request { Request::FromPipeline(LayoutControlMsg::SetScrollStates(new_scroll_states)) => { - self.handle_request_helper(Msg::SetScrollStates(new_scroll_states), &mut rw_data) + self.handle_request_helper(Msg::SetScrollStates(new_scroll_states)) }, Request::FromPipeline(LayoutControlMsg::ExitNow) => { - self.handle_request_helper(Msg::ExitNow, &mut rw_data); + self.handle_request_helper(Msg::ExitNow); }, Request::FromPipeline(LayoutControlMsg::PaintMetric(epoch, paint_time)) => { self.paint_time_metrics.maybe_set_metric(epoch, paint_time); }, - Request::FromScript(msg) => self.handle_request_helper(msg, &mut rw_data), + Request::FromScript(msg) => self.handle_request_helper(msg), Request::FromFontCache => { - let _rw_data = rw_data.lock(); self.outstanding_web_fonts.fetch_sub(1, Ordering::SeqCst); self.handle_web_font_loaded(); }, @@ -489,32 +575,23 @@ impl LayoutThread { } /// Receives and dispatches messages from other threads. - fn handle_request_helper( - &mut self, - request: Msg, - possibly_locked_rw_data: &mut RwData<'_, '_>, - ) { + fn handle_request_helper(&mut self, request: Msg) { match request { Msg::SetQuirksMode(mode) => self.handle_set_quirks_mode(mode), - Msg::GetRPC(response_chan) => { - response_chan - .send(Box::new(LayoutRPCImpl(self.rw_data.clone())) as Box<dyn LayoutRPC + Send>) - .unwrap(); - }, Msg::Reflow(data) => { let mut data = ScriptReflowResult::new(data); profile( profile_time::ProfilerCategory::LayoutPerform, self.profiler_metadata(), self.time_profiler_chan.clone(), - || self.handle_reflow(&mut data, possibly_locked_rw_data), + || self.handle_reflow(&mut data), ); }, Msg::SetScrollStates(new_scroll_states) => { - self.set_scroll_states(new_scroll_states, possibly_locked_rw_data); + self.set_scroll_states(new_scroll_states); }, Msg::CollectReports(reports_chan) => { - self.collect_reports(reports_chan, possibly_locked_rw_data); + self.collect_reports(reports_chan); }, Msg::RegisterPaint(_name, _properties, _painter) => {}, // Receiving the Exit message at this stage only happens when layout is undergoing a "force exit". @@ -522,24 +599,18 @@ impl LayoutThread { } } - fn collect_reports( - &self, - reports_chan: ReportsChan, - possibly_locked_rw_data: &mut RwData<'_, '_>, - ) { + fn collect_reports(&self, reports_chan: ReportsChan) { let mut reports = vec![]; // Servo uses vanilla jemalloc, which doesn't have a // malloc_enclosing_size_of function. let mut ops = MallocSizeOfOps::new(servo_allocator::usable_size, None, None); // FIXME(njn): Just measuring the display tree for now. - let rw_data = possibly_locked_rw_data.lock(); - let display_list = rw_data.display_list.as_ref(); let formatted_url = &format!("url({})", self.url); reports.push(Report { path: path![formatted_url, "layout-thread", "display-list"], kind: ReportKind::ExplicitJemallocHeapSize, - size: display_list.map_or(0, |sc| sc.size_of(&mut ops)), + size: 0, }); reports.push(Report { @@ -590,71 +661,12 @@ impl LayoutThread { } /// The high-level routine that performs layout. - fn handle_reflow( - &mut self, - data: &mut ScriptReflowResult, - possibly_locked_rw_data: &mut RwData<'_, '_>, - ) { + fn handle_reflow(&mut self, data: &mut ScriptReflowResult) { let document = unsafe { ServoLayoutNode::<DOMLayoutData>::new(&data.document) }; let document = document.as_document().unwrap(); - - let mut rw_data = possibly_locked_rw_data.lock(); - - let root_element = match document.root_element() { - None => { - // Since we cannot compute anything, give spec-required placeholders. - debug!("layout: No root node: bailing"); - match data.reflow_goal { - ReflowGoal::LayoutQuery(ref query_msg, _) => match query_msg { - &QueryMsg::ContentBoxQuery(_) => { - rw_data.content_box_response = None; - }, - &QueryMsg::ContentBoxesQuery(_) => { - rw_data.content_boxes_response = Vec::new(); - }, - &QueryMsg::NodesFromPointQuery(..) => { - rw_data.nodes_from_point_response = Vec::new(); - }, - &QueryMsg::ClientRectQuery(_) => { - rw_data.client_rect_response = Rect::zero(); - }, - &QueryMsg::ScrollingAreaQuery(_) => { - rw_data.scrolling_area_response = Rect::zero(); - }, - &QueryMsg::NodeScrollIdQuery(_) => { - rw_data.scroll_id_response = None; - }, - &QueryMsg::ResolvedStyleQuery(_, _, _) => { - rw_data.resolved_style_response = String::new(); - }, - &QueryMsg::ResolvedFontStyleQuery(_, _, _) => { - rw_data.resolved_font_style_response = None; - }, - &QueryMsg::OffsetParentQuery(_) => { - rw_data.offset_parent_response = OffsetParentResponse::empty(); - }, - &QueryMsg::StyleQuery => {}, - &QueryMsg::TextIndexQuery(..) => { - rw_data.text_index_response = TextIndexResponse(None); - }, - &QueryMsg::ElementInnerTextQuery(_) => { - rw_data.element_inner_text_response = String::new(); - }, - &QueryMsg::InnerWindowDimensionsQuery(browsing_context_id) => { - rw_data.inner_window_dimensions_response = self - .last_iframe_sizes - .borrow() - .get(&browsing_context_id) - .cloned(); - }, - }, - ReflowGoal::Full | - ReflowGoal::TickAnimations | - ReflowGoal::UpdateScrollNode(_) => {}, - } - return; - }, - Some(x) => x, + let Some(root_element) = document.root_element() else { + debug!("layout: No root node: bailing"); + return; }; // Calculate the actual viewport as per DEVICE-ADAPT § 6 @@ -850,124 +862,18 @@ impl LayoutThread { } self.first_reflow.set(false); - self.respond_to_query_if_necessary( - &data.reflow_goal, - &mut *rw_data, - &mut layout_context, - data.result.borrow_mut().as_mut().unwrap(), - document_shared_lock, - ); - } - fn respond_to_query_if_necessary( - &self, - reflow_goal: &ReflowGoal, - rw_data: &mut LayoutThreadData, - context: &mut LayoutContext, - reflow_result: &mut ReflowComplete, - shared_lock: &SharedRwLock, - ) { - reflow_result.pending_images = std::mem::take(&mut *context.pending_images.lock().unwrap()); - - match *reflow_goal { - ReflowGoal::LayoutQuery(ref querymsg, _) => match querymsg { - &QueryMsg::ContentBoxQuery(node) => { - rw_data.content_box_response = - process_content_box_request(node, self.fragment_tree.borrow().clone()); - }, - &QueryMsg::ContentBoxesQuery(node) => { - rw_data.content_boxes_response = - process_content_boxes_request(node, self.fragment_tree.borrow().clone()); - }, - &QueryMsg::TextIndexQuery(node, point_in_node) => { - let point_in_node = Point2D::new( - Au::from_f32_px(point_in_node.x), - Au::from_f32_px(point_in_node.y), - ); - rw_data.text_index_response = process_text_index_request(node, point_in_node); - }, - &QueryMsg::ClientRectQuery(node) => { - rw_data.client_rect_response = - process_node_geometry_request(node, self.fragment_tree.borrow().clone()); - }, - &QueryMsg::ScrollingAreaQuery(node) => { - rw_data.scrolling_area_response = - process_node_scroll_area_request(node, self.fragment_tree.borrow().clone()); - }, - &QueryMsg::NodeScrollIdQuery(node) => { - let node = unsafe { ServoLayoutNode::<DOMLayoutData>::new(&node) }; - rw_data.scroll_id_response = - Some(process_node_scroll_id_request(self.id, node)); - }, - &QueryMsg::ResolvedStyleQuery(node, ref pseudo, ref property) => { - let node = unsafe { ServoLayoutNode::<DOMLayoutData>::new(&node) }; - let fragment_tree = self.fragment_tree.borrow().clone(); - rw_data.resolved_style_response = process_resolved_style_request( - context, - node, - pseudo, - property, - fragment_tree, - ); - }, - &QueryMsg::ResolvedFontStyleQuery(node, ref property, ref value) => { - let node = unsafe { ServoLayoutNode::<DOMLayoutData>::new(&node) }; - rw_data.resolved_font_style_response = process_resolved_font_style_query( - context, - node, - property, - value, - self.url.clone(), - shared_lock, - ); - }, - &QueryMsg::OffsetParentQuery(node) => { - rw_data.offset_parent_response = - process_offset_parent_query(node, self.fragment_tree.borrow().clone()); - }, - &QueryMsg::StyleQuery => {}, - &QueryMsg::NodesFromPointQuery(client_point, ref reflow_goal) => { - let mut flags = match reflow_goal { - &NodesFromPointQueryType::Topmost => HitTestFlags::empty(), - &NodesFromPointQueryType::All => HitTestFlags::FIND_ALL, - }; - - // The point we get is not relative to the entire WebRender scene, but to this - // particular pipeline, so we need to tell WebRender about that. - flags.insert(HitTestFlags::POINT_RELATIVE_TO_PIPELINE_VIEWPORT); - - let client_point = units::DevicePoint::from_untyped(client_point); - let results = self.webrender_api.hit_test( - Some(self.id.to_webrender()), - client_point, - flags, - ); - - rw_data.nodes_from_point_response = - results.iter().map(|result| result.node).collect() - }, - &QueryMsg::ElementInnerTextQuery(node) => { - let node = unsafe { ServoLayoutNode::<DOMLayoutData>::new(&node) }; - rw_data.element_inner_text_response = process_element_inner_text_query(node); - }, - &QueryMsg::InnerWindowDimensionsQuery(_browsing_context_id) => { - // TODO(jdm): port the iframe sizing code from layout2013's display - // builder in order to support query iframe sizing. - rw_data.inner_window_dimensions_response = None; - }, - }, - ReflowGoal::UpdateScrollNode(scroll_state) => { - self.update_scroll_node_state(&scroll_state, rw_data); - }, - ReflowGoal::Full | ReflowGoal::TickAnimations => {}, + data.result.borrow_mut().as_mut().unwrap().pending_images = + std::mem::take(&mut *layout_context.pending_images.lock().unwrap()); + if let ReflowGoal::UpdateScrollNode(scroll_state) = data.reflow_goal { + self.update_scroll_node_state(&scroll_state); } } - fn update_scroll_node_state(&self, state: &ScrollState, rw_data: &mut LayoutThreadData) { - rw_data - .scroll_offsets + fn update_scroll_node_state(&self, state: &ScrollState) { + self.scroll_offsets + .borrow_mut() .insert(state.scroll_id, state.scroll_offset); - let point = Point2D::new(-state.scroll_offset.x, -state.scroll_offset.y); self.webrender_api.send_scroll_node( self.id.to_webrender(), @@ -976,12 +882,7 @@ impl LayoutThread { ); } - fn set_scroll_states( - &mut self, - new_scroll_states: Vec<ScrollState>, - possibly_locked_rw_data: &mut RwData<'_, '_>, - ) { - let mut rw_data = possibly_locked_rw_data.lock(); + fn set_scroll_states(&mut self, new_scroll_states: Vec<ScrollState>) { let mut script_scroll_states = vec![]; let mut layout_scroll_states = HashMap::new(); for new_state in &new_scroll_states { @@ -1000,7 +901,7 @@ impl LayoutThread { self.id, script_scroll_states, )); - rw_data.scroll_offsets = layout_scroll_states + self.scroll_offsets = RefCell::new(layout_scroll_states); } fn perform_post_style_recalc_layout_passes( diff --git a/components/script/dom/documentorshadowroot.rs b/components/script/dom/documentorshadowroot.rs index fec2b6372db..59e84acf13c 100644 --- a/components/script/dom/documentorshadowroot.rs +++ b/components/script/dom/documentorshadowroot.rs @@ -84,16 +84,15 @@ impl DocumentOrShadowRoot { pub fn nodes_from_point( &self, client_point: &Point2D<f32>, - reflow_goal: NodesFromPointQueryType, + query_type: NodesFromPointQueryType, ) -> Vec<UntrustedNodeAddress> { - if !self - .window - .layout_reflow(QueryMsg::NodesFromPointQuery(*client_point, reflow_goal)) - { + if !self.window.layout_reflow(QueryMsg::NodesFromPointQuery) { return vec![]; }; - self.window.layout_rpc().nodes_from_point_response() + self.window + .with_layout(|layout| layout.query_nodes_from_point(*client_point, query_type)) + .unwrap_or_default() } #[allow(unsafe_code)] diff --git a/components/script/dom/htmlelement.rs b/components/script/dom/htmlelement.rs index f40c5439de7..1eca57e2b60 100644 --- a/components/script/dom/htmlelement.rs +++ b/components/script/dom/htmlelement.rs @@ -454,10 +454,11 @@ impl HTMLElementMethods for HTMLElement { return node.GetTextContent().unwrap(); } - window.layout_reflow(QueryMsg::ElementInnerTextQuery( - node.to_trusted_node_address(), - )); - DOMString::from(window.layout_rpc().element_inner_text()) + window.layout_reflow(QueryMsg::ElementInnerTextQuery); + let text = window + .with_layout(|layout| layout.query_element_inner_text(node.to_trusted_node_address())) + .unwrap_or_default(); + DOMString::from(text) } // https://html.spec.whatwg.org/multipage/#the-innertext-idl-attribute diff --git a/components/script/dom/htmlinputelement.rs b/components/script/dom/htmlinputelement.rs index 644ba3b50fc..069c31ad806 100755 --- a/components/script/dom/htmlinputelement.rs +++ b/components/script/dom/htmlinputelement.rs @@ -26,7 +26,6 @@ use net_traits::blob_url_store::get_blob_origin; use net_traits::filemanager_thread::FileManagerThreadMsg; use net_traits::{CoreResourceMsg, IpcSend}; use profile_traits::ipc; -use script_layout_interface::rpc::TextIndexResponse; use script_traits::ScriptToConstellationChan; use servo_atoms::Atom; use style::attr::AttrValue; @@ -2537,8 +2536,7 @@ impl VirtualMethods for HTMLInputElement { // now. if let Some(point_in_target) = mouse_event.point_in_target() { let window = window_from_node(self); - let TextIndexResponse(index) = - window.text_index_query(self.upcast::<Node>(), point_in_target); + let index = window.text_index_query(self.upcast::<Node>(), point_in_target); if let Some(i) = index { self.textinput.borrow_mut().set_edit_point_index(i); // trigger redraw diff --git a/components/script/dom/window.rs b/components/script/dom/window.rs index c03903e9199..14b45c5615d 100644 --- a/components/script/dom/window.rs +++ b/components/script/dom/window.rs @@ -49,10 +49,6 @@ use profile_traits::ipc as ProfiledIpc; use profile_traits::mem::ProfilerChan as MemProfilerChan; use profile_traits::time::ProfilerChan as TimeProfilerChan; use script_layout_interface::message::{Msg, QueryMsg, Reflow, ReflowGoal, ScriptReflow}; -use script_layout_interface::rpc::{ - ContentBoxResponse, ContentBoxesResponse, LayoutRPC, NodeScrollIdResponse, - ResolvedStyleResponse, TextIndexResponse, -}; use script_layout_interface::{Layout, PendingImageState, TrustedNodeAddress}; use script_traits::webdriver_msg::{WebDriverJSError, WebDriverJSResult}; use script_traits::{ @@ -70,7 +66,7 @@ use style::error_reporting::{ContextualParseError, ParseErrorReporter}; use style::media_queries; use style::parser::ParserContext as CssParserContext; use style::properties::style_structs::Font; -use style::properties::{PropertyId, ShorthandId}; +use style::properties::PropertyId; use style::selector_parser::PseudoElement; use style::str::HTML_SPACE_CHARACTERS; use style::stylesheets::{CssRuleType, Origin, UrlExtraData}; @@ -2049,52 +2045,55 @@ impl Window { } pub fn resolved_font_style_query(&self, node: &Node, value: String) -> Option<ServoArc<Font>> { - let id = PropertyId::Shorthand(ShorthandId::Font); - if !self.layout_reflow(QueryMsg::ResolvedFontStyleQuery( - node.to_trusted_node_address(), - id, - value, - )) { + if !self.layout_reflow(QueryMsg::ResolvedFontStyleQuery) { return None; } - self.layout_rpc().resolved_font_style() - } - pub fn layout_rpc(&self) -> Box<dyn LayoutRPC> { - self.with_layout(|layout| layout.rpc()).unwrap() + let document = self.Document(); + self.with_layout(|layout| { + layout.query_resolved_font_style( + node.to_trusted_node_address(), + &value, + document.animations().sets.clone(), + document.current_animation_timeline_value(), + ) + }) + .unwrap() } pub fn content_box_query(&self, node: &Node) -> Option<UntypedRect<Au>> { - if !self.layout_reflow(QueryMsg::ContentBoxQuery(node.to_opaque())) { + if !self.layout_reflow(QueryMsg::ContentBox) { return None; } - let ContentBoxResponse(rect) = self.layout_rpc().content_box(); - rect + self.with_layout(|layout| layout.query_content_box(node.to_opaque())) + .unwrap_or(None) } pub fn content_boxes_query(&self, node: &Node) -> Vec<UntypedRect<Au>> { - if !self.layout_reflow(QueryMsg::ContentBoxesQuery(node.to_opaque())) { + if !self.layout_reflow(QueryMsg::ContentBoxes) { return vec![]; } - let ContentBoxesResponse(rects) = self.layout_rpc().content_boxes(); - rects + self.with_layout(|layout| layout.query_content_boxes(node.to_opaque())) + .unwrap_or_default() } pub fn client_rect_query(&self, node: &Node) -> UntypedRect<i32> { - if !self.layout_reflow(QueryMsg::ClientRectQuery(node.to_opaque())) { + if !self.layout_reflow(QueryMsg::ClientRectQuery) { return Rect::zero(); } - self.layout_rpc().node_geometry().client_rect + self.with_layout(|layout| layout.query_client_rect(node.to_opaque())) + .unwrap_or_default() } /// Find the scroll area of the given node, if it is not None. If the node /// is None, find the scroll area of the viewport. pub fn scrolling_area_query(&self, node: Option<&Node>) -> UntypedRect<i32> { let opaque = node.map(|node| node.to_opaque()); - if !self.layout_reflow(QueryMsg::ScrollingAreaQuery(opaque)) { + if !self.layout_reflow(QueryMsg::ScrollingAreaQuery) { return Rect::zero(); } - self.layout_rpc().scrolling_area().client_rect + self.with_layout(|layout| layout.query_scrolling_area(opaque)) + .unwrap_or_default() } pub fn scroll_offset_query(&self, node: &Node) -> Vector2D<f32, LayoutPixel> { @@ -2106,7 +2105,7 @@ impl Window { // https://drafts.csswg.org/cssom-view/#element-scrolling-members pub fn scroll_node(&self, node: &Node, x_: f64, y_: f64, behavior: ScrollBehavior) { - if !self.layout_reflow(QueryMsg::NodeScrollIdQuery(node.to_trusted_node_address())) { + if !self.layout_reflow(QueryMsg::NodeScrollIdQuery) { return; } @@ -2117,7 +2116,9 @@ impl Window { .borrow_mut() .insert(node.to_opaque(), Vector2D::new(x_ as f32, y_ as f32)); - let NodeScrollIdResponse(scroll_id) = self.layout_rpc().node_scroll_id(); + let scroll_id = self + .with_layout(|layout| layout.query_scroll_id(node.to_trusted_node_address())) + .unwrap(); // Step 12 self.perform_a_scroll( @@ -2135,32 +2136,45 @@ impl Window { pseudo: Option<PseudoElement>, property: PropertyId, ) -> DOMString { - if !self.layout_reflow(QueryMsg::ResolvedStyleQuery(element, pseudo, property)) { + if !self.layout_reflow(QueryMsg::ResolvedStyleQuery) { return DOMString::new(); } - let ResolvedStyleResponse(resolved) = self.layout_rpc().resolved_style(); - DOMString::from(resolved) + + let document = self.Document(); + DOMString::from( + self.with_layout(|layout| { + layout.query_resolved_style( + element, + pseudo, + property, + document.animations().sets.clone(), + document.current_animation_timeline_value(), + ) + }) + .unwrap(), + ) } pub fn inner_window_dimensions_query( &self, browsing_context: BrowsingContextId, ) -> Option<Size2D<f32, CSSPixel>> { - if !self.layout_reflow(QueryMsg::InnerWindowDimensionsQuery(browsing_context)) { + if !self.layout_reflow(QueryMsg::InnerWindowDimensionsQuery) { return None; } - self.layout_rpc().inner_window_dimensions() + self.with_layout(|layout| layout.query_inner_window_dimension(browsing_context)) + .unwrap() } #[allow(unsafe_code)] pub fn offset_parent_query(&self, node: &Node) -> (Option<DomRoot<Element>>, UntypedRect<Au>) { - if !self.layout_reflow(QueryMsg::OffsetParentQuery(node.to_opaque())) { + if !self.layout_reflow(QueryMsg::OffsetParentQuery) { return (None, Rect::zero()); } - // FIXME(nox): Layout can reply with a garbage value which doesn't - // actually correspond to an element, that's unsound. - let response = self.layout_rpc().offset_parent(); + let response = self + .with_layout(|layout| layout.query_offset_parent(node.to_opaque())) + .unwrap(); let element = response.node_address.and_then(|parent_node_address| { let node = unsafe { from_untrusted_node_address(parent_node_address) }; DomRoot::downcast(node) @@ -2172,11 +2186,12 @@ impl Window { &self, node: &Node, point_in_node: UntypedPoint2D<f32>, - ) -> TextIndexResponse { - if !self.layout_reflow(QueryMsg::TextIndexQuery(node.to_opaque(), point_in_node)) { - return TextIndexResponse(None); + ) -> Option<usize> { + if !self.layout_reflow(QueryMsg::TextIndexQuery) { + return None; } - self.layout_rpc().text_index() + self.with_layout(|layout| layout.query_text_indext(node.to_opaque(), point_in_node)) + .unwrap() } #[allow(unsafe_code)] @@ -2705,19 +2720,19 @@ fn debug_reflow_events(id: PipelineId, reflow_goal: &ReflowGoal, reason: &Reflow ReflowGoal::TickAnimations => "\tTickAnimations", ReflowGoal::UpdateScrollNode(_) => "\tUpdateScrollNode", ReflowGoal::LayoutQuery(ref query_msg, _) => match *query_msg { - QueryMsg::ContentBoxQuery(_n) => "\tContentBoxQuery", - QueryMsg::ContentBoxesQuery(_n) => "\tContentBoxesQuery", - QueryMsg::NodesFromPointQuery(..) => "\tNodesFromPointQuery", - QueryMsg::ClientRectQuery(_n) => "\tClientRectQuery", - QueryMsg::ScrollingAreaQuery(_n) => "\tNodeScrollGeometryQuery", - QueryMsg::NodeScrollIdQuery(_n) => "\tNodeScrollIdQuery", - QueryMsg::ResolvedStyleQuery(_, _, _) => "\tResolvedStyleQuery", - QueryMsg::ResolvedFontStyleQuery(..) => "\nResolvedFontStyleQuery", - QueryMsg::OffsetParentQuery(_n) => "\tOffsetParentQuery", + QueryMsg::ContentBox => "\tContentBoxQuery", + QueryMsg::ContentBoxes => "\tContentBoxesQuery", + QueryMsg::NodesFromPointQuery => "\tNodesFromPointQuery", + QueryMsg::ClientRectQuery => "\tClientRectQuery", + QueryMsg::ScrollingAreaQuery => "\tNodeScrollGeometryQuery", + QueryMsg::NodeScrollIdQuery => "\tNodeScrollIdQuery", + QueryMsg::ResolvedStyleQuery => "\tResolvedStyleQuery", + QueryMsg::ResolvedFontStyleQuery => "\nResolvedFontStyleQuery", + QueryMsg::OffsetParentQuery => "\tOffsetParentQuery", QueryMsg::StyleQuery => "\tStyleQuery", - QueryMsg::TextIndexQuery(..) => "\tTextIndexQuery", - QueryMsg::ElementInnerTextQuery(_) => "\tElementInnerTextQuery", - QueryMsg::InnerWindowDimensionsQuery(_) => "\tInnerWindowDimensionsQuery", + QueryMsg::TextIndexQuery => "\tTextIndexQuery", + QueryMsg::ElementInnerTextQuery => "\tElementInnerTextQuery", + QueryMsg::InnerWindowDimensionsQuery => "\tInnerWindowDimensionsQuery", }, }; diff --git a/components/shared/msg/constellation_msg.rs b/components/shared/msg/constellation_msg.rs index 44f3eb6b12e..24fda786c9d 100644 --- a/components/shared/msg/constellation_msg.rs +++ b/components/shared/msg/constellation_msg.rs @@ -462,7 +462,6 @@ pub enum LayoutHangAnnotation { RemoveStylesheet, SetQuirksMode, Reflow, - GetRPC, CollectReports, ExitNow, GetCurrentEpoch, diff --git a/components/shared/script_layout/lib.rs b/components/shared/script_layout/lib.rs index 121788d7b16..aca819980d7 100644 --- a/components/shared/script_layout/lib.rs +++ b/components/shared/script_layout/lib.rs @@ -9,7 +9,6 @@ #![deny(unsafe_code)] pub mod message; -pub mod rpc; pub mod wrapper_traits; use std::any::Any; @@ -17,15 +16,19 @@ use std::borrow::Cow; use std::sync::atomic::AtomicIsize; use std::sync::Arc; +use app_units::Au; use atomic_refcell::AtomicRefCell; use canvas_traits::canvas::{CanvasId, CanvasMsg}; +use euclid::default::{Point2D, Rect}; +use euclid::Size2D; use gfx::font_cache_thread::FontCacheThread; use gfx_traits::Epoch; use ipc_channel::ipc::IpcSender; use libc::c_void; use malloc_size_of_derive::MallocSizeOf; +use message::NodesFromPointQueryType; use metrics::PaintTimeMetrics; -use msg::constellation_msg::PipelineId; +use msg::constellation_msg::{BrowsingContextId, PipelineId}; use net_traits::image_cache::{ImageCache, PendingImageId}; use profile_traits::time; use script_traits::{ @@ -34,9 +37,15 @@ use script_traits::{ }; use servo_arc::Arc as ServoArc; use servo_url::{ImmutableOrigin, ServoUrl}; +use style::animation::DocumentAnimationSet; use style::data::ElementData; +use style::dom::OpaqueNode; +use style::properties::style_structs::Font; +use style::properties::PropertyId; +use style::selector_parser::PseudoElement; use style::stylesheets::Stylesheet; -use webrender_api::ImageKey; +use style_traits::CSSPixel; +use webrender_api::{ExternalScrollId, ImageKey}; #[derive(MallocSizeOf)] pub struct StyleData { @@ -195,11 +204,6 @@ pub trait Layout { /// Handle a a single mesasge from the FontCacheThread. fn handle_font_cache_msg(&mut self); - /// Return the interface used for scipt queries. - /// TODO: Make this part of the the Layout interface itself now that the - /// layout thread has been removed. - fn rpc(&self) -> Box<dyn rpc::LayoutRPC>; - /// Whether or not this layout is waiting for fonts from loaded stylesheets to finish loading. fn waiting_for_web_fonts_to_load(&self) -> bool; @@ -221,6 +225,39 @@ pub trait Layout { /// Removes a stylesheet from the Layout. fn remove_stylesheet(&mut self, stylesheet: ServoArc<Stylesheet>); + + fn query_content_box(&self, node: OpaqueNode) -> Option<Rect<Au>>; + fn query_content_boxes(&self, node: OpaqueNode) -> Vec<Rect<Au>>; + fn query_client_rect(&self, node: OpaqueNode) -> Rect<i32>; + fn query_element_inner_text(&self, node: TrustedNodeAddress) -> String; + fn query_inner_window_dimension( + &self, + context: BrowsingContextId, + ) -> Option<Size2D<f32, CSSPixel>>; + fn query_nodes_from_point( + &self, + point: Point2D<f32>, + query_type: NodesFromPointQueryType, + ) -> Vec<UntrustedNodeAddress>; + fn query_offset_parent(&self, node: OpaqueNode) -> OffsetParentResponse; + fn query_resolved_style( + &self, + node: TrustedNodeAddress, + pseudo: Option<PseudoElement>, + property_id: PropertyId, + animations: DocumentAnimationSet, + animation_timeline_value: f64, + ) -> String; + fn query_resolved_font_style( + &self, + node: TrustedNodeAddress, + value: &str, + animations: DocumentAnimationSet, + animation_timeline_value: f64, + ) -> Option<ServoArc<Font>>; + fn query_scroll_id(&self, node: TrustedNodeAddress) -> ExternalScrollId; + fn query_scrolling_area(&self, node: Option<OpaqueNode>) -> Rect<i32>; + fn query_text_indext(&self, node: OpaqueNode, point: Point2D<f32>) -> Option<usize>; } /// This trait is part of `script_layout_interface` because it depends on both `script_traits` @@ -236,3 +273,8 @@ pub trait ScriptThreadFactory { user_agent: Cow<'static, str>, ); } +#[derive(Clone, Default)] +pub struct OffsetParentResponse { + pub node_address: Option<UntrustedNodeAddress>, + pub rect: Rect<Au>, +} diff --git a/components/shared/script_layout/message.rs b/components/shared/script_layout/message.rs index e902bac4f7a..34de65cd227 100644 --- a/components/shared/script_layout/message.rs +++ b/components/shared/script_layout/message.rs @@ -4,21 +4,17 @@ use app_units::Au; use crossbeam_channel::Sender; -use euclid::default::{Point2D, Rect}; +use euclid::default::Rect; use malloc_size_of_derive::MallocSizeOf; -use msg::constellation_msg::BrowsingContextId; use profile_traits::mem::ReportsChan; use script_traits::{Painter, ScrollState, WindowSizeData}; use servo_atoms::Atom; use servo_url::ImmutableOrigin; use style::animation::DocumentAnimationSet; use style::context::QuirksMode; -use style::dom::OpaqueNode; use style::invalidation::element::restyle_hints::RestyleHint; -use style::properties::PropertyId; -use style::selector_parser::{PseudoElement, RestyleDamage, Snapshot}; +use style::selector_parser::{RestyleDamage, Snapshot}; -use crate::rpc::LayoutRPC; use crate::{PendingImage, TrustedNodeAddress}; /// Asynchronous messages that script can send to layout. @@ -29,9 +25,6 @@ pub enum Msg { /// Requests a reflow. Reflow(ScriptReflow), - /// Get an RPC interface. - GetRPC(Sender<Box<dyn LayoutRPC + Send>>), - /// Requests that layout measure its memory usage. The resulting reports are sent back /// via the supplied channel. CollectReports(ReportsChan), @@ -55,23 +48,19 @@ pub enum NodesFromPointQueryType { #[derive(Debug, PartialEq)] pub enum QueryMsg { - ContentBoxQuery(OpaqueNode), - ContentBoxesQuery(OpaqueNode), - ClientRectQuery(OpaqueNode), - ScrollingAreaQuery(Option<OpaqueNode>), - OffsetParentQuery(OpaqueNode), - TextIndexQuery(OpaqueNode, Point2D<f32>), - NodesFromPointQuery(Point2D<f32>, NodesFromPointQueryType), - - // FIXME(nox): The following queries use the TrustedNodeAddress to - // access actual DOM nodes, but those values can be constructed from - // garbage values such as `0xdeadbeef as *const _`, this is unsound. - NodeScrollIdQuery(TrustedNodeAddress), - ResolvedStyleQuery(TrustedNodeAddress, Option<PseudoElement>, PropertyId), + ContentBox, + ContentBoxes, + ClientRectQuery, + ScrollingAreaQuery, + OffsetParentQuery, + TextIndexQuery, + NodesFromPointQuery, + NodeScrollIdQuery, + ResolvedStyleQuery, StyleQuery, - ElementInnerTextQuery(TrustedNodeAddress), - ResolvedFontStyleQuery(TrustedNodeAddress, PropertyId, String), - InnerWindowDimensionsQuery(BrowsingContextId), + ElementInnerTextQuery, + ResolvedFontStyleQuery, + InnerWindowDimensionsQuery, } /// Any query to perform with this reflow. @@ -93,18 +82,18 @@ impl ReflowGoal { match *self { ReflowGoal::Full | ReflowGoal::TickAnimations | ReflowGoal::UpdateScrollNode(_) => true, ReflowGoal::LayoutQuery(ref querymsg, _) => match *querymsg { - QueryMsg::ElementInnerTextQuery(_) | - QueryMsg::InnerWindowDimensionsQuery(_) | - QueryMsg::NodesFromPointQuery(..) | - QueryMsg::ResolvedStyleQuery(..) | - QueryMsg::TextIndexQuery(..) => true, - QueryMsg::ClientRectQuery(_) | - QueryMsg::ContentBoxQuery(_) | - QueryMsg::ContentBoxesQuery(_) | - QueryMsg::NodeScrollIdQuery(_) | - QueryMsg::OffsetParentQuery(_) | - QueryMsg::ResolvedFontStyleQuery(..) | - QueryMsg::ScrollingAreaQuery(_) | + QueryMsg::ElementInnerTextQuery | + QueryMsg::InnerWindowDimensionsQuery | + QueryMsg::NodesFromPointQuery | + QueryMsg::ResolvedStyleQuery | + QueryMsg::TextIndexQuery => true, + QueryMsg::ClientRectQuery | + QueryMsg::ContentBox | + QueryMsg::ContentBoxes | + QueryMsg::NodeScrollIdQuery | + QueryMsg::OffsetParentQuery | + QueryMsg::ResolvedFontStyleQuery | + QueryMsg::ScrollingAreaQuery | QueryMsg::StyleQuery => false, }, } @@ -116,18 +105,18 @@ impl ReflowGoal { match *self { ReflowGoal::Full | ReflowGoal::TickAnimations | ReflowGoal::UpdateScrollNode(_) => true, ReflowGoal::LayoutQuery(ref querymsg, _) => match *querymsg { - QueryMsg::NodesFromPointQuery(..) | - QueryMsg::TextIndexQuery(..) | - QueryMsg::ElementInnerTextQuery(_) => true, - QueryMsg::ContentBoxQuery(_) | - QueryMsg::ContentBoxesQuery(_) | - QueryMsg::ClientRectQuery(_) | - QueryMsg::ScrollingAreaQuery(_) | - QueryMsg::NodeScrollIdQuery(_) | - QueryMsg::ResolvedStyleQuery(..) | - QueryMsg::ResolvedFontStyleQuery(..) | - QueryMsg::OffsetParentQuery(_) | - QueryMsg::InnerWindowDimensionsQuery(_) | + QueryMsg::NodesFromPointQuery | + QueryMsg::TextIndexQuery | + QueryMsg::ElementInnerTextQuery => true, + QueryMsg::ContentBox | + QueryMsg::ContentBoxes | + QueryMsg::ClientRectQuery | + QueryMsg::ScrollingAreaQuery | + QueryMsg::NodeScrollIdQuery | + QueryMsg::ResolvedStyleQuery | + QueryMsg::ResolvedFontStyleQuery | + QueryMsg::OffsetParentQuery | + QueryMsg::InnerWindowDimensionsQuery | QueryMsg::StyleQuery => false, }, } diff --git a/components/shared/script_layout/rpc.rs b/components/shared/script_layout/rpc.rs deleted file mode 100644 index 3778d8f975a..00000000000 --- a/components/shared/script_layout/rpc.rs +++ /dev/null @@ -1,75 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ - -use app_units::Au; -use euclid::default::Rect; -use euclid::Size2D; -use script_traits::UntrustedNodeAddress; -use servo_arc::Arc; -use style::properties::style_structs::Font; -use style_traits::CSSPixel; -use webrender_api::ExternalScrollId; - -/// Synchronous messages that script can send to layout. -/// -/// In general, you should use messages to talk to Layout. Use the RPC interface -/// if and only if the work is -/// -/// 1) read-only with respect to LayoutThreadData, -/// 2) small, -/// 3) and really needs to be fast. -pub trait LayoutRPC { - /// Requests the dimensions of the content box, as in the `getBoundingClientRect()` call. - fn content_box(&self) -> ContentBoxResponse; - /// Requests the dimensions of all the content boxes, as in the `getClientRects()` call. - fn content_boxes(&self) -> ContentBoxesResponse; - /// Requests the geometry of this node. Used by APIs such as `clientTop`. - fn node_geometry(&self) -> NodeGeometryResponse; - /// Requests the scroll geometry of this node. Used by APIs such as `scrollTop`. - fn scrolling_area(&self) -> NodeGeometryResponse; - /// Requests the scroll id of this node. Used by APIs such as `scrollTop` - fn node_scroll_id(&self) -> NodeScrollIdResponse; - /// Query layout for the resolved value of a given CSS property - fn resolved_style(&self) -> ResolvedStyleResponse; - /// Query layout to get the resolved font style for canvas. - fn resolved_font_style(&self) -> Option<Arc<Font>>; - fn offset_parent(&self) -> OffsetParentResponse; - fn text_index(&self) -> TextIndexResponse; - /// Requests the list of nodes from the given point. - fn nodes_from_point_response(&self) -> Vec<UntrustedNodeAddress>; - /// Query layout to get the inner text for a given element. - fn element_inner_text(&self) -> String; - /// Get the dimensions of an iframe's inner window. - fn inner_window_dimensions(&self) -> Option<Size2D<f32, CSSPixel>>; -} - -pub struct ContentBoxResponse(pub Option<Rect<Au>>); - -pub struct ContentBoxesResponse(pub Vec<Rect<Au>>); - -pub struct NodeGeometryResponse { - pub client_rect: Rect<i32>, -} - -pub struct NodeScrollIdResponse(pub ExternalScrollId); - -pub struct ResolvedStyleResponse(pub String); - -#[derive(Clone)] -pub struct OffsetParentResponse { - pub node_address: Option<UntrustedNodeAddress>, - pub rect: Rect<Au>, -} - -impl OffsetParentResponse { - pub fn empty() -> OffsetParentResponse { - OffsetParentResponse { - node_address: None, - rect: Rect::zero(), - } - } -} - -#[derive(Clone)] -pub struct TextIndexResponse(pub Option<usize>); |