From 72f031e2a13c6d7238748a57d3e0f53c9dfd6ae8 Mon Sep 17 00:00:00 2001 From: Patrick Walton Date: Mon, 18 May 2015 12:22:17 -0700 Subject: [PATCH] layout: Support inline incremental reflow, and stop reconstructing all flows when mousing over the document. This exposes more "jumpiness" on sites like Hacker News, but the bug that causes it was pre-existing. --- components/layout/construct.rs | 50 +++++++++++++++++++++-------- components/layout/css/node_style.rs | 40 ++++++++--------------- components/layout/incremental.rs | 1 - components/layout/layout_task.rs | 4 ++- components/layout/traversal.rs | 2 +- components/script/dom/node.rs | 4 +-- 6 files changed, 57 insertions(+), 44 deletions(-) diff --git a/components/layout/construct.rs b/components/layout/construct.rs index 95d07afec6f..ba9f077c785 100644 --- a/components/layout/construct.rs +++ b/components/layout/construct.rs @@ -1250,22 +1250,28 @@ impl<'a> FlowConstructor<'a> { return false } - match node.swap_out_construction_result() { - ConstructionResult::None => true, - ConstructionResult::Flow(mut flow, _) => { + let mut layout_data_ref = node.mutate_layout_data(); + let layout_data = layout_data_ref.as_mut().expect("no layout data"); + let style = (*node.get_style(&layout_data)).clone(); + let damage = layout_data.data.restyle_damage; + match node.get_construction_result(layout_data) { + &mut ConstructionResult::None => true, + &mut ConstructionResult::Flow(ref mut flow, _) => { // The node's flow is of the same type and has the same set of children and can // therefore be repaired by simply propagating damage and style to the flow. - flow::mut_base(&mut *flow).restyle_damage.insert(node.restyle_damage()); - flow.repair_style_and_bubble_inline_sizes(node.style()); + if !flow.is_block_flow() { + return false + } + flow::mut_base(&mut **flow).restyle_damage.insert(damage); + flow.repair_style_and_bubble_inline_sizes(&style); true } - ConstructionResult::ConstructionItem(ConstructionItem::InlineFragments( - mut inline_fragments_construction_result)) => { + &mut ConstructionResult::ConstructionItem(ConstructionItem::InlineFragments( + ref mut inline_fragments_construction_result)) => { if !inline_fragments_construction_result.splits.is_empty() { return false } - let damage = node.restyle_damage(); for fragment in inline_fragments_construction_result.fragments .fragments .iter_mut() { @@ -1274,17 +1280,34 @@ impl<'a> FlowConstructor<'a> { flow::mut_base(&mut *inline_block_fragment.flow_ref).restyle_damage .insert(damage); // FIXME(pcwalton): Fragment restyle damage too? - inline_block_fragment.flow_ref.repair_style_and_bubble_inline_sizes( - node.style()); + inline_block_fragment.flow_ref + .repair_style_and_bubble_inline_sizes(&style); + } + SpecificFragmentInfo::InlineAbsoluteHypothetical( + ref mut inline_absolute_hypothetical_fragment) => { + flow::mut_base(&mut *inline_absolute_hypothetical_fragment.flow_ref) + .restyle_damage.insert(damage); + // FIXME(pcwalton): Fragment restyle damage too? + inline_absolute_hypothetical_fragment + .flow_ref + .repair_style_and_bubble_inline_sizes(&style); + } + SpecificFragmentInfo::InlineAbsolute(ref mut inline_absolute_fragment) => { + flow::mut_base(&mut *inline_absolute_fragment.flow_ref).restyle_damage + .insert(damage); + // FIXME(pcwalton): Fragment restyle damage too? + inline_absolute_fragment.flow_ref + .repair_style_and_bubble_inline_sizes(&style); } _ => { - return false + fragment.repair_style(&style); + return true } } } true } - ConstructionResult::ConstructionItem(_) => { + &mut ConstructionResult::ConstructionItem(_) => { false } } @@ -1450,7 +1473,8 @@ trait NodeUtils { /// Returns true if this node doesn't render its kids and false otherwise. fn is_replaced_content(&self) -> bool; - fn get_construction_result<'a>(self, layout_data: &'a mut LayoutDataWrapper) -> &'a mut ConstructionResult; + fn get_construction_result<'a>(self, layout_data: &'a mut LayoutDataWrapper) + -> &'a mut ConstructionResult; /// Sets the construction result of a flow. fn set_flow_construction_result(self, result: ConstructionResult); diff --git a/components/layout/css/node_style.rs b/components/layout/css/node_style.rs index 5b33d8d4c2d..5f513a19399 100644 --- a/components/layout/css/node_style.rs +++ b/components/layout/css/node_style.rs @@ -4,6 +4,7 @@ //! Style retrieval from DOM elements. +use data::LayoutDataWrapper; use wrapper::{PseudoElementType, ThreadSafeLayoutNode}; use std::mem; @@ -12,6 +13,7 @@ use std::sync::Arc; /// Node mixin providing `style` method that returns a `NodeStyle` pub trait StyledNode { + fn get_style<'a>(&'a self, layout_data_ref: &'a LayoutDataWrapper) -> &'a Arc; /// Returns the style results for the given node. If CSS selector matching has not yet been /// performed, fails. fn style<'a>(&'a self) -> &'a Arc; @@ -22,37 +24,23 @@ pub trait StyledNode { } impl<'ln> StyledNode for ThreadSafeLayoutNode<'ln> { + #[inline] + fn get_style<'a>(&self, layout_data_ref: &'a LayoutDataWrapper) -> &'a Arc { + match self.get_pseudo_element_type() { + PseudoElementType::Before(_) => layout_data_ref.data.before_style.as_ref().unwrap(), + PseudoElementType::After(_) => layout_data_ref.data.after_style.as_ref().unwrap(), + PseudoElementType::Normal => layout_data_ref.shared_data.style.as_ref().unwrap(), + } + } + #[inline] #[allow(unsafe_code)] fn style<'a>(&'a self) -> &'a Arc { unsafe { let layout_data_ref = self.borrow_layout_data(); - match self.get_pseudo_element_type() { - PseudoElementType::Before(_) => { - mem::transmute(layout_data_ref.as_ref() - .unwrap() - .data - .before_style - .as_ref() - .unwrap()) - } - PseudoElementType::After(_) => { - mem::transmute(layout_data_ref.as_ref() - .unwrap() - .data - .after_style - .as_ref() - .unwrap()) - } - PseudoElementType::Normal => { - mem::transmute(layout_data_ref.as_ref() - .unwrap() - .shared_data - .style - .as_ref() - .unwrap()) - } - } + let layout_data = layout_data_ref.as_ref().expect("no layout data"); + mem::transmute::<&Arc, + &'a Arc>(self.get_style(&layout_data)) } } diff --git a/components/layout/incremental.rs b/components/layout/incremental.rs index f9fda729cfe..9a8cbd822f5 100644 --- a/components/layout/incremental.rs +++ b/components/layout/incremental.rs @@ -184,7 +184,6 @@ pub fn compute_damage(old: &Option>, new: &ComputedValues) - [ get_box.float, get_box.display, get_box.position ]); // FIXME: test somehow that we checked every CSS property - damage } diff --git a/components/layout/layout_task.rs b/components/layout/layout_task.rs index 9ac33d0d267..7b30e10e727 100644 --- a/components/layout/layout_task.rs +++ b/components/layout/layout_task.rs @@ -887,7 +887,8 @@ impl LayoutTask { // let the constellation know about the viewport constraints let ConstellationChan(ref constellation_chan) = rw_data.constellation_chan; - constellation_chan.send(ConstellationMsg::ViewportConstrained(self.id, constraints)).unwrap(); + constellation_chan.send(ConstellationMsg::ViewportConstrained( + self.id, constraints)).unwrap(); } } @@ -1074,6 +1075,7 @@ impl LayoutTask { } fn reflow_all_nodes(flow: &mut Flow) { + debug!("reflowing all nodes!"); flow::mut_base(flow).restyle_damage.insert(REFLOW | REPAINT); for child in flow::child_iter(flow) { diff --git a/components/layout/traversal.rs b/components/layout/traversal.rs index b362ac6975f..39169787cad 100644 --- a/components/layout/traversal.rs +++ b/components/layout/traversal.rs @@ -170,7 +170,7 @@ impl<'a> PreorderDomTraversal for RecalcStyleForNode<'a> { &some_bf, &mut applicable_declarations, &mut shareable); - } else { + } else if node.has_changed() { ThreadSafeLayoutNode::new(&node).set_restyle_damage( incremental::rebuild_and_reflow()) } diff --git a/components/script/dom/node.rs b/components/script/dom/node.rs index f7401c99b11..789d2920832 100644 --- a/components/script/dom/node.rs +++ b/components/script/dom/node.rs @@ -629,7 +629,7 @@ impl<'a> NodeHelpers for JSRef<'a, Node> { fn set_hover_state(self, state: bool) { self.set_flag(IN_HOVER_STATE, state); - self.dirty(NodeDamage::OtherNodeDamage); + self.dirty(NodeDamage::NodeStyleDamaged); } fn get_focus_state(self) -> bool { @@ -638,7 +638,7 @@ impl<'a> NodeHelpers for JSRef<'a, Node> { fn set_focus_state(self, state: bool) { self.set_flag(IN_FOCUS_STATE, state); - self.dirty(NodeDamage::OtherNodeDamage); + self.dirty(NodeDamage::NodeStyleDamaged); } fn get_disabled_state(self) -> bool {