diff options
-rw-r--r-- | components/layout/block.rs | 79 | ||||
-rw-r--r-- | components/layout/flow.rs | 32 | ||||
-rw-r--r-- | components/layout/inline.rs | 4 | ||||
-rw-r--r-- | components/layout/table.rs | 4 | ||||
-rw-r--r-- | components/layout/table_colgroup.rs | 4 | ||||
-rw-r--r-- | components/layout/table_row.rs | 5 | ||||
-rw-r--r-- | components/layout/table_rowgroup.rs | 5 | ||||
-rw-r--r-- | components/layout/table_wrapper.rs | 4 | ||||
-rw-r--r-- | tests/ref/basic.list | 1 | ||||
-rw-r--r-- | tests/ref/incremental_float_a.html | 36 | ||||
-rw-r--r-- | tests/ref/incremental_float_ref.html | 31 |
11 files changed, 157 insertions, 48 deletions
diff --git a/components/layout/block.rs b/components/layout/block.rs index e3d03f22c0c..8d2438de783 100644 --- a/components/layout/block.rs +++ b/components/layout/block.rs @@ -32,8 +32,9 @@ use context::LayoutContext; use css::node_style::StyledNode; use display_list_builder::{BlockFlowDisplayListBuilding, BlockLevel, FragmentDisplayListBuilding}; use floats::{ClearBoth, ClearLeft, ClearRight, FloatKind, FloatLeft, Floats, PlacementInfo}; -use flow::{AbsolutePositionInfo, BaseFlow, BlockFlowClass, FlowClass, Flow, ImmutableFlowUtils}; -use flow::{MutableFlowUtils, PreorderFlowTraversal, PostorderFlowTraversal, mut_base}; +use flow::{AbsolutePositionInfo, BaseFlow, BlockFlowClass, FloatIfNecessary, FlowClass, Flow}; +use flow::{ForceNonfloated, ImmutableFlowUtils, MutableFlowUtils, PreorderFlowTraversal}; +use flow::{PostorderFlowTraversal, mut_base}; use flow::{HAS_LEFT_FLOATED_DESCENDANTS, HAS_RIGHT_FLOATED_DESCENDANTS}; use flow::{IMPACTED_BY_LEFT_FLOATS, IMPACTED_BY_RIGHT_FLOATS}; use flow::{LAYERS_NEEDED_FOR_DESCENDANTS, NEEDS_LAYER}; @@ -569,7 +570,7 @@ impl BlockFlow { pub fn from_node(constructor: &mut FlowConstructor, node: &ThreadSafeLayoutNode) -> BlockFlow { let writing_mode = node.style().writing_mode; BlockFlow { - base: BaseFlow::new(Some((*node).clone()), writing_mode), + base: BaseFlow::new(Some((*node).clone()), writing_mode, ForceNonfloated), fragment: Fragment::new(constructor, node), static_b_offset: Au::new(0), inline_size_of_preceding_left_floats: Au(0), @@ -583,7 +584,7 @@ impl BlockFlow { pub fn from_node_and_fragment(node: &ThreadSafeLayoutNode, fragment: Fragment) -> BlockFlow { let writing_mode = node.style().writing_mode; BlockFlow { - base: BaseFlow::new(Some((*node).clone()), writing_mode), + base: BaseFlow::new(Some((*node).clone()), writing_mode, ForceNonfloated), fragment: fragment, static_b_offset: Au::new(0), inline_size_of_preceding_left_floats: Au(0), @@ -600,7 +601,7 @@ impl BlockFlow { -> BlockFlow { let writing_mode = node.style().writing_mode; BlockFlow { - base: BaseFlow::new(Some((*node).clone()), writing_mode), + base: BaseFlow::new(Some((*node).clone()), writing_mode, FloatIfNecessary), fragment: Fragment::new(constructor, node), static_b_offset: Au::new(0), inline_size_of_preceding_left_floats: Au(0), @@ -617,7 +618,7 @@ impl BlockFlow { -> BlockFlow { let writing_mode = node.style().writing_mode; BlockFlow { - base: BaseFlow::new(Some((*node).clone()), writing_mode), + base: BaseFlow::new(Some((*node).clone()), writing_mode, FloatIfNecessary), fragment: fragment, static_b_offset: Au::new(0), inline_size_of_preceding_left_floats: Au(0), @@ -866,7 +867,10 @@ impl BlockFlow { // Assume that the *hypothetical box* for an absolute flow starts immediately // after the block-end border edge of the previous flow. kid.as_block().hypothetical_position.b = cur_b; - kid.assign_block_size_for_inorder_child_if_necessary(layout_context); + kid.place_float_if_applicable(layout_context); + if !flow::base(kid).flags.is_float() { + kid.assign_block_size_for_inorder_child_if_necessary(layout_context); + } propagate_layer_flag_from_child(&mut layers_needed_for_descendants, kid); // Skip the collapsing and float processing for absolute flow kids and continue @@ -885,10 +889,7 @@ impl BlockFlow { margin_collapse_info.current_float_ceiling(); } propagate_layer_flag_from_child(&mut layers_needed_for_descendants, kid); - - let need_to_process_child_floats = - kid.assign_block_size_for_inorder_child_if_necessary(layout_context); - assert!(need_to_process_child_floats); // As it was a float itself... + kid.place_float_if_applicable(layout_context); let kid_base = flow::mut_base(kid); floats = kid_base.floats.clone(); @@ -907,8 +908,12 @@ impl BlockFlow { } // Lay the child out if this was an in-order traversal. - let need_to_process_child_floats = - kid.assign_block_size_for_inorder_child_if_necessary(layout_context); + let need_to_process_child_floats = if flow::base(kid).flags.is_float() { + kid.place_float_if_applicable(layout_context); + true + } else { + kid.assign_block_size_for_inorder_child_if_necessary(layout_context) + }; // Mark flows for layerization if necessary to handle painting order correctly. propagate_layer_flag_from_child(&mut layers_needed_for_descendants, kid); @@ -1066,8 +1071,9 @@ impl BlockFlow { // has not been calculated yet. (See `calculate_absolute_block_size_and_margins` for that.) // Also don't remove the dirty bits if we're a block formatting context since our inline // size has not yet been computed. (See `assign_inline_position_for_formatting_context()`.) - if !self.base.flags.contains(IS_ABSOLUTELY_POSITIONED) && - self.formatting_context_type() == NonformattingContext { + if (self.base.flags.is_float() || + self.formatting_context_type() == NonformattingContext) && + !self.base.flags.contains(IS_ABSOLUTELY_POSITIONED) { self.base.restyle_damage.remove(REFLOW_OUT_OF_FLOW | REFLOW); } } @@ -1113,8 +1119,13 @@ impl BlockFlow { self.fragment.margin.block_start); if !self.base.flags.contains(IS_ABSOLUTELY_POSITIONED) { - self.base.position = self.base.position.translate(&float_offset) - .translate(&margin_offset); + let mut origin = LogicalPoint::new(self.base.writing_mode, + self.hypothetical_position.i, + self.base.position.start.b); + origin = origin.add_point(&float_offset).add_point(&margin_offset); + self.base.position = LogicalRect::from_point_size(self.base.writing_mode, + origin, + self.base.position.size); } } @@ -1321,7 +1332,8 @@ impl BlockFlow { // and its inline-size is our content inline-size. { let kid_base = flow::mut_base(kid); - if !kid_base.flags.contains(IS_ABSOLUTELY_POSITIONED) { + if !kid_base.flags.contains(IS_ABSOLUTELY_POSITIONED) || + !kid_base.flags.is_float() { kid_base.position.start.i = inline_start_content_edge } kid_base.block_container_inline_size = content_inline_size; @@ -1414,11 +1426,11 @@ impl BlockFlow { } let info = PlacementInfo { - size: LogicalSize::new( - self.fragment.style.writing_mode, - self.base.position.size.inline + self.fragment.margin.inline_start_end() + - self.fragment.border_padding.inline_start_end(), - self.fragment.border_box.size.block), + size: LogicalSize::new(self.fragment.style.writing_mode, + self.base.position.size.inline + + self.fragment.margin.inline_start_end() + + self.fragment.border_padding.inline_start_end(), + self.fragment.border_box.size.block), ceiling: self.base.position.start.b, max_inline_size: MAX_AU, kind: FloatLeft, @@ -1426,10 +1438,12 @@ impl BlockFlow { // Offset our position by whatever displacement is needed to not impact the floats. let rect = self.base.floats.place_between_floats(&info); - self.base.position.start.i = self.base.position.start.i + rect.start.i; + self.base.position.start.i = self.hypothetical_position.i + rect.start.i; // TODO(pcwalton): If the inline-size of this flow is different from the size we estimated // earlier, lay it out again. + + self.base.restyle_damage.remove(REFLOW_OUT_OF_FLOW | REFLOW); } fn is_inline_block(&self) -> bool { @@ -1602,19 +1616,17 @@ impl Flow for BlockFlow { None); } - /// Assigns block-sizes in-order; or, if this is a float, places the float. The default - /// implementation simply assigns block-sizes if this flow is impacted by floats. Returns true - /// if this child affected the floats in the flow somehow or false otherwise; thus, if true, - /// then the parent flow is expected to take the `floats` member of this flow into account. - /// - /// This is called on child flows by the parent. Hence, we can assume that `assign_block_size` - /// has already been called on the child (because of the bottom-up traversal). + fn place_float_if_applicable<'a>(&mut self, _: &'a LayoutContext<'a>) { + if self.base.flags.is_float() { + self.place_float(); + } + } + fn assign_block_size_for_inorder_child_if_necessary<'a>(&mut self, layout_context: &'a LayoutContext<'a>) -> bool { if self.base.flags.is_float() { - self.place_float(); - return true + return false } let is_formatting_context = self.formatting_context_type() != NonformattingContext; @@ -2010,7 +2022,6 @@ pub trait ISizeAndMarginsComputer { // We also resize the block itself, to ensure that overflow is not calculated // as the inline-size of our parent. We might be smaller and we might be larger if we // overflow. - flow::mut_base(block).position.size.inline = inline_size + extra_inline_size_from_margin; } diff --git a/components/layout/flow.rs b/components/layout/flow.rs index 0049d77eb8e..d95154a6746 100644 --- a/components/layout/flow.rs +++ b/components/layout/flow.rs @@ -191,6 +191,9 @@ pub trait Flow: fmt::Show + ToString + Sync { panic!("assign_block_size not yet implemented") } + /// If this is a float, places it. The default implementation does nothing. + fn place_float_if_applicable<'a>(&mut self, _: &'a LayoutContext<'a>) {} + /// Assigns block-sizes in-order; or, if this is a float, places the float. The default /// implementation simply assigns block-sizes if this flow is impacted by floats. Returns true /// if this child was impacted by floats or false otherwise. @@ -568,7 +571,7 @@ impl FlowFlags { #[inline] pub fn is_float(&self) -> bool { - self.floats_left() || self.floats_right() + self.contains(FLOATS_LEFT) || self.contains(FLOATS_RIGHT) } #[inline] @@ -835,9 +838,22 @@ impl Drop for BaseFlow { } } +/// Whether a base flow should be forced to be nonfloated. This can affect e.g. `TableFlow`, which +/// is never floated because the table wrapper flow is the floated one. +#[deriving(Clone, PartialEq)] +pub enum ForceNonfloatedFlag { + /// The flow should be floated if the node has a `float` property. + FloatIfNecessary, + /// The flow should be forced to be nonfloated. + ForceNonfloated, +} + impl BaseFlow { #[inline] - pub fn new(node: Option<ThreadSafeLayoutNode>, writing_mode: WritingMode) -> BaseFlow { + pub fn new(node: Option<ThreadSafeLayoutNode>, + writing_mode: WritingMode, + force_nonfloated: ForceNonfloatedFlag) + -> BaseFlow { let mut flags = FlowFlags::empty(); match node { None => {} @@ -849,11 +865,15 @@ impl BaseFlow { } _ => {} } - match node_style.get_box().float { - float::none => {} - float::left => flags.insert(FLOATS_LEFT), - float::right => flags.insert(FLOATS_RIGHT), + + if force_nonfloated == FloatIfNecessary { + match node_style.get_box().float { + float::none => {} + float::left => flags.insert(FLOATS_LEFT), + float::right => flags.insert(FLOATS_RIGHT), + } } + match node_style.get_box().clear { clear::none => {} clear::left => flags.insert(CLEARS_LEFT), diff --git a/components/layout/inline.rs b/components/layout/inline.rs index 31ca89d3c75..73332023d5d 100644 --- a/components/layout/inline.rs +++ b/components/layout/inline.rs @@ -8,7 +8,7 @@ use css::node_style::StyledNode; use context::LayoutContext; use display_list_builder::{ContentLevel, DisplayListResult, FragmentDisplayListBuilding}; use floats::{FloatLeft, Floats, PlacementInfo}; -use flow::{BaseFlow, FlowClass, Flow, InlineFlowClass, MutableFlowUtils}; +use flow::{BaseFlow, FlowClass, Flow, ForceNonfloated, InlineFlowClass, MutableFlowUtils}; use flow::{IS_ABSOLUTELY_POSITIONED}; use flow; use fragment::{Fragment, InlineAbsoluteHypotheticalFragment, InlineBlockFragment}; @@ -706,7 +706,7 @@ pub struct InlineFlow { impl InlineFlow { pub fn from_fragments(fragments: InlineFragments, writing_mode: WritingMode) -> InlineFlow { InlineFlow { - base: BaseFlow::new(None, writing_mode), + base: BaseFlow::new(None, writing_mode, ForceNonfloated), fragments: fragments, lines: Vec::new(), minimum_block_size_above_baseline: Au(0), diff --git a/components/layout/table.rs b/components/layout/table.rs index 773e18faf05..72f11d66fbf 100644 --- a/components/layout/table.rs +++ b/components/layout/table.rs @@ -11,8 +11,8 @@ use block::{ISizeConstraintInput, ISizeConstraintSolution}; use construct::FlowConstructor; use context::LayoutContext; use floats::FloatKind; -use flow::{TableFlowClass, FlowClass, Flow, ImmutableFlowUtils}; -use flow::{IMPACTED_BY_LEFT_FLOATS, IMPACTED_BY_RIGHT_FLOATS}; +use flow::{Flow, FlowClass, IMPACTED_BY_LEFT_FLOATS, IMPACTED_BY_RIGHT_FLOATS, ImmutableFlowUtils}; +use flow::{TableFlowClass}; use fragment::{Fragment, FragmentBoundsIterator}; use layout_debug; use model::{IntrinsicISizes, IntrinsicISizesContribution}; diff --git a/components/layout/table_colgroup.rs b/components/layout/table_colgroup.rs index dbc826db9f2..e8caa10e88d 100644 --- a/components/layout/table_colgroup.rs +++ b/components/layout/table_colgroup.rs @@ -8,7 +8,7 @@ use context::LayoutContext; use css::node_style::StyledNode; -use flow::{BaseFlow, TableColGroupFlowClass, FlowClass, Flow}; +use flow::{BaseFlow, ForceNonfloated, TableColGroupFlowClass, FlowClass, Flow}; use fragment::{Fragment, FragmentBoundsIterator, TableColumnFragment}; use layout_debug; use wrapper::ThreadSafeLayoutNode; @@ -44,7 +44,7 @@ impl TableColGroupFlow { -> TableColGroupFlow { let writing_mode = node.style().writing_mode; TableColGroupFlow { - base: BaseFlow::new(Some((*node).clone()), writing_mode), + base: BaseFlow::new(Some((*node).clone()), writing_mode, ForceNonfloated), fragment: Some(fragment), cols: fragments, inline_sizes: vec!(), diff --git a/components/layout/table_row.rs b/components/layout/table_row.rs index d834ecd144f..4c12ef1ef87 100644 --- a/components/layout/table_row.rs +++ b/components/layout/table_row.rs @@ -79,7 +79,10 @@ impl TableRowFlow { // cells). let mut max_y = Au(0); for kid in self.block_flow.base.child_iter() { - kid.assign_block_size_for_inorder_child_if_necessary(layout_context); + kid.place_float_if_applicable(layout_context); + if !flow::base(kid).flags.is_float() { + kid.assign_block_size_for_inorder_child_if_necessary(layout_context); + } { let child_fragment = kid.as_table_cell().fragment(); diff --git a/components/layout/table_rowgroup.rs b/components/layout/table_rowgroup.rs index 50e35e40c73..865c0a3c081 100644 --- a/components/layout/table_rowgroup.rs +++ b/components/layout/table_rowgroup.rs @@ -74,7 +74,10 @@ impl TableRowGroupFlow { let mut cur_y = block_start_offset; for kid in self.block_flow.base.child_iter() { - kid.assign_block_size_for_inorder_child_if_necessary(layout_context); + kid.place_float_if_applicable(layout_context); + if !flow::base(kid).flags.is_float() { + kid.assign_block_size_for_inorder_child_if_necessary(layout_context); + } let child_node = flow::mut_base(kid); child_node.position.start.b = cur_y; diff --git a/components/layout/table_wrapper.rs b/components/layout/table_wrapper.rs index 78d050351bc..7ec0ed874a4 100644 --- a/components/layout/table_wrapper.rs +++ b/components/layout/table_wrapper.rs @@ -301,6 +301,10 @@ impl Flow for TableWrapperFlow { self.block_flow.compute_absolute_position() } + fn place_float_if_applicable<'a>(&mut self, layout_context: &'a LayoutContext<'a>) { + self.block_flow.place_float_if_applicable(layout_context) + } + fn assign_block_size_for_inorder_child_if_necessary<'a>(&mut self, layout_context: &'a LayoutContext<'a>) -> bool { diff --git a/tests/ref/basic.list b/tests/ref/basic.list index c4d7c923c4c..b1480e1d856 100644 --- a/tests/ref/basic.list +++ b/tests/ref/basic.list @@ -184,3 +184,4 @@ fragment=top != ../html/acid2.html acid2_ref.html == linear_gradients_reverse_a.html linear_gradients_reverse_ref.html != linear_gradients_corners_a.html linear_gradients_corners_ref.html == linear_gradients_lengths_a.html linear_gradients_lengths_ref.html +== incremental_float_a.html incremental_float_ref.html diff --git a/tests/ref/incremental_float_a.html b/tests/ref/incremental_float_a.html new file mode 100644 index 00000000000..02e762b82e9 --- /dev/null +++ b/tests/ref/incremental_float_a.html @@ -0,0 +1,36 @@ +<!DOCTYPE html> +<html> +<head> +<style> +nav.floaty { + float: left; +} +section { + clear: both; + position: relative; +} +</style> +</head> +<body> +<section> +<nav>This floats</nav> +<div>This doesn't</div> +</section> +<section> +<nav>This floats</nav> +<div style="overflow: hidden;">This is a block formatting context</div> +</section> +<section> +<nav>This floats</nav> +<div style="position: absolute; top: 0; left: 0; width: 100px; height: 100px;"> + This is abspos +</div> +</section> +<script> +var elements = document.getElementsByTagName('nav'); +for (var i = 0; i < elements.length; i++) + elements[i].setAttribute('class', 'floaty'); +</script> +</body> +</html> + diff --git a/tests/ref/incremental_float_ref.html b/tests/ref/incremental_float_ref.html new file mode 100644 index 00000000000..7b52f8a8f49 --- /dev/null +++ b/tests/ref/incremental_float_ref.html @@ -0,0 +1,31 @@ +<!DOCTYPE html> +<html> +<head> +<style> +nav { + float: left; +} +section { + clear: both; + position: relative; +} +</style> +</head> +<body> +<section> +<nav>This floats</nav> +<div>This doesn't</div> +</section> +<section> +<nav>This floats</nav> +<div style="overflow: hidden;">This is a block formatting context</div> +</section> +<section> +<nav>This floats</nav> +<div style="position: absolute; top: 0; left: 0; width: 100px; height: 100px;"> + This is abspos +</div> +</section> +</body> +</html> + |