mirror of
https://github.com/servo/servo.git
synced 2025-07-23 07:13:52 +01:00
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.
This commit is contained in:
parent
07391e346b
commit
b7d089930e
12 changed files with 667 additions and 1174 deletions
|
@ -6,22 +6,14 @@
|
||||||
|
|
||||||
use std::cmp::{max, min};
|
use std::cmp::{max, min};
|
||||||
use std::ops::Deref;
|
use std::ops::Deref;
|
||||||
use std::sync::{Arc, Mutex};
|
|
||||||
|
|
||||||
use app_units::Au;
|
use app_units::Au;
|
||||||
use euclid::default::{Box2D, Point2D, Rect, Size2D, Vector2D};
|
use euclid::default::{Box2D, Point2D, Rect, Size2D, Vector2D};
|
||||||
use euclid::Size2D as TypedSize2D;
|
|
||||||
use ipc_channel::ipc::IpcSender;
|
|
||||||
use msg::constellation_msg::PipelineId;
|
use msg::constellation_msg::PipelineId;
|
||||||
use script_layout_interface::rpc::{
|
|
||||||
ContentBoxResponse, ContentBoxesResponse, LayoutRPC, NodeGeometryResponse,
|
|
||||||
NodeScrollIdResponse, OffsetParentResponse, ResolvedStyleResponse, TextIndexResponse,
|
|
||||||
};
|
|
||||||
use script_layout_interface::wrapper_traits::{
|
use script_layout_interface::wrapper_traits::{
|
||||||
LayoutNode, ThreadSafeLayoutElement, ThreadSafeLayoutNode,
|
LayoutNode, ThreadSafeLayoutElement, ThreadSafeLayoutNode,
|
||||||
};
|
};
|
||||||
use script_layout_interface::{LayoutElementType, LayoutNodeType};
|
use script_layout_interface::{LayoutElementType, LayoutNodeType, OffsetParentResponse};
|
||||||
use script_traits::{LayoutMsg as ConstellationMsg, UntrustedNodeAddress};
|
|
||||||
use servo_arc::Arc as ServoArc;
|
use servo_arc::Arc as ServoArc;
|
||||||
use servo_url::ServoUrl;
|
use servo_url::ServoUrl;
|
||||||
use style::computed_values::display::T as Display;
|
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::style_structs::{self, Font};
|
||||||
use style::properties::{
|
use style::properties::{
|
||||||
parse_one_declaration_into, ComputedValues, Importance, LonghandId, PropertyDeclarationBlock,
|
parse_one_declaration_into, ComputedValues, Importance, LonghandId, PropertyDeclarationBlock,
|
||||||
PropertyDeclarationId, PropertyId, SourcePropertyDeclaration,
|
PropertyDeclarationId, PropertyId, ShorthandId, SourcePropertyDeclaration,
|
||||||
};
|
};
|
||||||
use style::selector_parser::PseudoElement;
|
use style::selector_parser::PseudoElement;
|
||||||
use style::shared_lock::SharedRwLock;
|
use style::shared_lock::SharedRwLock;
|
||||||
use style::stylesheets::{CssRuleType, Origin, UrlExtraData};
|
use style::stylesheets::{CssRuleType, Origin, UrlExtraData};
|
||||||
use style_traits::{CSSPixel, ParsingMode, ToCss};
|
use style_traits::{ParsingMode, ToCss};
|
||||||
use webrender_api::ExternalScrollId;
|
use webrender_api::ExternalScrollId;
|
||||||
|
|
||||||
use crate::construct::ConstructionResult;
|
use crate::construct::ConstructionResult;
|
||||||
use crate::context::LayoutContext;
|
use crate::display_list::items::OpaqueNode;
|
||||||
use crate::display_list::items::{DisplayList, OpaqueNode, ScrollOffsetMap};
|
|
||||||
use crate::display_list::IndexableText;
|
use crate::display_list::IndexableText;
|
||||||
use crate::flow::{Flow, GetBaseFlow};
|
use crate::flow::{Flow, GetBaseFlow};
|
||||||
use crate::fragment::{Fragment, FragmentBorderBoxIterator, FragmentFlags, SpecificFragmentInfo};
|
use crate::fragment::{Fragment, FragmentBorderBoxIterator, FragmentFlags, SpecificFragmentInfo};
|
||||||
|
@ -51,60 +42,6 @@ use crate::inline::InlineFragmentNodeFlags;
|
||||||
use crate::sequential;
|
use crate::sequential;
|
||||||
use crate::wrapper::LayoutNodeLayoutData;
|
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
|
// https://drafts.csswg.org/cssom-view/#overflow-directions
|
||||||
fn overflow_direction(writing_mode: &WritingMode) -> OverflowDirection {
|
fn overflow_direction(writing_mode: &WritingMode) -> OverflowDirection {
|
||||||
match (
|
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 {
|
struct UnioningFragmentBorderBoxIterator {
|
||||||
node_address: OpaqueNode,
|
node_address: OpaqueNode,
|
||||||
rect: Option<Rect<Au>>,
|
rect: Option<Rect<Au>>,
|
||||||
|
@ -788,14 +641,13 @@ pub fn process_scrolling_area_request(
|
||||||
|
|
||||||
fn create_font_declaration(
|
fn create_font_declaration(
|
||||||
value: &str,
|
value: &str,
|
||||||
property: &PropertyId,
|
|
||||||
url_data: &ServoUrl,
|
url_data: &ServoUrl,
|
||||||
quirks_mode: QuirksMode,
|
quirks_mode: QuirksMode,
|
||||||
) -> Option<PropertyDeclarationBlock> {
|
) -> Option<PropertyDeclarationBlock> {
|
||||||
let mut declarations = SourcePropertyDeclaration::default();
|
let mut declarations = SourcePropertyDeclaration::default();
|
||||||
let result = parse_one_declaration_into(
|
let result = parse_one_declaration_into(
|
||||||
&mut declarations,
|
&mut declarations,
|
||||||
property.clone(),
|
PropertyId::Shorthand(ShorthandId::Font),
|
||||||
value,
|
value,
|
||||||
Origin::Author,
|
Origin::Author,
|
||||||
&UrlExtraData(url_data.get_arc()),
|
&UrlExtraData(url_data.get_arc()),
|
||||||
|
@ -839,10 +691,9 @@ where
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn process_resolved_font_style_request<'dom, E>(
|
pub fn process_resolved_font_style_request<'dom, E>(
|
||||||
context: &LayoutContext,
|
context: &SharedStyleContext,
|
||||||
node: E,
|
node: E,
|
||||||
value: &str,
|
value: &str,
|
||||||
property: &PropertyId,
|
|
||||||
url_data: ServoUrl,
|
url_data: ServoUrl,
|
||||||
shared_lock: &SharedRwLock,
|
shared_lock: &SharedRwLock,
|
||||||
) -> Option<ServoArc<Font>>
|
) -> Option<ServoArc<Font>>
|
||||||
|
@ -853,8 +704,8 @@ where
|
||||||
use style::traversal::resolve_style;
|
use style::traversal::resolve_style;
|
||||||
|
|
||||||
// 1. Parse the given font property value
|
// 1. Parse the given font property value
|
||||||
let quirks_mode = context.style_context.quirks_mode();
|
let quirks_mode = context.quirks_mode();
|
||||||
let declarations = create_font_declaration(value, property, &url_data, quirks_mode)?;
|
let declarations = create_font_declaration(value, &url_data, quirks_mode)?;
|
||||||
|
|
||||||
// TODO: Reject 'inherit' and 'initial' values for the font property.
|
// TODO: Reject 'inherit' and 'initial' values for the font property.
|
||||||
|
|
||||||
|
@ -866,7 +717,7 @@ where
|
||||||
} else {
|
} else {
|
||||||
let mut tlc = ThreadLocalStyleContext::new();
|
let mut tlc = ThreadLocalStyleContext::new();
|
||||||
let mut context = StyleContext {
|
let mut context = StyleContext {
|
||||||
shared: &context.style_context,
|
shared: context,
|
||||||
thread_local: &mut tlc,
|
thread_local: &mut tlc,
|
||||||
};
|
};
|
||||||
let styles = resolve_style(&mut context, element, RuleInclusion::All, None, None);
|
let styles = resolve_style(&mut context, element, RuleInclusion::All, None, None);
|
||||||
|
@ -874,22 +725,13 @@ where
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
let default_declarations =
|
let default_declarations =
|
||||||
create_font_declaration("10px sans-serif", property, &url_data, quirks_mode).unwrap();
|
create_font_declaration("10px sans-serif", &url_data, quirks_mode).unwrap();
|
||||||
resolve_for_declarations::<E>(
|
resolve_for_declarations::<E>(context, None, default_declarations, shared_lock)
|
||||||
&context.style_context,
|
|
||||||
None,
|
|
||||||
default_declarations,
|
|
||||||
shared_lock,
|
|
||||||
)
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// 3. Resolve the parsed value with resolved styles of the parent element
|
// 3. Resolve the parsed value with resolved styles of the parent element
|
||||||
let computed_values = resolve_for_declarations::<E>(
|
let computed_values =
|
||||||
&context.style_context,
|
resolve_for_declarations::<E>(context, Some(&*parent_style), declarations, shared_lock);
|
||||||
Some(&*parent_style),
|
|
||||||
declarations,
|
|
||||||
shared_lock,
|
|
||||||
);
|
|
||||||
|
|
||||||
Some(computed_values.clone_font())
|
Some(computed_values.clone_font())
|
||||||
}
|
}
|
||||||
|
@ -897,7 +739,7 @@ where
|
||||||
/// Return the resolved value of property for a given (pseudo)element.
|
/// Return the resolved value of property for a given (pseudo)element.
|
||||||
/// <https://drafts.csswg.org/cssom/#resolved-value>
|
/// <https://drafts.csswg.org/cssom/#resolved-value>
|
||||||
pub fn process_resolved_style_request<'dom>(
|
pub fn process_resolved_style_request<'dom>(
|
||||||
context: &LayoutContext,
|
context: &SharedStyleContext,
|
||||||
node: impl LayoutNode<'dom>,
|
node: impl LayoutNode<'dom>,
|
||||||
pseudo: &Option<PseudoElement>,
|
pseudo: &Option<PseudoElement>,
|
||||||
property: &PropertyId,
|
property: &PropertyId,
|
||||||
|
@ -921,7 +763,7 @@ pub fn process_resolved_style_request<'dom>(
|
||||||
|
|
||||||
let mut tlc = ThreadLocalStyleContext::new();
|
let mut tlc = ThreadLocalStyleContext::new();
|
||||||
let mut context = StyleContext {
|
let mut context = StyleContext {
|
||||||
shared: &context.style_context,
|
shared: context,
|
||||||
thread_local: &mut tlc,
|
thread_local: &mut tlc,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1112,7 +954,7 @@ pub fn process_offset_parent_query(
|
||||||
rect: Rect::new(origin, size),
|
rect: Rect::new(origin, size),
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
_ => OffsetParentResponse::empty(),
|
_ => OffsetParentResponse::default(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -3,22 +3,17 @@
|
||||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
//! Utilities for querying the layout, as needed by layout.
|
//! Utilities for querying the layout, as needed by layout.
|
||||||
use std::collections::HashMap;
|
use std::sync::Arc;
|
||||||
use std::sync::{Arc, Mutex};
|
|
||||||
|
|
||||||
use app_units::Au;
|
use app_units::Au;
|
||||||
use euclid::default::{Point2D, Rect};
|
use euclid::default::{Point2D, Rect};
|
||||||
use euclid::{SideOffsets2D, Size2D, Vector2D};
|
use euclid::{SideOffsets2D, Size2D, Vector2D};
|
||||||
use log::warn;
|
use log::warn;
|
||||||
use msg::constellation_msg::PipelineId;
|
use msg::constellation_msg::PipelineId;
|
||||||
use script_layout_interface::rpc::{
|
|
||||||
ContentBoxResponse, ContentBoxesResponse, LayoutRPC, NodeGeometryResponse,
|
|
||||||
NodeScrollIdResponse, OffsetParentResponse, ResolvedStyleResponse, TextIndexResponse,
|
|
||||||
};
|
|
||||||
use script_layout_interface::wrapper_traits::{
|
use script_layout_interface::wrapper_traits::{
|
||||||
LayoutNode, ThreadSafeLayoutElement, ThreadSafeLayoutNode,
|
LayoutNode, ThreadSafeLayoutElement, ThreadSafeLayoutNode,
|
||||||
};
|
};
|
||||||
use script_traits::UntrustedNodeAddress;
|
use script_layout_interface::OffsetParentResponse;
|
||||||
use servo_arc::Arc as ServoArc;
|
use servo_arc::Arc as ServoArc;
|
||||||
use servo_url::ServoUrl;
|
use servo_url::ServoUrl;
|
||||||
use style::computed_values::position::T as Position;
|
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::style_structs::Font;
|
||||||
use style::properties::{
|
use style::properties::{
|
||||||
parse_one_declaration_into, ComputedValues, Importance, LonghandId, PropertyDeclarationBlock,
|
parse_one_declaration_into, ComputedValues, Importance, LonghandId, PropertyDeclarationBlock,
|
||||||
PropertyDeclarationId, PropertyId, SourcePropertyDeclaration,
|
PropertyDeclarationId, PropertyId, ShorthandId, SourcePropertyDeclaration,
|
||||||
};
|
};
|
||||||
use style::selector_parser::PseudoElement;
|
use style::selector_parser::PseudoElement;
|
||||||
use style::shared_lock::SharedRwLock;
|
use style::shared_lock::SharedRwLock;
|
||||||
|
@ -35,146 +30,11 @@ use style::stylesheets::{CssRuleType, Origin, UrlExtraData};
|
||||||
use style::stylist::RuleInclusion;
|
use style::stylist::RuleInclusion;
|
||||||
use style::traversal::resolve_style;
|
use style::traversal::resolve_style;
|
||||||
use style::values::generics::text::LineHeight;
|
use style::values::generics::text::LineHeight;
|
||||||
use style_traits::{CSSPixel, ParsingMode, ToCss};
|
use style_traits::{ParsingMode, ToCss};
|
||||||
use webrender_api::units::LayoutPixel;
|
use webrender_api::ExternalScrollId;
|
||||||
use webrender_api::{DisplayListBuilder, ExternalScrollId};
|
|
||||||
|
|
||||||
use crate::context::LayoutContext;
|
|
||||||
use crate::fragment_tree::{Fragment, FragmentFlags, FragmentTree, Tag};
|
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(
|
pub fn process_content_box_request(
|
||||||
requested_node: OpaqueNode,
|
requested_node: OpaqueNode,
|
||||||
fragment_tree: Option<Arc<FragmentTree>>,
|
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.
|
/// Return the resolved value of property for a given (pseudo)element.
|
||||||
/// <https://drafts.csswg.org/cssom/#resolved-value>
|
/// <https://drafts.csswg.org/cssom/#resolved-value>
|
||||||
pub fn process_resolved_style_request<'dom>(
|
pub fn process_resolved_style_request<'dom>(
|
||||||
context: &LayoutContext,
|
context: &SharedStyleContext,
|
||||||
node: impl LayoutNode<'dom>,
|
node: impl LayoutNode<'dom>,
|
||||||
pseudo: &Option<PseudoElement>,
|
pseudo: &Option<PseudoElement>,
|
||||||
property: &PropertyId,
|
property: &PropertyId,
|
||||||
|
@ -386,7 +246,7 @@ pub fn process_resolved_style_request<'dom>(
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn process_resolved_style_request_for_unstyled_node<'dom>(
|
pub fn process_resolved_style_request_for_unstyled_node<'dom>(
|
||||||
context: &LayoutContext,
|
context: &SharedStyleContext,
|
||||||
node: impl LayoutNode<'dom>,
|
node: impl LayoutNode<'dom>,
|
||||||
pseudo: &Option<PseudoElement>,
|
pseudo: &Option<PseudoElement>,
|
||||||
property: &PropertyId,
|
property: &PropertyId,
|
||||||
|
@ -398,7 +258,7 @@ pub fn process_resolved_style_request_for_unstyled_node<'dom>(
|
||||||
|
|
||||||
let mut tlc = ThreadLocalStyleContext::new();
|
let mut tlc = ThreadLocalStyleContext::new();
|
||||||
let mut context = StyleContext {
|
let mut context = StyleContext {
|
||||||
shared: &context.style_context,
|
shared: context,
|
||||||
thread_local: &mut tlc,
|
thread_local: &mut tlc,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -449,8 +309,7 @@ pub fn process_offset_parent_query(
|
||||||
node: OpaqueNode,
|
node: OpaqueNode,
|
||||||
fragment_tree: Option<Arc<FragmentTree>>,
|
fragment_tree: Option<Arc<FragmentTree>>,
|
||||||
) -> OffsetParentResponse {
|
) -> OffsetParentResponse {
|
||||||
process_offset_parent_query_inner(node, fragment_tree)
|
process_offset_parent_query_inner(node, fragment_tree).unwrap_or_default()
|
||||||
.unwrap_or_else(OffsetParentResponse::empty)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
|
@ -656,14 +515,13 @@ pub fn process_element_inner_text_query<'dom>(_node: impl LayoutNode<'dom>) -> S
|
||||||
"".to_owned()
|
"".to_owned()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn process_text_index_request(_node: OpaqueNode, _point: Point2D<Au>) -> TextIndexResponse {
|
pub fn process_text_index_request(_node: OpaqueNode, _point: Point2D<Au>) -> Option<usize> {
|
||||||
TextIndexResponse(None)
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn process_resolved_font_style_query<'dom, E>(
|
pub fn process_resolved_font_style_query<'dom, E>(
|
||||||
context: &LayoutContext,
|
context: &SharedStyleContext,
|
||||||
node: E,
|
node: E,
|
||||||
property: &PropertyId,
|
|
||||||
value: &str,
|
value: &str,
|
||||||
url_data: ServoUrl,
|
url_data: ServoUrl,
|
||||||
shared_lock: &SharedRwLock,
|
shared_lock: &SharedRwLock,
|
||||||
|
@ -673,14 +531,13 @@ where
|
||||||
{
|
{
|
||||||
fn create_font_declaration(
|
fn create_font_declaration(
|
||||||
value: &str,
|
value: &str,
|
||||||
property: &PropertyId,
|
|
||||||
url_data: &ServoUrl,
|
url_data: &ServoUrl,
|
||||||
quirks_mode: QuirksMode,
|
quirks_mode: QuirksMode,
|
||||||
) -> Option<PropertyDeclarationBlock> {
|
) -> Option<PropertyDeclarationBlock> {
|
||||||
let mut declarations = SourcePropertyDeclaration::default();
|
let mut declarations = SourcePropertyDeclaration::default();
|
||||||
let result = parse_one_declaration_into(
|
let result = parse_one_declaration_into(
|
||||||
&mut declarations,
|
&mut declarations,
|
||||||
property.clone(),
|
PropertyId::Shorthand(ShorthandId::Font),
|
||||||
value,
|
value,
|
||||||
Origin::Author,
|
Origin::Author,
|
||||||
&UrlExtraData(url_data.get_arc()),
|
&UrlExtraData(url_data.get_arc()),
|
||||||
|
@ -724,8 +581,8 @@ where
|
||||||
|
|
||||||
// https://html.spec.whatwg.org/multipage/#dom-context-2d-font
|
// https://html.spec.whatwg.org/multipage/#dom-context-2d-font
|
||||||
// 1. Parse the given font property value
|
// 1. Parse the given font property value
|
||||||
let quirks_mode = context.style_context.quirks_mode();
|
let quirks_mode = context.quirks_mode();
|
||||||
let declarations = create_font_declaration(value, property, &url_data, quirks_mode)?;
|
let declarations = create_font_declaration(value, &url_data, quirks_mode)?;
|
||||||
|
|
||||||
// TODO: Reject 'inherit' and 'initial' values for the font property.
|
// TODO: Reject 'inherit' and 'initial' values for the font property.
|
||||||
|
|
||||||
|
@ -737,7 +594,7 @@ where
|
||||||
} else {
|
} else {
|
||||||
let mut tlc = ThreadLocalStyleContext::new();
|
let mut tlc = ThreadLocalStyleContext::new();
|
||||||
let mut context = StyleContext {
|
let mut context = StyleContext {
|
||||||
shared: &context.style_context,
|
shared: context,
|
||||||
thread_local: &mut tlc,
|
thread_local: &mut tlc,
|
||||||
};
|
};
|
||||||
let styles = resolve_style(&mut context, element, RuleInclusion::All, None, None);
|
let styles = resolve_style(&mut context, element, RuleInclusion::All, None, None);
|
||||||
|
@ -745,22 +602,13 @@ where
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
let default_declarations =
|
let default_declarations =
|
||||||
create_font_declaration("10px sans-serif", property, &url_data, quirks_mode).unwrap();
|
create_font_declaration("10px sans-serif", &url_data, quirks_mode).unwrap();
|
||||||
resolve_for_declarations::<E>(
|
resolve_for_declarations::<E>(context, None, default_declarations, shared_lock)
|
||||||
&context.style_context,
|
|
||||||
None,
|
|
||||||
default_declarations,
|
|
||||||
shared_lock,
|
|
||||||
)
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// 3. Resolve the parsed value with resolved styles of the parent element
|
// 3. Resolve the parsed value with resolved styles of the parent element
|
||||||
let computed_values = resolve_for_declarations::<E>(
|
let computed_values =
|
||||||
&context.style_context,
|
resolve_for_declarations::<E>(context, Some(&*parent_style), declarations, shared_lock);
|
||||||
Some(&*parent_style),
|
|
||||||
declarations,
|
|
||||||
shared_lock,
|
|
||||||
);
|
|
||||||
|
|
||||||
Some(computed_values.clone_font())
|
Some(computed_values.clone_font())
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,11 +14,11 @@ use std::collections::HashMap;
|
||||||
use std::ops::{Deref, DerefMut};
|
use std::ops::{Deref, DerefMut};
|
||||||
use std::process;
|
use std::process;
|
||||||
use std::sync::atomic::{AtomicUsize, Ordering};
|
use std::sync::atomic::{AtomicUsize, Ordering};
|
||||||
use std::sync::{Arc, Mutex, MutexGuard};
|
use std::sync::{Arc, Mutex};
|
||||||
|
|
||||||
use app_units::Au;
|
use app_units::Au;
|
||||||
use embedder_traits::resources::{self, Resource};
|
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 euclid::{Point2D, Rect, Scale, Size2D};
|
||||||
use fnv::FnvHashMap;
|
use fnv::FnvHashMap;
|
||||||
use fxhash::{FxHashMap, FxHashSet};
|
use fxhash::{FxHashMap, FxHashSet};
|
||||||
|
@ -32,7 +32,7 @@ use layout::construct::ConstructionResult;
|
||||||
use layout::context::{
|
use layout::context::{
|
||||||
malloc_size_of_persistent_local_context, LayoutContext, RegisteredPainter, RegisteredPainters,
|
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::display_list::{IndexableText, ToLayout};
|
||||||
use layout::flow::{Flow, FlowFlags, GetBaseFlow, ImmutableFlowUtils, MutableOwnedFlowUtils};
|
use layout::flow::{Flow, FlowFlags, GetBaseFlow, ImmutableFlowUtils, MutableOwnedFlowUtils};
|
||||||
use layout::flow_ref::FlowRef;
|
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_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_element_inner_text_query, process_node_scroll_id_request, process_offset_parent_query,
|
||||||
process_resolved_font_style_request, process_resolved_style_request,
|
process_resolved_font_style_request, process_resolved_style_request,
|
||||||
process_scrolling_area_request, LayoutRPCImpl, LayoutThreadData,
|
process_scrolling_area_request,
|
||||||
};
|
};
|
||||||
use layout::traversal::{
|
use layout::traversal::{
|
||||||
construct_flows_at_ancestors, ComputeStackingRelativePositions, PreorderFlowTraversal,
|
construct_flows_at_ancestors, ComputeStackingRelativePositions, PreorderFlowTraversal,
|
||||||
|
@ -63,11 +63,12 @@ use profile_traits::time::{
|
||||||
};
|
};
|
||||||
use script::layout_dom::{ServoLayoutDocument, ServoLayoutElement, ServoLayoutNode};
|
use script::layout_dom::{ServoLayoutDocument, ServoLayoutElement, ServoLayoutNode};
|
||||||
use script_layout_interface::message::{
|
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::wrapper_traits::LayoutNode;
|
||||||
use script_layout_interface::{Layout, LayoutConfig, LayoutFactory};
|
use script_layout_interface::{
|
||||||
|
Layout, LayoutConfig, LayoutFactory, OffsetParentResponse, TrustedNodeAddress,
|
||||||
|
};
|
||||||
use script_traits::{
|
use script_traits::{
|
||||||
ConstellationControlMsg, DrawAPaintImageResult, IFrameSizeMsg, LayoutControlMsg,
|
ConstellationControlMsg, DrawAPaintImageResult, IFrameSizeMsg, LayoutControlMsg,
|
||||||
LayoutMsg as ConstellationMsg, PaintWorkletError, Painter, ScrollState, UntrustedNodeAddress,
|
LayoutMsg as ConstellationMsg, PaintWorkletError, Painter, ScrollState, UntrustedNodeAddress,
|
||||||
|
@ -81,13 +82,14 @@ use style::animation::{AnimationSetKey, DocumentAnimationSet, ElementAnimationSe
|
||||||
use style::context::{
|
use style::context::{
|
||||||
QuirksMode, RegisteredSpeculativePainter, RegisteredSpeculativePainters, SharedStyleContext,
|
QuirksMode, RegisteredSpeculativePainter, RegisteredSpeculativePainters, SharedStyleContext,
|
||||||
};
|
};
|
||||||
use style::dom::{ShowSubtree, ShowSubtreeDataAndPrimaryValues, TElement, TNode};
|
use style::dom::{OpaqueNode, ShowSubtree, ShowSubtreeDataAndPrimaryValues, TElement, TNode};
|
||||||
use style::driver;
|
use style::driver;
|
||||||
use style::error_reporting::RustLogReporter;
|
use style::error_reporting::RustLogReporter;
|
||||||
use style::global_style_data::{GLOBAL_STYLE_DATA, STYLE_THREAD_POOL};
|
use style::global_style_data::{GLOBAL_STYLE_DATA, STYLE_THREAD_POOL};
|
||||||
use style::invalidation::element::restyle_hints::RestyleHint;
|
use style::invalidation::element::restyle_hints::RestyleHint;
|
||||||
use style::logical_geometry::LogicalPoint;
|
use style::logical_geometry::LogicalPoint;
|
||||||
use style::media_queries::{Device, MediaList, MediaType};
|
use style::media_queries::{Device, MediaList, MediaType};
|
||||||
|
use style::properties::style_structs::Font;
|
||||||
use style::properties::PropertyId;
|
use style::properties::PropertyId;
|
||||||
use style::selector_parser::{PseudoElement, SnapshotMap};
|
use style::selector_parser::{PseudoElement, SnapshotMap};
|
||||||
use style::servo::restyle_damage::ServoRestyleDamage;
|
use style::servo::restyle_damage::ServoRestyleDamage;
|
||||||
|
@ -158,11 +160,14 @@ pub struct LayoutThread {
|
||||||
/// constraints.
|
/// constraints.
|
||||||
viewport_size: UntypedSize2D<Au>,
|
viewport_size: UntypedSize2D<Au>,
|
||||||
|
|
||||||
/// A mutex to allow for fast, read-only RPC of layout's internal data
|
/// The root stacking context.
|
||||||
/// structures, while still letting the LayoutThread modify them.
|
display_list: RefCell<Option<DisplayList>>,
|
||||||
///
|
|
||||||
/// All the other elements of this struct are read-only.
|
/// A map that stores all of the indexable text in this layout.
|
||||||
rw_data: Arc<Mutex<LayoutThreadData>>,
|
indexable_text: RefCell<IndexableText>,
|
||||||
|
|
||||||
|
/// Scroll offsets of scrolling regions.
|
||||||
|
scroll_offsets: RefCell<ScrollOffsetMap>,
|
||||||
|
|
||||||
webrender_image_cache: Arc<RwLock<FnvHashMap<(ServoUrl, UsePlaceholder), WebRenderImageInfo>>>,
|
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 {
|
impl Layout for LayoutThread {
|
||||||
fn process(&mut self, msg: script_layout_interface::message::Msg) {
|
fn process(&mut self, msg: script_layout_interface::message::Msg) {
|
||||||
self.handle_request(Request::FromScript(msg));
|
self.handle_request(Request::FromScript(msg));
|
||||||
|
@ -308,10 +263,6 @@ impl Layout for LayoutThread {
|
||||||
self.handle_request(Request::FromFontCache);
|
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 {
|
fn waiting_for_web_fonts_to_load(&self) -> bool {
|
||||||
self.outstanding_web_fonts.load(Ordering::SeqCst) != 0
|
self.outstanding_web_fonts.load(Ordering::SeqCst) != 0
|
||||||
}
|
}
|
||||||
|
@ -350,6 +301,178 @@ impl Layout for LayoutThread {
|
||||||
self.stylist
|
self.stylist
|
||||||
.remove_stylesheet(DocumentStyleSheet(stylesheet.clone()), &guard);
|
.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 {
|
enum Request {
|
||||||
FromPipeline(LayoutControlMsg),
|
FromPipeline(LayoutControlMsg),
|
||||||
|
@ -358,6 +481,10 @@ enum Request {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl LayoutThread {
|
impl LayoutThread {
|
||||||
|
fn root_flow_for_query(&self) -> Option<FlowRef> {
|
||||||
|
self.root_flow.borrow().clone()
|
||||||
|
}
|
||||||
|
|
||||||
fn new(
|
fn new(
|
||||||
id: PipelineId,
|
id: PipelineId,
|
||||||
url: ServoUrl,
|
url: ServoUrl,
|
||||||
|
@ -397,7 +524,7 @@ impl LayoutThread {
|
||||||
url,
|
url,
|
||||||
is_iframe,
|
is_iframe,
|
||||||
script_chan,
|
script_chan,
|
||||||
constellation_chan: constellation_chan.clone(),
|
constellation_chan,
|
||||||
time_profiler_chan,
|
time_profiler_chan,
|
||||||
registered_painters: RegisteredPaintersImpl(Default::default()),
|
registered_painters: RegisteredPaintersImpl(Default::default()),
|
||||||
image_cache,
|
image_cache,
|
||||||
|
@ -416,24 +543,9 @@ impl LayoutThread {
|
||||||
),
|
),
|
||||||
webrender_api,
|
webrender_api,
|
||||||
stylist: Stylist::new(device, QuirksMode::NoQuirks),
|
stylist: Stylist::new(device, QuirksMode::NoQuirks),
|
||||||
rw_data: Arc::new(Mutex::new(LayoutThreadData {
|
display_list: Default::default(),
|
||||||
constellation_chan,
|
indexable_text: Default::default(),
|
||||||
display_list: None,
|
scroll_offsets: Default::default(),
|
||||||
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,
|
|
||||||
})),
|
|
||||||
webrender_image_cache: Arc::new(RwLock::new(FnvHashMap::default())),
|
webrender_image_cache: Arc::new(RwLock::new(FnvHashMap::default())),
|
||||||
paint_time_metrics,
|
paint_time_metrics,
|
||||||
layout_query_waiting_time: Histogram::new(),
|
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.
|
// Create a layout context for use in building display lists, hit testing, &c.
|
||||||
fn build_layout_context<'a>(
|
fn build_layout_context<'a>(
|
||||||
&'a self,
|
&'a self,
|
||||||
|
@ -461,17 +594,13 @@ impl LayoutThread {
|
||||||
LayoutContext {
|
LayoutContext {
|
||||||
id: self.id,
|
id: self.id,
|
||||||
origin,
|
origin,
|
||||||
style_context: SharedStyleContext {
|
style_context: self.build_shared_style_context(
|
||||||
stylist: &self.stylist,
|
|
||||||
options: GLOBAL_STYLE_DATA.options.clone(),
|
|
||||||
guards,
|
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,
|
snapshot_map,
|
||||||
},
|
animation_timeline_value,
|
||||||
|
animations,
|
||||||
|
traversal_flags,
|
||||||
|
),
|
||||||
image_cache: self.image_cache.clone(),
|
image_cache: self.image_cache.clone(),
|
||||||
font_cache_thread: Mutex::new(self.font_cache_thread.clone()),
|
font_cache_thread: Mutex::new(self.font_cache_thread.clone()),
|
||||||
webrender_image_cache: self.webrender_image_cache.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
|
/// Receives and dispatches messages from the script and constellation threads
|
||||||
fn handle_request<'a, 'b>(&mut self, request: Request) {
|
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 {
|
match request {
|
||||||
Request::FromPipeline(LayoutControlMsg::SetScrollStates(new_scroll_states)) => {
|
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) => {
|
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)) => {
|
Request::FromPipeline(LayoutControlMsg::PaintMetric(epoch, paint_time)) => {
|
||||||
self.paint_time_metrics.maybe_set_metric(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 => {
|
Request::FromFontCache => {
|
||||||
let _rw_data = rw_data.lock();
|
|
||||||
self.outstanding_web_fonts.fetch_sub(1, Ordering::SeqCst);
|
self.outstanding_web_fonts.fetch_sub(1, Ordering::SeqCst);
|
||||||
self.handle_web_font_loaded();
|
self.handle_web_font_loaded();
|
||||||
},
|
},
|
||||||
|
@ -509,32 +630,23 @@ impl LayoutThread {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Receives and dispatches messages from other threads.
|
/// Receives and dispatches messages from other threads.
|
||||||
fn handle_request_helper(
|
fn handle_request_helper(&mut self, request: Msg) {
|
||||||
&mut self,
|
|
||||||
request: Msg,
|
|
||||||
possibly_locked_rw_data: &mut RwData<'_, '_>,
|
|
||||||
) {
|
|
||||||
match request {
|
match request {
|
||||||
Msg::SetQuirksMode(mode) => self.handle_set_quirks_mode(mode),
|
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) => {
|
Msg::Reflow(data) => {
|
||||||
let mut data = ScriptReflowResult::new(data);
|
let mut data = ScriptReflowResult::new(data);
|
||||||
profile(
|
profile(
|
||||||
profile_time::ProfilerCategory::LayoutPerform,
|
profile_time::ProfilerCategory::LayoutPerform,
|
||||||
self.profiler_metadata(),
|
self.profiler_metadata(),
|
||||||
self.time_profiler_chan.clone(),
|
self.time_profiler_chan.clone(),
|
||||||
|| self.handle_reflow(&mut data, possibly_locked_rw_data),
|
|| self.handle_reflow(&mut data),
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
Msg::SetScrollStates(new_scroll_states) => {
|
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) => {
|
Msg::CollectReports(reports_chan) => {
|
||||||
self.collect_reports(reports_chan, possibly_locked_rw_data);
|
self.collect_reports(reports_chan);
|
||||||
},
|
},
|
||||||
Msg::RegisterPaint(name, mut properties, painter) => {
|
Msg::RegisterPaint(name, mut properties, painter) => {
|
||||||
debug!("Registering the painter");
|
debug!("Registering the painter");
|
||||||
|
@ -561,24 +673,20 @@ impl LayoutThread {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn collect_reports(
|
fn collect_reports(&self, reports_chan: ReportsChan) {
|
||||||
&self,
|
|
||||||
reports_chan: ReportsChan,
|
|
||||||
possibly_locked_rw_data: &mut RwData<'_, '_>,
|
|
||||||
) {
|
|
||||||
let mut reports = vec![];
|
let mut reports = vec![];
|
||||||
// Servo uses vanilla jemalloc, which doesn't have a
|
// Servo uses vanilla jemalloc, which doesn't have a
|
||||||
// malloc_enclosing_size_of function.
|
// malloc_enclosing_size_of function.
|
||||||
let mut ops = MallocSizeOfOps::new(servo_allocator::usable_size, None, None);
|
let mut ops = MallocSizeOfOps::new(servo_allocator::usable_size, None, None);
|
||||||
|
|
||||||
// FIXME(njn): Just measuring the display tree for now.
|
// FIXME(njn): Just measuring the display tree for now.
|
||||||
let rw_data = possibly_locked_rw_data.lock();
|
let display_list = self.display_list.borrow();
|
||||||
let display_list = rw_data.display_list.as_ref();
|
let display_list_ref = display_list.as_ref();
|
||||||
let formatted_url = &format!("url({})", self.url);
|
let formatted_url = &format!("url({})", self.url);
|
||||||
reports.push(Report {
|
reports.push(Report {
|
||||||
path: path![formatted_url, "layout-thread", "display-list"],
|
path: path![formatted_url, "layout-thread", "display-list"],
|
||||||
kind: ReportKind::ExplicitJemallocHeapSize,
|
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 {
|
reports.push(Report {
|
||||||
|
@ -768,7 +876,6 @@ impl LayoutThread {
|
||||||
document: Option<&ServoLayoutDocument<LayoutData>>,
|
document: Option<&ServoLayoutDocument<LayoutData>>,
|
||||||
layout_root: &mut dyn Flow,
|
layout_root: &mut dyn Flow,
|
||||||
layout_context: &mut LayoutContext,
|
layout_context: &mut LayoutContext,
|
||||||
rw_data: &mut LayoutThreadData,
|
|
||||||
) {
|
) {
|
||||||
let writing_mode = layout_root.base().writing_mode;
|
let writing_mode = layout_root.base().writing_mode;
|
||||||
let (metadata, sender) = (self.profiler_metadata(), self.time_profiler_chan.clone());
|
let (metadata, sender) = (self.profiler_metadata(), self.time_profiler_chan.clone());
|
||||||
|
@ -791,7 +898,7 @@ impl LayoutThread {
|
||||||
.base()
|
.base()
|
||||||
.restyle_damage
|
.restyle_damage
|
||||||
.contains(ServoRestyleDamage::REPAINT) ||
|
.contains(ServoRestyleDamage::REPAINT) ||
|
||||||
rw_data.display_list.is_none()
|
self.display_list.borrow().is_none()
|
||||||
{
|
{
|
||||||
if reflow_goal.needs_display_list() {
|
if reflow_goal.needs_display_list() {
|
||||||
let background_color = get_root_flow_background_color(layout_root);
|
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);
|
let iframe_sizes = std::mem::take(&mut build_state.iframe_sizes);
|
||||||
self.update_iframe_sizes(iframe_sizes);
|
self.update_iframe_sizes(iframe_sizes);
|
||||||
|
|
||||||
rw_data.indexable_text = std::mem::take(&mut build_state.indexable_text);
|
*self.indexable_text.borrow_mut() =
|
||||||
rw_data.display_list = Some(build_state.to_display_list());
|
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();
|
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 {
|
if self.debug.dump_display_list {
|
||||||
display_list.print();
|
display_list.print();
|
||||||
}
|
}
|
||||||
|
@ -873,11 +981,7 @@ impl LayoutThread {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The high-level routine that performs layout.
|
/// The high-level routine that performs layout.
|
||||||
fn handle_reflow(
|
fn handle_reflow(&mut self, data: &mut ScriptReflowResult) {
|
||||||
&mut self,
|
|
||||||
data: &mut ScriptReflowResult,
|
|
||||||
possibly_locked_rw_data: &mut RwData<'_, '_>,
|
|
||||||
) {
|
|
||||||
let document = unsafe { ServoLayoutNode::new(&data.document) };
|
let document = unsafe { ServoLayoutNode::new(&data.document) };
|
||||||
let document = document.as_document().unwrap();
|
let document = document.as_document().unwrap();
|
||||||
|
|
||||||
|
@ -888,8 +992,6 @@ impl LayoutThread {
|
||||||
debug!("Number of objects in DOM: {}", data.dom_count);
|
debug!("Number of objects in DOM: {}", data.dom_count);
|
||||||
debug!("layout: parallel? {}", self.parallel_flag);
|
debug!("layout: parallel? {}", self.parallel_flag);
|
||||||
|
|
||||||
let mut rw_data = possibly_locked_rw_data.lock();
|
|
||||||
|
|
||||||
// Record the time that layout query has been waited.
|
// Record the time that layout query has been waited.
|
||||||
let now = time::precise_time_ns();
|
let now = time::precise_time_ns();
|
||||||
if let ReflowGoal::LayoutQuery(_, timestamp) = data.reflow_goal {
|
if let ReflowGoal::LayoutQuery(_, timestamp) = data.reflow_goal {
|
||||||
|
@ -898,57 +1000,9 @@ impl LayoutThread {
|
||||||
.expect("layout: wrong layout query timestamp");
|
.expect("layout: wrong layout query timestamp");
|
||||||
};
|
};
|
||||||
|
|
||||||
let root_element = match document.root_element() {
|
let Some(root_element) = document.root_element() else {
|
||||||
None => {
|
debug!("layout: No root node: bailing");
|
||||||
// Since we cannot compute anything, give spec-required placeholders.
|
return;
|
||||||
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,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
debug!(
|
debug!(
|
||||||
|
@ -1156,129 +1210,24 @@ impl LayoutThread {
|
||||||
&data.reflow_info,
|
&data.reflow_info,
|
||||||
&data.reflow_goal,
|
&data.reflow_goal,
|
||||||
Some(&document),
|
Some(&document),
|
||||||
&mut rw_data,
|
|
||||||
&mut layout_context,
|
&mut layout_context,
|
||||||
thread_pool,
|
thread_pool,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
self.first_reflow.set(false);
|
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(
|
data.result.borrow_mut().as_mut().unwrap().pending_images =
|
||||||
&self,
|
std::mem::take(&mut *layout_context.pending_images.lock().unwrap());
|
||||||
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());
|
|
||||||
|
|
||||||
let mut root_flow = match self.root_flow.borrow().clone() {
|
if let ReflowGoal::UpdateScrollNode(scroll_state) = data.reflow_goal {
|
||||||
Some(root_flow) => root_flow,
|
self.update_scroll_node_state(&scroll_state);
|
||||||
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 => {},
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn update_scroll_node_state(&self, state: &ScrollState, rw_data: &mut LayoutThreadData) {
|
fn update_scroll_node_state(&self, state: &ScrollState) {
|
||||||
rw_data
|
self.scroll_offsets
|
||||||
.scroll_offsets
|
.borrow_mut()
|
||||||
.insert(state.scroll_id, state.scroll_offset);
|
.insert(state.scroll_id, state.scroll_offset);
|
||||||
|
|
||||||
let point = Point2D::new(-state.scroll_offset.x, -state.scroll_offset.y);
|
let point = Point2D::new(-state.scroll_offset.x, -state.scroll_offset.y);
|
||||||
|
@ -1289,12 +1238,7 @@ impl LayoutThread {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn set_scroll_states(
|
fn set_scroll_states(&mut self, new_scroll_states: Vec<ScrollState>) {
|
||||||
&mut self,
|
|
||||||
new_scroll_states: Vec<ScrollState>,
|
|
||||||
possibly_locked_rw_data: &mut RwData<'_, '_>,
|
|
||||||
) {
|
|
||||||
let mut rw_data = possibly_locked_rw_data.lock();
|
|
||||||
let mut script_scroll_states = vec![];
|
let mut script_scroll_states = vec![];
|
||||||
let mut layout_scroll_states = HashMap::new();
|
let mut layout_scroll_states = HashMap::new();
|
||||||
for new_state in &new_scroll_states {
|
for new_state in &new_scroll_states {
|
||||||
|
@ -1313,7 +1257,7 @@ impl LayoutThread {
|
||||||
self.id,
|
self.id,
|
||||||
script_scroll_states,
|
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.
|
/// Cancel animations for any nodes which have been removed from flow tree.
|
||||||
|
@ -1363,7 +1307,6 @@ impl LayoutThread {
|
||||||
data: &Reflow,
|
data: &Reflow,
|
||||||
reflow_goal: &ReflowGoal,
|
reflow_goal: &ReflowGoal,
|
||||||
document: Option<&ServoLayoutDocument<LayoutData>>,
|
document: Option<&ServoLayoutDocument<LayoutData>>,
|
||||||
rw_data: &mut LayoutThreadData,
|
|
||||||
context: &mut LayoutContext,
|
context: &mut LayoutContext,
|
||||||
thread_pool: Option<&rayon::ThreadPool>,
|
thread_pool: Option<&rayon::ThreadPool>,
|
||||||
) {
|
) {
|
||||||
|
@ -1449,14 +1392,7 @@ impl LayoutThread {
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
self.perform_post_main_layout_passes(
|
self.perform_post_main_layout_passes(data, root_flow, reflow_goal, document, context);
|
||||||
data,
|
|
||||||
root_flow,
|
|
||||||
reflow_goal,
|
|
||||||
document,
|
|
||||||
rw_data,
|
|
||||||
context,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn perform_post_main_layout_passes(
|
fn perform_post_main_layout_passes(
|
||||||
|
@ -1465,7 +1401,6 @@ impl LayoutThread {
|
||||||
mut root_flow: &mut FlowRef,
|
mut root_flow: &mut FlowRef,
|
||||||
reflow_goal: &ReflowGoal,
|
reflow_goal: &ReflowGoal,
|
||||||
document: Option<&ServoLayoutDocument<LayoutData>>,
|
document: Option<&ServoLayoutDocument<LayoutData>>,
|
||||||
rw_data: &mut LayoutThreadData,
|
|
||||||
layout_context: &mut LayoutContext,
|
layout_context: &mut LayoutContext,
|
||||||
) {
|
) {
|
||||||
// Build the display list if necessary, and send it to the painter.
|
// Build the display list if necessary, and send it to the painter.
|
||||||
|
@ -1475,7 +1410,6 @@ impl LayoutThread {
|
||||||
document,
|
document,
|
||||||
FlowRef::deref_mut(&mut root_flow),
|
FlowRef::deref_mut(&mut root_flow),
|
||||||
&mut *layout_context,
|
&mut *layout_context,
|
||||||
rw_data,
|
|
||||||
);
|
);
|
||||||
|
|
||||||
if self.debug.trace_layout {
|
if self.debug.trace_layout {
|
||||||
|
|
|
@ -13,12 +13,12 @@ use std::collections::HashMap;
|
||||||
use std::ops::{Deref, DerefMut};
|
use std::ops::{Deref, DerefMut};
|
||||||
use std::process;
|
use std::process;
|
||||||
use std::sync::atomic::{AtomicUsize, Ordering};
|
use std::sync::atomic::{AtomicUsize, Ordering};
|
||||||
use std::sync::{Arc, Mutex, MutexGuard};
|
use std::sync::{Arc, Mutex};
|
||||||
|
|
||||||
use app_units::Au;
|
use app_units::Au;
|
||||||
use embedder_traits::resources::{self, Resource};
|
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 euclid::{Point2D, Scale, Size2D, Vector2D};
|
||||||
use fnv::FnvHashMap;
|
use fnv::FnvHashMap;
|
||||||
use fxhash::FxHashMap;
|
use fxhash::FxHashMap;
|
||||||
use gfx::font_cache_thread::FontCacheThread;
|
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_content_box_request, process_content_boxes_request, process_element_inner_text_query,
|
||||||
process_node_geometry_request, process_node_scroll_area_request,
|
process_node_geometry_request, process_node_scroll_area_request,
|
||||||
process_node_scroll_id_request, process_offset_parent_query, process_resolved_font_style_query,
|
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::traversal::RecalcStyle;
|
||||||
use layout::{layout_debug, BoxTree, FragmentTree};
|
use layout::{layout_debug, BoxTree, FragmentTree};
|
||||||
|
@ -51,10 +51,11 @@ use profile_traits::time::{
|
||||||
};
|
};
|
||||||
use script::layout_dom::{ServoLayoutDocument, ServoLayoutElement, ServoLayoutNode};
|
use script::layout_dom::{ServoLayoutDocument, ServoLayoutElement, ServoLayoutNode};
|
||||||
use script_layout_interface::message::{
|
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::{
|
use script_traits::{
|
||||||
ConstellationControlMsg, DrawAPaintImageResult, IFrameSizeMsg, LayoutControlMsg,
|
ConstellationControlMsg, DrawAPaintImageResult, IFrameSizeMsg, LayoutControlMsg,
|
||||||
LayoutMsg as ConstellationMsg, PaintWorkletError, Painter, ScrollState, UntrustedNodeAddress,
|
LayoutMsg as ConstellationMsg, PaintWorkletError, Painter, ScrollState, UntrustedNodeAddress,
|
||||||
|
@ -68,14 +69,15 @@ use style::animation::DocumentAnimationSet;
|
||||||
use style::context::{
|
use style::context::{
|
||||||
QuirksMode, RegisteredSpeculativePainter, RegisteredSpeculativePainters, SharedStyleContext,
|
QuirksMode, RegisteredSpeculativePainter, RegisteredSpeculativePainters, SharedStyleContext,
|
||||||
};
|
};
|
||||||
use style::dom::{TElement, TNode};
|
use style::dom::{OpaqueNode, TElement, TNode};
|
||||||
use style::driver;
|
use style::driver;
|
||||||
use style::error_reporting::RustLogReporter;
|
use style::error_reporting::RustLogReporter;
|
||||||
use style::global_style_data::{GLOBAL_STYLE_DATA, STYLE_THREAD_POOL};
|
use style::global_style_data::{GLOBAL_STYLE_DATA, STYLE_THREAD_POOL};
|
||||||
use style::invalidation::element::restyle_hints::RestyleHint;
|
use style::invalidation::element::restyle_hints::RestyleHint;
|
||||||
use style::media_queries::{Device, MediaList, MediaType};
|
use style::media_queries::{Device, MediaList, MediaType};
|
||||||
|
use style::properties::style_structs::Font;
|
||||||
use style::properties::PropertyId;
|
use style::properties::PropertyId;
|
||||||
use style::selector_parser::SnapshotMap;
|
use style::selector_parser::{PseudoElement, SnapshotMap};
|
||||||
use style::shared_lock::{SharedRwLock, SharedRwLockReadGuard, StylesheetGuards};
|
use style::shared_lock::{SharedRwLock, SharedRwLockReadGuard, StylesheetGuards};
|
||||||
use style::stylesheets::{
|
use style::stylesheets::{
|
||||||
DocumentStyleSheet, Origin, Stylesheet, StylesheetInDocument, UrlExtraData,
|
DocumentStyleSheet, Origin, Stylesheet, StylesheetInDocument, UrlExtraData,
|
||||||
|
@ -86,7 +88,8 @@ use style::traversal::DomTraversal;
|
||||||
use style::traversal_flags::TraversalFlags;
|
use style::traversal_flags::TraversalFlags;
|
||||||
use style_traits::{CSSPixel, DevicePixel, SpeculativePainter};
|
use style_traits::{CSSPixel, DevicePixel, SpeculativePainter};
|
||||||
use url::Url;
|
use url::Url;
|
||||||
use webrender_api::{units, HitTestFlags};
|
use webrender_api::units::LayoutPixel;
|
||||||
|
use webrender_api::{units, ExternalScrollId, HitTestFlags};
|
||||||
|
|
||||||
/// Information needed by layout.
|
/// Information needed by layout.
|
||||||
pub struct LayoutThread {
|
pub struct LayoutThread {
|
||||||
|
@ -143,11 +146,8 @@ pub struct LayoutThread {
|
||||||
/// constraints.
|
/// constraints.
|
||||||
viewport_size: UntypedSize2D<Au>,
|
viewport_size: UntypedSize2D<Au>,
|
||||||
|
|
||||||
/// A mutex to allow for fast, read-only RPC of layout's internal data
|
/// Scroll offsets of nodes that scroll.
|
||||||
/// structures, while still letting the LayoutThread modify them.
|
scroll_offsets: RefCell<HashMap<ExternalScrollId, Vector2D<f32, LayoutPixel>>>,
|
||||||
///
|
|
||||||
/// All the other elements of this struct are read-only.
|
|
||||||
rw_data: Arc<Mutex<LayoutThreadData>>,
|
|
||||||
|
|
||||||
webrender_image_cache: Arc<RwLock<FnvHashMap<(ServoUrl, UsePlaceholder), WebRenderImageInfo>>>,
|
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 {
|
impl Layout for LayoutThread {
|
||||||
fn process(&mut self, msg: script_layout_interface::message::Msg) {
|
fn process(&mut self, msg: script_layout_interface::message::Msg) {
|
||||||
self.handle_request(Request::FromScript(msg));
|
self.handle_request(Request::FromScript(msg));
|
||||||
|
@ -287,10 +237,6 @@ impl Layout for LayoutThread {
|
||||||
self.handle_request(Request::FromFontCache);
|
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 {
|
fn waiting_for_web_fonts_to_load(&self) -> bool {
|
||||||
self.outstanding_web_fonts.load(Ordering::SeqCst) != 0
|
self.outstanding_web_fonts.load(Ordering::SeqCst) != 0
|
||||||
}
|
}
|
||||||
|
@ -330,6 +276,152 @@ impl Layout for LayoutThread {
|
||||||
self.stylist
|
self.stylist
|
||||||
.remove_stylesheet(DocumentStyleSheet(stylesheet.clone()), &guard);
|
.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 {
|
enum Request {
|
||||||
|
@ -398,23 +490,8 @@ impl LayoutThread {
|
||||||
Au::from_f32_px(window_size.initial_viewport.height),
|
Au::from_f32_px(window_size.initial_viewport.height),
|
||||||
),
|
),
|
||||||
webrender_api: webrender_api_sender,
|
webrender_api: webrender_api_sender,
|
||||||
|
scroll_offsets: Default::default(),
|
||||||
stylist: Stylist::new(device, QuirksMode::NoQuirks),
|
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(),
|
webrender_image_cache: Default::default(),
|
||||||
paint_time_metrics,
|
paint_time_metrics,
|
||||||
last_iframe_sizes: Default::default(),
|
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.
|
// Create a layout context for use in building display lists, hit testing, &c.
|
||||||
fn build_layout_context<'a>(
|
fn build_layout_context<'a>(
|
||||||
&'a self,
|
&'a self,
|
||||||
|
@ -441,17 +539,13 @@ impl LayoutThread {
|
||||||
LayoutContext {
|
LayoutContext {
|
||||||
id: self.id,
|
id: self.id,
|
||||||
origin,
|
origin,
|
||||||
style_context: SharedStyleContext {
|
style_context: self.build_shared_style_context(
|
||||||
stylist: &self.stylist,
|
|
||||||
options: GLOBAL_STYLE_DATA.options.clone(),
|
|
||||||
guards,
|
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,
|
snapshot_map,
|
||||||
},
|
animation_timeline_value,
|
||||||
|
animations,
|
||||||
|
traversal_flags,
|
||||||
|
),
|
||||||
image_cache: self.image_cache.clone(),
|
image_cache: self.image_cache.clone(),
|
||||||
font_cache_thread: Mutex::new(self.font_cache_thread.clone()),
|
font_cache_thread: Mutex::new(self.font_cache_thread.clone()),
|
||||||
webrender_image_cache: self.webrender_image_cache.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
|
/// Receives and dispatches messages from the script and constellation threads
|
||||||
fn handle_request<'a, 'b>(&mut self, request: Request) {
|
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 {
|
match request {
|
||||||
Request::FromPipeline(LayoutControlMsg::SetScrollStates(new_scroll_states)) => {
|
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) => {
|
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)) => {
|
Request::FromPipeline(LayoutControlMsg::PaintMetric(epoch, paint_time)) => {
|
||||||
self.paint_time_metrics.maybe_set_metric(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 => {
|
Request::FromFontCache => {
|
||||||
let _rw_data = rw_data.lock();
|
|
||||||
self.outstanding_web_fonts.fetch_sub(1, Ordering::SeqCst);
|
self.outstanding_web_fonts.fetch_sub(1, Ordering::SeqCst);
|
||||||
self.handle_web_font_loaded();
|
self.handle_web_font_loaded();
|
||||||
},
|
},
|
||||||
|
@ -489,32 +575,23 @@ impl LayoutThread {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Receives and dispatches messages from other threads.
|
/// Receives and dispatches messages from other threads.
|
||||||
fn handle_request_helper(
|
fn handle_request_helper(&mut self, request: Msg) {
|
||||||
&mut self,
|
|
||||||
request: Msg,
|
|
||||||
possibly_locked_rw_data: &mut RwData<'_, '_>,
|
|
||||||
) {
|
|
||||||
match request {
|
match request {
|
||||||
Msg::SetQuirksMode(mode) => self.handle_set_quirks_mode(mode),
|
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) => {
|
Msg::Reflow(data) => {
|
||||||
let mut data = ScriptReflowResult::new(data);
|
let mut data = ScriptReflowResult::new(data);
|
||||||
profile(
|
profile(
|
||||||
profile_time::ProfilerCategory::LayoutPerform,
|
profile_time::ProfilerCategory::LayoutPerform,
|
||||||
self.profiler_metadata(),
|
self.profiler_metadata(),
|
||||||
self.time_profiler_chan.clone(),
|
self.time_profiler_chan.clone(),
|
||||||
|| self.handle_reflow(&mut data, possibly_locked_rw_data),
|
|| self.handle_reflow(&mut data),
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
Msg::SetScrollStates(new_scroll_states) => {
|
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) => {
|
Msg::CollectReports(reports_chan) => {
|
||||||
self.collect_reports(reports_chan, possibly_locked_rw_data);
|
self.collect_reports(reports_chan);
|
||||||
},
|
},
|
||||||
Msg::RegisterPaint(_name, _properties, _painter) => {},
|
Msg::RegisterPaint(_name, _properties, _painter) => {},
|
||||||
// Receiving the Exit message at this stage only happens when layout is undergoing a "force exit".
|
// 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(
|
fn collect_reports(&self, reports_chan: ReportsChan) {
|
||||||
&self,
|
|
||||||
reports_chan: ReportsChan,
|
|
||||||
possibly_locked_rw_data: &mut RwData<'_, '_>,
|
|
||||||
) {
|
|
||||||
let mut reports = vec![];
|
let mut reports = vec![];
|
||||||
// Servo uses vanilla jemalloc, which doesn't have a
|
// Servo uses vanilla jemalloc, which doesn't have a
|
||||||
// malloc_enclosing_size_of function.
|
// malloc_enclosing_size_of function.
|
||||||
let mut ops = MallocSizeOfOps::new(servo_allocator::usable_size, None, None);
|
let mut ops = MallocSizeOfOps::new(servo_allocator::usable_size, None, None);
|
||||||
|
|
||||||
// FIXME(njn): Just measuring the display tree for now.
|
// 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);
|
let formatted_url = &format!("url({})", self.url);
|
||||||
reports.push(Report {
|
reports.push(Report {
|
||||||
path: path![formatted_url, "layout-thread", "display-list"],
|
path: path![formatted_url, "layout-thread", "display-list"],
|
||||||
kind: ReportKind::ExplicitJemallocHeapSize,
|
kind: ReportKind::ExplicitJemallocHeapSize,
|
||||||
size: display_list.map_or(0, |sc| sc.size_of(&mut ops)),
|
size: 0,
|
||||||
});
|
});
|
||||||
|
|
||||||
reports.push(Report {
|
reports.push(Report {
|
||||||
|
@ -590,71 +661,12 @@ impl LayoutThread {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The high-level routine that performs layout.
|
/// The high-level routine that performs layout.
|
||||||
fn handle_reflow(
|
fn handle_reflow(&mut self, data: &mut ScriptReflowResult) {
|
||||||
&mut self,
|
|
||||||
data: &mut ScriptReflowResult,
|
|
||||||
possibly_locked_rw_data: &mut RwData<'_, '_>,
|
|
||||||
) {
|
|
||||||
let document = unsafe { ServoLayoutNode::<DOMLayoutData>::new(&data.document) };
|
let document = unsafe { ServoLayoutNode::<DOMLayoutData>::new(&data.document) };
|
||||||
let document = document.as_document().unwrap();
|
let document = document.as_document().unwrap();
|
||||||
|
let Some(root_element) = document.root_element() else {
|
||||||
let mut rw_data = possibly_locked_rw_data.lock();
|
debug!("layout: No root node: bailing");
|
||||||
|
return;
|
||||||
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,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// Calculate the actual viewport as per DEVICE-ADAPT § 6
|
// Calculate the actual viewport as per DEVICE-ADAPT § 6
|
||||||
|
@ -850,124 +862,18 @@ impl LayoutThread {
|
||||||
}
|
}
|
||||||
|
|
||||||
self.first_reflow.set(false);
|
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(
|
data.result.borrow_mut().as_mut().unwrap().pending_images =
|
||||||
&self,
|
std::mem::take(&mut *layout_context.pending_images.lock().unwrap());
|
||||||
reflow_goal: &ReflowGoal,
|
if let ReflowGoal::UpdateScrollNode(scroll_state) = data.reflow_goal {
|
||||||
rw_data: &mut LayoutThreadData,
|
self.update_scroll_node_state(&scroll_state);
|
||||||
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 => {},
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn update_scroll_node_state(&self, state: &ScrollState, rw_data: &mut LayoutThreadData) {
|
fn update_scroll_node_state(&self, state: &ScrollState) {
|
||||||
rw_data
|
self.scroll_offsets
|
||||||
.scroll_offsets
|
.borrow_mut()
|
||||||
.insert(state.scroll_id, state.scroll_offset);
|
.insert(state.scroll_id, state.scroll_offset);
|
||||||
|
|
||||||
let point = Point2D::new(-state.scroll_offset.x, -state.scroll_offset.y);
|
let point = Point2D::new(-state.scroll_offset.x, -state.scroll_offset.y);
|
||||||
self.webrender_api.send_scroll_node(
|
self.webrender_api.send_scroll_node(
|
||||||
self.id.to_webrender(),
|
self.id.to_webrender(),
|
||||||
|
@ -976,12 +882,7 @@ impl LayoutThread {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn set_scroll_states(
|
fn set_scroll_states(&mut self, new_scroll_states: Vec<ScrollState>) {
|
||||||
&mut self,
|
|
||||||
new_scroll_states: Vec<ScrollState>,
|
|
||||||
possibly_locked_rw_data: &mut RwData<'_, '_>,
|
|
||||||
) {
|
|
||||||
let mut rw_data = possibly_locked_rw_data.lock();
|
|
||||||
let mut script_scroll_states = vec![];
|
let mut script_scroll_states = vec![];
|
||||||
let mut layout_scroll_states = HashMap::new();
|
let mut layout_scroll_states = HashMap::new();
|
||||||
for new_state in &new_scroll_states {
|
for new_state in &new_scroll_states {
|
||||||
|
@ -1000,7 +901,7 @@ impl LayoutThread {
|
||||||
self.id,
|
self.id,
|
||||||
script_scroll_states,
|
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(
|
fn perform_post_style_recalc_layout_passes(
|
||||||
|
|
|
@ -84,16 +84,15 @@ impl DocumentOrShadowRoot {
|
||||||
pub fn nodes_from_point(
|
pub fn nodes_from_point(
|
||||||
&self,
|
&self,
|
||||||
client_point: &Point2D<f32>,
|
client_point: &Point2D<f32>,
|
||||||
reflow_goal: NodesFromPointQueryType,
|
query_type: NodesFromPointQueryType,
|
||||||
) -> Vec<UntrustedNodeAddress> {
|
) -> Vec<UntrustedNodeAddress> {
|
||||||
if !self
|
if !self.window.layout_reflow(QueryMsg::NodesFromPointQuery) {
|
||||||
.window
|
|
||||||
.layout_reflow(QueryMsg::NodesFromPointQuery(*client_point, reflow_goal))
|
|
||||||
{
|
|
||||||
return vec![];
|
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)]
|
#[allow(unsafe_code)]
|
||||||
|
|
|
@ -454,10 +454,11 @@ impl HTMLElementMethods for HTMLElement {
|
||||||
return node.GetTextContent().unwrap();
|
return node.GetTextContent().unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
window.layout_reflow(QueryMsg::ElementInnerTextQuery(
|
window.layout_reflow(QueryMsg::ElementInnerTextQuery);
|
||||||
node.to_trusted_node_address(),
|
let text = window
|
||||||
));
|
.with_layout(|layout| layout.query_element_inner_text(node.to_trusted_node_address()))
|
||||||
DOMString::from(window.layout_rpc().element_inner_text())
|
.unwrap_or_default();
|
||||||
|
DOMString::from(text)
|
||||||
}
|
}
|
||||||
|
|
||||||
// https://html.spec.whatwg.org/multipage/#the-innertext-idl-attribute
|
// https://html.spec.whatwg.org/multipage/#the-innertext-idl-attribute
|
||||||
|
|
|
@ -26,7 +26,6 @@ use net_traits::blob_url_store::get_blob_origin;
|
||||||
use net_traits::filemanager_thread::FileManagerThreadMsg;
|
use net_traits::filemanager_thread::FileManagerThreadMsg;
|
||||||
use net_traits::{CoreResourceMsg, IpcSend};
|
use net_traits::{CoreResourceMsg, IpcSend};
|
||||||
use profile_traits::ipc;
|
use profile_traits::ipc;
|
||||||
use script_layout_interface::rpc::TextIndexResponse;
|
|
||||||
use script_traits::ScriptToConstellationChan;
|
use script_traits::ScriptToConstellationChan;
|
||||||
use servo_atoms::Atom;
|
use servo_atoms::Atom;
|
||||||
use style::attr::AttrValue;
|
use style::attr::AttrValue;
|
||||||
|
@ -2537,8 +2536,7 @@ impl VirtualMethods for HTMLInputElement {
|
||||||
// now.
|
// now.
|
||||||
if let Some(point_in_target) = mouse_event.point_in_target() {
|
if let Some(point_in_target) = mouse_event.point_in_target() {
|
||||||
let window = window_from_node(self);
|
let window = window_from_node(self);
|
||||||
let TextIndexResponse(index) =
|
let index = window.text_index_query(self.upcast::<Node>(), point_in_target);
|
||||||
window.text_index_query(self.upcast::<Node>(), point_in_target);
|
|
||||||
if let Some(i) = index {
|
if let Some(i) = index {
|
||||||
self.textinput.borrow_mut().set_edit_point_index(i);
|
self.textinput.borrow_mut().set_edit_point_index(i);
|
||||||
// trigger redraw
|
// trigger redraw
|
||||||
|
|
|
@ -49,10 +49,6 @@ use profile_traits::ipc as ProfiledIpc;
|
||||||
use profile_traits::mem::ProfilerChan as MemProfilerChan;
|
use profile_traits::mem::ProfilerChan as MemProfilerChan;
|
||||||
use profile_traits::time::ProfilerChan as TimeProfilerChan;
|
use profile_traits::time::ProfilerChan as TimeProfilerChan;
|
||||||
use script_layout_interface::message::{Msg, QueryMsg, Reflow, ReflowGoal, ScriptReflow};
|
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_layout_interface::{Layout, PendingImageState, TrustedNodeAddress};
|
||||||
use script_traits::webdriver_msg::{WebDriverJSError, WebDriverJSResult};
|
use script_traits::webdriver_msg::{WebDriverJSError, WebDriverJSResult};
|
||||||
use script_traits::{
|
use script_traits::{
|
||||||
|
@ -70,7 +66,7 @@ use style::error_reporting::{ContextualParseError, ParseErrorReporter};
|
||||||
use style::media_queries;
|
use style::media_queries;
|
||||||
use style::parser::ParserContext as CssParserContext;
|
use style::parser::ParserContext as CssParserContext;
|
||||||
use style::properties::style_structs::Font;
|
use style::properties::style_structs::Font;
|
||||||
use style::properties::{PropertyId, ShorthandId};
|
use style::properties::PropertyId;
|
||||||
use style::selector_parser::PseudoElement;
|
use style::selector_parser::PseudoElement;
|
||||||
use style::str::HTML_SPACE_CHARACTERS;
|
use style::str::HTML_SPACE_CHARACTERS;
|
||||||
use style::stylesheets::{CssRuleType, Origin, UrlExtraData};
|
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>> {
|
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) {
|
||||||
if !self.layout_reflow(QueryMsg::ResolvedFontStyleQuery(
|
|
||||||
node.to_trusted_node_address(),
|
|
||||||
id,
|
|
||||||
value,
|
|
||||||
)) {
|
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
self.layout_rpc().resolved_font_style()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn layout_rpc(&self) -> Box<dyn LayoutRPC> {
|
let document = self.Document();
|
||||||
self.with_layout(|layout| layout.rpc()).unwrap()
|
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>> {
|
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;
|
return None;
|
||||||
}
|
}
|
||||||
let ContentBoxResponse(rect) = self.layout_rpc().content_box();
|
self.with_layout(|layout| layout.query_content_box(node.to_opaque()))
|
||||||
rect
|
.unwrap_or(None)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn content_boxes_query(&self, node: &Node) -> Vec<UntypedRect<Au>> {
|
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![];
|
return vec![];
|
||||||
}
|
}
|
||||||
let ContentBoxesResponse(rects) = self.layout_rpc().content_boxes();
|
self.with_layout(|layout| layout.query_content_boxes(node.to_opaque()))
|
||||||
rects
|
.unwrap_or_default()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn client_rect_query(&self, node: &Node) -> UntypedRect<i32> {
|
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();
|
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
|
/// 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.
|
/// is None, find the scroll area of the viewport.
|
||||||
pub fn scrolling_area_query(&self, node: Option<&Node>) -> UntypedRect<i32> {
|
pub fn scrolling_area_query(&self, node: Option<&Node>) -> UntypedRect<i32> {
|
||||||
let opaque = node.map(|node| node.to_opaque());
|
let opaque = node.map(|node| node.to_opaque());
|
||||||
if !self.layout_reflow(QueryMsg::ScrollingAreaQuery(opaque)) {
|
if !self.layout_reflow(QueryMsg::ScrollingAreaQuery) {
|
||||||
return Rect::zero();
|
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> {
|
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
|
// https://drafts.csswg.org/cssom-view/#element-scrolling-members
|
||||||
pub fn scroll_node(&self, node: &Node, x_: f64, y_: f64, behavior: ScrollBehavior) {
|
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;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2117,7 +2116,9 @@ impl Window {
|
||||||
.borrow_mut()
|
.borrow_mut()
|
||||||
.insert(node.to_opaque(), Vector2D::new(x_ as f32, y_ as f32));
|
.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
|
// Step 12
|
||||||
self.perform_a_scroll(
|
self.perform_a_scroll(
|
||||||
|
@ -2135,32 +2136,45 @@ impl Window {
|
||||||
pseudo: Option<PseudoElement>,
|
pseudo: Option<PseudoElement>,
|
||||||
property: PropertyId,
|
property: PropertyId,
|
||||||
) -> DOMString {
|
) -> DOMString {
|
||||||
if !self.layout_reflow(QueryMsg::ResolvedStyleQuery(element, pseudo, property)) {
|
if !self.layout_reflow(QueryMsg::ResolvedStyleQuery) {
|
||||||
return DOMString::new();
|
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(
|
pub fn inner_window_dimensions_query(
|
||||||
&self,
|
&self,
|
||||||
browsing_context: BrowsingContextId,
|
browsing_context: BrowsingContextId,
|
||||||
) -> Option<Size2D<f32, CSSPixel>> {
|
) -> Option<Size2D<f32, CSSPixel>> {
|
||||||
if !self.layout_reflow(QueryMsg::InnerWindowDimensionsQuery(browsing_context)) {
|
if !self.layout_reflow(QueryMsg::InnerWindowDimensionsQuery) {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
self.layout_rpc().inner_window_dimensions()
|
self.with_layout(|layout| layout.query_inner_window_dimension(browsing_context))
|
||||||
|
.unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(unsafe_code)]
|
#[allow(unsafe_code)]
|
||||||
pub fn offset_parent_query(&self, node: &Node) -> (Option<DomRoot<Element>>, UntypedRect<Au>) {
|
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());
|
return (None, Rect::zero());
|
||||||
}
|
}
|
||||||
|
|
||||||
// FIXME(nox): Layout can reply with a garbage value which doesn't
|
let response = self
|
||||||
// actually correspond to an element, that's unsound.
|
.with_layout(|layout| layout.query_offset_parent(node.to_opaque()))
|
||||||
let response = self.layout_rpc().offset_parent();
|
.unwrap();
|
||||||
let element = response.node_address.and_then(|parent_node_address| {
|
let element = response.node_address.and_then(|parent_node_address| {
|
||||||
let node = unsafe { from_untrusted_node_address(parent_node_address) };
|
let node = unsafe { from_untrusted_node_address(parent_node_address) };
|
||||||
DomRoot::downcast(node)
|
DomRoot::downcast(node)
|
||||||
|
@ -2172,11 +2186,12 @@ impl Window {
|
||||||
&self,
|
&self,
|
||||||
node: &Node,
|
node: &Node,
|
||||||
point_in_node: UntypedPoint2D<f32>,
|
point_in_node: UntypedPoint2D<f32>,
|
||||||
) -> TextIndexResponse {
|
) -> Option<usize> {
|
||||||
if !self.layout_reflow(QueryMsg::TextIndexQuery(node.to_opaque(), point_in_node)) {
|
if !self.layout_reflow(QueryMsg::TextIndexQuery) {
|
||||||
return TextIndexResponse(None);
|
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)]
|
#[allow(unsafe_code)]
|
||||||
|
@ -2705,19 +2720,19 @@ fn debug_reflow_events(id: PipelineId, reflow_goal: &ReflowGoal, reason: &Reflow
|
||||||
ReflowGoal::TickAnimations => "\tTickAnimations",
|
ReflowGoal::TickAnimations => "\tTickAnimations",
|
||||||
ReflowGoal::UpdateScrollNode(_) => "\tUpdateScrollNode",
|
ReflowGoal::UpdateScrollNode(_) => "\tUpdateScrollNode",
|
||||||
ReflowGoal::LayoutQuery(ref query_msg, _) => match *query_msg {
|
ReflowGoal::LayoutQuery(ref query_msg, _) => match *query_msg {
|
||||||
QueryMsg::ContentBoxQuery(_n) => "\tContentBoxQuery",
|
QueryMsg::ContentBox => "\tContentBoxQuery",
|
||||||
QueryMsg::ContentBoxesQuery(_n) => "\tContentBoxesQuery",
|
QueryMsg::ContentBoxes => "\tContentBoxesQuery",
|
||||||
QueryMsg::NodesFromPointQuery(..) => "\tNodesFromPointQuery",
|
QueryMsg::NodesFromPointQuery => "\tNodesFromPointQuery",
|
||||||
QueryMsg::ClientRectQuery(_n) => "\tClientRectQuery",
|
QueryMsg::ClientRectQuery => "\tClientRectQuery",
|
||||||
QueryMsg::ScrollingAreaQuery(_n) => "\tNodeScrollGeometryQuery",
|
QueryMsg::ScrollingAreaQuery => "\tNodeScrollGeometryQuery",
|
||||||
QueryMsg::NodeScrollIdQuery(_n) => "\tNodeScrollIdQuery",
|
QueryMsg::NodeScrollIdQuery => "\tNodeScrollIdQuery",
|
||||||
QueryMsg::ResolvedStyleQuery(_, _, _) => "\tResolvedStyleQuery",
|
QueryMsg::ResolvedStyleQuery => "\tResolvedStyleQuery",
|
||||||
QueryMsg::ResolvedFontStyleQuery(..) => "\nResolvedFontStyleQuery",
|
QueryMsg::ResolvedFontStyleQuery => "\nResolvedFontStyleQuery",
|
||||||
QueryMsg::OffsetParentQuery(_n) => "\tOffsetParentQuery",
|
QueryMsg::OffsetParentQuery => "\tOffsetParentQuery",
|
||||||
QueryMsg::StyleQuery => "\tStyleQuery",
|
QueryMsg::StyleQuery => "\tStyleQuery",
|
||||||
QueryMsg::TextIndexQuery(..) => "\tTextIndexQuery",
|
QueryMsg::TextIndexQuery => "\tTextIndexQuery",
|
||||||
QueryMsg::ElementInnerTextQuery(_) => "\tElementInnerTextQuery",
|
QueryMsg::ElementInnerTextQuery => "\tElementInnerTextQuery",
|
||||||
QueryMsg::InnerWindowDimensionsQuery(_) => "\tInnerWindowDimensionsQuery",
|
QueryMsg::InnerWindowDimensionsQuery => "\tInnerWindowDimensionsQuery",
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -462,7 +462,6 @@ pub enum LayoutHangAnnotation {
|
||||||
RemoveStylesheet,
|
RemoveStylesheet,
|
||||||
SetQuirksMode,
|
SetQuirksMode,
|
||||||
Reflow,
|
Reflow,
|
||||||
GetRPC,
|
|
||||||
CollectReports,
|
CollectReports,
|
||||||
ExitNow,
|
ExitNow,
|
||||||
GetCurrentEpoch,
|
GetCurrentEpoch,
|
||||||
|
|
|
@ -9,7 +9,6 @@
|
||||||
#![deny(unsafe_code)]
|
#![deny(unsafe_code)]
|
||||||
|
|
||||||
pub mod message;
|
pub mod message;
|
||||||
pub mod rpc;
|
|
||||||
pub mod wrapper_traits;
|
pub mod wrapper_traits;
|
||||||
|
|
||||||
use std::any::Any;
|
use std::any::Any;
|
||||||
|
@ -17,15 +16,19 @@ use std::borrow::Cow;
|
||||||
use std::sync::atomic::AtomicIsize;
|
use std::sync::atomic::AtomicIsize;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
|
use app_units::Au;
|
||||||
use atomic_refcell::AtomicRefCell;
|
use atomic_refcell::AtomicRefCell;
|
||||||
use canvas_traits::canvas::{CanvasId, CanvasMsg};
|
use canvas_traits::canvas::{CanvasId, CanvasMsg};
|
||||||
|
use euclid::default::{Point2D, Rect};
|
||||||
|
use euclid::Size2D;
|
||||||
use gfx::font_cache_thread::FontCacheThread;
|
use gfx::font_cache_thread::FontCacheThread;
|
||||||
use gfx_traits::Epoch;
|
use gfx_traits::Epoch;
|
||||||
use ipc_channel::ipc::IpcSender;
|
use ipc_channel::ipc::IpcSender;
|
||||||
use libc::c_void;
|
use libc::c_void;
|
||||||
use malloc_size_of_derive::MallocSizeOf;
|
use malloc_size_of_derive::MallocSizeOf;
|
||||||
|
use message::NodesFromPointQueryType;
|
||||||
use metrics::PaintTimeMetrics;
|
use metrics::PaintTimeMetrics;
|
||||||
use msg::constellation_msg::PipelineId;
|
use msg::constellation_msg::{BrowsingContextId, PipelineId};
|
||||||
use net_traits::image_cache::{ImageCache, PendingImageId};
|
use net_traits::image_cache::{ImageCache, PendingImageId};
|
||||||
use profile_traits::time;
|
use profile_traits::time;
|
||||||
use script_traits::{
|
use script_traits::{
|
||||||
|
@ -34,9 +37,15 @@ use script_traits::{
|
||||||
};
|
};
|
||||||
use servo_arc::Arc as ServoArc;
|
use servo_arc::Arc as ServoArc;
|
||||||
use servo_url::{ImmutableOrigin, ServoUrl};
|
use servo_url::{ImmutableOrigin, ServoUrl};
|
||||||
|
use style::animation::DocumentAnimationSet;
|
||||||
use style::data::ElementData;
|
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 style::stylesheets::Stylesheet;
|
||||||
use webrender_api::ImageKey;
|
use style_traits::CSSPixel;
|
||||||
|
use webrender_api::{ExternalScrollId, ImageKey};
|
||||||
|
|
||||||
#[derive(MallocSizeOf)]
|
#[derive(MallocSizeOf)]
|
||||||
pub struct StyleData {
|
pub struct StyleData {
|
||||||
|
@ -195,11 +204,6 @@ pub trait Layout {
|
||||||
/// Handle a a single mesasge from the FontCacheThread.
|
/// Handle a a single mesasge from the FontCacheThread.
|
||||||
fn handle_font_cache_msg(&mut self);
|
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.
|
/// Whether or not this layout is waiting for fonts from loaded stylesheets to finish loading.
|
||||||
fn waiting_for_web_fonts_to_load(&self) -> bool;
|
fn waiting_for_web_fonts_to_load(&self) -> bool;
|
||||||
|
|
||||||
|
@ -221,6 +225,39 @@ pub trait Layout {
|
||||||
|
|
||||||
/// Removes a stylesheet from the Layout.
|
/// Removes a stylesheet from the Layout.
|
||||||
fn remove_stylesheet(&mut self, stylesheet: ServoArc<Stylesheet>);
|
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`
|
/// 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>,
|
user_agent: Cow<'static, str>,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
#[derive(Clone, Default)]
|
||||||
|
pub struct OffsetParentResponse {
|
||||||
|
pub node_address: Option<UntrustedNodeAddress>,
|
||||||
|
pub rect: Rect<Au>,
|
||||||
|
}
|
||||||
|
|
|
@ -4,21 +4,17 @@
|
||||||
|
|
||||||
use app_units::Au;
|
use app_units::Au;
|
||||||
use crossbeam_channel::Sender;
|
use crossbeam_channel::Sender;
|
||||||
use euclid::default::{Point2D, Rect};
|
use euclid::default::Rect;
|
||||||
use malloc_size_of_derive::MallocSizeOf;
|
use malloc_size_of_derive::MallocSizeOf;
|
||||||
use msg::constellation_msg::BrowsingContextId;
|
|
||||||
use profile_traits::mem::ReportsChan;
|
use profile_traits::mem::ReportsChan;
|
||||||
use script_traits::{Painter, ScrollState, WindowSizeData};
|
use script_traits::{Painter, ScrollState, WindowSizeData};
|
||||||
use servo_atoms::Atom;
|
use servo_atoms::Atom;
|
||||||
use servo_url::ImmutableOrigin;
|
use servo_url::ImmutableOrigin;
|
||||||
use style::animation::DocumentAnimationSet;
|
use style::animation::DocumentAnimationSet;
|
||||||
use style::context::QuirksMode;
|
use style::context::QuirksMode;
|
||||||
use style::dom::OpaqueNode;
|
|
||||||
use style::invalidation::element::restyle_hints::RestyleHint;
|
use style::invalidation::element::restyle_hints::RestyleHint;
|
||||||
use style::properties::PropertyId;
|
use style::selector_parser::{RestyleDamage, Snapshot};
|
||||||
use style::selector_parser::{PseudoElement, RestyleDamage, Snapshot};
|
|
||||||
|
|
||||||
use crate::rpc::LayoutRPC;
|
|
||||||
use crate::{PendingImage, TrustedNodeAddress};
|
use crate::{PendingImage, TrustedNodeAddress};
|
||||||
|
|
||||||
/// Asynchronous messages that script can send to layout.
|
/// Asynchronous messages that script can send to layout.
|
||||||
|
@ -29,9 +25,6 @@ pub enum Msg {
|
||||||
/// Requests a reflow.
|
/// Requests a reflow.
|
||||||
Reflow(ScriptReflow),
|
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
|
/// Requests that layout measure its memory usage. The resulting reports are sent back
|
||||||
/// via the supplied channel.
|
/// via the supplied channel.
|
||||||
CollectReports(ReportsChan),
|
CollectReports(ReportsChan),
|
||||||
|
@ -55,23 +48,19 @@ pub enum NodesFromPointQueryType {
|
||||||
|
|
||||||
#[derive(Debug, PartialEq)]
|
#[derive(Debug, PartialEq)]
|
||||||
pub enum QueryMsg {
|
pub enum QueryMsg {
|
||||||
ContentBoxQuery(OpaqueNode),
|
ContentBox,
|
||||||
ContentBoxesQuery(OpaqueNode),
|
ContentBoxes,
|
||||||
ClientRectQuery(OpaqueNode),
|
ClientRectQuery,
|
||||||
ScrollingAreaQuery(Option<OpaqueNode>),
|
ScrollingAreaQuery,
|
||||||
OffsetParentQuery(OpaqueNode),
|
OffsetParentQuery,
|
||||||
TextIndexQuery(OpaqueNode, Point2D<f32>),
|
TextIndexQuery,
|
||||||
NodesFromPointQuery(Point2D<f32>, NodesFromPointQueryType),
|
NodesFromPointQuery,
|
||||||
|
NodeScrollIdQuery,
|
||||||
// FIXME(nox): The following queries use the TrustedNodeAddress to
|
ResolvedStyleQuery,
|
||||||
// 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),
|
|
||||||
StyleQuery,
|
StyleQuery,
|
||||||
ElementInnerTextQuery(TrustedNodeAddress),
|
ElementInnerTextQuery,
|
||||||
ResolvedFontStyleQuery(TrustedNodeAddress, PropertyId, String),
|
ResolvedFontStyleQuery,
|
||||||
InnerWindowDimensionsQuery(BrowsingContextId),
|
InnerWindowDimensionsQuery,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Any query to perform with this reflow.
|
/// Any query to perform with this reflow.
|
||||||
|
@ -93,18 +82,18 @@ impl ReflowGoal {
|
||||||
match *self {
|
match *self {
|
||||||
ReflowGoal::Full | ReflowGoal::TickAnimations | ReflowGoal::UpdateScrollNode(_) => true,
|
ReflowGoal::Full | ReflowGoal::TickAnimations | ReflowGoal::UpdateScrollNode(_) => true,
|
||||||
ReflowGoal::LayoutQuery(ref querymsg, _) => match *querymsg {
|
ReflowGoal::LayoutQuery(ref querymsg, _) => match *querymsg {
|
||||||
QueryMsg::ElementInnerTextQuery(_) |
|
QueryMsg::ElementInnerTextQuery |
|
||||||
QueryMsg::InnerWindowDimensionsQuery(_) |
|
QueryMsg::InnerWindowDimensionsQuery |
|
||||||
QueryMsg::NodesFromPointQuery(..) |
|
QueryMsg::NodesFromPointQuery |
|
||||||
QueryMsg::ResolvedStyleQuery(..) |
|
QueryMsg::ResolvedStyleQuery |
|
||||||
QueryMsg::TextIndexQuery(..) => true,
|
QueryMsg::TextIndexQuery => true,
|
||||||
QueryMsg::ClientRectQuery(_) |
|
QueryMsg::ClientRectQuery |
|
||||||
QueryMsg::ContentBoxQuery(_) |
|
QueryMsg::ContentBox |
|
||||||
QueryMsg::ContentBoxesQuery(_) |
|
QueryMsg::ContentBoxes |
|
||||||
QueryMsg::NodeScrollIdQuery(_) |
|
QueryMsg::NodeScrollIdQuery |
|
||||||
QueryMsg::OffsetParentQuery(_) |
|
QueryMsg::OffsetParentQuery |
|
||||||
QueryMsg::ResolvedFontStyleQuery(..) |
|
QueryMsg::ResolvedFontStyleQuery |
|
||||||
QueryMsg::ScrollingAreaQuery(_) |
|
QueryMsg::ScrollingAreaQuery |
|
||||||
QueryMsg::StyleQuery => false,
|
QueryMsg::StyleQuery => false,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
@ -116,18 +105,18 @@ impl ReflowGoal {
|
||||||
match *self {
|
match *self {
|
||||||
ReflowGoal::Full | ReflowGoal::TickAnimations | ReflowGoal::UpdateScrollNode(_) => true,
|
ReflowGoal::Full | ReflowGoal::TickAnimations | ReflowGoal::UpdateScrollNode(_) => true,
|
||||||
ReflowGoal::LayoutQuery(ref querymsg, _) => match *querymsg {
|
ReflowGoal::LayoutQuery(ref querymsg, _) => match *querymsg {
|
||||||
QueryMsg::NodesFromPointQuery(..) |
|
QueryMsg::NodesFromPointQuery |
|
||||||
QueryMsg::TextIndexQuery(..) |
|
QueryMsg::TextIndexQuery |
|
||||||
QueryMsg::ElementInnerTextQuery(_) => true,
|
QueryMsg::ElementInnerTextQuery => true,
|
||||||
QueryMsg::ContentBoxQuery(_) |
|
QueryMsg::ContentBox |
|
||||||
QueryMsg::ContentBoxesQuery(_) |
|
QueryMsg::ContentBoxes |
|
||||||
QueryMsg::ClientRectQuery(_) |
|
QueryMsg::ClientRectQuery |
|
||||||
QueryMsg::ScrollingAreaQuery(_) |
|
QueryMsg::ScrollingAreaQuery |
|
||||||
QueryMsg::NodeScrollIdQuery(_) |
|
QueryMsg::NodeScrollIdQuery |
|
||||||
QueryMsg::ResolvedStyleQuery(..) |
|
QueryMsg::ResolvedStyleQuery |
|
||||||
QueryMsg::ResolvedFontStyleQuery(..) |
|
QueryMsg::ResolvedFontStyleQuery |
|
||||||
QueryMsg::OffsetParentQuery(_) |
|
QueryMsg::OffsetParentQuery |
|
||||||
QueryMsg::InnerWindowDimensionsQuery(_) |
|
QueryMsg::InnerWindowDimensionsQuery |
|
||||||
QueryMsg::StyleQuery => false,
|
QueryMsg::StyleQuery => false,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
|
@ -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>);
|
|
Loading…
Add table
Add a link
Reference in a new issue