Auto merge of #7557 - glennw:fix-layout-panic, r=pcwalton

Handle cases where the layout root is None. Fixes #6375.



<!-- Reviewable:start -->
[<img src="https://reviewable.io/review_button.png" height=40 alt="Review on Reviewable"/>](https://reviewable.io/reviews/servo/servo/7557)
<!-- Reviewable:end -->
This commit is contained in:
bors-servo 2015-09-08 20:39:09 -06:00
commit 4221b354cf
3 changed files with 196 additions and 96 deletions

View file

@ -156,6 +156,14 @@ pub struct LayoutTaskData {
pub visible_rects: Arc<HashMap<LayerId, Rect<Au>, DefaultState<FnvHasher>>>, pub visible_rects: Arc<HashMap<LayerId, Rect<Au>, DefaultState<FnvHasher>>>,
} }
impl LayoutTaskData {
pub fn layout_root(&self) -> Option<FlowRef> {
self.root_flow.as_ref().map(|root_flow| {
root_flow.clone()
})
}
}
/// Information needed by the layout task. /// Information needed by the layout task.
pub struct LayoutTask { pub struct LayoutTask {
/// The ID of the pipeline that we belong to. /// The ID of the pipeline that we belong to.
@ -786,10 +794,6 @@ impl LayoutTask {
Some(flow) Some(flow)
} }
fn get_layout_root(&self, node: LayoutNode) -> FlowRef {
self.try_get_layout_root(node).expect("no layout root")
}
/// Performs layout constraint solving. /// Performs layout constraint solving.
/// ///
/// This corresponds to `Reflow()` in Gecko and `layout()` in WebKit/Blink and should be /// This corresponds to `Reflow()` in Gecko and `layout()` in WebKit/Blink and should be
@ -1161,7 +1165,7 @@ impl LayoutTask {
}); });
// Retrieve the (possibly rebuilt) root flow. // Retrieve the (possibly rebuilt) root flow.
rw_data.root_flow = Some(self.get_layout_root((*node).clone())); rw_data.root_flow = self.try_get_layout_root((*node).clone());
// Kick off animations if any were triggered. // Kick off animations if any were triggered.
animation::process_new_animations(&mut *rw_data, self.id); animation::process_new_animations(&mut *rw_data, self.id);
@ -1178,22 +1182,22 @@ impl LayoutTask {
&mut rw_data, &mut rw_data,
&mut shared_layout_context); &mut shared_layout_context);
let mut root_flow = (*rw_data.root_flow.as_ref().unwrap()).clone(); if let Some(mut root_flow) = rw_data.layout_root() {
match data.query_type { match data.query_type {
ReflowQueryType::ContentBoxQuery(node) => ReflowQueryType::ContentBoxQuery(node) =>
process_content_box_request(node, &mut root_flow, &mut rw_data), process_content_box_request(node, &mut root_flow, &mut rw_data),
ReflowQueryType::ContentBoxesQuery(node) => ReflowQueryType::ContentBoxesQuery(node) =>
process_content_boxes_request(node, &mut root_flow, &mut rw_data), process_content_boxes_request(node, &mut root_flow, &mut rw_data),
ReflowQueryType::NodeGeometryQuery(node) => ReflowQueryType::NodeGeometryQuery(node) =>
self.process_node_geometry_request(node, &mut root_flow, &mut rw_data), self.process_node_geometry_request(node, &mut root_flow, &mut rw_data),
ReflowQueryType::ResolvedStyleQuery(node, ref pseudo, ref property) => ReflowQueryType::ResolvedStyleQuery(node, ref pseudo, ref property) =>
self.process_resolved_style_request(node, pseudo, property, &mut root_flow, &mut rw_data), self.process_resolved_style_request(node, pseudo, property, &mut root_flow, &mut rw_data),
ReflowQueryType::OffsetParentQuery(node) => ReflowQueryType::OffsetParentQuery(node) =>
self.process_offset_parent_query(node, &mut root_flow, &mut rw_data), self.process_offset_parent_query(node, &mut root_flow, &mut rw_data),
ReflowQueryType::NoQuery => {} ReflowQueryType::NoQuery => {}
}
} }
// Tell script that we're done. // Tell script that we're done.
// //
// FIXME(pcwalton): This should probably be *one* channel, but we can't fix this without // FIXME(pcwalton): This should probably be *one* channel, but we can't fix this without
@ -1279,23 +1283,16 @@ impl LayoutTask {
&self.url, &self.url,
reflow_info.goal); reflow_info.goal);
match rw_data.root_flow.as_ref() { if let Some(mut root_flow) = rw_data.layout_root() {
None => { // Perform an abbreviated style recalc that operates without access to the DOM.
// We haven't performed a single layout yet! Do nothing. let animations = &*rw_data.running_animations;
return profile(time::ProfilerCategory::LayoutStyleRecalc,
} self.profiler_metadata(),
Some(ref root_flow) => { self.time_profiler_chan.clone(),
// Perform an abbreviated style recalc that operates without access to the DOM. || {
let mut root_flow = (*root_flow).clone(); animation::recalc_style_for_animations(flow_ref::deref_mut(&mut root_flow),
let animations = &*rw_data.running_animations; animations)
profile(time::ProfilerCategory::LayoutStyleRecalc, });
self.profiler_metadata(),
self.time_profiler_chan.clone(),
|| {
animation::recalc_style_for_animations(flow_ref::deref_mut(&mut root_flow),
animations)
});
}
} }
self.perform_post_style_recalc_layout_passes(&reflow_info, self.perform_post_style_recalc_layout_passes(&reflow_info,
@ -1307,54 +1304,55 @@ impl LayoutTask {
data: &Reflow, data: &Reflow,
rw_data: &mut LayoutTaskData, rw_data: &mut LayoutTaskData,
layout_context: &mut SharedLayoutContext) { layout_context: &mut SharedLayoutContext) {
let mut root_flow = (*rw_data.root_flow.as_ref().unwrap()).clone(); if let Some(mut root_flow) = rw_data.layout_root() {
profile(time::ProfilerCategory::LayoutRestyleDamagePropagation, profile(time::ProfilerCategory::LayoutRestyleDamagePropagation,
self.profiler_metadata(), self.profiler_metadata(),
self.time_profiler_chan.clone(), self.time_profiler_chan.clone(),
|| { || {
if opts::get().nonincremental_layout || flow_ref::deref_mut(&mut root_flow) if opts::get().nonincremental_layout || flow_ref::deref_mut(&mut root_flow)
.compute_layout_damage() .compute_layout_damage()
.contains(REFLOW_ENTIRE_DOCUMENT) { .contains(REFLOW_ENTIRE_DOCUMENT) {
flow_ref::deref_mut(&mut root_flow).reflow_entire_document() flow_ref::deref_mut(&mut root_flow).reflow_entire_document()
}
});
// Verification of the flow tree, which ensures that all nodes were either marked as leaves
// or as non-leaves. This becomes a no-op in release builds. (It is inconsequential to
// memory safety but is a useful debugging tool.)
self.verify_flow_tree(&mut root_flow);
if opts::get().trace_layout {
layout_debug::begin_trace(root_flow.clone());
} }
});
// Verification of the flow tree, which ensures that all nodes were either marked as leaves // Resolve generated content.
// or as non-leaves. This becomes a no-op in release builds. (It is inconsequential to profile(time::ProfilerCategory::LayoutGeneratedContent,
// memory safety but is a useful debugging tool.) self.profiler_metadata(),
self.verify_flow_tree(&mut root_flow); self.time_profiler_chan.clone(),
|| sequential::resolve_generated_content(&mut root_flow, &layout_context));
if opts::get().trace_layout { // Perform the primary layout passes over the flow tree to compute the locations of all
layout_debug::begin_trace(root_flow.clone()); // the boxes.
profile(time::ProfilerCategory::LayoutMain,
self.profiler_metadata(),
self.time_profiler_chan.clone(),
|| {
match rw_data.parallel_traversal {
None => {
// Sequential mode.
self.solve_constraints(&mut root_flow, &layout_context)
}
Some(ref mut parallel) => {
// Parallel mode.
self.solve_constraints_parallel(parallel,
&mut root_flow,
&mut *layout_context);
}
}
});
self.perform_post_main_layout_passes(data, rw_data, layout_context);
} }
// Resolve generated content.
profile(time::ProfilerCategory::LayoutGeneratedContent,
self.profiler_metadata(),
self.time_profiler_chan.clone(),
|| sequential::resolve_generated_content(&mut root_flow, &layout_context));
// Perform the primary layout passes over the flow tree to compute the locations of all
// the boxes.
profile(time::ProfilerCategory::LayoutMain,
self.profiler_metadata(),
self.time_profiler_chan.clone(),
|| {
match rw_data.parallel_traversal {
None => {
// Sequential mode.
self.solve_constraints(&mut root_flow, &layout_context)
}
Some(ref mut parallel) => {
// Parallel mode.
self.solve_constraints_parallel(parallel,
&mut root_flow,
&mut *layout_context);
}
}
});
self.perform_post_main_layout_passes(data, rw_data, layout_context);
} }
fn perform_post_main_layout_passes<'a>(&'a self, fn perform_post_main_layout_passes<'a>(&'a self,
@ -1362,22 +1360,23 @@ impl LayoutTask {
rw_data: &mut LayoutTaskData, rw_data: &mut LayoutTaskData,
layout_context: &mut SharedLayoutContext) { layout_context: &mut SharedLayoutContext) {
// Build the display list if necessary, and send it to the painter. // Build the display list if necessary, and send it to the painter.
let mut root_flow = (*rw_data.root_flow.as_ref().unwrap()).clone(); if let Some(mut root_flow) = rw_data.layout_root() {
self.compute_abs_pos_and_build_display_list(data, self.compute_abs_pos_and_build_display_list(data,
&mut root_flow, &mut root_flow,
&mut *layout_context, &mut *layout_context,
rw_data); rw_data);
self.first_reflow.set(false); self.first_reflow.set(false);
if opts::get().trace_layout { if opts::get().trace_layout {
layout_debug::end_trace(); layout_debug::end_trace();
}
if opts::get().dump_flow_tree {
root_flow.dump();
}
rw_data.generation += 1;
} }
if opts::get().dump_flow_tree {
root_flow.dump();
}
rw_data.generation += 1;
} }
unsafe fn dirty_all_nodes(node: &mut LayoutNode) { unsafe fn dirty_all_nodes(node: &mut LayoutNode) {

View file

@ -1,3 +1,3 @@
[root-box-003.htm] [root-box-003.htm]
type: reftest type: reftest
expected: CRASH expected: TIMEOUT

View file

@ -1,3 +1,104 @@
[Document-createElement-namespace.html] [Document-createElement-namespace.html]
type: testharness type: testharness
disabled: Issue 6386 [Created element's namespace in created XML document]
expected: FAIL
[Created element's namespace in created XHTML document]
expected: FAIL
[Created element's namespace in created SVG document]
expected: FAIL
[Created element's namespace in created MathML document]
expected: FAIL
[Created element's namespace in empty.xhtml]
expected: FAIL
[Created element's namespace in empty.xml]
expected: FAIL
[Created element's namespace in empty.svg]
expected: FAIL
[Created element's namespace in minimal_html.xhtml]
expected: FAIL
[Created element's namespace in minimal_html.xml]
expected: FAIL
[Created element's namespace in minimal_html.svg]
expected: FAIL
[Created element's namespace in xhtml.xhtml]
expected: FAIL
[Created element's namespace in xhtml.xml]
expected: FAIL
[Created element's namespace in xhtml.svg]
expected: FAIL
[Created element's namespace in svg.xhtml]
expected: FAIL
[Created element's namespace in svg.xml]
expected: FAIL
[Created element's namespace in svg.svg]
expected: FAIL
[Created element's namespace in mathml.xhtml]
expected: FAIL
[Created element's namespace in mathml.xml]
expected: FAIL
[Created element's namespace in mathml.svg]
expected: FAIL
[Created element's namespace in bare_xhtml.xhtml]
expected: FAIL
[Created element's namespace in bare_xhtml.xml]
expected: FAIL
[Created element's namespace in bare_xhtml.svg]
expected: FAIL
[Created element's namespace in bare_svg.xhtml]
expected: FAIL
[Created element's namespace in bare_svg.xml]
expected: FAIL
[Created element's namespace in bare_svg.svg]
expected: FAIL
[Created element's namespace in bare_mathml.xhtml]
expected: FAIL
[Created element's namespace in bare_mathml.xml]
expected: FAIL
[Created element's namespace in bare_mathml.svg]
expected: FAIL
[Created element's namespace in xhtml_ns_removed.xhtml]
expected: FAIL
[Created element's namespace in xhtml_ns_removed.xml]
expected: FAIL
[Created element's namespace in xhtml_ns_removed.svg]
expected: FAIL
[Created element's namespace in xhtml_ns_changed.xhtml]
expected: FAIL
[Created element's namespace in xhtml_ns_changed.xml]
expected: FAIL
[Created element's namespace in xhtml_ns_changed.svg]
expected: FAIL