mirror of
https://github.com/servo/servo.git
synced 2025-08-03 04:30:10 +01:00
layout: Make incremental reflow more fine-grained by introducing "reflow
out-of-flow" and "reconstruct flow" damage bits. This is needed for good performance on the maze solver.
This commit is contained in:
parent
7712052e13
commit
08fc7c2795
20 changed files with 644 additions and 403 deletions
|
@ -2,8 +2,11 @@
|
|||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
use flow::{mod, Flow};
|
||||
|
||||
use std::fmt;
|
||||
use std::sync::Arc;
|
||||
use style::computed_values::float;
|
||||
use style::ComputedValues;
|
||||
|
||||
bitflags! {
|
||||
|
@ -18,22 +21,67 @@ bitflags! {
|
|||
#[doc = "bottom-up."]
|
||||
static BubbleISizes = 0x02,
|
||||
|
||||
#[doc = "Recompute actual inline-sizes and block-sizes, only taking out-of-flow children \
|
||||
into account. \
|
||||
Propagates up the flow tree because the computation is top-down."]
|
||||
static ReflowOutOfFlow = 0x04,
|
||||
|
||||
#[doc = "Recompute actual inline_sizes and block_sizes."]
|
||||
#[doc = "Propagates up the flow tree because the computation is"]
|
||||
#[doc = "top-down."]
|
||||
static Reflow = 0x04
|
||||
static Reflow = 0x08,
|
||||
|
||||
#[doc = "The entire flow needs to be reconstructed."]
|
||||
static ReconstructFlow = 0x10
|
||||
}
|
||||
}
|
||||
|
||||
bitflags! {
|
||||
flags SpecialRestyleDamage: u8 {
|
||||
#[doc="If this flag is set, we need to reflow the entire document. This is more or less a \
|
||||
temporary hack to deal with cases that we don't handle incrementally yet."]
|
||||
static ReflowEntireDocument = 0x01,
|
||||
}
|
||||
}
|
||||
|
||||
impl RestyleDamage {
|
||||
/// Elements of self which should also get set on any ancestor flow.
|
||||
pub fn propagate_up(self) -> RestyleDamage {
|
||||
self & Reflow
|
||||
/// Supposing a flow has the given `position` property and this damage, returns the damage that
|
||||
/// we should add to the *parent* of this flow.
|
||||
pub fn damage_for_parent(self, child_is_absolutely_positioned: bool) -> RestyleDamage {
|
||||
if child_is_absolutely_positioned {
|
||||
self & (Repaint | ReflowOutOfFlow)
|
||||
} else {
|
||||
self & (Repaint | Reflow | ReflowOutOfFlow)
|
||||
}
|
||||
}
|
||||
|
||||
/// Elements of self which should also get set on any child flows.
|
||||
pub fn propagate_down(self) -> RestyleDamage {
|
||||
self & BubbleISizes
|
||||
/// Supposing the *parent* of a flow with the given `position` property has this damage,
|
||||
/// returns the damage that we should add to this flow.
|
||||
pub fn damage_for_child(self,
|
||||
parent_is_absolutely_positioned: bool,
|
||||
child_is_absolutely_positioned: bool)
|
||||
-> RestyleDamage {
|
||||
match (parent_is_absolutely_positioned, child_is_absolutely_positioned) {
|
||||
(false, true) => {
|
||||
// Absolute children are out-of-flow and therefore insulated from changes.
|
||||
//
|
||||
// FIXME(pcwalton): Au contraire, if the containing block dimensions change!
|
||||
self & Repaint
|
||||
}
|
||||
(true, false) => {
|
||||
// Changing the position of an absolutely-positioned block requires us to reflow
|
||||
// its kids.
|
||||
if self.contains(ReflowOutOfFlow) {
|
||||
self | Reflow
|
||||
} else {
|
||||
self
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
// TODO(pcwalton): Take floatedness into account.
|
||||
self & (Repaint | Reflow)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -42,9 +90,11 @@ impl fmt::Show for RestyleDamage {
|
|||
let mut first_elem = true;
|
||||
|
||||
let to_iter =
|
||||
[ (Repaint, "Repaint")
|
||||
, (BubbleISizes, "BubbleISizes")
|
||||
, (Reflow, "Reflow")
|
||||
[ (Repaint, "Repaint")
|
||||
, (BubbleISizes, "BubbleISizes")
|
||||
, (ReflowOutOfFlow, "ReflowOutOfFlow")
|
||||
, (Reflow, "Reflow")
|
||||
, (ReconstructFlow, "ReconstructFlow")
|
||||
];
|
||||
|
||||
for &(damage, damage_str) in to_iter.iter() {
|
||||
|
@ -78,7 +128,7 @@ macro_rules! add_if_not_equal(
|
|||
pub fn compute_damage(old: &Option<Arc<ComputedValues>>, new: &ComputedValues) -> RestyleDamage {
|
||||
let old: &ComputedValues =
|
||||
match old.as_ref() {
|
||||
None => return Repaint | BubbleISizes | Reflow,
|
||||
None => return RestyleDamage::all(),
|
||||
Some(cv) => &**cv,
|
||||
};
|
||||
|
||||
|
@ -90,23 +140,83 @@ pub fn compute_damage(old: &Option<Arc<ComputedValues>>, new: &ComputedValues) -
|
|||
|
||||
// FIXME: We can short-circuit more of this.
|
||||
|
||||
add_if_not_equal!(old, new, damage, [ 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 ]);
|
||||
add_if_not_equal!(old, new, damage,
|
||||
[ 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
|
||||
]);
|
||||
|
||||
add_if_not_equal!(old, new, damage, [ Repaint, BubbleISizes, Reflow ],
|
||||
[ get_border.border_top_width, get_border.border_right_width,
|
||||
get_border.border_bottom_width, get_border.border_left_width,
|
||||
get_margin.margin_top, get_margin.margin_right,
|
||||
get_margin.margin_bottom, get_margin.margin_left,
|
||||
get_padding.padding_top, get_padding.padding_right,
|
||||
get_padding.padding_bottom, get_padding.padding_left,
|
||||
get_box.position, get_box.width, get_box.height, get_box.float, get_box.display,
|
||||
get_font.font_family, get_font.font_size, get_font.font_style, get_font.font_weight,
|
||||
get_inheritedtext.text_align, get_text.text_decoration, get_inheritedbox.line_height ]);
|
||||
add_if_not_equal!(old, new, damage,
|
||||
[ Repaint, ReflowOutOfFlow ], [
|
||||
get_positionoffsets.top, get_positionoffsets.left,
|
||||
get_positionoffsets.right, get_positionoffsets.bottom
|
||||
]);
|
||||
|
||||
add_if_not_equal!(old, new, damage,
|
||||
[ Repaint, BubbleISizes, ReflowOutOfFlow, Reflow ], [
|
||||
get_border.border_top_width, get_border.border_right_width,
|
||||
get_border.border_bottom_width, get_border.border_left_width,
|
||||
get_margin.margin_top, get_margin.margin_right,
|
||||
get_margin.margin_bottom, get_margin.margin_left,
|
||||
get_padding.padding_top, get_padding.padding_right,
|
||||
get_padding.padding_bottom, get_padding.padding_left,
|
||||
get_box.width, get_box.height,
|
||||
get_font.font_family, get_font.font_size, get_font.font_style, get_font.font_weight,
|
||||
get_inheritedtext.text_align, get_text.text_decoration, get_inheritedbox.line_height
|
||||
]);
|
||||
|
||||
add_if_not_equal!(old, new, damage,
|
||||
[ Repaint, BubbleISizes, ReflowOutOfFlow, Reflow, ReconstructFlow ],
|
||||
[ get_box.float, get_box.display, get_box.position ]);
|
||||
|
||||
// FIXME: test somehow that we checked every CSS property
|
||||
|
||||
damage
|
||||
}
|
||||
|
||||
pub trait LayoutDamageComputation {
|
||||
fn compute_layout_damage(self) -> SpecialRestyleDamage;
|
||||
fn reflow_entire_document(self);
|
||||
}
|
||||
|
||||
impl<'a> LayoutDamageComputation for &'a mut Flow+'a {
|
||||
fn compute_layout_damage(self) -> SpecialRestyleDamage {
|
||||
let mut special_damage = SpecialRestyleDamage::empty();
|
||||
let is_absolutely_positioned = flow::base(self).flags.is_absolutely_positioned();
|
||||
|
||||
{
|
||||
let self_base = flow::mut_base(self);
|
||||
for kid in self_base.children.iter_mut() {
|
||||
let child_is_absolutely_positioned =
|
||||
flow::base(kid).flags.is_absolutely_positioned();
|
||||
flow::mut_base(kid).restyle_damage
|
||||
.insert(self_base.restyle_damage.damage_for_child(
|
||||
is_absolutely_positioned,
|
||||
child_is_absolutely_positioned));
|
||||
special_damage.insert(kid.compute_layout_damage());
|
||||
self_base.restyle_damage
|
||||
.insert(flow::base(kid).restyle_damage.damage_for_parent(
|
||||
child_is_absolutely_positioned));
|
||||
}
|
||||
}
|
||||
|
||||
let self_base = flow::base(self);
|
||||
if self_base.flags.float_kind() != float::none &&
|
||||
self_base.restyle_damage.intersects(Reflow) {
|
||||
special_damage.insert(ReflowEntireDocument);
|
||||
}
|
||||
|
||||
special_damage
|
||||
}
|
||||
|
||||
fn reflow_entire_document(self) {
|
||||
let self_base = flow::mut_base(self);
|
||||
self_base.restyle_damage.insert(RestyleDamage::all());
|
||||
self_base.restyle_damage.remove(ReconstructFlow);
|
||||
for kid in self_base.children.iter_mut() {
|
||||
kid.reflow_entire_document();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue