Auto merge of #10021 - pcwalton:skip-layout-traversals, r=mbrubeck

layout: Skip layout traversals that obviously won't do anything.

This reduces CPU usage when mousing over simple pages (example.com). More complex pages (Wikipedia) still reflow a lot due to other bugs.

Additionally, this change causes Servo to stop painting the results of hit test queries. This is also a win for CPU usage.

This significantly improves #9999, though there's more that can be done. I'll leave it open in case @paulrouget thinks this PR isn't enough.

r? @mbrubeck

<!-- Reviewable:start -->
---
This change is [<img src="https://reviewable.io/review_button.svg" height="35" align="absmiddle" alt="Reviewable"/>](https://reviewable.io/reviews/servo/servo/10021)
<!-- Reviewable:end -->
This commit is contained in:
bors-servo 2016-03-22 03:37:49 +05:30
commit 9813d11f86
4 changed files with 71 additions and 56 deletions

View file

@ -167,7 +167,8 @@ pub fn compute_damage(old: Option<&Arc<ComputedValues>>, new: &ComputedValues) -
[ REPAINT ], [
get_color.color, get_background.background_color,
get_border.border_top_color, get_border.border_right_color,
get_border.border_bottom_color, get_border.border_left_color
get_border.border_bottom_color, get_border.border_left_color,
get_effects.transform, get_box.z_index
]);
add_if_not_equal!(old, new, damage,
@ -252,7 +253,6 @@ impl<'a> LayoutDamageComputation for &'a mut Flow {
has_counter_affecting_children = has_counter_affecting_children ||
flow::base(kid).flags.intersects(AFFECTS_COUNTERS |
HAS_COUNTER_AFFECTING_CHILDREN);
}
}

View file

@ -30,7 +30,8 @@ use gfx::font_context;
use gfx::paint_thread::LayoutToPaintMsg;
use gfx_traits::{color, Epoch, LayerId, ScrollPolicy};
use heapsize::HeapSizeOf;
use incremental::{LayoutDamageComputation, REFLOW, REFLOW_ENTIRE_DOCUMENT, REPAINT};
use incremental::{LayoutDamageComputation, REFLOW, REFLOW_ENTIRE_DOCUMENT, REFLOW_OUT_OF_FLOW};
use incremental::{REPAINT};
use ipc_channel::ipc::{self, IpcReceiver, IpcSender};
use ipc_channel::router::ROUTER;
use layout_debug;
@ -869,6 +870,8 @@ impl LayoutThread {
flow::mut_base(flow_ref::deref_mut(layout_root)).clip =
ClippingRegion::from_rect(&data.page_clip_rect);
if flow::base(&**layout_root).restyle_damage.contains(REPAINT) ||
rw_data.display_list.is_none() {
let mut root_stacking_context =
StackingContext::new(StackingContextId::new(0),
StackingContextType::Real,
@ -888,7 +891,6 @@ impl LayoutThread {
&mut root_stacking_context,
shared_layout_context);
if data.goal == ReflowGoal::ForDisplay {
debug!("Done building display list.");
let root_background_color = get_root_flow_background_color(
@ -905,13 +907,20 @@ impl LayoutThread {
let origin = Rect::new(Point2D::new(Au(0), Au(0)), root_size);
root_stacking_context.bounds = origin;
root_stacking_context.overflow = origin;
root_stacking_context.layer_info = Some(LayerInfo::new(layout_root.layer_id(),
root_stacking_context.layer_info =
Some(LayerInfo::new(layout_root.layer_id(),
ScrollPolicy::Scrollable,
None,
root_background_color));
let display_list = DisplayList::new(root_stacking_context,
&mut Some(display_list_entries));
rw_data.display_list =
Some(Arc::new(DisplayList::new(root_stacking_context,
&mut Some(display_list_entries))))
}
if data.goal == ReflowGoal::ForDisplay {
let display_list = (*rw_data.display_list.as_ref().unwrap()).clone();
if opts::get().dump_display_list {
display_list.print();
}
@ -919,9 +928,6 @@ impl LayoutThread {
println!("{}", serde_json::to_string_pretty(&display_list).unwrap());
}
let display_list = Arc::new(display_list);
rw_data.display_list = Some(display_list.clone());
debug!("Layout done!");
self.epoch.next();
@ -942,7 +948,10 @@ impl LayoutThread {
epoch,
Some(root_scroll_layer_id),
&mut auxiliary_lists_builder);
let root_background_color = webrender_traits::ColorF::new(root_background_color.r,
let root_background_color = get_root_flow_background_color(
flow_ref::deref_mut(layout_root));
let root_background_color =
webrender_traits::ColorF::new(root_background_color.r,
root_background_color.g,
root_background_color.b,
root_background_color.a);
@ -1323,6 +1332,7 @@ impl LayoutThread {
// Perform the primary layout passes over the flow tree to compute the locations of all
// the boxes.
if flow::base(&*root_flow).restyle_damage.intersects(REFLOW | REFLOW_OUT_OF_FLOW) {
profile(time::ProfilerCategory::LayoutMain,
self.profiler_metadata(),
self.time_profiler_chan.clone(),
@ -1343,6 +1353,7 @@ impl LayoutThread {
}
}
});
}
profile(time::ProfilerCategory::LayoutStoreOverflow,
self.profiler_metadata(),

View file

@ -234,6 +234,6 @@ impl<'a> BuildDisplayList<'a> {
#[inline]
fn should_process(&self) -> bool {
self.state.layout_context.shared_context().goal == ReflowGoal::ForDisplay
true
}
}

View file

@ -1021,7 +1021,11 @@ impl Window {
debug!("script: layout joined");
// Pending reflows require display, so only reset the pending reflow count if this reflow
// was to be displayed.
if goal == ReflowGoal::ForDisplay {
self.pending_reflow_count.set(0);
}
if let Some(marker) = marker {
self.emit_timeline_marker(marker.end());
@ -1104,7 +1108,7 @@ impl Window {
pub fn hit_test_query(&self, hit_test_request: Point2D<f32>, update_cursor: bool)
-> Option<UntrustedNodeAddress> {
self.reflow(ReflowGoal::ForDisplay,
self.reflow(ReflowGoal::ForScriptQuery,
ReflowQueryType::HitTestQuery(hit_test_request, update_cursor),
ReflowReason::Query);
self.layout_rpc.hit_test().node_address