From df6b64181b276482c4082b2064d3b9c4ed86b970 Mon Sep 17 00:00:00 2001 From: moe <35686186+csmoe@users.noreply.github.com> Date: Fri, 16 Mar 2018 14:06:27 +0800 Subject: [PATCH 1/3] extract querymsg from ReflowGoal --- components/layout_thread/lib.rs | 212 +++++++++--------- components/script/dom/document.rs | 4 +- components/script/dom/htmlelement.rs | 4 +- components/script/dom/window.rs | 52 ++--- components/script_layout_interface/message.rs | 59 +++-- 5 files changed, 177 insertions(+), 154 deletions(-) diff --git a/components/layout_thread/lib.rs b/components/layout_thread/lib.rs index 2ce013f658c..0bb38326865 100644 --- a/components/layout_thread/lib.rs +++ b/components/layout_thread/lib.rs @@ -94,7 +94,7 @@ use profile_traits::mem::{self, Report, ReportKind, ReportsChan}; use profile_traits::time::{self, TimerMetadata, profile}; use profile_traits::time::{TimerMetadataFrameType, TimerMetadataReflowType}; use script_layout_interface::message::{Msg, NewLayoutThreadInfo, NodesFromPointQueryType, Reflow}; -use script_layout_interface::message::{ReflowComplete, ReflowGoal, ScriptReflow}; +use script_layout_interface::message::{ReflowComplete, QueryMsg, ReflowGoal, ScriptReflow}; use script_layout_interface::rpc::{LayoutRPC, StyleResponse, OffsetParentResponse}; use script_layout_interface::rpc::TextIndexResponse; use script_layout_interface::wrapper_traits::LayoutNode; @@ -1083,38 +1083,40 @@ impl LayoutThread { // Since we cannot compute anything, give spec-required placeholders. debug!("layout: No root node: bailing"); match data.reflow_goal { - ReflowGoal::ContentBoxQuery(_) => { - rw_data.content_box_response = None; - }, - ReflowGoal::ContentBoxesQuery(_) => { - rw_data.content_boxes_response = Vec::new(); - }, - ReflowGoal::NodesFromPointQuery(..) => { - rw_data.nodes_from_point_response = Vec::new(); - }, - ReflowGoal::NodeGeometryQuery(_) => { - rw_data.client_rect_response = Rect::zero(); - }, - ReflowGoal::NodeScrollGeometryQuery(_) => { - rw_data.scroll_area_response = Rect::zero(); - }, - ReflowGoal::NodeScrollIdQuery(_) => { - rw_data.scroll_id_response = None; - }, - ReflowGoal::ResolvedStyleQuery(_, _, _) => { - rw_data.resolved_style_response = String::new(); - }, - ReflowGoal::OffsetParentQuery(_) => { - rw_data.offset_parent_response = OffsetParentResponse::empty(); - }, - ReflowGoal::StyleQuery(_) => { - rw_data.style_response = StyleResponse(None); - }, - ReflowGoal::TextIndexQuery(..) => { - rw_data.text_index_response = TextIndexResponse(None); - } - ReflowGoal::ElementInnerTextQuery(_) => { - rw_data.element_inner_text_response = String::new(); + ReflowGoal::LayoutQuery(ref quermsg, _) => match quermsg { + &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::NodeGeometryQuery(_) => { + rw_data.client_rect_response = Rect::zero(); + }, + &QueryMsg::NodeScrollGeometryQuery(_) => { + rw_data.scroll_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(_) => { + rw_data.style_response = StyleResponse(None); + }, + &QueryMsg::TextIndexQuery(..) => { + rw_data.text_index_response = TextIndexResponse(None); + } + &QueryMsg::ElementInnerTextQuery(_) => { + rw_data.element_inner_text_response = String::new(); + }, }, ReflowGoal::Full | ReflowGoal:: TickAnimations => {} } @@ -1355,80 +1357,82 @@ impl LayoutThread { }; let root_flow = FlowRef::deref_mut(&mut root_flow); match *reflow_goal { - ReflowGoal::ContentBoxQuery(node) => { - let node = unsafe { ServoLayoutNode::new(&node) }; - rw_data.content_box_response = process_content_box_request(node, root_flow); - }, - ReflowGoal::ContentBoxesQuery(node) => { - let node = unsafe { ServoLayoutNode::new(&node) }; - rw_data.content_boxes_response = process_content_boxes_request(node, root_flow); - }, - ReflowGoal::TextIndexQuery(node, point_in_node) => { - let node = unsafe { ServoLayoutNode::new(&node) }; - let opaque_node = node.opaque(); - 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(opaque_node, point_in_node) - ); - }, - ReflowGoal::NodeGeometryQuery(node) => { - let node = unsafe { ServoLayoutNode::new(&node) }; - rw_data.client_rect_response = process_node_geometry_request(node, root_flow); - }, - ReflowGoal::NodeScrollGeometryQuery(node) => { - let node = unsafe { ServoLayoutNode::new(&node) }; - rw_data.scroll_area_response = process_node_scroll_area_request(node, root_flow); - }, - ReflowGoal::NodeScrollIdQuery(node) => { - let node = unsafe { ServoLayoutNode::new(&node) }; - rw_data.scroll_id_response = Some(process_node_scroll_id_request(self.id, node)); - }, - ReflowGoal::ResolvedStyleQuery(node, ref pseudo, ref property) => { - let node = unsafe { ServoLayoutNode::new(&node) }; - rw_data.resolved_style_response = - process_resolved_style_request(context, - node, - pseudo, - property, - root_flow); - }, - ReflowGoal::OffsetParentQuery(node) => { - let node = unsafe { ServoLayoutNode::new(&node) }; - rw_data.offset_parent_response = process_offset_parent_query(node, root_flow); - }, - ReflowGoal::StyleQuery(node) => { - let node = unsafe { ServoLayoutNode::new(&node) }; - rw_data.style_response = process_style_query(node); - }, - ReflowGoal::NodesFromPointQuery(client_point, ref reflow_goal) => { - let mut flags = match reflow_goal { - &NodesFromPointQueryType::Topmost => webrender_api::HitTestFlags::empty(), - &NodesFromPointQueryType::All => webrender_api::HitTestFlags::FIND_ALL, - }; + ReflowGoal::LayoutQuery(ref querymsg, _) => match querymsg { + &QueryMsg::ContentBoxQuery(node) => { + let node = unsafe { ServoLayoutNode::new(&node) }; + rw_data.content_box_response = process_content_box_request(node, root_flow); + }, + &QueryMsg::ContentBoxesQuery(node) => { + let node = unsafe { ServoLayoutNode::new(&node) }; + rw_data.content_boxes_response = process_content_boxes_request(node, root_flow); + }, + &QueryMsg::TextIndexQuery(node, point_in_node) => { + let node = unsafe { ServoLayoutNode::new(&node) }; + let opaque_node = node.opaque(); + 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(opaque_node, point_in_node) + ); + }, + &QueryMsg::NodeGeometryQuery(node) => { + let node = unsafe { ServoLayoutNode::new(&node) }; + rw_data.client_rect_response = process_node_geometry_request(node, root_flow); + }, + &QueryMsg::NodeScrollGeometryQuery(node) => { + let node = unsafe { ServoLayoutNode::new(&node) }; + rw_data.scroll_area_response = process_node_scroll_area_request(node, root_flow); + }, + &QueryMsg::NodeScrollIdQuery(node) => { + let node = 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 = unsafe { ServoLayoutNode::new(&node) }; + rw_data.resolved_style_response = + process_resolved_style_request(context, + node, + pseudo, + property, + root_flow); + }, + &QueryMsg::OffsetParentQuery(node) => { + let node = unsafe { ServoLayoutNode::new(&node) }; + rw_data.offset_parent_response = process_offset_parent_query(node, root_flow); + }, + &QueryMsg::StyleQuery(node) => { + let node = unsafe { ServoLayoutNode::new(&node) }; + rw_data.style_response = process_style_query(node); + }, + &QueryMsg::NodesFromPointQuery(client_point, ref reflow_goal) => { + let mut flags = match reflow_goal { + &NodesFromPointQueryType::Topmost => webrender_api::HitTestFlags::empty(), + &NodesFromPointQueryType::All => webrender_api::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(webrender_api::HitTestFlags::POINT_RELATIVE_TO_PIPELINE_VIEWPORT); + // 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(webrender_api::HitTestFlags::POINT_RELATIVE_TO_PIPELINE_VIEWPORT); - let client_point = webrender_api::WorldPoint::from_untyped(&client_point); - let results = self.webrender_api.hit_test( - self.webrender_document, - Some(self.id.to_webrender()), - client_point, - flags - ); + let client_point = webrender_api::WorldPoint::from_untyped(&client_point); + let results = self.webrender_api.hit_test( + self.webrender_document, + Some(self.id.to_webrender()), + client_point, + flags + ); - rw_data.nodes_from_point_response = results.items.iter() - .map(|item| UntrustedNodeAddress(item.tag.0 as *const c_void)) - .collect() - }, - ReflowGoal::ElementInnerTextQuery(node) => { - let node = unsafe { ServoLayoutNode::new(&node) }; - rw_data.element_inner_text_response = - process_element_inner_text_query(node, &rw_data.indexable_text); + rw_data.nodes_from_point_response = results.items.iter() + .map(|item| UntrustedNodeAddress(item.tag.0 as *const c_void)) + .collect() + }, + &QueryMsg::ElementInnerTextQuery(node) => { + let node = unsafe { ServoLayoutNode::new(&node) }; + rw_data.element_inner_text_response = + process_element_inner_text_query(node, &rw_data.indexable_text); + }, }, ReflowGoal::Full | ReflowGoal::TickAnimations => {} } diff --git a/components/script/dom/document.rs b/components/script/dom/document.rs index 49bc45b27c1..1f202dcc55c 100644 --- a/components/script/dom/document.rs +++ b/components/script/dom/document.rs @@ -108,7 +108,7 @@ use net_traits::response::HttpsState; use num_traits::ToPrimitive; use profile_traits::time::{TimerMetadata, TimerMetadataFrameType, TimerMetadataReflowType}; use ref_slice::ref_slice; -use script_layout_interface::message::{Msg, NodesFromPointQueryType, ReflowGoal}; +use script_layout_interface::message::{Msg, NodesFromPointQueryType, QueryMsg, ReflowGoal}; use script_runtime::{CommonScriptMsg, ScriptThreadEventCategory}; use script_thread::{MainThreadScriptMsg, ScriptThread}; use script_traits::{AnimationState, DocumentActivity, MouseButton, MouseEventType}; @@ -1968,7 +1968,7 @@ impl Document { client_point: &Point2D, reflow_goal: NodesFromPointQueryType) -> Vec { - if !self.window.reflow(ReflowGoal::NodesFromPointQuery(*client_point, reflow_goal), + if !self.window.reflow(ReflowGoal::LayoutQuery(QueryMsg::NodesFromPointQuery(*client_point, reflow_goal), u64::default()), ReflowReason::Query) { return vec!(); }; diff --git a/components/script/dom/htmlelement.rs b/components/script/dom/htmlelement.rs index 021f25161b9..e1eb260d285 100644 --- a/components/script/dom/htmlelement.rs +++ b/components/script/dom/htmlelement.rs @@ -35,7 +35,7 @@ use dom::virtualmethods::VirtualMethods; use dom::window::ReflowReason; use dom_struct::dom_struct; use html5ever::{LocalName, Prefix}; -use script_layout_interface::message::ReflowGoal; +use script_layout_interface::message::{QueryMsg, ReflowGoal}; use std::collections::HashSet; use std::default::Default; use std::rc::Rc; @@ -419,7 +419,7 @@ impl HTMLElementMethods for HTMLElement { return node.GetTextContent().unwrap(); } - window.reflow(ReflowGoal::ElementInnerTextQuery(node.to_trusted_node_address()), ReflowReason::Query); + window.reflow(ReflowGoal::LayoutQuery(QueryMsg::ElementInnerTextQuery(node.to_trusted_node_address()), u64::default()), ReflowReason::Query); DOMString::from(window.layout().element_inner_text()) } diff --git a/components/script/dom/window.rs b/components/script/dom/window.rs index f6177e90fcf..5d4e3c3a72e 100644 --- a/components/script/dom/window.rs +++ b/components/script/dom/window.rs @@ -66,7 +66,7 @@ use num_traits::ToPrimitive; use profile_traits::mem::ProfilerChan as MemProfilerChan; use profile_traits::time::ProfilerChan as TimeProfilerChan; use script_layout_interface::{TrustedNodeAddress, PendingImageState}; -use script_layout_interface::message::{Msg, Reflow, ReflowGoal, ScriptReflow}; +use script_layout_interface::message::{Msg, Reflow, QueryMsg, ReflowGoal, ScriptReflow}; use script_layout_interface::reporter::CSSErrorReporter; use script_layout_interface::rpc::{ContentBoxResponse, ContentBoxesResponse, LayoutRPC}; use script_layout_interface::rpc::{NodeScrollIdResponse, ResolvedStyleResponse, TextIndexResponse}; @@ -1374,12 +1374,16 @@ impl Window { issued_reflow } + pub fn layout_reflow(&self, query_msg: QuerMsg) -> bool { + self.reflow(ReflowGoal::LayoutQuery(query_msg, time::precise_time_ns()), ReflowReason::Query) + } + pub fn layout(&self) -> &LayoutRPC { &*self.layout_rpc } pub fn content_box_query(&self, content_box_request: TrustedNodeAddress) -> Option> { - if !self.reflow(ReflowGoal::ContentBoxQuery(content_box_request), ReflowReason::Query) { + if !self.layout_reflow(QueryMsg::ContentBoxQuery(content_box_request)) { return None; } let ContentBoxResponse(rect) = self.layout_rpc.content_box(); @@ -1387,7 +1391,7 @@ impl Window { } pub fn content_boxes_query(&self, content_boxes_request: TrustedNodeAddress) -> Vec> { - if !self.reflow(ReflowGoal::ContentBoxesQuery(content_boxes_request), ReflowReason::Query) { + if !self.layout_reflow(QueryMsg::ContentBoxesQuery(content_boxes_request)) { return vec![]; } let ContentBoxesResponse(rects) = self.layout_rpc.content_boxes(); @@ -1395,14 +1399,14 @@ impl Window { } pub fn client_rect_query(&self, node_geometry_request: TrustedNodeAddress) -> Rect { - if !self.reflow(ReflowGoal::NodeGeometryQuery(node_geometry_request), ReflowReason::Query) { + if !self.layout_reflow(QueryMsg::NodeGeometryQuery(node_geometry_request)) { return Rect::zero(); } self.layout_rpc.node_geometry().client_rect } pub fn scroll_area_query(&self, node: TrustedNodeAddress) -> Rect { - if !self.reflow(ReflowGoal::NodeScrollGeometryQuery(node), ReflowReason::Query) { + if !self.layout_reflow(QueryMsg::NodeScrollGeometryQuery(node)) { return Rect::zero(); } self.layout_rpc.node_scroll_area().client_rect @@ -1425,10 +1429,7 @@ impl Window { y_: f64, behavior: ScrollBehavior ) { - if !self.reflow( - ReflowGoal::NodeScrollIdQuery(node.to_trusted_node_address()), - ReflowReason::Query - ) { + if !self.layout_reflow(QueryMsg::NodeScrollIdQuery(node.to_trusted_node_address())) { return; } @@ -1452,8 +1453,7 @@ impl Window { element: TrustedNodeAddress, pseudo: Option, property: PropertyId) -> DOMString { - if !self.reflow(ReflowGoal::ResolvedStyleQuery(element, pseudo, property), - ReflowReason::Query) { + if !self.layout_reflow(QueryMsg::ResolvedStyleQuery(element, pseudo, property)) { return DOMString::new(); } let ResolvedStyleResponse(resolved) = self.layout_rpc.resolved_style(); @@ -1462,7 +1462,7 @@ impl Window { #[allow(unsafe_code)] pub fn offset_parent_query(&self, node: TrustedNodeAddress) -> (Option>, Rect) { - if !self.reflow(ReflowGoal::OffsetParentQuery(node), ReflowReason::Query) { + if !self.layout_reflow(QueryMsg::OffsetParentQuery(node)) { return (None, Rect::zero()); } @@ -1477,7 +1477,7 @@ impl Window { } pub fn style_query(&self, node: TrustedNodeAddress) -> Option> { - if !self.reflow(ReflowGoal::StyleQuery(node), ReflowReason::Query) { + if !self.layout_reflow(QueryMsg::StyleQuery(node)) { return None } self.layout_rpc.style().0 @@ -1488,7 +1488,7 @@ impl Window { node: TrustedNodeAddress, point_in_node: Point2D ) -> TextIndexResponse { - if !self.reflow(ReflowGoal::TextIndexQuery(node, point_in_node), ReflowReason::Query) { + if !self.layout_reflow(QueryMsg::TextIndexQuery(node, point_in_node)) { return TextIndexResponse(None); } self.layout_rpc.text_index() @@ -1870,18 +1870,20 @@ fn debug_reflow_events(id: PipelineId, reflow_goal: &ReflowGoal, reason: &Reflow let mut debug_msg = format!("**** pipeline={}", id); debug_msg.push_str(match *reflow_goal { ReflowGoal::Full => "\tFull", - ReflowGoal::ContentBoxQuery(_n) => "\tContentBoxQuery", - ReflowGoal::ContentBoxesQuery(_n) => "\tContentBoxesQuery", - ReflowGoal::NodesFromPointQuery(..) => "\tNodesFromPointQuery", - ReflowGoal::NodeGeometryQuery(_n) => "\tNodeGeometryQuery", - ReflowGoal::NodeScrollGeometryQuery(_n) => "\tNodeScrollGeometryQuery", - ReflowGoal::NodeScrollIdQuery(_n) => "\tNodeScrollIdQuery", - ReflowGoal::ResolvedStyleQuery(_, _, _) => "\tResolvedStyleQuery", - ReflowGoal::OffsetParentQuery(_n) => "\tOffsetParentQuery", - ReflowGoal::StyleQuery(_n) => "\tStyleQuery", - ReflowGoal::TextIndexQuery(..) => "\tTextIndexQuery", ReflowGoal::TickAnimations => "\tTickAnimations", - ReflowGoal::ElementInnerTextQuery(_) => "\tElementInnerTextQuery", + ReflowGoal::LayoutQuery(ref query_msg, _) => match query_msg { + &QueryMsg::ContentBoxQuery(_n) => "\tContentBoxQuery", + &QueryMsg::ContentBoxesQuery(_n) => "\tContentBoxesQuery", + &QueryMsg::NodesFromPointQuery(..) => "\tNodesFromPointQuery", + &QueryMsg::NodeGeometryQuery(_n) => "\tNodeGeometryQuery", + &QueryMsg::NodeScrollGeometryQuery(_n) => "\tNodeScrollGeometryQuery", + &QueryMsg::NodeScrollIdQuery(_n) => "\tNodeScrollIdQuery", + &QueryMsg::ResolvedStyleQuery(_, _, _) => "\tResolvedStyleQuery", + &QueryMsg::OffsetParentQuery(_n) => "\tOffsetParentQuery", + &QueryMsg::StyleQuery(_n) => "\tStyleQuery", + &QueryMsg::TextIndexQuery(..) => "\tTextIndexQuery", + &QueryMsg::ElementInnerTextQuery(_) => "\tElementInnerTextQuery", + }, }); debug_msg.push_str(match *reason { diff --git a/components/script_layout_interface/message.rs b/components/script_layout_interface/message.rs index ef408600270..ac52d9373ce 100644 --- a/components/script_layout_interface/message.rs +++ b/components/script_layout_interface/message.rs @@ -2,7 +2,7 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -use {OpaqueStyleAndLayoutData, TrustedNodeAddress, PendingImage}; +use {OpaqueStyleAndLayoutData, PendingImage, TrustedNodeAddress}; use app_units::Au; use euclid::{Point2D, Rect}; use gfx_traits::Epoch; @@ -106,11 +106,8 @@ pub enum NodesFromPointQueryType { Topmost, } -/// Any query to perform with this reflow. #[derive(Debug, PartialEq)] -pub enum ReflowGoal { - Full, - TickAnimations, +pub enum QueryMsg { ContentBoxQuery(TrustedNodeAddress), ContentBoxesQuery(TrustedNodeAddress), NodeScrollIdQuery(TrustedNodeAddress), @@ -124,19 +121,33 @@ pub enum ReflowGoal { ElementInnerTextQuery(TrustedNodeAddress), } +/// Any query to perform with this reflow. +#[derive(Debug, PartialEq)] +pub enum ReflowGoal { + Full, + TickAnimations, + LayoutQuery(QueryMsg, u64), +} + impl ReflowGoal { /// Returns true if the given ReflowQuery needs a full, up-to-date display list to /// be present or false if it only needs stacking-relative positions. pub fn needs_display_list(&self) -> bool { match *self { - ReflowGoal::NodesFromPointQuery(..) | ReflowGoal::TextIndexQuery(..) | - ReflowGoal::TickAnimations | ReflowGoal::ElementInnerTextQuery(_) | - ReflowGoal::Full => true, - ReflowGoal::ContentBoxQuery(_) | ReflowGoal::ContentBoxesQuery(_) | - ReflowGoal::NodeGeometryQuery(_) | ReflowGoal::NodeScrollGeometryQuery(_) | - ReflowGoal::NodeScrollIdQuery(_) | - ReflowGoal::ResolvedStyleQuery(..) | ReflowGoal::OffsetParentQuery(_) | - ReflowGoal::StyleQuery(_) => false, + ReflowGoal::Full | ReflowGoal::TickAnimations => true, + ReflowGoal::LayoutQuery(ref querymsg, _) => match querymsg { + &QueryMsg::NodesFromPointQuery(..) | + &QueryMsg::TextIndexQuery(..) | + &QueryMsg::ElementInnerTextQuery(_) => true, + &QueryMsg::ContentBoxQuery(_) | + &QueryMsg::ContentBoxesQuery(_) | + &QueryMsg::NodeGeometryQuery(_) | + &QueryMsg::NodeScrollGeometryQuery(_) | + &QueryMsg::NodeScrollIdQuery(_) | + &QueryMsg::ResolvedStyleQuery(..) | + &QueryMsg::OffsetParentQuery(_) | + &QueryMsg::StyleQuery(_) => false, + }, } } @@ -144,14 +155,20 @@ impl ReflowGoal { /// false if a layout_thread display list is sufficient. pub fn needs_display(&self) -> bool { match *self { - ReflowGoal::StyleQuery(_) | ReflowGoal::TextIndexQuery(..) | - ReflowGoal::ContentBoxQuery(_) | ReflowGoal::ContentBoxesQuery(_) | - ReflowGoal::NodeGeometryQuery(_) | ReflowGoal::NodeScrollGeometryQuery(_) | - ReflowGoal::NodeScrollIdQuery(_) | ReflowGoal::ResolvedStyleQuery(..) | - ReflowGoal::OffsetParentQuery(_) => false, - ReflowGoal::NodesFromPointQuery(..) | ReflowGoal::Full | - ReflowGoal::ElementInnerTextQuery(_) | - ReflowGoal::TickAnimations => true, + ReflowGoal::Full | ReflowGoal::TickAnimations => true, + ReflowGoal::LayoutQuery(ref querymsg, _) => match querymsg { + &QueryMsg::NodesFromPointQuery(..) | + &QueryMsg::TextIndexQuery(..) | + &QueryMsg::ElementInnerTextQuery(_) => true, + &QueryMsg::ContentBoxQuery(_) | + &QueryMsg::ContentBoxesQuery(_) | + &QueryMsg::NodeGeometryQuery(_) | + &QueryMsg::NodeScrollGeometryQuery(_) | + &QueryMsg::NodeScrollIdQuery(_) | + &QueryMsg::ResolvedStyleQuery(..) | + &QueryMsg::OffsetParentQuery(_) | + &QueryMsg::StyleQuery(_) => false, + }, } } } From 98fe118be44e829ec6f236ff8f527a7b518f755e Mon Sep 17 00:00:00 2001 From: csmoe <35686186+csmoe@users.noreply.github.com> Date: Sat, 17 Mar 2018 00:40:13 +0800 Subject: [PATCH 2/3] introduce layout query timestamp --- Cargo.lock | 2 ++ components/layout_thread/Cargo.toml | 1 + components/layout_thread/lib.rs | 20 +++++++++++++++++- components/script/dom/document.rs | 3 +-- components/script/dom/htmlelement.rs | 5 ++--- components/script/dom/window.rs | 4 ++-- components/script_layout_interface/Cargo.toml | 1 + components/script_layout_interface/lib.rs | 1 + components/script_layout_interface/message.rs | 21 +++++++++++++++++++ 9 files changed, 50 insertions(+), 8 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 63096eaceb0..8f6d1bf36a0 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1455,6 +1455,7 @@ dependencies = [ "servo_url 0.0.1", "style 0.0.1", "style_traits 0.0.1", + "time 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)", "webrender_api 0.57.0 (git+https://github.com/servo/webrender)", ] @@ -2527,6 +2528,7 @@ dependencies = [ "servo_atoms 0.0.1", "servo_url 0.0.1", "style 0.0.1", + "time 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)", "webrender_api 0.57.0 (git+https://github.com/servo/webrender)", ] diff --git a/components/layout_thread/Cargo.toml b/components/layout_thread/Cargo.toml index 1c43b48e409..d07746c54c9 100644 --- a/components/layout_thread/Cargo.toml +++ b/components/layout_thread/Cargo.toml @@ -26,6 +26,7 @@ layout_traits = {path = "../layout_traits"} lazy_static = "1" libc = "0.2" log = "0.3.5" +time = "0.1.17" malloc_size_of = { path = "../malloc_size_of" } metrics = {path = "../metrics"} msg = {path = "../msg"} diff --git a/components/layout_thread/lib.rs b/components/layout_thread/lib.rs index 0bb38326865..d3798d6e05b 100644 --- a/components/layout_thread/lib.rs +++ b/components/layout_thread/lib.rs @@ -46,6 +46,7 @@ extern crate servo_geometry; extern crate servo_url; extern crate style; extern crate style_traits; +extern crate time as std_time; extern crate webrender_api; mod dom_wrapper; @@ -260,6 +261,9 @@ pub struct LayoutThread { /// Paint time metrics. paint_time_metrics: PaintTimeMetrics, + + /// The time a layout query has waited before serviced by layout thread. + layout_query_timestamp: u64, } impl LayoutThreadFactory for LayoutThread { @@ -332,6 +336,12 @@ impl Deref for ScriptReflowResult { } } +impl DerefMut for ScriptReflowResult { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.script_reflow + } +} + impl ScriptReflowResult { fn new(script_reflow: ScriptReflow) -> ScriptReflowResult { ScriptReflowResult { @@ -541,6 +551,7 @@ impl LayoutThread { }, layout_threads: layout_threads, paint_time_metrics: paint_time_metrics, + layout_query_timestamp: 0u64, } } @@ -858,6 +869,9 @@ impl LayoutThread { // Drop the root flow explicitly to avoid holding style data, such as // rule nodes. The `Stylist` checks when it is dropped that all rule // nodes have been GCed, so we want drop anyone who holds them first. + let now = std_time::precise_time_ns(); + let waiting_time = now - self.layout_query_timestamp; + debug!("layout: query has been waited: {}", waiting_time); self.root_flow.borrow_mut().take(); // Drop the rayon threadpool if present. let _ = self.parallel_traversal.take(); @@ -1066,6 +1080,9 @@ impl LayoutThread { fn handle_reflow<'a, 'b>(&mut self, data: &mut ScriptReflowResult, possibly_locked_rw_data: &mut RwData<'a, 'b>) { + // Set layout query timestamp + data.reflow_goal.set_timestamp(); + let document = unsafe { ServoLayoutNode::new(&data.document) }; let document = document.as_document().unwrap(); @@ -1080,10 +1097,11 @@ impl LayoutThread { let element = match document.root_element() { None => { + self.layout_query_timestamp = data.reflow_goal.timestamp().expect("Not a QueryMsg"); // Since we cannot compute anything, give spec-required placeholders. debug!("layout: No root node: bailing"); match data.reflow_goal { - ReflowGoal::LayoutQuery(ref quermsg, _) => match quermsg { + ReflowGoal::LayoutQuery(ref query_msg, _) => match query_msg { &QueryMsg::ContentBoxQuery(_) => { rw_data.content_box_response = None; }, diff --git a/components/script/dom/document.rs b/components/script/dom/document.rs index 1f202dcc55c..68a24e9dcbc 100644 --- a/components/script/dom/document.rs +++ b/components/script/dom/document.rs @@ -1968,8 +1968,7 @@ impl Document { client_point: &Point2D, reflow_goal: NodesFromPointQueryType) -> Vec { - if !self.window.reflow(ReflowGoal::LayoutQuery(QueryMsg::NodesFromPointQuery(*client_point, reflow_goal), u64::default()), - ReflowReason::Query) { + if !self.window.layout_reflow(QueryMsg::NodesFromPointQuery(*client_point, reflow_goal)) { return vec!(); }; diff --git a/components/script/dom/htmlelement.rs b/components/script/dom/htmlelement.rs index e1eb260d285..e28ff1053a2 100644 --- a/components/script/dom/htmlelement.rs +++ b/components/script/dom/htmlelement.rs @@ -32,10 +32,9 @@ use dom::node::{document_from_node, window_from_node}; use dom::nodelist::NodeList; use dom::text::Text; use dom::virtualmethods::VirtualMethods; -use dom::window::ReflowReason; use dom_struct::dom_struct; use html5ever::{LocalName, Prefix}; -use script_layout_interface::message::{QueryMsg, ReflowGoal}; +use script_layout_interface::message::QueryMsg; use std::collections::HashSet; use std::default::Default; use std::rc::Rc; @@ -419,7 +418,7 @@ impl HTMLElementMethods for HTMLElement { return node.GetTextContent().unwrap(); } - window.reflow(ReflowGoal::LayoutQuery(QueryMsg::ElementInnerTextQuery(node.to_trusted_node_address()), u64::default()), ReflowReason::Query); + window.layout_reflow(QueryMsg::ElementInnerTextQuery(node.to_trusted_node_address())); DOMString::from(window.layout().element_inner_text()) } diff --git a/components/script/dom/window.rs b/components/script/dom/window.rs index 5d4e3c3a72e..bbaee9ea7c8 100644 --- a/components/script/dom/window.rs +++ b/components/script/dom/window.rs @@ -1374,8 +1374,8 @@ impl Window { issued_reflow } - pub fn layout_reflow(&self, query_msg: QuerMsg) -> bool { - self.reflow(ReflowGoal::LayoutQuery(query_msg, time::precise_time_ns()), ReflowReason::Query) + pub fn layout_reflow(&self, query_msg: QueryMsg) -> bool { + self.reflow(ReflowGoal::LayoutQuery(query_msg, 0u64), ReflowReason::Query) } pub fn layout(&self) -> &LayoutRPC { diff --git a/components/script_layout_interface/Cargo.toml b/components/script_layout_interface/Cargo.toml index caddb62a1de..18fb45385b8 100644 --- a/components/script_layout_interface/Cargo.toml +++ b/components/script_layout_interface/Cargo.toml @@ -20,6 +20,7 @@ html5ever = "0.22" ipc-channel = "0.9" libc = "0.2" log = "0.3.5" +time = "0.1.17" malloc_size_of = { path = "../malloc_size_of" } malloc_size_of_derive = { path = "../malloc_size_of_derive" } metrics = {path = "../metrics"} diff --git a/components/script_layout_interface/lib.rs b/components/script_layout_interface/lib.rs index dc2c6f515a7..289dd7c0c8b 100644 --- a/components/script_layout_interface/lib.rs +++ b/components/script_layout_interface/lib.rs @@ -33,6 +33,7 @@ extern crate servo_arc; extern crate servo_atoms; extern crate servo_url; extern crate style; +extern crate time; extern crate webrender_api; pub mod message; diff --git a/components/script_layout_interface/message.rs b/components/script_layout_interface/message.rs index ac52d9373ce..8a8b1f8b0d0 100644 --- a/components/script_layout_interface/message.rs +++ b/components/script_layout_interface/message.rs @@ -24,6 +24,7 @@ use style::context::QuirksMode; use style::properties::PropertyId; use style::selector_parser::PseudoElement; use style::stylesheets::Stylesheet; +use time; /// Asynchronous messages that script can send to layout. pub enum Msg { @@ -171,6 +172,26 @@ impl ReflowGoal { }, } } + + /// Set the timestamp of query message. + pub fn set_timestamp(&mut self) { + match *self { + ReflowGoal::LayoutQuery(_, ref mut timestamp) => { + *timestamp = time::precise_time_ns(); + }, + _ => (), + } + } + + /// Get the query timestamp. + pub fn timestamp(&self) -> Option { + match *self { + ReflowGoal::LayoutQuery(_, ref timestamp) => { + Some(*timestamp) + }, + _ => None, + } + } } /// Information needed for a reflow. From 054d65763dcd148d2dfecf7a51a5d3b0f61c5694 Mon Sep 17 00:00:00 2001 From: csmoe <35686186+csmoe@users.noreply.github.com> Date: Thu, 22 Mar 2018 12:27:38 +0800 Subject: [PATCH 3/3] fix time measure --- Cargo.lock | 7 +++++ components/layout_thread/Cargo.toml | 1 + components/layout_thread/lib.rs | 29 +++++++++++++------ components/script/dom/window.rs | 2 +- components/script_layout_interface/lib.rs | 1 - components/script_layout_interface/message.rs | 21 -------------- 6 files changed, 29 insertions(+), 32 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 8f6d1bf36a0..5d5a43b9eb9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1153,6 +1153,11 @@ dependencies = [ "pkg-config 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "histogram" +version = "0.6.8" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "html5ever" version = "0.22.0" @@ -1427,6 +1432,7 @@ dependencies = [ "fnv 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", "gfx 0.0.1", "gfx_traits 0.0.1", + "histogram 0.6.8 (registry+https://github.com/rust-lang/crates.io-index)", "html5ever 0.22.0 (registry+https://github.com/rust-lang/crates.io-index)", "ipc-channel 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", "layout 0.0.1", @@ -3796,6 +3802,7 @@ dependencies = [ "checksum harfbuzz-sys 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)" = "52aa65c5649a0a2f1b27ab30093b3cc84681e17ddb552267e21948c5a6fa6b05" "checksum heartbeats-simple 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9ad003ce233955e9d95f2c69cde84e68302ba9ba4a673d351c9bff93c738aadc" "checksum heartbeats-simple-sys 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "e1a408c0011427cc0e0049f7861c70377819aedfc006e8c901b1c70fd98fb1a4" +"checksum histogram 0.6.8 (registry+https://github.com/rust-lang/crates.io-index)" = "1bdcec4094c1ca961b685384ea7af76af5718230b3f34657d1a71fd2dcf4cc9d" "checksum html5ever 0.22.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e579ac8647178ab915d400d7d22938bda5cd351c6c62e1c294d56884ccfc75fe" "checksum httparse 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a6e7a63e511f9edffbab707141fbb8707d1a3098615fb2adbd5769cdfcc9b17d" "checksum hyper 0.10.13 (registry+https://github.com/rust-lang/crates.io-index)" = "368cb56b2740ebf4230520e2b90ebb0461e69034d85d1945febd9b3971426db2" diff --git a/components/layout_thread/Cargo.toml b/components/layout_thread/Cargo.toml index d07746c54c9..5c74a51b8bf 100644 --- a/components/layout_thread/Cargo.toml +++ b/components/layout_thread/Cargo.toml @@ -19,6 +19,7 @@ euclid = "0.17" fnv = "1.0" gfx = {path = "../gfx"} gfx_traits = {path = "../gfx_traits"} +histogram = "0.6.8" html5ever = "0.22" ipc-channel = "0.9" layout = {path = "../layout"} diff --git a/components/layout_thread/lib.rs b/components/layout_thread/lib.rs index d3798d6e05b..cdfa0f092c2 100644 --- a/components/layout_thread/lib.rs +++ b/components/layout_thread/lib.rs @@ -13,6 +13,7 @@ extern crate euclid; extern crate fnv; extern crate gfx; extern crate gfx_traits; +extern crate histogram; #[macro_use] extern crate html5ever; extern crate ipc_channel; @@ -61,6 +62,7 @@ use gfx::font; use gfx::font_cache_thread::FontCacheThread; use gfx::font_context; use gfx_traits::{Epoch, node_id_from_scroll_id}; +use histogram::Histogram; use ipc_channel::ipc::{self, IpcReceiver, IpcSender}; use ipc_channel::router::ROUTER; use layout::animation; @@ -263,7 +265,7 @@ pub struct LayoutThread { paint_time_metrics: PaintTimeMetrics, /// The time a layout query has waited before serviced by layout thread. - layout_query_timestamp: u64, + layout_query_waiting_time: Histogram, } impl LayoutThreadFactory for LayoutThread { @@ -551,7 +553,7 @@ impl LayoutThread { }, layout_threads: layout_threads, paint_time_metrics: paint_time_metrics, - layout_query_timestamp: 0u64, + layout_query_waiting_time: Histogram::new(), } } @@ -869,9 +871,16 @@ impl LayoutThread { // Drop the root flow explicitly to avoid holding style data, such as // rule nodes. The `Stylist` checks when it is dropped that all rule // nodes have been GCed, so we want drop anyone who holds them first. - let now = std_time::precise_time_ns(); - let waiting_time = now - self.layout_query_timestamp; - debug!("layout: query has been waited: {}", waiting_time); + let waiting_time_min = self.layout_query_waiting_time.minimum().unwrap_or(0); + let waiting_time_max = self.layout_query_waiting_time.maximum().unwrap_or(0); + let waiting_time_mean = self.layout_query_waiting_time.mean().unwrap_or(0); + let waiting_time_stddev = self.layout_query_waiting_time.stddev().unwrap_or(0); + debug!("layout: query waiting time: min: {}, max: {}, mean: {}, standard_deviation: {}", + waiting_time_min, + waiting_time_max, + waiting_time_mean, + waiting_time_stddev); + self.root_flow.borrow_mut().take(); // Drop the rayon threadpool if present. let _ = self.parallel_traversal.take(); @@ -1080,9 +1089,6 @@ impl LayoutThread { fn handle_reflow<'a, 'b>(&mut self, data: &mut ScriptReflowResult, possibly_locked_rw_data: &mut RwData<'a, 'b>) { - // Set layout query timestamp - data.reflow_goal.set_timestamp(); - let document = unsafe { ServoLayoutNode::new(&data.document) }; let document = document.as_document().unwrap(); @@ -1095,9 +1101,14 @@ impl LayoutThread { let mut rw_data = possibly_locked_rw_data.lock(); + // Record the time that layout query has been waited. + let now = std_time::precise_time_ns(); + if let ReflowGoal::LayoutQuery(_, timestamp) = data.reflow_goal { + self.layout_query_waiting_time.increment(now - timestamp).expect("layout: wrong layout query timestamp"); + }; + let element = match document.root_element() { None => { - self.layout_query_timestamp = data.reflow_goal.timestamp().expect("Not a QueryMsg"); // Since we cannot compute anything, give spec-required placeholders. debug!("layout: No root node: bailing"); match data.reflow_goal { diff --git a/components/script/dom/window.rs b/components/script/dom/window.rs index bbaee9ea7c8..4e91083c443 100644 --- a/components/script/dom/window.rs +++ b/components/script/dom/window.rs @@ -1375,7 +1375,7 @@ impl Window { } pub fn layout_reflow(&self, query_msg: QueryMsg) -> bool { - self.reflow(ReflowGoal::LayoutQuery(query_msg, 0u64), ReflowReason::Query) + self.reflow(ReflowGoal::LayoutQuery(query_msg, time::precise_time_ns()), ReflowReason::Query) } pub fn layout(&self) -> &LayoutRPC { diff --git a/components/script_layout_interface/lib.rs b/components/script_layout_interface/lib.rs index 289dd7c0c8b..dc2c6f515a7 100644 --- a/components/script_layout_interface/lib.rs +++ b/components/script_layout_interface/lib.rs @@ -33,7 +33,6 @@ extern crate servo_arc; extern crate servo_atoms; extern crate servo_url; extern crate style; -extern crate time; extern crate webrender_api; pub mod message; diff --git a/components/script_layout_interface/message.rs b/components/script_layout_interface/message.rs index 8a8b1f8b0d0..ac52d9373ce 100644 --- a/components/script_layout_interface/message.rs +++ b/components/script_layout_interface/message.rs @@ -24,7 +24,6 @@ use style::context::QuirksMode; use style::properties::PropertyId; use style::selector_parser::PseudoElement; use style::stylesheets::Stylesheet; -use time; /// Asynchronous messages that script can send to layout. pub enum Msg { @@ -172,26 +171,6 @@ impl ReflowGoal { }, } } - - /// Set the timestamp of query message. - pub fn set_timestamp(&mut self) { - match *self { - ReflowGoal::LayoutQuery(_, ref mut timestamp) => { - *timestamp = time::precise_time_ns(); - }, - _ => (), - } - } - - /// Get the query timestamp. - pub fn timestamp(&self) -> Option { - match *self { - ReflowGoal::LayoutQuery(_, ref timestamp) => { - Some(*timestamp) - }, - _ => None, - } - } } /// Information needed for a reflow.