auto merge of #3904 : pcwalton/servo/maze-solver-float-placement, r=cgaebel

r? @glennw @cgaebel
This commit is contained in:
bors-servo 2014-11-18 16:39:25 -07:00
commit a07401ca4e
11 changed files with 176 additions and 73 deletions

View file

@ -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),
@ -639,7 +640,7 @@ impl BlockFlow {
} else {
AbsoluteNonReplacedType
}
} else if self.is_float() {
} else if self.base.flags.is_float() {
if self.is_replaced_content() {
FloatReplacedType
} else {
@ -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
@ -877,7 +881,7 @@ impl BlockFlow {
// Assign block-size now for the child if it was impacted by floats and we couldn't
// before.
flow::mut_base(kid).floats = floats.clone();
if kid.is_float() {
if flow::base(kid).flags.is_float() {
flow::mut_base(kid).position.start.b = cur_b;
{
let kid_block = kid.as_block();
@ -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);
}
}
@ -1225,7 +1236,7 @@ impl BlockFlow {
pub fn propagate_and_compute_used_inline_size(&mut self, layout_context: &LayoutContext) {
let containing_block_inline_size = self.base.block_container_inline_size;
self.compute_used_inline_size(layout_context, containing_block_inline_size);
if self.is_float() {
if self.base.flags.is_float() {
self.float.as_mut().unwrap().containing_inline_size = containing_block_inline_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 {
@ -1547,7 +1561,7 @@ impl Flow for BlockFlow {
}
debug!("assign_inline_sizes({}): assigning inline_size for flow",
if self.is_float() {
if self.base.flags.is_float() {
"float"
} else {
"block"
@ -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.is_float() {
self.place_float();
return true
if self.base.flags.is_float() {
return false
}
let is_formatting_context = self.formatting_context_type() != NonformattingContext;
@ -1655,7 +1667,7 @@ impl Flow for BlockFlow {
if !self.base.flags.contains(IS_ABSOLUTELY_POSITIONED) {
self.base.position.size.block = self.fragment.border_box.size.block;
}
} else if self.is_root() || self.is_float() || self.is_inline_block() {
} else if self.is_root() || self.base.flags.is_float() || self.is_inline_block() {
// Root element margins should never be collapsed according to CSS § 8.3.1.
debug!("assign_block_size: assigning block_size for root flow");
self.assign_block_size_block_base(ctx, MarginsMayNotCollapse);
@ -1772,10 +1784,6 @@ impl Flow for BlockFlow {
self.flags.contains(IS_ROOT)
}
fn is_float(&self) -> bool {
self.float.is_some()
}
/// The 'position' property of this flow.
fn positioning(&self) -> position::T {
self.fragment.style.get_box().position
@ -1822,7 +1830,7 @@ impl Flow for BlockFlow {
}
fn build_display_list(&mut self, layout_context: &LayoutContext) {
if self.is_float() {
if self.base.flags.is_float() {
// TODO(#2009, pcwalton): This is a pseudo-stacking context. We need to merge `z-index:
// auto` kids into the parent stacking context, when that is supported.
self.build_display_list_for_floating_block(layout_context)
@ -2014,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;
}

View file

@ -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.
@ -241,10 +244,6 @@ pub trait Flow: fmt::Show + ToString + Sync {
false
}
fn is_float(&self) -> bool {
false
}
/// The 'position' property of this flow.
fn positioning(&self) -> position::T {
position::static_
@ -570,6 +569,11 @@ impl FlowFlags {
}
}
#[inline]
pub fn is_float(&self) -> bool {
self.contains(FLOATS_LEFT) || self.contains(FLOATS_RIGHT)
}
#[inline]
pub fn clears_floats(&self) -> bool {
self.contains(CLEARS_LEFT) || self.contains(CLEARS_RIGHT)
@ -834,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 => {}
@ -848,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),

View file

@ -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),
@ -1116,7 +1116,8 @@ impl Flow for InlineFlow {
// Assign block sizes for any inline-block descendants.
for kid in self.base.child_iter() {
if flow::base(kid).flags.contains(IS_ABSOLUTELY_POSITIONED) || kid.is_float() {
if flow::base(kid).flags.contains(IS_ABSOLUTELY_POSITIONED) ||
flow::base(kid).flags.is_float() {
continue
}
kid.assign_block_size_for_inorder_child_if_necessary(layout_context);

View file

@ -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};

View file

@ -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!(),

View file

@ -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();

View file

@ -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;

View file

@ -191,7 +191,7 @@ impl TableWrapperFlow {
layout_context: &LayoutContext,
parent_flow_inline_size: Au) {
// Delegate to the appropriate inline size computer to find the constraint inputs.
let input = if self.is_float() {
let input = if self.block_flow.base.flags.is_float() {
FloatNonReplaced.compute_inline_size_constraint_inputs(&mut self.block_flow,
parent_flow_inline_size,
layout_context)
@ -202,7 +202,7 @@ impl TableWrapperFlow {
};
// Delegate to the appropriate inline size computer to write the constraint solutions in.
if self.is_float() {
if self.block_flow.base.flags.is_float() {
let solution = FloatNonReplaced.solve_inline_size_constraints(&mut self.block_flow,
&input);
FloatNonReplaced.set_inline_size_constraint_solutions(&mut self.block_flow, solution);
@ -221,10 +221,6 @@ impl Flow for TableWrapperFlow {
TableWrapperFlowClass
}
fn is_float(&self) -> bool {
self.block_flow.is_float()
}
fn as_table_wrapper<'a>(&'a mut self) -> &'a mut TableWrapperFlow {
self
}
@ -251,7 +247,7 @@ impl Flow for TableWrapperFlow {
fn assign_inline_sizes(&mut self, layout_context: &LayoutContext) {
debug!("assign_inline_sizes({}): assigning inline_size for flow",
if self.is_float() {
if self.block_flow.base.flags.is_float() {
"floated table_wrapper"
} else {
"table_wrapper"
@ -267,7 +263,7 @@ impl Flow for TableWrapperFlow {
// Our inline-size was set to the inline-size of the containing block by the flow's parent.
// Now compute the real value.
let containing_block_inline_size = self.block_flow.base.block_container_inline_size;
if self.is_float() {
if self.block_flow.base.flags.is_float() {
self.block_flow.float.as_mut().unwrap().containing_inline_size =
containing_block_inline_size;
}
@ -305,10 +301,14 @@ 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 {
if self.block_flow.is_float() {
if self.block_flow.base.flags.is_float() {
self.block_flow.place_float();
return true
}
@ -343,7 +343,7 @@ impl Flow for TableWrapperFlow {
impl fmt::Show for TableWrapperFlow {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
if self.is_float() {
if self.block_flow.base.flags.is_float() {
write!(f, "TableWrapperFlow(Float): {}", self.block_flow.fragment)
} else {
write!(f, "TableWrapperFlow: {}", self.block_flow.fragment)

View file

@ -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

View file

@ -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>

View file

@ -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>