mirror of
https://github.com/servo/servo.git
synced 2025-06-10 09:33:13 +00:00
auto merge of #3640 : cgaebel/servo/incremental-flow-construction, r=pcwalton
This also hides the not-yet-working parts of incremental reflow behind a runtime flag. As I get the failing reftests passing, I'll send pull requests for them one by one.
This commit is contained in:
commit
56989b8dec
13 changed files with 310 additions and 82 deletions
|
@ -43,7 +43,7 @@ use table_rowgroup::TableRowGroupFlow;
|
||||||
use table_row::TableRowFlow;
|
use table_row::TableRowFlow;
|
||||||
use table_cell::TableCellFlow;
|
use table_cell::TableCellFlow;
|
||||||
use text::TextRunScanner;
|
use text::TextRunScanner;
|
||||||
use util::{LayoutDataAccess, OpaqueNodeMethods};
|
use util::{LayoutDataAccess, OpaqueNodeMethods, LayoutDataWrapper};
|
||||||
use wrapper::{PostorderNodeMutTraversal, TLayoutNode, ThreadSafeLayoutNode};
|
use wrapper::{PostorderNodeMutTraversal, TLayoutNode, ThreadSafeLayoutNode};
|
||||||
use wrapper::{Before, After, Normal};
|
use wrapper::{Before, After, Normal};
|
||||||
|
|
||||||
|
@ -80,6 +80,22 @@ pub enum ConstructionResult {
|
||||||
ConstructionItemConstructionResult(ConstructionItem),
|
ConstructionItemConstructionResult(ConstructionItem),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl ConstructionResult {
|
||||||
|
pub fn swap_out(&mut self, layout_context: &LayoutContext) -> ConstructionResult {
|
||||||
|
if layout_context.shared.opts.incremental_layout {
|
||||||
|
match *self {
|
||||||
|
NoConstructionResult =>
|
||||||
|
return NoConstructionResult,
|
||||||
|
FlowConstructionResult(ref flow_ref, ref abs_descendants) =>
|
||||||
|
return FlowConstructionResult((*flow_ref).clone(), (*abs_descendants).clone()),
|
||||||
|
ConstructionItemConstructionResult(_) => {},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mem::replace(self, NoConstructionResult)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Represents the output of flow construction for a DOM node that has not yet resulted in a
|
/// Represents the output of flow construction for a DOM node that has not yet resulted in a
|
||||||
/// complete flow. Construction items bubble up the tree until they find a `Flow` to be attached
|
/// complete flow. Construction items bubble up the tree until they find a `Flow` to be attached
|
||||||
/// to.
|
/// to.
|
||||||
|
@ -345,7 +361,7 @@ impl<'a> FlowConstructor<'a> {
|
||||||
&mut InlineFragmentsAccumulator,
|
&mut InlineFragmentsAccumulator,
|
||||||
abs_descendants: &mut Descendants,
|
abs_descendants: &mut Descendants,
|
||||||
first_fragment: &mut bool) {
|
first_fragment: &mut bool) {
|
||||||
match kid.swap_out_construction_result() {
|
match kid.swap_out_construction_result(self.layout_context) {
|
||||||
NoConstructionResult => {}
|
NoConstructionResult => {}
|
||||||
FlowConstructionResult(kid_flow, kid_abs_descendants) => {
|
FlowConstructionResult(kid_flow, kid_abs_descendants) => {
|
||||||
// If kid_flow is TableCaptionFlow, kid_flow should be added under
|
// If kid_flow is TableCaptionFlow, kid_flow should be added under
|
||||||
|
@ -546,7 +562,7 @@ impl<'a> FlowConstructor<'a> {
|
||||||
if kid.get_pseudo_element_type() != Normal {
|
if kid.get_pseudo_element_type() != Normal {
|
||||||
self.process(&kid);
|
self.process(&kid);
|
||||||
}
|
}
|
||||||
match kid.swap_out_construction_result() {
|
match kid.swap_out_construction_result(self.layout_context) {
|
||||||
NoConstructionResult => {}
|
NoConstructionResult => {}
|
||||||
FlowConstructionResult(flow, kid_abs_descendants) => {
|
FlowConstructionResult(flow, kid_abs_descendants) => {
|
||||||
// {ib} split. Flush the accumulator to our new split and make a new
|
// {ib} split. Flush the accumulator to our new split and make a new
|
||||||
|
@ -727,12 +743,13 @@ impl<'a> FlowConstructor<'a> {
|
||||||
table_wrapper_flow: &mut FlowRef,
|
table_wrapper_flow: &mut FlowRef,
|
||||||
node: &ThreadSafeLayoutNode) {
|
node: &ThreadSafeLayoutNode) {
|
||||||
for kid in node.children() {
|
for kid in node.children() {
|
||||||
match kid.swap_out_construction_result() {
|
match kid.swap_out_construction_result(self.layout_context) {
|
||||||
NoConstructionResult | ConstructionItemConstructionResult(_) => {}
|
NoConstructionResult | ConstructionItemConstructionResult(_) => {}
|
||||||
FlowConstructionResult(kid_flow, _) => {
|
FlowConstructionResult(kid_flow, _) => {
|
||||||
// Only kid flows with table-caption are matched here.
|
// Only kid flows with table-caption are matched here.
|
||||||
assert!(kid_flow.get().is_table_caption());
|
if kid_flow.get().is_table_caption() {
|
||||||
table_wrapper_flow.add_new_child(kid_flow);
|
table_wrapper_flow.add_new_child(kid_flow);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -889,7 +906,7 @@ impl<'a> FlowConstructor<'a> {
|
||||||
for kid in node.children() {
|
for kid in node.children() {
|
||||||
// CSS 2.1 § 17.2.1. Treat all non-column child fragments of `table-column-group`
|
// CSS 2.1 § 17.2.1. Treat all non-column child fragments of `table-column-group`
|
||||||
// as `display: none`.
|
// as `display: none`.
|
||||||
match kid.swap_out_construction_result() {
|
match kid.swap_out_construction_result(self.layout_context) {
|
||||||
ConstructionItemConstructionResult(TableColumnFragmentConstructionItem(
|
ConstructionItemConstructionResult(TableColumnFragmentConstructionItem(
|
||||||
fragment)) => {
|
fragment)) => {
|
||||||
col_fragments.push(fragment);
|
col_fragments.push(fragment);
|
||||||
|
@ -958,7 +975,7 @@ impl<'a> PostorderNodeMutTraversal for FlowConstructor<'a> {
|
||||||
// results of children.
|
// results of children.
|
||||||
(display::none, _, _) => {
|
(display::none, _, _) => {
|
||||||
for child in node.children() {
|
for child in node.children() {
|
||||||
drop(child.swap_out_construction_result())
|
drop(child.swap_out_construction_result(self.layout_context))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1063,12 +1080,14 @@ trait NodeUtils {
|
||||||
/// Returns true if this node doesn't render its kids and false otherwise.
|
/// Returns true if this node doesn't render its kids and false otherwise.
|
||||||
fn is_replaced_content(&self) -> bool;
|
fn is_replaced_content(&self) -> bool;
|
||||||
|
|
||||||
|
fn get_construction_result<'a>(self, layout_data: &'a mut LayoutDataWrapper) -> &'a mut ConstructionResult;
|
||||||
|
|
||||||
/// Sets the construction result of a flow.
|
/// Sets the construction result of a flow.
|
||||||
fn set_flow_construction_result(&self, result: ConstructionResult);
|
fn set_flow_construction_result(self, result: ConstructionResult);
|
||||||
|
|
||||||
/// Replaces the flow construction result in a node with `NoConstructionResult` and returns the
|
/// Replaces the flow construction result in a node with `NoConstructionResult` and returns the
|
||||||
/// old value.
|
/// old value.
|
||||||
fn swap_out_construction_result(&self) -> ConstructionResult;
|
fn swap_out_construction_result(self, layout_context: &LayoutContext) -> ConstructionResult;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'ln> NodeUtils for ThreadSafeLayoutNode<'ln> {
|
impl<'ln> NodeUtils for ThreadSafeLayoutNode<'ln> {
|
||||||
|
@ -1087,43 +1106,30 @@ impl<'ln> NodeUtils for ThreadSafeLayoutNode<'ln> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
fn get_construction_result<'a>(self, layout_data: &'a mut LayoutDataWrapper) -> &'a mut ConstructionResult {
|
||||||
fn set_flow_construction_result(&self, result: ConstructionResult) {
|
match self.get_pseudo_element_type() {
|
||||||
let mut layout_data_ref = self.mutate_layout_data();
|
Before(_) => &mut layout_data.data.before_flow_construction_result,
|
||||||
match &mut *layout_data_ref {
|
After (_) => &mut layout_data.data.after_flow_construction_result,
|
||||||
&Some(ref mut layout_data) =>{
|
Normal => &mut layout_data.data.flow_construction_result,
|
||||||
match self.get_pseudo_element_type() {
|
|
||||||
Before(_) => layout_data.data.before_flow_construction_result = result,
|
|
||||||
After(_) => layout_data.data.after_flow_construction_result = result,
|
|
||||||
Normal => layout_data.data.flow_construction_result = result,
|
|
||||||
}
|
|
||||||
},
|
|
||||||
&None => fail!("no layout data"),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn swap_out_construction_result(&self) -> ConstructionResult {
|
fn set_flow_construction_result(self, result: ConstructionResult) {
|
||||||
let mut layout_data_ref = self.mutate_layout_data();
|
let mut layout_data_ref = self.mutate_layout_data();
|
||||||
match &mut *layout_data_ref {
|
let layout_data = layout_data_ref.as_mut().expect("no layout data");
|
||||||
&Some(ref mut layout_data) => {
|
|
||||||
match self.get_pseudo_element_type() {
|
let dst = self.get_construction_result(layout_data);
|
||||||
Before(_) => {
|
|
||||||
mem::replace(&mut layout_data.data.before_flow_construction_result,
|
*dst = result;
|
||||||
NoConstructionResult)
|
}
|
||||||
}
|
|
||||||
After(_) => {
|
#[inline(always)]
|
||||||
mem::replace(&mut layout_data.data.after_flow_construction_result,
|
fn swap_out_construction_result(self, layout_context: &LayoutContext) -> ConstructionResult {
|
||||||
NoConstructionResult)
|
let mut layout_data_ref = self.mutate_layout_data();
|
||||||
}
|
let layout_data = layout_data_ref.as_mut().expect("no layout data");
|
||||||
Normal => {
|
|
||||||
mem::replace(&mut layout_data.data.flow_construction_result,
|
self.get_construction_result(layout_data).swap_out(layout_context)
|
||||||
NoConstructionResult)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
&None => fail!("no layout data"),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -14,6 +14,7 @@ use sync::Arc;
|
||||||
/// Node mixin providing `style` method that returns a `NodeStyle`
|
/// Node mixin providing `style` method that returns a `NodeStyle`
|
||||||
pub trait StyledNode {
|
pub trait StyledNode {
|
||||||
fn style<'a>(&'a self) -> &'a Arc<ComputedValues>;
|
fn style<'a>(&'a self) -> &'a Arc<ComputedValues>;
|
||||||
|
fn unstyle(self);
|
||||||
fn restyle_damage(self) -> RestyleDamage;
|
fn restyle_damage(self) -> RestyleDamage;
|
||||||
fn set_restyle_damage(self, damage: RestyleDamage);
|
fn set_restyle_damage(self, damage: RestyleDamage);
|
||||||
}
|
}
|
||||||
|
@ -24,6 +25,10 @@ impl<'ln> StyledNode for ThreadSafeLayoutNode<'ln> {
|
||||||
self.get_css_select_results()
|
self.get_css_select_results()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn unstyle(self) {
|
||||||
|
self.remove_css_select_results()
|
||||||
|
}
|
||||||
|
|
||||||
fn restyle_damage(self) -> RestyleDamage {
|
fn restyle_damage(self) -> RestyleDamage {
|
||||||
self.get_restyle_damage()
|
self.get_restyle_damage()
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,6 +13,7 @@ use sync::Arc;
|
||||||
pub trait NodeUtil {
|
pub trait NodeUtil {
|
||||||
fn get_css_select_results<'a>(&'a self) -> &'a Arc<ComputedValues>;
|
fn get_css_select_results<'a>(&'a self) -> &'a Arc<ComputedValues>;
|
||||||
fn have_css_select_results(&self) -> bool;
|
fn have_css_select_results(&self) -> bool;
|
||||||
|
fn remove_css_select_results(self);
|
||||||
|
|
||||||
fn get_restyle_damage(self) -> RestyleDamage;
|
fn get_restyle_damage(self) -> RestyleDamage;
|
||||||
fn set_restyle_damage(self, damage: RestyleDamage);
|
fn set_restyle_damage(self, damage: RestyleDamage);
|
||||||
|
@ -60,6 +61,20 @@ impl<'ln> NodeUtil for ThreadSafeLayoutNode<'ln> {
|
||||||
layout_data_ref.as_ref().unwrap().shared_data.style.is_some()
|
layout_data_ref.as_ref().unwrap().shared_data.style.is_some()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn remove_css_select_results(self) {
|
||||||
|
let mut layout_data_ref = self.mutate_layout_data();
|
||||||
|
let layout_data = layout_data_ref.as_mut().expect("no layout data");
|
||||||
|
|
||||||
|
let style =
|
||||||
|
match self.get_pseudo_element_type() {
|
||||||
|
Before(_) => &mut layout_data.data.before_style,
|
||||||
|
After (_) => &mut layout_data.data.after_style,
|
||||||
|
Normal => &mut layout_data.shared_data.style,
|
||||||
|
};
|
||||||
|
|
||||||
|
*style = None;
|
||||||
|
}
|
||||||
|
|
||||||
/// Get the description of how to account for recent style changes.
|
/// Get the description of how to account for recent style changes.
|
||||||
/// This is a simple bitfield and fine to copy by value.
|
/// This is a simple bitfield and fine to copy by value.
|
||||||
fn get_restyle_damage(self) -> RestyleDamage {
|
fn get_restyle_damage(self) -> RestyleDamage {
|
||||||
|
|
|
@ -32,7 +32,7 @@ use floats::Floats;
|
||||||
use flow_list::{FlowList, FlowListIterator, MutFlowListIterator};
|
use flow_list::{FlowList, FlowListIterator, MutFlowListIterator};
|
||||||
use flow_ref::FlowRef;
|
use flow_ref::FlowRef;
|
||||||
use fragment::{Fragment, TableRowFragment, TableCellFragment};
|
use fragment::{Fragment, TableRowFragment, TableCellFragment};
|
||||||
use incremental::RestyleDamage;
|
use incremental::{RestyleDamage, Reflow};
|
||||||
use inline::InlineFlow;
|
use inline::InlineFlow;
|
||||||
use model::{CollapsibleMargins, IntrinsicISizes, MarginCollapseInfo};
|
use model::{CollapsibleMargins, IntrinsicISizes, MarginCollapseInfo};
|
||||||
use parallel::FlowParallelInfo;
|
use parallel::FlowParallelInfo;
|
||||||
|
@ -432,7 +432,13 @@ pub trait MutableFlowUtils {
|
||||||
/// This is called in a bottom-up traversal (specifically, the assign-block-size traversal).
|
/// This is called in a bottom-up traversal (specifically, the assign-block-size traversal).
|
||||||
/// So, kids have their flow origin already set. In the case of absolute flow kids, they have
|
/// So, kids have their flow origin already set. In the case of absolute flow kids, they have
|
||||||
/// their hypothetical box position already set.
|
/// their hypothetical box position already set.
|
||||||
fn collect_static_block_offsets_from_children(&mut self);
|
fn collect_static_block_offsets_from_children(self);
|
||||||
|
|
||||||
|
fn propagate_restyle_damage(self);
|
||||||
|
|
||||||
|
/// At the moment, reflow isn't idempotent. This function resets this flow
|
||||||
|
/// (and all its descendants, recursively), and marks them as needing reflow.
|
||||||
|
fn nonincremental_reset(self);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait MutableOwnedFlowUtils {
|
pub trait MutableOwnedFlowUtils {
|
||||||
|
@ -589,6 +595,7 @@ impl FlowFlags {
|
||||||
/// The Descendants of a flow.
|
/// The Descendants of a flow.
|
||||||
///
|
///
|
||||||
/// Also, details about their position wrt this flow.
|
/// Also, details about their position wrt this flow.
|
||||||
|
#[deriving(Clone)]
|
||||||
pub struct Descendants {
|
pub struct Descendants {
|
||||||
/// Links to every descendant. This must be private because it is unsafe to leak `FlowRef`s to
|
/// Links to every descendant. This must be private because it is unsafe to leak `FlowRef`s to
|
||||||
/// layout.
|
/// layout.
|
||||||
|
@ -1155,9 +1162,9 @@ impl<'a> MutableFlowUtils for &'a mut Flow + 'a {
|
||||||
/// assign-block-size traversal). So, kids have their flow origin already set.
|
/// assign-block-size traversal). So, kids have their flow origin already set.
|
||||||
/// In the case of absolute flow kids, they have their hypothetical box
|
/// In the case of absolute flow kids, they have their hypothetical box
|
||||||
/// position already set.
|
/// position already set.
|
||||||
fn collect_static_block_offsets_from_children(&mut self) {
|
fn collect_static_block_offsets_from_children(self) {
|
||||||
let mut absolute_descendant_block_offsets = Vec::new();
|
let mut absolute_descendant_block_offsets = Vec::new();
|
||||||
for kid in mut_base(*self).child_iter() {
|
for kid in mut_base(self).child_iter() {
|
||||||
let mut gives_absolute_offsets = true;
|
let mut gives_absolute_offsets = true;
|
||||||
if kid.is_block_like() {
|
if kid.is_block_like() {
|
||||||
let kid_block = kid.as_block();
|
let kid_block = kid.as_block();
|
||||||
|
@ -1189,7 +1196,88 @@ impl<'a> MutableFlowUtils for &'a mut Flow + 'a {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
mut_base(*self).abs_descendants.static_block_offsets = absolute_descendant_block_offsets
|
mut_base(self).abs_descendants.static_block_offsets = absolute_descendant_block_offsets
|
||||||
|
}
|
||||||
|
|
||||||
|
fn propagate_restyle_damage(self) {
|
||||||
|
struct DirtyFloats {
|
||||||
|
left: bool,
|
||||||
|
right: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
fn doit(flow: &mut Flow, down: RestyleDamage, dirty_floats: &mut DirtyFloats) -> RestyleDamage {
|
||||||
|
match flow.float_clearance() {
|
||||||
|
clear::none => {}
|
||||||
|
clear::left => {
|
||||||
|
(*dirty_floats).left = false;
|
||||||
|
}
|
||||||
|
clear::right => {
|
||||||
|
(*dirty_floats).right = false;
|
||||||
|
}
|
||||||
|
clear::both => {
|
||||||
|
(*dirty_floats).left = false;
|
||||||
|
(*dirty_floats).right = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
match flow.float_kind() {
|
||||||
|
float::none => {}
|
||||||
|
float::left => {
|
||||||
|
(*dirty_floats).left = true;
|
||||||
|
}
|
||||||
|
float::right => {
|
||||||
|
(*dirty_floats).right = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut my_damage = mut_base(flow).restyle_damage;
|
||||||
|
my_damage.insert(down);
|
||||||
|
|
||||||
|
if (*dirty_floats).left || (*dirty_floats).right {
|
||||||
|
my_damage = RestyleDamage::all();
|
||||||
|
}
|
||||||
|
|
||||||
|
let down_damage = my_damage.propagate_down();
|
||||||
|
|
||||||
|
for kid in child_iter(flow) {
|
||||||
|
my_damage.insert(doit(kid, down_damage, dirty_floats));
|
||||||
|
}
|
||||||
|
|
||||||
|
mut_base(flow).restyle_damage = my_damage;
|
||||||
|
|
||||||
|
my_damage.propagate_up()
|
||||||
|
}
|
||||||
|
|
||||||
|
doit(self, RestyleDamage::empty(), &mut DirtyFloats { left: false, right: false });
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
fn nonincremental_reset(self) {
|
||||||
|
fn reset_flow(flow: &mut Flow) {
|
||||||
|
let base = mut_base(flow);
|
||||||
|
|
||||||
|
if !base.restyle_damage.contains(Reflow) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
let writing_mode = base.writing_mode;
|
||||||
|
|
||||||
|
base.position = LogicalRect::zero(writing_mode);
|
||||||
|
base.overflow = LogicalRect::zero(writing_mode);
|
||||||
|
base.floats = Floats::new(writing_mode);
|
||||||
|
base.collapsible_margins = CollapsibleMargins::new();
|
||||||
|
base.abs_position = Zero::zero();
|
||||||
|
base.block_container_explicit_block_size = None;
|
||||||
|
base.display_list = DisplayList::new();
|
||||||
|
base.layers = DList::new();
|
||||||
|
base.absolute_position_info = AbsolutePositionInfo::new(writing_mode);
|
||||||
|
}
|
||||||
|
|
||||||
|
reset_flow(self);
|
||||||
|
|
||||||
|
for child in child_iter(self) {
|
||||||
|
child.nonincremental_reset();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
|
|
||||||
use css::matching::{ApplicableDeclarations, MatchMethods};
|
use css::matching::{ApplicableDeclarations, MatchMethods};
|
||||||
use css::node_style::StyledNode;
|
use css::node_style::StyledNode;
|
||||||
use construct::{FlowConstructionResult, NoConstructionResult};
|
use construct::FlowConstructionResult;
|
||||||
use context::{LayoutContext, SharedLayoutContext};
|
use context::{LayoutContext, SharedLayoutContext};
|
||||||
use flow::{Flow, ImmutableFlowUtils, MutableFlowUtils, MutableOwnedFlowUtils};
|
use flow::{Flow, ImmutableFlowUtils, MutableFlowUtils, MutableOwnedFlowUtils};
|
||||||
use flow::{PreorderFlowTraversal, PostorderFlowTraversal};
|
use flow::{PreorderFlowTraversal, PostorderFlowTraversal};
|
||||||
|
@ -479,14 +479,12 @@ impl LayoutTask {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Retrieves the flow tree root from the root node.
|
/// Retrieves the flow tree root from the root node.
|
||||||
fn get_layout_root(&self, node: LayoutNode) -> FlowRef {
|
fn get_layout_root(&self, node: LayoutNode, layout_context: &LayoutContext) -> FlowRef {
|
||||||
let mut layout_data_ref = node.mutate_layout_data();
|
let mut layout_data_ref = node.mutate_layout_data();
|
||||||
let result = match &mut *layout_data_ref {
|
let layout_data = layout_data_ref.as_mut().expect("no layout data for root node");
|
||||||
&Some(ref mut layout_data) => {
|
|
||||||
mem::replace(&mut layout_data.data.flow_construction_result, NoConstructionResult)
|
let result = layout_data.data.flow_construction_result.swap_out(layout_context);
|
||||||
}
|
|
||||||
&None => fail!("no layout data for root node"),
|
|
||||||
};
|
|
||||||
let mut flow = match result {
|
let mut flow = match result {
|
||||||
FlowConstructionResult(mut flow, abs_descendants) => {
|
FlowConstructionResult(mut flow, abs_descendants) => {
|
||||||
// Note: Assuming that the root has display 'static' (as per
|
// Note: Assuming that the root has display 'static' (as per
|
||||||
|
@ -499,6 +497,7 @@ impl LayoutTask {
|
||||||
}
|
}
|
||||||
_ => fail!("Flow construction didn't result in a flow at the root of the tree!"),
|
_ => fail!("Flow construction didn't result in a flow at the root of the tree!"),
|
||||||
};
|
};
|
||||||
|
|
||||||
flow.get_mut().mark_as_root();
|
flow.get_mut().mark_as_root();
|
||||||
flow
|
flow
|
||||||
}
|
}
|
||||||
|
@ -657,7 +656,23 @@ impl LayoutTask {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
self.get_layout_root((*node).clone())
|
self.get_layout_root((*node).clone(), &LayoutContext::new(&shared_layout_ctx))
|
||||||
|
});
|
||||||
|
|
||||||
|
profile(time::LayoutRestyleDamagePropagation,
|
||||||
|
Some((&data.url, data.iframe, self.first_reflow.get())),
|
||||||
|
self.time_profiler_chan.clone(),
|
||||||
|
|| {
|
||||||
|
layout_root.get_mut().propagate_restyle_damage();
|
||||||
|
});
|
||||||
|
|
||||||
|
profile(time::LayoutNonIncrementalReset,
|
||||||
|
Some((&data.url, data.iframe, self.first_reflow.get())),
|
||||||
|
self.time_profiler_chan.clone(),
|
||||||
|
|| {
|
||||||
|
if shared_layout_ctx.opts.incremental_layout {
|
||||||
|
layout_root.get_mut().nonincremental_reset();
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// Verification of the flow tree, which ensures that all nodes were either marked as leaves
|
// Verification of the flow tree, which ensures that all nodes were either marked as leaves
|
||||||
|
|
|
@ -132,8 +132,15 @@ impl<'a> PreorderDomTraversal for RecalcStyleForNode<'a> {
|
||||||
// Just needs to be wrapped in an option for `match_node`.
|
// Just needs to be wrapped in an option for `match_node`.
|
||||||
let some_bf = Some(bf);
|
let some_bf = Some(bf);
|
||||||
|
|
||||||
if node.is_dirty() {
|
if node.is_dirty() || node.has_dirty_siblings() {
|
||||||
// First, check to see whether we can share a style with someone.
|
// Remove existing CSS styles from changed nodes, to force
|
||||||
|
// non-incremental reflow.
|
||||||
|
if node.has_changed() {
|
||||||
|
let node = ThreadSafeLayoutNode::new(&node);
|
||||||
|
node.unstyle();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check to see whether we can share a style with someone.
|
||||||
let style_sharing_candidate_cache =
|
let style_sharing_candidate_cache =
|
||||||
self.layout_context.style_sharing_candidate_cache();
|
self.layout_context.style_sharing_candidate_cache();
|
||||||
let sharing_result = unsafe {
|
let sharing_result = unsafe {
|
||||||
|
@ -194,17 +201,31 @@ impl<'a> PostorderDomTraversal for ConstructFlows<'a> {
|
||||||
fn process(&self, node: LayoutNode) {
|
fn process(&self, node: LayoutNode) {
|
||||||
// Construct flows for this node.
|
// Construct flows for this node.
|
||||||
{
|
{
|
||||||
let node = ThreadSafeLayoutNode::new(&node);
|
let tnode = ThreadSafeLayoutNode::new(&node);
|
||||||
let mut flow_constructor = FlowConstructor::new(self.layout_context);
|
|
||||||
flow_constructor.process(&node);
|
// Always re-construct if incremental layout is turned off.
|
||||||
|
if !self.layout_context.shared.opts.incremental_layout {
|
||||||
|
unsafe {
|
||||||
|
node.set_dirty_descendants(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if node.has_dirty_descendants() {
|
||||||
|
tnode.set_restyle_damage(RestyleDamage::all());
|
||||||
|
debug!("Constructing flow for {}", tnode.debug_id());
|
||||||
|
let mut flow_constructor = FlowConstructor::new(self.layout_context);
|
||||||
|
flow_constructor.process(&tnode);
|
||||||
|
}
|
||||||
|
|
||||||
// Reset the layout damage in this node. It's been propagated to the
|
// Reset the layout damage in this node. It's been propagated to the
|
||||||
// flow by the flow constructor.
|
// flow by the flow constructor.
|
||||||
node.set_restyle_damage(RestyleDamage::empty());
|
tnode.set_restyle_damage(RestyleDamage::empty());
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
|
node.set_changed(false);
|
||||||
node.set_dirty(false);
|
node.set_dirty(false);
|
||||||
|
node.set_dirty_siblings(false);
|
||||||
node.set_dirty_descendants(false);
|
node.set_dirty_descendants(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -49,7 +49,7 @@ use script::dom::htmlimageelement::{HTMLImageElement, LayoutHTMLImageElementHelp
|
||||||
use script::dom::htmlinputelement::{HTMLInputElement, LayoutHTMLInputElementHelpers};
|
use script::dom::htmlinputelement::{HTMLInputElement, LayoutHTMLInputElementHelpers};
|
||||||
use script::dom::node::{DocumentNodeTypeId, ElementNodeTypeId, Node, NodeTypeId};
|
use script::dom::node::{DocumentNodeTypeId, ElementNodeTypeId, Node, NodeTypeId};
|
||||||
use script::dom::node::{LayoutNodeHelpers, RawLayoutNodeHelpers, SharedLayoutData, TextNodeTypeId};
|
use script::dom::node::{LayoutNodeHelpers, RawLayoutNodeHelpers, SharedLayoutData, TextNodeTypeId};
|
||||||
use script::dom::node::{IsDirty, HasDirtyDescendants};
|
use script::dom::node::{HasChanged, IsDirty, HasDirtySiblings, HasDirtyDescendants};
|
||||||
use script::dom::text::Text;
|
use script::dom::text::Text;
|
||||||
use script::layout_interface::LayoutChan;
|
use script::layout_interface::LayoutChan;
|
||||||
use servo_msg::constellation_msg::{PipelineId, SubpageId};
|
use servo_msg::constellation_msg::{PipelineId, SubpageId};
|
||||||
|
@ -267,6 +267,11 @@ impl<'ln> LayoutNode<'ln> {
|
||||||
self.parent_node()
|
self.parent_node()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn debug_id(self) -> uint {
|
||||||
|
let opaque: OpaqueNode = OpaqueNodeMethods::from_layout_node(&self);
|
||||||
|
opaque.to_untrusted_node_address() as uint
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'ln> TNode<'ln, LayoutElement<'ln>> for LayoutNode<'ln> {
|
impl<'ln> TNode<'ln, LayoutElement<'ln>> for LayoutNode<'ln> {
|
||||||
|
@ -343,6 +348,14 @@ impl<'ln> TNode<'ln, LayoutElement<'ln>> for LayoutNode<'ln> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn has_changed(self) -> bool {
|
||||||
|
unsafe { self.node.get_flag(HasChanged) }
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe fn set_changed(self, value: bool) {
|
||||||
|
self.node.set_flag(HasChanged, value)
|
||||||
|
}
|
||||||
|
|
||||||
fn is_dirty(self) -> bool {
|
fn is_dirty(self) -> bool {
|
||||||
unsafe { self.node.get_flag(IsDirty) }
|
unsafe { self.node.get_flag(IsDirty) }
|
||||||
}
|
}
|
||||||
|
@ -351,6 +364,14 @@ impl<'ln> TNode<'ln, LayoutElement<'ln>> for LayoutNode<'ln> {
|
||||||
self.node.set_flag(IsDirty, value)
|
self.node.set_flag(IsDirty, value)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn has_dirty_siblings(self) -> bool {
|
||||||
|
unsafe { self.node.get_flag(HasDirtySiblings) }
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe fn set_dirty_siblings(self, value: bool) {
|
||||||
|
self.node.set_flag(HasDirtySiblings, value);
|
||||||
|
}
|
||||||
|
|
||||||
fn has_dirty_descendants(self) -> bool {
|
fn has_dirty_descendants(self) -> bool {
|
||||||
unsafe { self.node.get_flag(HasDirtyDescendants) }
|
unsafe { self.node.get_flag(HasDirtyDescendants) }
|
||||||
}
|
}
|
||||||
|
@ -668,6 +689,10 @@ impl<'ln> ThreadSafeLayoutNode<'ln> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn debug_id(self) -> uint {
|
||||||
|
self.node.debug_id()
|
||||||
|
}
|
||||||
|
|
||||||
/// Returns the next sibling of this node. Unsafe and private because this can lead to races.
|
/// Returns the next sibling of this node. Unsafe and private because this can lead to races.
|
||||||
unsafe fn next_sibling(&self) -> Option<ThreadSafeLayoutNode<'ln>> {
|
unsafe fn next_sibling(&self) -> Option<ThreadSafeLayoutNode<'ln>> {
|
||||||
if self.pseudo.is_before() {
|
if self.pseudo.is_before() {
|
||||||
|
|
|
@ -135,18 +135,24 @@ bitflags! {
|
||||||
static InDisabledState = 0x04,
|
static InDisabledState = 0x04,
|
||||||
#[doc = "Specifies whether this node is in enabled state."]
|
#[doc = "Specifies whether this node is in enabled state."]
|
||||||
static InEnabledState = 0x08,
|
static InEnabledState = 0x08,
|
||||||
#[doc = "Specifies whether this node has changed since the last reflow."]
|
#[doc = "Specifies whether this node _must_ be reflowed regardless of style differences."]
|
||||||
static IsDirty = 0x10,
|
static HasChanged = 0x10,
|
||||||
|
#[doc = "Specifies whether this node needs style recalc on next reflow."]
|
||||||
|
static IsDirty = 0x20,
|
||||||
|
#[doc = "Specifies whether this node has siblings (inclusive of itself) which \
|
||||||
|
changed since the last reflow."]
|
||||||
|
static HasDirtySiblings = 0x40,
|
||||||
#[doc = "Specifies whether this node has descendants (inclusive of itself) which \
|
#[doc = "Specifies whether this node has descendants (inclusive of itself) which \
|
||||||
have changed since the last reflow."]
|
have changed since the last reflow."]
|
||||||
static HasDirtyDescendants = 0x20,
|
static HasDirtyDescendants = 0x80,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl NodeFlags {
|
impl NodeFlags {
|
||||||
pub fn new(type_id: NodeTypeId) -> NodeFlags {
|
pub fn new(type_id: NodeTypeId) -> NodeFlags {
|
||||||
|
let dirty = HasChanged | IsDirty | HasDirtySiblings | HasDirtyDescendants;
|
||||||
match type_id {
|
match type_id {
|
||||||
DocumentNodeTypeId => IsInDoc | IsDirty,
|
DocumentNodeTypeId => IsInDoc | dirty,
|
||||||
// The following elements are enabled by default.
|
// The following elements are enabled by default.
|
||||||
ElementNodeTypeId(HTMLButtonElementTypeId) |
|
ElementNodeTypeId(HTMLButtonElementTypeId) |
|
||||||
ElementNodeTypeId(HTMLInputElementTypeId) |
|
ElementNodeTypeId(HTMLInputElementTypeId) |
|
||||||
|
@ -155,8 +161,8 @@ impl NodeFlags {
|
||||||
ElementNodeTypeId(HTMLOptGroupElementTypeId) |
|
ElementNodeTypeId(HTMLOptGroupElementTypeId) |
|
||||||
ElementNodeTypeId(HTMLOptionElementTypeId) |
|
ElementNodeTypeId(HTMLOptionElementTypeId) |
|
||||||
//ElementNodeTypeId(HTMLMenuItemElementTypeId) |
|
//ElementNodeTypeId(HTMLMenuItemElementTypeId) |
|
||||||
ElementNodeTypeId(HTMLFieldSetElementTypeId) => InEnabledState | IsDirty,
|
ElementNodeTypeId(HTMLFieldSetElementTypeId) => InEnabledState | dirty,
|
||||||
_ => IsDirty,
|
_ => dirty,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -414,9 +420,15 @@ pub trait NodeHelpers<'a> {
|
||||||
fn get_enabled_state(self) -> bool;
|
fn get_enabled_state(self) -> bool;
|
||||||
fn set_enabled_state(self, state: bool);
|
fn set_enabled_state(self, state: bool);
|
||||||
|
|
||||||
|
fn get_has_changed(self) -> bool;
|
||||||
|
fn set_has_changed(self, state: bool);
|
||||||
|
|
||||||
fn get_is_dirty(self) -> bool;
|
fn get_is_dirty(self) -> bool;
|
||||||
fn set_is_dirty(self, state: bool);
|
fn set_is_dirty(self, state: bool);
|
||||||
|
|
||||||
|
fn get_has_dirty_siblings(self) -> bool;
|
||||||
|
fn set_has_dirty_siblings(self, state: bool);
|
||||||
|
|
||||||
fn get_has_dirty_descendants(self) -> bool;
|
fn get_has_dirty_descendants(self) -> bool;
|
||||||
fn set_has_dirty_descendants(self, state: bool);
|
fn set_has_dirty_descendants(self, state: bool);
|
||||||
|
|
||||||
|
@ -574,6 +586,14 @@ impl<'a> NodeHelpers<'a> for JSRef<'a, Node> {
|
||||||
self.set_flag(InEnabledState, state)
|
self.set_flag(InEnabledState, state)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn get_has_changed(self) -> bool {
|
||||||
|
self.get_flag(HasChanged)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_has_changed(self, state: bool) {
|
||||||
|
self.set_flag(HasChanged, state)
|
||||||
|
}
|
||||||
|
|
||||||
fn get_is_dirty(self) -> bool {
|
fn get_is_dirty(self) -> bool {
|
||||||
self.get_flag(IsDirty)
|
self.get_flag(IsDirty)
|
||||||
}
|
}
|
||||||
|
@ -582,6 +602,14 @@ impl<'a> NodeHelpers<'a> for JSRef<'a, Node> {
|
||||||
self.set_flag(IsDirty, state)
|
self.set_flag(IsDirty, state)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn get_has_dirty_siblings(self) -> bool {
|
||||||
|
self.get_flag(HasDirtySiblings)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_has_dirty_siblings(self, state: bool) {
|
||||||
|
self.set_flag(HasDirtySiblings, state)
|
||||||
|
}
|
||||||
|
|
||||||
fn get_has_dirty_descendants(self) -> bool {
|
fn get_has_dirty_descendants(self) -> bool {
|
||||||
self.get_flag(HasDirtyDescendants)
|
self.get_flag(HasDirtyDescendants)
|
||||||
}
|
}
|
||||||
|
@ -591,24 +619,24 @@ impl<'a> NodeHelpers<'a> for JSRef<'a, Node> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn dirty(self) {
|
fn dirty(self) {
|
||||||
// 1. Dirty descendants.
|
// 1. Dirty self.
|
||||||
fn dirty_subtree(node: JSRef<Node>) {
|
self.set_has_changed(true);
|
||||||
node.set_is_dirty(true);
|
|
||||||
|
|
||||||
let mut has_dirty_descendants = false;
|
// 2. Dirty descendants.
|
||||||
|
fn dirty_subtree(node: JSRef<Node>) {
|
||||||
|
// Stop if this subtree is already dirty.
|
||||||
|
if node.get_is_dirty() { return }
|
||||||
|
|
||||||
|
node.set_flag(IsDirty | HasDirtySiblings | HasDirtyDescendants, true);
|
||||||
|
|
||||||
for kid in node.children() {
|
for kid in node.children() {
|
||||||
dirty_subtree(kid);
|
dirty_subtree(kid);
|
||||||
has_dirty_descendants = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if has_dirty_descendants {
|
|
||||||
node.set_has_dirty_descendants(true);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
dirty_subtree(self);
|
dirty_subtree(self);
|
||||||
|
|
||||||
// 2. Dirty siblings.
|
// 3. Dirty siblings.
|
||||||
//
|
//
|
||||||
// TODO(cgaebel): This is a very conservative way to account for sibling
|
// TODO(cgaebel): This is a very conservative way to account for sibling
|
||||||
// selectors. Maybe we can do something smarter in the future.
|
// selectors. Maybe we can do something smarter in the future.
|
||||||
|
@ -619,10 +647,10 @@ impl<'a> NodeHelpers<'a> for JSRef<'a, Node> {
|
||||||
};
|
};
|
||||||
|
|
||||||
for sibling in parent.root().children() {
|
for sibling in parent.root().children() {
|
||||||
sibling.set_is_dirty(true);
|
sibling.set_has_dirty_siblings(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 3. Dirty ancestors.
|
// 4. Dirty ancestors.
|
||||||
for ancestor in self.ancestors() {
|
for ancestor in self.ancestors() {
|
||||||
if ancestor.get_has_dirty_descendants() { break }
|
if ancestor.get_has_dirty_descendants() { break }
|
||||||
ancestor.set_has_dirty_descendants(true);
|
ancestor.set_has_dirty_descendants(true);
|
||||||
|
@ -2249,9 +2277,15 @@ impl<'a> style::TNode<'a, JSRef<'a, Element>> for JSRef<'a, Node> {
|
||||||
elem.unwrap().html_element_in_html_document()
|
elem.unwrap().html_element_in_html_document()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn has_changed(self) -> bool { self.get_has_changed() }
|
||||||
|
unsafe fn set_changed(self, value: bool) { self.set_has_changed(value) }
|
||||||
|
|
||||||
fn is_dirty(self) -> bool { self.get_is_dirty() }
|
fn is_dirty(self) -> bool { self.get_is_dirty() }
|
||||||
unsafe fn set_dirty(self, value: bool) { self.set_is_dirty(value) }
|
unsafe fn set_dirty(self, value: bool) { self.set_is_dirty(value) }
|
||||||
|
|
||||||
|
fn has_dirty_siblings(self) -> bool { self.get_has_dirty_siblings() }
|
||||||
|
unsafe fn set_dirty_siblings(self, value: bool) { self.set_has_dirty_siblings(value) }
|
||||||
|
|
||||||
fn has_dirty_descendants(self) -> bool { self.get_has_dirty_descendants() }
|
fn has_dirty_descendants(self) -> bool { self.get_has_dirty_descendants() }
|
||||||
unsafe fn set_dirty_descendants(self, value: bool) { self.set_has_dirty_descendants(value) }
|
unsafe fn set_dirty_descendants(self, value: bool) { self.set_has_dirty_descendants(value) }
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,9 +21,15 @@ pub trait TNode<'a, E: TElement<'a>> : Clone + Copy {
|
||||||
fn match_attr(self, attr: &AttrSelector, test: |&str| -> bool) -> bool;
|
fn match_attr(self, attr: &AttrSelector, test: |&str| -> bool) -> bool;
|
||||||
fn is_html_element_in_html_document(self) -> bool;
|
fn is_html_element_in_html_document(self) -> bool;
|
||||||
|
|
||||||
|
fn has_changed(self) -> bool;
|
||||||
|
unsafe fn set_changed(self, value: bool);
|
||||||
|
|
||||||
fn is_dirty(self) -> bool;
|
fn is_dirty(self) -> bool;
|
||||||
unsafe fn set_dirty(self, value: bool);
|
unsafe fn set_dirty(self, value: bool);
|
||||||
|
|
||||||
|
fn has_dirty_siblings(self) -> bool;
|
||||||
|
unsafe fn set_dirty_siblings(self, value: bool);
|
||||||
|
|
||||||
fn has_dirty_descendants(self) -> bool;
|
fn has_dirty_descendants(self) -> bool;
|
||||||
unsafe fn set_dirty_descendants(self, value: bool);
|
unsafe fn set_dirty_descendants(self, value: bool);
|
||||||
}
|
}
|
||||||
|
|
|
@ -59,6 +59,8 @@ pub struct Opts {
|
||||||
/// sequential algorithm.
|
/// sequential algorithm.
|
||||||
pub layout_threads: uint,
|
pub layout_threads: uint,
|
||||||
|
|
||||||
|
pub incremental_layout: bool,
|
||||||
|
|
||||||
/// True to exit after the page load (`-x`).
|
/// True to exit after the page load (`-x`).
|
||||||
pub exit_after_load: bool,
|
pub exit_after_load: bool,
|
||||||
|
|
||||||
|
@ -126,6 +128,7 @@ pub fn from_cmdline_args(args: &[String]) -> Option<Opts> {
|
||||||
getopts::optflagopt("m", "memory-profile", "Memory profiler flag and output interval", "10"),
|
getopts::optflagopt("m", "memory-profile", "Memory profiler flag and output interval", "10"),
|
||||||
getopts::optflag("x", "exit", "Exit after load flag"),
|
getopts::optflag("x", "exit", "Exit after load flag"),
|
||||||
getopts::optopt("y", "layout-threads", "Number of threads to use for layout", "1"),
|
getopts::optopt("y", "layout-threads", "Number of threads to use for layout", "1"),
|
||||||
|
getopts::optflag("i", "incremental-layout", "Whether or not to use incremental layout."),
|
||||||
getopts::optflag("z", "headless", "Headless mode"),
|
getopts::optflag("z", "headless", "Headless mode"),
|
||||||
getopts::optflag("f", "hard-fail", "Exit on task failure instead of displaying about:failure"),
|
getopts::optflag("f", "hard-fail", "Exit on task failure instead of displaying about:failure"),
|
||||||
getopts::optflag("b", "bubble-widths", "Bubble intrinsic widths separately like other engines"),
|
getopts::optflag("b", "bubble-widths", "Bubble intrinsic widths separately like other engines"),
|
||||||
|
@ -208,6 +211,8 @@ pub fn from_cmdline_args(args: &[String]) -> Option<Opts> {
|
||||||
None => cmp::max(rt::default_sched_threads() * 3 / 4, 1),
|
None => cmp::max(rt::default_sched_threads() * 3 / 4, 1),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let incremental_layout = opt_match.opt_present("i");
|
||||||
|
|
||||||
let mut bubble_inline_sizes_separately = opt_match.opt_present("b");
|
let mut bubble_inline_sizes_separately = opt_match.opt_present("b");
|
||||||
|
|
||||||
let trace_layout = opt_match.opt_present("trace-layout");
|
let trace_layout = opt_match.opt_present("trace-layout");
|
||||||
|
@ -242,6 +247,7 @@ pub fn from_cmdline_args(args: &[String]) -> Option<Opts> {
|
||||||
memory_profiler_period: memory_profiler_period,
|
memory_profiler_period: memory_profiler_period,
|
||||||
enable_experimental: opt_match.opt_present("e"),
|
enable_experimental: opt_match.opt_present("e"),
|
||||||
layout_threads: layout_threads,
|
layout_threads: layout_threads,
|
||||||
|
incremental_layout: incremental_layout,
|
||||||
exit_after_load: opt_match.opt_present("x"),
|
exit_after_load: opt_match.opt_present("x"),
|
||||||
output_file: opt_match.opt_str("o"),
|
output_file: opt_match.opt_str("o"),
|
||||||
headless: opt_match.opt_present("z"),
|
headless: opt_match.opt_present("z"),
|
||||||
|
|
|
@ -68,6 +68,8 @@ pub enum TimeProfilerCategory {
|
||||||
CompositingCategory,
|
CompositingCategory,
|
||||||
LayoutPerformCategory,
|
LayoutPerformCategory,
|
||||||
LayoutStyleRecalcCategory,
|
LayoutStyleRecalcCategory,
|
||||||
|
LayoutRestyleDamagePropagation,
|
||||||
|
LayoutNonIncrementalReset,
|
||||||
LayoutSelectorMatchCategory,
|
LayoutSelectorMatchCategory,
|
||||||
LayoutTreeBuilderCategory,
|
LayoutTreeBuilderCategory,
|
||||||
LayoutDamagePropagateCategory,
|
LayoutDamagePropagateCategory,
|
||||||
|
@ -86,6 +88,8 @@ impl Formatable for TimeProfilerCategory {
|
||||||
fn format(&self) -> String {
|
fn format(&self) -> String {
|
||||||
let padding = match *self {
|
let padding = match *self {
|
||||||
LayoutStyleRecalcCategory |
|
LayoutStyleRecalcCategory |
|
||||||
|
LayoutRestyleDamagePropagation |
|
||||||
|
LayoutNonIncrementalReset |
|
||||||
LayoutMainCategory |
|
LayoutMainCategory |
|
||||||
LayoutDispListBuildCategory |
|
LayoutDispListBuildCategory |
|
||||||
LayoutShapingCategory |
|
LayoutShapingCategory |
|
||||||
|
@ -99,6 +103,8 @@ impl Formatable for TimeProfilerCategory {
|
||||||
CompositingCategory => "Compositing",
|
CompositingCategory => "Compositing",
|
||||||
LayoutPerformCategory => "Layout",
|
LayoutPerformCategory => "Layout",
|
||||||
LayoutStyleRecalcCategory => "Style Recalc",
|
LayoutStyleRecalcCategory => "Style Recalc",
|
||||||
|
LayoutRestyleDamagePropagation => "Restyle Damage Propagation",
|
||||||
|
LayoutNonIncrementalReset => "Non-incremental reset (temporary)",
|
||||||
LayoutSelectorMatchCategory => "Selector Matching",
|
LayoutSelectorMatchCategory => "Selector Matching",
|
||||||
LayoutTreeBuilderCategory => "Tree Building",
|
LayoutTreeBuilderCategory => "Tree Building",
|
||||||
LayoutDamagePropagateCategory => "Damage Propagation",
|
LayoutDamagePropagateCategory => "Damage Propagation",
|
||||||
|
|
|
@ -60,6 +60,7 @@ pub extern "C" fn cef_run_message_loop() {
|
||||||
memory_profiler_period: None,
|
memory_profiler_period: None,
|
||||||
enable_experimental: false,
|
enable_experimental: false,
|
||||||
layout_threads: 1,
|
layout_threads: 1,
|
||||||
|
incremental_layout: false,
|
||||||
//layout_threads: cmp::max(rt::default_sched_threads() * 3 / 4, 1),
|
//layout_threads: cmp::max(rt::default_sched_threads() * 3 / 4, 1),
|
||||||
exit_after_load: false,
|
exit_after_load: false,
|
||||||
output_file: None,
|
output_file: None,
|
||||||
|
|
|
@ -242,7 +242,7 @@ fn capture(reftest: &Reftest, side: uint) -> (u32, u32, Vec<u8>) {
|
||||||
Ok(status) => status,
|
Ok(status) => status,
|
||||||
Err(e) => fail!("failed to execute process: {}", e),
|
Err(e) => fail!("failed to execute process: {}", e),
|
||||||
};
|
};
|
||||||
assert!(retval == ExitStatus(0));
|
assert_eq!(retval, ExitStatus(0));
|
||||||
|
|
||||||
let image = png::load_png(&from_str::<Path>(png_filename.as_slice()).unwrap()).unwrap();
|
let image = png::load_png(&from_str::<Path>(png_filename.as_slice()).unwrap()).unwrap();
|
||||||
let rgba8_bytes = match image.pixels {
|
let rgba8_bytes = match image.pixels {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue