layout: Add a REPOSITION restyle damage type.

Separating out `REPOSITION` from `REPAINT` allows us to compute
stacking-context-relative positions without rebuilding the display list.
This saves a lot of time when responding to script-to-layout queries.
This commit is contained in:
Patrick Walton 2016-09-20 16:14:54 -07:00
parent 1235f4bff6
commit 65e3db1c0d
6 changed files with 52 additions and 35 deletions

View file

@ -51,6 +51,7 @@ use model::{self, IntrinsicISizes, MarginCollapseInfo};
use model::{CollapsibleMargins, MaybeAuto, specified, specified_or_none}; use model::{CollapsibleMargins, MaybeAuto, specified, specified_or_none};
use rustc_serialize::{Encodable, Encoder}; use rustc_serialize::{Encodable, Encoder};
use script_layout_interface::restyle_damage::{BUBBLE_ISIZES, REFLOW, REFLOW_OUT_OF_FLOW}; use script_layout_interface::restyle_damage::{BUBBLE_ISIZES, REFLOW, REFLOW_OUT_OF_FLOW};
use script_layout_interface::restyle_damage::REPOSITION;
use std::cmp::{max, min}; use std::cmp::{max, min};
use std::fmt; use std::fmt;
use std::sync::Arc; use std::sync::Arc;
@ -2114,6 +2115,8 @@ impl Flow for BlockFlow {
flow::mut_base(kid).stacking_relative_position_of_display_port = flow::mut_base(kid).stacking_relative_position_of_display_port =
stacking_relative_position_of_display_port_for_children; stacking_relative_position_of_display_port_for_children;
} }
self.base.restyle_damage.remove(REPOSITION)
} }
fn mark_as_root(&mut self) { fn mark_as_root(&mut self) {

View file

@ -42,7 +42,8 @@ use model::{CollapsibleMargins, IntrinsicISizes, MarginCollapseInfo};
use multicol::MulticolFlow; use multicol::MulticolFlow;
use parallel::FlowParallelInfo; use parallel::FlowParallelInfo;
use rustc_serialize::{Encodable, Encoder}; use rustc_serialize::{Encodable, Encoder};
use script_layout_interface::restyle_damage::{RECONSTRUCT_FLOW, REFLOW, REFLOW_OUT_OF_FLOW, REPAINT, RestyleDamage}; use script_layout_interface::restyle_damage::{RECONSTRUCT_FLOW, REFLOW, REFLOW_OUT_OF_FLOW};
use script_layout_interface::restyle_damage::{REPAINT, REPOSITION, RestyleDamage};
use script_layout_interface::wrapper_traits::{PseudoElementType, ThreadSafeLayoutNode}; use script_layout_interface::wrapper_traits::{PseudoElementType, ThreadSafeLayoutNode};
use std::{fmt, mem, raw}; use std::{fmt, mem, raw};
use std::iter::Zip; use std::iter::Zip;
@ -320,6 +321,7 @@ pub trait Flow: fmt::Debug + Sync + Send + 'static {
/// Phase 4 of reflow: computes absolute positions. /// Phase 4 of reflow: computes absolute positions.
fn compute_absolute_position(&mut self, _: &SharedLayoutContext) { fn compute_absolute_position(&mut self, _: &SharedLayoutContext) {
// The default implementation is a no-op. // The default implementation is a no-op.
mut_base(self).restyle_damage.remove(REPOSITION)
} }
/// Phase 5 of reflow: builds display lists. /// Phase 5 of reflow: builds display lists.

View file

@ -25,8 +25,8 @@ use gfx_traits::print_tree::PrintTree;
use layout_debug; use layout_debug;
use model::IntrinsicISizesContribution; use model::IntrinsicISizesContribution;
use range::{Range, RangeIndex}; use range::{Range, RangeIndex};
use script_layout_interface::restyle_damage::{BUBBLE_ISIZES, REFLOW}; use script_layout_interface::restyle_damage::{BUBBLE_ISIZES, REFLOW, REFLOW_OUT_OF_FLOW};
use script_layout_interface::restyle_damage::{REFLOW_OUT_OF_FLOW, RESOLVE_GENERATED_CONTENT}; use script_layout_interface::restyle_damage::{REPOSITION, RESOLVE_GENERATED_CONTENT};
use script_layout_interface::wrapper_traits::PseudoElementType; use script_layout_interface::wrapper_traits::PseudoElementType;
use std::{fmt, i32, isize, mem}; use std::{fmt, i32, isize, mem};
use std::cmp::max; use std::cmp::max;
@ -1650,6 +1650,8 @@ impl Flow for InlineFlow {
_ => {} _ => {}
} }
} }
self.base.restyle_damage.remove(REPOSITION)
} }
fn update_late_computed_inline_position_if_necessary(&mut self, _: Au) {} fn update_late_computed_inline_position_if_necessary(&mut self, _: Au) {}

View file

@ -17,7 +17,7 @@ use generated_content::ResolveGeneratedContent;
use gfx::display_list::{DisplayItem, StackingContext}; use gfx::display_list::{DisplayItem, StackingContext};
use script_layout_interface::restyle_damage::{REFLOW, STORE_OVERFLOW}; use script_layout_interface::restyle_damage::{REFLOW, STORE_OVERFLOW};
use style::context::StyleContext; use style::context::StyleContext;
use traversal::{AssignBSizes, AssignISizes, BubbleISizes, BuildDisplayList, ComputeAbsolutePositions}; use traversal::{AssignBSizes, AssignISizes, BubbleISizes, BuildDisplayList};
use util::opts; use util::opts;
pub use style::sequential::traverse_dom; pub use style::sequential::traverse_dom;
@ -78,7 +78,6 @@ pub fn build_display_list_for_subtree(flow_root: &mut Flow,
root_stacking_context: &mut StackingContext, root_stacking_context: &mut StackingContext,
shared_layout_context: &SharedLayoutContext) shared_layout_context: &SharedLayoutContext)
-> Vec<DisplayItem> { -> Vec<DisplayItem> {
flow_root.traverse_preorder(&ComputeAbsolutePositions { layout_context: shared_layout_context });
let mut children = vec![]; let mut children = vec![];
flow_root.collect_stacking_contexts(root_stacking_context.id, flow_root.collect_stacking_contexts(root_stacking_context.id,
&mut children); &mut children);

View file

@ -75,7 +75,7 @@ use layout::query::{process_margin_style_query, process_node_overflow_request, p
use layout::query::{process_node_geometry_request, process_node_layer_id_request, process_node_scroll_area_request}; use layout::query::{process_node_geometry_request, process_node_layer_id_request, process_node_scroll_area_request};
use layout::query::process_offset_parent_query; use layout::query::process_offset_parent_query;
use layout::sequential; use layout::sequential;
use layout::traversal::RecalcStyleAndConstructFlows; use layout::traversal::{ComputeAbsolutePositions, RecalcStyleAndConstructFlows};
use layout::webrender_helpers::{WebRenderDisplayListConverter, WebRenderFrameBuilder}; use layout::webrender_helpers::{WebRenderDisplayListConverter, WebRenderFrameBuilder};
use layout::wrapper::{LayoutNodeLayoutData, NonOpaqueStyleAndLayoutData}; use layout::wrapper::{LayoutNodeLayoutData, NonOpaqueStyleAndLayoutData};
use layout_traits::LayoutThreadFactory; use layout_traits::LayoutThreadFactory;
@ -89,7 +89,8 @@ use script::layout_wrapper::{ServoLayoutDocument, ServoLayoutNode};
use script_layout_interface::{OpaqueStyleAndLayoutData, PartialStyleAndLayoutData}; use script_layout_interface::{OpaqueStyleAndLayoutData, PartialStyleAndLayoutData};
use script_layout_interface::message::{Msg, NewLayoutThreadInfo, Reflow, ReflowQueryType, ScriptReflow}; use script_layout_interface::message::{Msg, NewLayoutThreadInfo, Reflow, ReflowQueryType, ScriptReflow};
use script_layout_interface::reporter::CSSErrorReporter; use script_layout_interface::reporter::CSSErrorReporter;
use script_layout_interface::restyle_damage::{REFLOW, REFLOW_OUT_OF_FLOW, REPAINT, STORE_OVERFLOW}; use script_layout_interface::restyle_damage::{REFLOW, REFLOW_OUT_OF_FLOW, REPAINT, REPOSITION};
use script_layout_interface::restyle_damage::STORE_OVERFLOW;
use script_layout_interface::rpc::{LayoutRPC, MarginStyleResponse, NodeOverflowResponse, OffsetParentResponse}; use script_layout_interface::rpc::{LayoutRPC, MarginStyleResponse, NodeOverflowResponse, OffsetParentResponse};
use script_layout_interface::wrapper_traits::LayoutNode; use script_layout_interface::wrapper_traits::LayoutNode;
use script_traits::{ConstellationControlMsg, LayoutControlMsg, LayoutMsg as ConstellationMsg}; use script_traits::{ConstellationControlMsg, LayoutControlMsg, LayoutMsg as ConstellationMsg};
@ -919,6 +920,12 @@ impl LayoutThread {
flow::mut_base(layout_root).clip = flow::mut_base(layout_root).clip =
ClippingRegion::from_rect(&data.page_clip_rect); ClippingRegion::from_rect(&data.page_clip_rect);
if flow::base(layout_root).restyle_damage.contains(REPOSITION) {
layout_root.traverse_preorder(&ComputeAbsolutePositions {
layout_context: shared_layout_context
});
}
if flow::base(layout_root).restyle_damage.contains(REPAINT) || if flow::base(layout_root).restyle_damage.contains(REPAINT) ||
rw_data.display_list.is_none() { rw_data.display_list.is_none() {
let mut root_stacking_context = StackingContext::new(StackingContextId::new(0), let mut root_stacking_context = StackingContext::new(StackingContextId::new(0),

View file

@ -15,31 +15,36 @@ bitflags! {
#[doc = "Currently unused; need to decide how this propagates."] #[doc = "Currently unused; need to decide how this propagates."]
const REPAINT = 0x01, const REPAINT = 0x01,
#[doc = "The stacking-context-relative position of this node or its descendants has \
changed."]
#[doc = "Propagates both up and down the flow tree."]
const REPOSITION = 0x02,
#[doc = "Recompute the overflow regions (bounding box of object and all descendants)."] #[doc = "Recompute the overflow regions (bounding box of object and all descendants)."]
#[doc = "Propagates down the flow tree because the computation is bottom-up."] #[doc = "Propagates down the flow tree because the computation is bottom-up."]
const STORE_OVERFLOW = 0x02, const STORE_OVERFLOW = 0x04,
#[doc = "Recompute intrinsic inline_sizes (minimum and preferred)."] #[doc = "Recompute intrinsic inline_sizes (minimum and preferred)."]
#[doc = "Propagates down the flow tree because the computation is"] #[doc = "Propagates down the flow tree because the computation is"]
#[doc = "bottom-up."] #[doc = "bottom-up."]
const BUBBLE_ISIZES = 0x04, const BUBBLE_ISIZES = 0x08,
#[doc = "Recompute actual inline-sizes and block-sizes, only taking out-of-flow children \ #[doc = "Recompute actual inline-sizes and block-sizes, only taking out-of-flow children \
into account. \ into account. \
Propagates up the flow tree because the computation is top-down."] Propagates up the flow tree because the computation is top-down."]
const REFLOW_OUT_OF_FLOW = 0x08, const REFLOW_OUT_OF_FLOW = 0x10,
#[doc = "Recompute actual inline_sizes and block_sizes."] #[doc = "Recompute actual inline_sizes and block_sizes."]
#[doc = "Propagates up the flow tree because the computation is"] #[doc = "Propagates up the flow tree because the computation is"]
#[doc = "top-down."] #[doc = "top-down."]
const REFLOW = 0x10, const REFLOW = 0x20,
#[doc = "Re-resolve generated content. \ #[doc = "Re-resolve generated content. \
Propagates up the flow tree because the computation is inorder."] Propagates up the flow tree because the computation is inorder."]
const RESOLVE_GENERATED_CONTENT = 0x20, const RESOLVE_GENERATED_CONTENT = 0x40,
#[doc = "The entire flow needs to be reconstructed."] #[doc = "The entire flow needs to be reconstructed."]
const RECONSTRUCT_FLOW = 0x40 const RECONSTRUCT_FLOW = 0x80
} }
} }
@ -63,7 +68,8 @@ impl TRestyleDamage for RestyleDamage {
/// `RestyleDamage::all()` will result in unnecessary sequential resolution /// `RestyleDamage::all()` will result in unnecessary sequential resolution
/// of generated content. /// of generated content.
fn rebuild_and_reflow() -> RestyleDamage { fn rebuild_and_reflow() -> RestyleDamage {
REPAINT | STORE_OVERFLOW | BUBBLE_ISIZES | REFLOW_OUT_OF_FLOW | REFLOW | RECONSTRUCT_FLOW REPAINT | REPOSITION | STORE_OVERFLOW | BUBBLE_ISIZES | REFLOW_OUT_OF_FLOW | REFLOW |
RECONSTRUCT_FLOW
} }
} }
@ -72,9 +78,10 @@ impl RestyleDamage {
/// returns the damage that we should add to the *parent* of this flow. /// 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 { pub fn damage_for_parent(self, child_is_absolutely_positioned: bool) -> RestyleDamage {
if child_is_absolutely_positioned { if child_is_absolutely_positioned {
self & (REPAINT | STORE_OVERFLOW | REFLOW_OUT_OF_FLOW | RESOLVE_GENERATED_CONTENT) self & (REPAINT | REPOSITION | STORE_OVERFLOW | REFLOW_OUT_OF_FLOW |
RESOLVE_GENERATED_CONTENT)
} else { } else {
self & (REPAINT | STORE_OVERFLOW | REFLOW | REFLOW_OUT_OF_FLOW | self & (REPAINT | REPOSITION | STORE_OVERFLOW | REFLOW | REFLOW_OUT_OF_FLOW |
RESOLVE_GENERATED_CONTENT) RESOLVE_GENERATED_CONTENT)
} }
} }
@ -90,7 +97,7 @@ impl RestyleDamage {
// Absolute children are out-of-flow and therefore insulated from changes. // Absolute children are out-of-flow and therefore insulated from changes.
// //
// FIXME(pcwalton): Au contraire, if the containing block dimensions change! // FIXME(pcwalton): Au contraire, if the containing block dimensions change!
self & REPAINT self & (REPAINT | REPOSITION)
} }
(true, false) => { (true, false) => {
// Changing the position of an absolutely-positioned block requires us to reflow // Changing the position of an absolutely-positioned block requires us to reflow
@ -103,7 +110,7 @@ impl RestyleDamage {
} }
_ => { _ => {
// TODO(pcwalton): Take floatedness into account. // TODO(pcwalton): Take floatedness into account.
self & (REPAINT | REFLOW) self & (REPAINT | REPOSITION | REFLOW)
} }
} }
} }
@ -115,6 +122,7 @@ impl fmt::Display for RestyleDamage {
let to_iter = let to_iter =
[ (REPAINT, "Repaint") [ (REPAINT, "Repaint")
, (REPOSITION, "Reposition")
, (STORE_OVERFLOW, "StoreOverflow") , (STORE_OVERFLOW, "StoreOverflow")
, (BUBBLE_ISIZES, "BubbleISizes") , (BUBBLE_ISIZES, "BubbleISizes")
, (REFLOW_OUT_OF_FLOW, "ReflowOutOfFlow") , (REFLOW_OUT_OF_FLOW, "ReflowOutOfFlow")
@ -163,14 +171,8 @@ fn compute_damage(old: &ServoComputedValues, new: &ServoComputedValues) -> Resty
// FIXME: Test somehow that every property is included. // FIXME: Test somehow that every property is included.
add_if_not_equal!(old, new, damage, add_if_not_equal!(old, new, damage,
[ [REPAINT, REPOSITION, STORE_OVERFLOW, BUBBLE_ISIZES, REFLOW_OUT_OF_FLOW,
REPAINT, REFLOW, RECONSTRUCT_FLOW], [
STORE_OVERFLOW,
BUBBLE_ISIZES,
REFLOW_OUT_OF_FLOW,
REFLOW,
RECONSTRUCT_FLOW
], [
get_box.float, get_box.display, get_box.position, get_counters.content, get_box.float, get_box.display, get_box.position, get_counters.content,
get_counters.counter_reset, get_counters.counter_increment, get_counters.counter_reset, get_counters.counter_increment,
get_inheritedbox._servo_under_display_none, get_inheritedbox._servo_under_display_none,
@ -191,8 +193,8 @@ fn compute_damage(old: &ServoComputedValues, new: &ServoComputedValues) -> Resty
get_column.column_width, get_column.column_count get_column.column_width, get_column.column_count
]) || (new.get_box().display == display::T::inline && ]) || (new.get_box().display == display::T::inline &&
add_if_not_equal!(old, new, damage, add_if_not_equal!(old, new, damage,
[REPAINT, STORE_OVERFLOW, BUBBLE_ISIZES, REFLOW_OUT_OF_FLOW, REFLOW, [REPAINT, REPOSITION, STORE_OVERFLOW, BUBBLE_ISIZES,
RECONSTRUCT_FLOW], [ REFLOW_OUT_OF_FLOW, REFLOW, RECONSTRUCT_FLOW], [
// For inline boxes only, border/padding styles are used in flow construction (to decide // For inline boxes only, border/padding styles are used in flow construction (to decide
// whether to create fragments for empty flows). // whether to create fragments for empty flows).
get_border.border_top_width, get_border.border_right_width, get_border.border_top_width, get_border.border_right_width,
@ -200,7 +202,8 @@ fn compute_damage(old: &ServoComputedValues, new: &ServoComputedValues) -> Resty
get_padding.padding_top, get_padding.padding_right, get_padding.padding_top, get_padding.padding_right,
get_padding.padding_bottom, get_padding.padding_left get_padding.padding_bottom, get_padding.padding_left
])) || add_if_not_equal!(old, new, damage, ])) || add_if_not_equal!(old, new, damage,
[ REPAINT, STORE_OVERFLOW, BUBBLE_ISIZES, REFLOW_OUT_OF_FLOW, REFLOW ], [REPAINT, REPOSITION, STORE_OVERFLOW, BUBBLE_ISIZES,
REFLOW_OUT_OF_FLOW, REFLOW],
[get_border.border_top_width, get_border.border_right_width, [get_border.border_top_width, get_border.border_right_width,
get_border.border_bottom_width, get_border.border_left_width, get_border.border_bottom_width, get_border.border_left_width,
get_margin.margin_top, get_margin.margin_right, get_margin.margin_top, get_margin.margin_right,
@ -225,9 +228,12 @@ fn compute_damage(old: &ServoComputedValues, new: &ServoComputedValues) -> Resty
get_position.flex_shrink, get_position.flex_shrink,
get_position.align_self get_position.align_self
]) || add_if_not_equal!(old, new, damage, ]) || add_if_not_equal!(old, new, damage,
[ REPAINT, STORE_OVERFLOW, REFLOW_OUT_OF_FLOW ], [ [REPAINT, REPOSITION, STORE_OVERFLOW, REFLOW_OUT_OF_FLOW], [
get_position.top, get_position.left, get_position.top, get_position.left,
get_position.right, get_position.bottom get_position.right, get_position.bottom,
get_effects.opacity,
get_effects.transform, get_effects.transform_style, get_effects.transform_origin,
get_effects.perspective, get_effects.perspective_origin
]) || add_if_not_equal!(old, new, damage, ]) || add_if_not_equal!(old, new, damage,
[REPAINT], [ [REPAINT], [
get_color.color, get_background.background_color, get_color.color, get_background.background_color,
@ -245,9 +251,7 @@ fn compute_damage(old: &ServoComputedValues, new: &ServoComputedValues) -> Resty
get_inheritedtext._servo_text_decorations_in_effect, get_inheritedtext._servo_text_decorations_in_effect,
get_pointing.cursor, get_pointing.pointer_events, get_pointing.cursor, get_pointing.pointer_events,
get_effects.box_shadow, get_effects.clip, get_inheritedtext.text_shadow, get_effects.filter, get_effects.box_shadow, get_effects.clip, get_inheritedtext.text_shadow, get_effects.filter,
get_effects.transform, get_effects.backface_visibility, get_effects.transform_style, get_effects.mix_blend_mode, get_inheritedbox.image_rendering,
get_effects.transform_origin, get_effects.perspective, get_effects.perspective_origin,
get_effects.mix_blend_mode, get_effects.opacity, get_inheritedbox.image_rendering,
// Note: May require REFLOW et al. if `visibility: collapse` is implemented. // Note: May require REFLOW et al. if `visibility: collapse` is implemented.
get_inheritedbox.visibility get_inheritedbox.visibility