Auto merge of #20307 - csmoe:measure_query_time, r=jdm

Measure time required before a layout query is serviced by the layout thread

<!-- Please describe your changes on the following line: -->

- [X] extract QueryMsg from ReflowGoal
- [X] introduce QueryMsg timestamp

---
<!-- Thank you for contributing to Servo! Please replace each `[ ]` by `[X]` when the step is complete, and replace `__` with appropriate data: -->
- [X] `./mach build -d` does not report any errors
- [X] `./mach test-tidy` does not report any errors
- [x] These changes fix #19795 (github issue number if applicable).

<!-- Either: -->
- [ ] There are tests for these changes OR
- [ ] These changes do not require tests because _____

<!-- Also, please make sure that "Allow edits from maintainers" checkbox is checked, so that we can help you if you get stuck somewhere along the way.-->

<!-- Pull requests that do not address these steps are welcome, but they will require additional verification as part of the review process. -->

<!-- Reviewable:start -->
---
This change is [<img src="https://reviewable.io/review_button.svg" height="34" align="absmiddle" alt="Reviewable"/>](https://reviewable.io/reviews/servo/servo/20307)
<!-- Reviewable:end -->
This commit is contained in:
bors-servo 2018-03-26 15:42:03 -04:00 committed by GitHub
commit 4b8416fafb
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
8 changed files with 218 additions and 156 deletions

9
Cargo.lock generated
View file

@ -1169,6 +1169,11 @@ dependencies = [
"pkg-config 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", "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]] [[package]]
name = "html5ever" name = "html5ever"
version = "0.22.0" version = "0.22.0"
@ -1443,6 +1448,7 @@ dependencies = [
"fnv 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", "fnv 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)",
"gfx 0.0.1", "gfx 0.0.1",
"gfx_traits 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)", "html5ever 0.22.0 (registry+https://github.com/rust-lang/crates.io-index)",
"ipc-channel 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)", "ipc-channel 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)",
"layout 0.0.1", "layout 0.0.1",
@ -1471,6 +1477,7 @@ dependencies = [
"servo_url 0.0.1", "servo_url 0.0.1",
"style 0.0.1", "style 0.0.1",
"style_traits 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)", "webrender_api 0.57.0 (git+https://github.com/servo/webrender)",
] ]
@ -2563,6 +2570,7 @@ dependencies = [
"servo_atoms 0.0.1", "servo_atoms 0.0.1",
"servo_url 0.0.1", "servo_url 0.0.1",
"style 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)", "webrender_api 0.57.0 (git+https://github.com/servo/webrender)",
] ]
@ -3847,6 +3855,7 @@ dependencies = [
"checksum harfbuzz-sys 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)" = "52aa65c5649a0a2f1b27ab30093b3cc84681e17ddb552267e21948c5a6fa6b05" "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 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 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 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 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" "checksum hyper 0.10.13 (registry+https://github.com/rust-lang/crates.io-index)" = "368cb56b2740ebf4230520e2b90ebb0461e69034d85d1945febd9b3971426db2"

View file

@ -19,6 +19,7 @@ euclid = "0.17"
fnv = "1.0" fnv = "1.0"
gfx = {path = "../gfx"} gfx = {path = "../gfx"}
gfx_traits = {path = "../gfx_traits"} gfx_traits = {path = "../gfx_traits"}
histogram = "0.6.8"
html5ever = "0.22" html5ever = "0.22"
ipc-channel = "0.10" ipc-channel = "0.10"
layout = {path = "../layout"} layout = {path = "../layout"}
@ -26,6 +27,7 @@ layout_traits = {path = "../layout_traits"}
lazy_static = "1" lazy_static = "1"
libc = "0.2" libc = "0.2"
log = "0.3.5" log = "0.3.5"
time = "0.1.17"
malloc_size_of = { path = "../malloc_size_of" } malloc_size_of = { path = "../malloc_size_of" }
metrics = {path = "../metrics"} metrics = {path = "../metrics"}
msg = {path = "../msg"} msg = {path = "../msg"}

View file

@ -13,6 +13,7 @@ extern crate euclid;
extern crate fnv; extern crate fnv;
extern crate gfx; extern crate gfx;
extern crate gfx_traits; extern crate gfx_traits;
extern crate histogram;
#[macro_use] #[macro_use]
extern crate html5ever; extern crate html5ever;
extern crate ipc_channel; extern crate ipc_channel;
@ -46,6 +47,7 @@ extern crate servo_geometry;
extern crate servo_url; extern crate servo_url;
extern crate style; extern crate style;
extern crate style_traits; extern crate style_traits;
extern crate time as std_time;
extern crate webrender_api; extern crate webrender_api;
mod dom_wrapper; mod dom_wrapper;
@ -60,6 +62,7 @@ use gfx::font;
use gfx::font_cache_thread::FontCacheThread; use gfx::font_cache_thread::FontCacheThread;
use gfx::font_context; use gfx::font_context;
use gfx_traits::{Epoch, node_id_from_scroll_id}; use gfx_traits::{Epoch, node_id_from_scroll_id};
use histogram::Histogram;
use ipc_channel::ipc::{self, IpcReceiver, IpcSender}; use ipc_channel::ipc::{self, IpcReceiver, IpcSender};
use ipc_channel::router::ROUTER; use ipc_channel::router::ROUTER;
use layout::animation; use layout::animation;
@ -94,7 +97,7 @@ use profile_traits::mem::{self, Report, ReportKind, ReportsChan};
use profile_traits::time::{self, TimerMetadata, profile}; use profile_traits::time::{self, TimerMetadata, profile};
use profile_traits::time::{TimerMetadataFrameType, TimerMetadataReflowType}; use profile_traits::time::{TimerMetadataFrameType, TimerMetadataReflowType};
use script_layout_interface::message::{Msg, NewLayoutThreadInfo, NodesFromPointQueryType, Reflow}; 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::{LayoutRPC, StyleResponse, OffsetParentResponse};
use script_layout_interface::rpc::TextIndexResponse; use script_layout_interface::rpc::TextIndexResponse;
use script_layout_interface::wrapper_traits::LayoutNode; use script_layout_interface::wrapper_traits::LayoutNode;
@ -260,6 +263,9 @@ pub struct LayoutThread {
/// Paint time metrics. /// Paint time metrics.
paint_time_metrics: PaintTimeMetrics, paint_time_metrics: PaintTimeMetrics,
/// The time a layout query has waited before serviced by layout thread.
layout_query_waiting_time: Histogram,
} }
impl LayoutThreadFactory for LayoutThread { impl LayoutThreadFactory for LayoutThread {
@ -332,6 +338,12 @@ impl Deref for ScriptReflowResult {
} }
} }
impl DerefMut for ScriptReflowResult {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.script_reflow
}
}
impl ScriptReflowResult { impl ScriptReflowResult {
fn new(script_reflow: ScriptReflow) -> ScriptReflowResult { fn new(script_reflow: ScriptReflow) -> ScriptReflowResult {
ScriptReflowResult { ScriptReflowResult {
@ -541,6 +553,7 @@ impl LayoutThread {
}, },
layout_threads: layout_threads, layout_threads: layout_threads,
paint_time_metrics: paint_time_metrics, paint_time_metrics: paint_time_metrics,
layout_query_waiting_time: Histogram::new(),
} }
} }
@ -858,6 +871,16 @@ impl LayoutThread {
// Drop the root flow explicitly to avoid holding style data, such as // Drop the root flow explicitly to avoid holding style data, such as
// rule nodes. The `Stylist` checks when it is dropped that all rule // 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. // nodes have been GCed, so we want drop anyone who holds them first.
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(); self.root_flow.borrow_mut().take();
// Drop the rayon threadpool if present. // Drop the rayon threadpool if present.
let _ = self.parallel_traversal.take(); let _ = self.parallel_traversal.take();
@ -1078,43 +1101,51 @@ impl LayoutThread {
let mut rw_data = possibly_locked_rw_data.lock(); 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() { let element = match document.root_element() {
None => { None => {
// Since we cannot compute anything, give spec-required placeholders. // Since we cannot compute anything, give spec-required placeholders.
debug!("layout: No root node: bailing"); debug!("layout: No root node: bailing");
match data.reflow_goal { match data.reflow_goal {
ReflowGoal::ContentBoxQuery(_) => { ReflowGoal::LayoutQuery(ref query_msg, _) => match query_msg {
rw_data.content_box_response = None; &QueryMsg::ContentBoxQuery(_) => {
}, rw_data.content_box_response = None;
ReflowGoal::ContentBoxesQuery(_) => { },
rw_data.content_boxes_response = Vec::new(); &QueryMsg::ContentBoxesQuery(_) => {
}, rw_data.content_boxes_response = Vec::new();
ReflowGoal::NodesFromPointQuery(..) => { },
rw_data.nodes_from_point_response = Vec::new(); &QueryMsg::NodesFromPointQuery(..) => {
}, rw_data.nodes_from_point_response = Vec::new();
ReflowGoal::NodeGeometryQuery(_) => { },
rw_data.client_rect_response = Rect::zero(); &QueryMsg::NodeGeometryQuery(_) => {
}, rw_data.client_rect_response = Rect::zero();
ReflowGoal::NodeScrollGeometryQuery(_) => { },
rw_data.scroll_area_response = Rect::zero(); &QueryMsg::NodeScrollGeometryQuery(_) => {
}, rw_data.scroll_area_response = Rect::zero();
ReflowGoal::NodeScrollIdQuery(_) => { },
rw_data.scroll_id_response = None; &QueryMsg::NodeScrollIdQuery(_) => {
}, rw_data.scroll_id_response = None;
ReflowGoal::ResolvedStyleQuery(_, _, _) => { },
rw_data.resolved_style_response = String::new(); &QueryMsg::ResolvedStyleQuery(_, _, _) => {
}, rw_data.resolved_style_response = String::new();
ReflowGoal::OffsetParentQuery(_) => { },
rw_data.offset_parent_response = OffsetParentResponse::empty(); &QueryMsg::OffsetParentQuery(_) => {
}, rw_data.offset_parent_response = OffsetParentResponse::empty();
ReflowGoal::StyleQuery(_) => { },
rw_data.style_response = StyleResponse(None); &QueryMsg::StyleQuery(_) => {
}, rw_data.style_response = StyleResponse(None);
ReflowGoal::TextIndexQuery(..) => { },
rw_data.text_index_response = TextIndexResponse(None); &QueryMsg::TextIndexQuery(..) => {
} rw_data.text_index_response = TextIndexResponse(None);
ReflowGoal::ElementInnerTextQuery(_) => { }
rw_data.element_inner_text_response = String::new(); &QueryMsg::ElementInnerTextQuery(_) => {
rw_data.element_inner_text_response = String::new();
},
}, },
ReflowGoal::Full | ReflowGoal:: TickAnimations => {} ReflowGoal::Full | ReflowGoal:: TickAnimations => {}
} }
@ -1355,80 +1386,82 @@ impl LayoutThread {
}; };
let root_flow = FlowRef::deref_mut(&mut root_flow); let root_flow = FlowRef::deref_mut(&mut root_flow);
match *reflow_goal { match *reflow_goal {
ReflowGoal::ContentBoxQuery(node) => { ReflowGoal::LayoutQuery(ref querymsg, _) => match querymsg {
let node = unsafe { ServoLayoutNode::new(&node) }; &QueryMsg::ContentBoxQuery(node) => {
rw_data.content_box_response = process_content_box_request(node, root_flow); 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) }; &QueryMsg::ContentBoxesQuery(node) => {
rw_data.content_boxes_response = process_content_boxes_request(node, root_flow); 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) }; &QueryMsg::TextIndexQuery(node, point_in_node) => {
let opaque_node = node.opaque(); let node = unsafe { ServoLayoutNode::new(&node) };
let point_in_node = Point2D::new( let opaque_node = node.opaque();
Au::from_f32_px(point_in_node.x), let point_in_node = Point2D::new(
Au::from_f32_px(point_in_node.y) 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) 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) }; &QueryMsg::NodeGeometryQuery(node) => {
rw_data.client_rect_response = process_node_geometry_request(node, root_flow); 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) }; &QueryMsg::NodeScrollGeometryQuery(node) => {
rw_data.scroll_area_response = process_node_scroll_area_request(node, root_flow); 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) }; &QueryMsg::NodeScrollIdQuery(node) => {
rw_data.scroll_id_response = Some(process_node_scroll_id_request(self.id, 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) }; &QueryMsg::ResolvedStyleQuery(node, ref pseudo, ref property) => {
rw_data.resolved_style_response = let node = unsafe { ServoLayoutNode::new(&node) };
process_resolved_style_request(context, rw_data.resolved_style_response =
node, process_resolved_style_request(context,
pseudo, node,
property, pseudo,
root_flow); property,
}, root_flow);
ReflowGoal::OffsetParentQuery(node) => { },
let node = unsafe { ServoLayoutNode::new(&node) }; &QueryMsg::OffsetParentQuery(node) => {
rw_data.offset_parent_response = process_offset_parent_query(node, root_flow); 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) }; &QueryMsg::StyleQuery(node) => {
rw_data.style_response = process_style_query(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 { &QueryMsg::NodesFromPointQuery(client_point, ref reflow_goal) => {
&NodesFromPointQueryType::Topmost => webrender_api::HitTestFlags::empty(), let mut flags = match reflow_goal {
&NodesFromPointQueryType::All => webrender_api::HitTestFlags::FIND_ALL, &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 // 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. // particular pipeline, so we need to tell WebRender about that.
flags.insert(webrender_api::HitTestFlags::POINT_RELATIVE_TO_PIPELINE_VIEWPORT); flags.insert(webrender_api::HitTestFlags::POINT_RELATIVE_TO_PIPELINE_VIEWPORT);
let client_point = webrender_api::WorldPoint::from_untyped(&client_point); let client_point = webrender_api::WorldPoint::from_untyped(&client_point);
let results = self.webrender_api.hit_test( let results = self.webrender_api.hit_test(
self.webrender_document, self.webrender_document,
Some(self.id.to_webrender()), Some(self.id.to_webrender()),
client_point, client_point,
flags flags
); );
rw_data.nodes_from_point_response = results.items.iter() rw_data.nodes_from_point_response = results.items.iter()
.map(|item| UntrustedNodeAddress(item.tag.0 as *const c_void)) .map(|item| UntrustedNodeAddress(item.tag.0 as *const c_void))
.collect() .collect()
}, },
ReflowGoal::ElementInnerTextQuery(node) => { &QueryMsg::ElementInnerTextQuery(node) => {
let node = unsafe { ServoLayoutNode::new(&node) }; let node = unsafe { ServoLayoutNode::new(&node) };
rw_data.element_inner_text_response = rw_data.element_inner_text_response =
process_element_inner_text_query(node, &rw_data.indexable_text); process_element_inner_text_query(node, &rw_data.indexable_text);
},
}, },
ReflowGoal::Full | ReflowGoal::TickAnimations => {} ReflowGoal::Full | ReflowGoal::TickAnimations => {}
} }

View file

@ -109,7 +109,7 @@ use num_traits::ToPrimitive;
use profile_traits::ipc; use profile_traits::ipc;
use profile_traits::time::{TimerMetadata, TimerMetadataFrameType, TimerMetadataReflowType}; use profile_traits::time::{TimerMetadata, TimerMetadataFrameType, TimerMetadataReflowType};
use ref_slice::ref_slice; 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_runtime::{CommonScriptMsg, ScriptThreadEventCategory};
use script_thread::{MainThreadScriptMsg, ScriptThread}; use script_thread::{MainThreadScriptMsg, ScriptThread};
use script_traits::{AnimationState, DocumentActivity, MouseButton, MouseEventType}; use script_traits::{AnimationState, DocumentActivity, MouseButton, MouseEventType};
@ -1969,8 +1969,7 @@ impl Document {
client_point: &Point2D<f32>, client_point: &Point2D<f32>,
reflow_goal: NodesFromPointQueryType) reflow_goal: NodesFromPointQueryType)
-> Vec<UntrustedNodeAddress> { -> Vec<UntrustedNodeAddress> {
if !self.window.reflow(ReflowGoal::NodesFromPointQuery(*client_point, reflow_goal), if !self.window.layout_reflow(QueryMsg::NodesFromPointQuery(*client_point, reflow_goal)) {
ReflowReason::Query) {
return vec!(); return vec!();
}; };

View file

@ -32,10 +32,9 @@ use dom::node::{document_from_node, window_from_node};
use dom::nodelist::NodeList; use dom::nodelist::NodeList;
use dom::text::Text; use dom::text::Text;
use dom::virtualmethods::VirtualMethods; use dom::virtualmethods::VirtualMethods;
use dom::window::ReflowReason;
use dom_struct::dom_struct; use dom_struct::dom_struct;
use html5ever::{LocalName, Prefix}; use html5ever::{LocalName, Prefix};
use script_layout_interface::message::ReflowGoal; use script_layout_interface::message::QueryMsg;
use std::collections::HashSet; use std::collections::HashSet;
use std::default::Default; use std::default::Default;
use std::rc::Rc; use std::rc::Rc;
@ -419,7 +418,7 @@ impl HTMLElementMethods for HTMLElement {
return node.GetTextContent().unwrap(); return node.GetTextContent().unwrap();
} }
window.reflow(ReflowGoal::ElementInnerTextQuery(node.to_trusted_node_address()), ReflowReason::Query); window.layout_reflow(QueryMsg::ElementInnerTextQuery(node.to_trusted_node_address()));
DOMString::from(window.layout().element_inner_text()) DOMString::from(window.layout().element_inner_text())
} }

View file

@ -67,7 +67,7 @@ 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::{TrustedNodeAddress, PendingImageState}; 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::reporter::CSSErrorReporter;
use script_layout_interface::rpc::{ContentBoxResponse, ContentBoxesResponse, LayoutRPC}; use script_layout_interface::rpc::{ContentBoxResponse, ContentBoxesResponse, LayoutRPC};
use script_layout_interface::rpc::{NodeScrollIdResponse, ResolvedStyleResponse, TextIndexResponse}; use script_layout_interface::rpc::{NodeScrollIdResponse, ResolvedStyleResponse, TextIndexResponse};
@ -1385,12 +1385,16 @@ impl Window {
issued_reflow issued_reflow
} }
pub fn layout_reflow(&self, query_msg: QueryMsg) -> bool {
self.reflow(ReflowGoal::LayoutQuery(query_msg, time::precise_time_ns()), ReflowReason::Query)
}
pub fn layout(&self) -> &LayoutRPC { pub fn layout(&self) -> &LayoutRPC {
&*self.layout_rpc &*self.layout_rpc
} }
pub fn content_box_query(&self, content_box_request: TrustedNodeAddress) -> Option<Rect<Au>> { pub fn content_box_query(&self, content_box_request: TrustedNodeAddress) -> Option<Rect<Au>> {
if !self.reflow(ReflowGoal::ContentBoxQuery(content_box_request), ReflowReason::Query) { if !self.layout_reflow(QueryMsg::ContentBoxQuery(content_box_request)) {
return None; return None;
} }
let ContentBoxResponse(rect) = self.layout_rpc.content_box(); let ContentBoxResponse(rect) = self.layout_rpc.content_box();
@ -1398,7 +1402,7 @@ impl Window {
} }
pub fn content_boxes_query(&self, content_boxes_request: TrustedNodeAddress) -> Vec<Rect<Au>> { pub fn content_boxes_query(&self, content_boxes_request: TrustedNodeAddress) -> Vec<Rect<Au>> {
if !self.reflow(ReflowGoal::ContentBoxesQuery(content_boxes_request), ReflowReason::Query) { if !self.layout_reflow(QueryMsg::ContentBoxesQuery(content_boxes_request)) {
return vec![]; return vec![];
} }
let ContentBoxesResponse(rects) = self.layout_rpc.content_boxes(); let ContentBoxesResponse(rects) = self.layout_rpc.content_boxes();
@ -1406,14 +1410,14 @@ impl Window {
} }
pub fn client_rect_query(&self, node_geometry_request: TrustedNodeAddress) -> Rect<i32> { pub fn client_rect_query(&self, node_geometry_request: TrustedNodeAddress) -> Rect<i32> {
if !self.reflow(ReflowGoal::NodeGeometryQuery(node_geometry_request), ReflowReason::Query) { if !self.layout_reflow(QueryMsg::NodeGeometryQuery(node_geometry_request)) {
return Rect::zero(); return Rect::zero();
} }
self.layout_rpc.node_geometry().client_rect self.layout_rpc.node_geometry().client_rect
} }
pub fn scroll_area_query(&self, node: TrustedNodeAddress) -> Rect<i32> { pub fn scroll_area_query(&self, node: TrustedNodeAddress) -> Rect<i32> {
if !self.reflow(ReflowGoal::NodeScrollGeometryQuery(node), ReflowReason::Query) { if !self.layout_reflow(QueryMsg::NodeScrollGeometryQuery(node)) {
return Rect::zero(); return Rect::zero();
} }
self.layout_rpc.node_scroll_area().client_rect self.layout_rpc.node_scroll_area().client_rect
@ -1436,10 +1440,7 @@ impl Window {
y_: f64, y_: f64,
behavior: ScrollBehavior behavior: ScrollBehavior
) { ) {
if !self.reflow( if !self.layout_reflow(QueryMsg::NodeScrollIdQuery(node.to_trusted_node_address())) {
ReflowGoal::NodeScrollIdQuery(node.to_trusted_node_address()),
ReflowReason::Query
) {
return; return;
} }
@ -1463,8 +1464,7 @@ impl Window {
element: TrustedNodeAddress, element: TrustedNodeAddress,
pseudo: Option<PseudoElement>, pseudo: Option<PseudoElement>,
property: PropertyId) -> DOMString { property: PropertyId) -> DOMString {
if !self.reflow(ReflowGoal::ResolvedStyleQuery(element, pseudo, property), if !self.layout_reflow(QueryMsg::ResolvedStyleQuery(element, pseudo, property)) {
ReflowReason::Query) {
return DOMString::new(); return DOMString::new();
} }
let ResolvedStyleResponse(resolved) = self.layout_rpc.resolved_style(); let ResolvedStyleResponse(resolved) = self.layout_rpc.resolved_style();
@ -1473,7 +1473,7 @@ impl Window {
#[allow(unsafe_code)] #[allow(unsafe_code)]
pub fn offset_parent_query(&self, node: TrustedNodeAddress) -> (Option<DomRoot<Element>>, Rect<Au>) { pub fn offset_parent_query(&self, node: TrustedNodeAddress) -> (Option<DomRoot<Element>>, Rect<Au>) {
if !self.reflow(ReflowGoal::OffsetParentQuery(node), ReflowReason::Query) { if !self.layout_reflow(QueryMsg::OffsetParentQuery(node)) {
return (None, Rect::zero()); return (None, Rect::zero());
} }
@ -1488,7 +1488,7 @@ impl Window {
} }
pub fn style_query(&self, node: TrustedNodeAddress) -> Option<servo_arc::Arc<ComputedValues>> { pub fn style_query(&self, node: TrustedNodeAddress) -> Option<servo_arc::Arc<ComputedValues>> {
if !self.reflow(ReflowGoal::StyleQuery(node), ReflowReason::Query) { if !self.layout_reflow(QueryMsg::StyleQuery(node)) {
return None return None
} }
self.layout_rpc.style().0 self.layout_rpc.style().0
@ -1499,7 +1499,7 @@ impl Window {
node: TrustedNodeAddress, node: TrustedNodeAddress,
point_in_node: Point2D<f32> point_in_node: Point2D<f32>
) -> TextIndexResponse { ) -> 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); return TextIndexResponse(None);
} }
self.layout_rpc.text_index() self.layout_rpc.text_index()
@ -1881,18 +1881,20 @@ fn debug_reflow_events(id: PipelineId, reflow_goal: &ReflowGoal, reason: &Reflow
let mut debug_msg = format!("**** pipeline={}", id); let mut debug_msg = format!("**** pipeline={}", id);
debug_msg.push_str(match *reflow_goal { debug_msg.push_str(match *reflow_goal {
ReflowGoal::Full => "\tFull", 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::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 { debug_msg.push_str(match *reason {

View file

@ -20,6 +20,7 @@ html5ever = "0.22"
ipc-channel = "0.10" ipc-channel = "0.10"
libc = "0.2" libc = "0.2"
log = "0.3.5" log = "0.3.5"
time = "0.1.17"
malloc_size_of = { path = "../malloc_size_of" } malloc_size_of = { path = "../malloc_size_of" }
malloc_size_of_derive = { path = "../malloc_size_of_derive" } malloc_size_of_derive = { path = "../malloc_size_of_derive" }
metrics = {path = "../metrics"} metrics = {path = "../metrics"}

View file

@ -2,7 +2,7 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this * 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/. */ * 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 app_units::Au;
use euclid::{Point2D, Rect}; use euclid::{Point2D, Rect};
use gfx_traits::Epoch; use gfx_traits::Epoch;
@ -106,11 +106,8 @@ pub enum NodesFromPointQueryType {
Topmost, Topmost,
} }
/// Any query to perform with this reflow.
#[derive(Debug, PartialEq)] #[derive(Debug, PartialEq)]
pub enum ReflowGoal { pub enum QueryMsg {
Full,
TickAnimations,
ContentBoxQuery(TrustedNodeAddress), ContentBoxQuery(TrustedNodeAddress),
ContentBoxesQuery(TrustedNodeAddress), ContentBoxesQuery(TrustedNodeAddress),
NodeScrollIdQuery(TrustedNodeAddress), NodeScrollIdQuery(TrustedNodeAddress),
@ -124,19 +121,33 @@ pub enum ReflowGoal {
ElementInnerTextQuery(TrustedNodeAddress), ElementInnerTextQuery(TrustedNodeAddress),
} }
/// Any query to perform with this reflow.
#[derive(Debug, PartialEq)]
pub enum ReflowGoal {
Full,
TickAnimations,
LayoutQuery(QueryMsg, u64),
}
impl ReflowGoal { impl ReflowGoal {
/// Returns true if the given ReflowQuery needs a full, up-to-date display list to /// 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. /// be present or false if it only needs stacking-relative positions.
pub fn needs_display_list(&self) -> bool { pub fn needs_display_list(&self) -> bool {
match *self { match *self {
ReflowGoal::NodesFromPointQuery(..) | ReflowGoal::TextIndexQuery(..) | ReflowGoal::Full | ReflowGoal::TickAnimations => true,
ReflowGoal::TickAnimations | ReflowGoal::ElementInnerTextQuery(_) | ReflowGoal::LayoutQuery(ref querymsg, _) => match querymsg {
ReflowGoal::Full => true, &QueryMsg::NodesFromPointQuery(..) |
ReflowGoal::ContentBoxQuery(_) | ReflowGoal::ContentBoxesQuery(_) | &QueryMsg::TextIndexQuery(..) |
ReflowGoal::NodeGeometryQuery(_) | ReflowGoal::NodeScrollGeometryQuery(_) | &QueryMsg::ElementInnerTextQuery(_) => true,
ReflowGoal::NodeScrollIdQuery(_) | &QueryMsg::ContentBoxQuery(_) |
ReflowGoal::ResolvedStyleQuery(..) | ReflowGoal::OffsetParentQuery(_) | &QueryMsg::ContentBoxesQuery(_) |
ReflowGoal::StyleQuery(_) => false, &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. /// false if a layout_thread display list is sufficient.
pub fn needs_display(&self) -> bool { pub fn needs_display(&self) -> bool {
match *self { match *self {
ReflowGoal::StyleQuery(_) | ReflowGoal::TextIndexQuery(..) | ReflowGoal::Full | ReflowGoal::TickAnimations => true,
ReflowGoal::ContentBoxQuery(_) | ReflowGoal::ContentBoxesQuery(_) | ReflowGoal::LayoutQuery(ref querymsg, _) => match querymsg {
ReflowGoal::NodeGeometryQuery(_) | ReflowGoal::NodeScrollGeometryQuery(_) | &QueryMsg::NodesFromPointQuery(..) |
ReflowGoal::NodeScrollIdQuery(_) | ReflowGoal::ResolvedStyleQuery(..) | &QueryMsg::TextIndexQuery(..) |
ReflowGoal::OffsetParentQuery(_) => false, &QueryMsg::ElementInnerTextQuery(_) => true,
ReflowGoal::NodesFromPointQuery(..) | ReflowGoal::Full | &QueryMsg::ContentBoxQuery(_) |
ReflowGoal::ElementInnerTextQuery(_) | &QueryMsg::ContentBoxesQuery(_) |
ReflowGoal::TickAnimations => true, &QueryMsg::NodeGeometryQuery(_) |
&QueryMsg::NodeScrollGeometryQuery(_) |
&QueryMsg::NodeScrollIdQuery(_) |
&QueryMsg::ResolvedStyleQuery(..) |
&QueryMsg::OffsetParentQuery(_) |
&QueryMsg::StyleQuery(_) => false,
},
} }
} }
} }