mirror of
https://github.com/servo/servo.git
synced 2025-08-05 05:30:08 +01:00
layout: Rewrite the block formatting context/float inline-size
speculation code. The old code tried to do the speculation as a single bottom-up pass after intrinsic inline-size calculation, which was unable to handle cases like this: <div> <div style="float: left">Foo</div> </div> <div> <div style="overflow: hidden">Bar</div> </div> No single bottom-up pass could possibly handle this case, because the inline-size of the float flowing out of the "Foo" block could never make it down to the "Bar" block, where it is needed for speculation. On the pages I tried, this regresses layout performance by 1%-2%. I first noticed this breaking some pages, like the Google SERPs, several months ago.
This commit is contained in:
parent
9b2ae3a62f
commit
b29719e36b
15 changed files with 346 additions and 184 deletions
|
@ -33,10 +33,7 @@ use display_list_builder::BlockFlowDisplayListBuilding;
|
||||||
use display_list_builder::{BorderPaintingMode, DisplayListBuildState, FragmentDisplayListBuilding};
|
use display_list_builder::{BorderPaintingMode, DisplayListBuildState, FragmentDisplayListBuilding};
|
||||||
use euclid::{Point2D, Rect, Size2D};
|
use euclid::{Point2D, Rect, Size2D};
|
||||||
use floats::{ClearType, FloatKind, Floats, PlacementInfo};
|
use floats::{ClearType, FloatKind, Floats, PlacementInfo};
|
||||||
use flow::{BLOCK_POSITION_IS_STATIC};
|
use flow::{BLOCK_POSITION_IS_STATIC, CLEARS_LEFT, CLEARS_RIGHT, INLINE_POSITION_IS_STATIC};
|
||||||
use flow::{CLEARS_LEFT, CLEARS_RIGHT};
|
|
||||||
use flow::{HAS_LEFT_FLOATED_DESCENDANTS, HAS_RIGHT_FLOATED_DESCENDANTS};
|
|
||||||
use flow::{IMPACTED_BY_LEFT_FLOATS, IMPACTED_BY_RIGHT_FLOATS, INLINE_POSITION_IS_STATIC};
|
|
||||||
use flow::{IS_ABSOLUTELY_POSITIONED};
|
use flow::{IS_ABSOLUTELY_POSITIONED};
|
||||||
use flow::{ImmutableFlowUtils, LateAbsolutePositionInfo, MutableFlowUtils, OpaqueFlow};
|
use flow::{ImmutableFlowUtils, LateAbsolutePositionInfo, MutableFlowUtils, OpaqueFlow};
|
||||||
use flow::{NEEDS_LAYER, PostorderFlowTraversal, PreorderFlowTraversal, FragmentationContext};
|
use flow::{NEEDS_LAYER, PostorderFlowTraversal, PreorderFlowTraversal, FragmentationContext};
|
||||||
|
@ -497,7 +494,7 @@ pub enum MarginsMayCollapseFlag {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(PartialEq)]
|
#[derive(PartialEq)]
|
||||||
enum FormattingContextType {
|
pub enum FormattingContextType {
|
||||||
None,
|
None,
|
||||||
Block,
|
Block,
|
||||||
Other,
|
Other,
|
||||||
|
@ -844,7 +841,7 @@ impl BlockFlow {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Assign block-size now for the child if it was impacted by floats and we couldn't
|
// Assign block-size now for the child if it might have floats in and we couldn't
|
||||||
// before.
|
// before.
|
||||||
flow::mut_base(kid).floats = floats.clone();
|
flow::mut_base(kid).floats = floats.clone();
|
||||||
if flow::base(kid).flags.is_float() {
|
if flow::base(kid).flags.is_float() {
|
||||||
|
@ -1289,9 +1286,8 @@ impl BlockFlow {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Assigns the computed inline-start content edge and inline-size to all the children of this
|
/// Assigns the computed inline-start content edge and inline-size to all the children of this
|
||||||
/// block flow. Also computes whether each child will be impacted by floats. The given
|
/// block flow. The given `callback`, if supplied, will be called once per child; it is
|
||||||
/// `callback`, if supplied, will be called once per child; it is currently used to push down
|
/// currently used to push down column sizes for tables.
|
||||||
/// column sizes for tables.
|
|
||||||
///
|
///
|
||||||
/// `#[inline(always)]` because this is called only from block or table inline-size assignment
|
/// `#[inline(always)]` because this is called only from block or table inline-size assignment
|
||||||
/// and the code for block layout is significantly simpler.
|
/// and the code for block layout is significantly simpler.
|
||||||
|
@ -1308,34 +1304,8 @@ impl BlockFlow {
|
||||||
WritingMode,
|
WritingMode,
|
||||||
&mut Au,
|
&mut Au,
|
||||||
&mut Au) {
|
&mut Au) {
|
||||||
// Keep track of whether floats could impact each child.
|
|
||||||
let mut inline_start_floats_impact_child =
|
|
||||||
self.base.flags.contains(IMPACTED_BY_LEFT_FLOATS);
|
|
||||||
let mut inline_end_floats_impact_child =
|
|
||||||
self.base.flags.contains(IMPACTED_BY_RIGHT_FLOATS);
|
|
||||||
|
|
||||||
let flags = self.base.flags.clone();
|
let flags = self.base.flags.clone();
|
||||||
|
|
||||||
// Remember the inline-sizes of the last left and right floats, if there were any. These
|
|
||||||
// are used for estimating the inline-sizes of block formatting contexts. (We estimate that
|
|
||||||
// the inline-size of any block formatting context that we see will be based on the
|
|
||||||
// inline-size of the containing block as well as the last float seen before it in each
|
|
||||||
// direction.)
|
|
||||||
let mut inline_size_of_preceding_left_floats = Au(0);
|
|
||||||
let mut inline_size_of_preceding_right_floats = Au(0);
|
|
||||||
if self.formatting_context_type() == FormattingContextType::None {
|
|
||||||
if inline_start_content_edge > Au(0) {
|
|
||||||
inline_size_of_preceding_left_floats =
|
|
||||||
max(self.inline_size_of_preceding_left_floats - inline_start_content_edge,
|
|
||||||
Au(0));
|
|
||||||
}
|
|
||||||
if inline_end_content_edge > Au(0) {
|
|
||||||
inline_size_of_preceding_right_floats =
|
|
||||||
max(self.inline_size_of_preceding_right_floats - inline_end_content_edge,
|
|
||||||
Au(0));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let opaque_self = OpaqueFlow::from_flow(self);
|
let opaque_self = OpaqueFlow::from_flow(self);
|
||||||
|
|
||||||
// Calculate non-auto block size to pass to children.
|
// Calculate non-auto block size to pass to children.
|
||||||
|
@ -1358,29 +1328,6 @@ impl BlockFlow {
|
||||||
while let Some((i, kid)) = iterator.next() {
|
while let Some((i, kid)) = iterator.next() {
|
||||||
flow::mut_base(kid).block_container_explicit_block_size = explicit_content_size;
|
flow::mut_base(kid).block_container_explicit_block_size = explicit_content_size;
|
||||||
|
|
||||||
// Determine float impaction, and update the inline size speculations if necessary.
|
|
||||||
if flow::base(kid).flags.contains(CLEARS_LEFT) {
|
|
||||||
inline_start_floats_impact_child = false;
|
|
||||||
inline_size_of_preceding_left_floats = Au(0);
|
|
||||||
}
|
|
||||||
if flow::base(kid).flags.contains(CLEARS_RIGHT) {
|
|
||||||
inline_end_floats_impact_child = false;
|
|
||||||
inline_size_of_preceding_right_floats = Au(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Update the speculated inline size if this child is floated.
|
|
||||||
match flow::base(kid).flags.float_kind() {
|
|
||||||
float::T::none => {}
|
|
||||||
float::T::left => {
|
|
||||||
inline_size_of_preceding_left_floats = inline_size_of_preceding_left_floats +
|
|
||||||
flow::base(kid).intrinsic_inline_sizes.preferred_inline_size;
|
|
||||||
}
|
|
||||||
float::T::right => {
|
|
||||||
inline_size_of_preceding_right_floats = inline_size_of_preceding_right_floats +
|
|
||||||
flow::base(kid).intrinsic_inline_sizes.preferred_inline_size;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// The inline-start margin edge of the child flow is at our inline-start content edge,
|
// The inline-start margin edge of the child flow is at our inline-start content edge,
|
||||||
// and its inline-size is our content inline-size.
|
// and its inline-size is our content inline-size.
|
||||||
let kid_mode = flow::base(kid).writing_mode;
|
let kid_mode = flow::base(kid).writing_mode;
|
||||||
|
@ -1399,24 +1346,6 @@ impl BlockFlow {
|
||||||
kid_base.block_container_writing_mode = containing_block_mode;
|
kid_base.block_container_writing_mode = containing_block_mode;
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
|
||||||
let kid_base = flow::mut_base(kid);
|
|
||||||
inline_start_floats_impact_child = inline_start_floats_impact_child ||
|
|
||||||
kid_base.flags.contains(HAS_LEFT_FLOATED_DESCENDANTS);
|
|
||||||
inline_end_floats_impact_child = inline_end_floats_impact_child ||
|
|
||||||
kid_base.flags.contains(HAS_RIGHT_FLOATED_DESCENDANTS);
|
|
||||||
kid_base.flags.set(IMPACTED_BY_LEFT_FLOATS, inline_start_floats_impact_child);
|
|
||||||
kid_base.flags.set(IMPACTED_BY_RIGHT_FLOATS, inline_end_floats_impact_child);
|
|
||||||
}
|
|
||||||
|
|
||||||
if kid.is_block_flow() {
|
|
||||||
let kid_block = kid.as_mut_block();
|
|
||||||
kid_block.inline_size_of_preceding_left_floats =
|
|
||||||
inline_size_of_preceding_left_floats;
|
|
||||||
kid_block.inline_size_of_preceding_right_floats =
|
|
||||||
inline_size_of_preceding_right_floats;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Call the callback to propagate extra inline size information down to the child. This
|
// Call the callback to propagate extra inline size information down to the child. This
|
||||||
// is currently used for tables.
|
// is currently used for tables.
|
||||||
callback(kid,
|
callback(kid,
|
||||||
|
@ -1445,7 +1374,7 @@ impl BlockFlow {
|
||||||
|
|
||||||
/// Determines the type of formatting context this is. See the definition of
|
/// Determines the type of formatting context this is. See the definition of
|
||||||
/// `FormattingContextType`.
|
/// `FormattingContextType`.
|
||||||
fn formatting_context_type(&self) -> FormattingContextType {
|
pub fn formatting_context_type(&self) -> FormattingContextType {
|
||||||
let style = self.fragment.style();
|
let style = self.fragment.style();
|
||||||
if style.get_box().float != float::T::none {
|
if style.get_box().float != float::T::none {
|
||||||
return FormattingContextType::Other
|
return FormattingContextType::Other
|
||||||
|
@ -1528,8 +1457,6 @@ impl BlockFlow {
|
||||||
let _scope = layout_debug_scope!("block::bubble_inline_sizes {:x}", self.base.debug_id());
|
let _scope = layout_debug_scope!("block::bubble_inline_sizes {:x}", self.base.debug_id());
|
||||||
|
|
||||||
let mut flags = self.base.flags;
|
let mut flags = self.base.flags;
|
||||||
flags.remove(HAS_LEFT_FLOATED_DESCENDANTS);
|
|
||||||
flags.remove(HAS_RIGHT_FLOATED_DESCENDANTS);
|
|
||||||
|
|
||||||
// Find the maximum inline-size from children.
|
// Find the maximum inline-size from children.
|
||||||
let mut computation = self.fragment.compute_intrinsic_inline_sizes();
|
let mut computation = self.fragment.compute_intrinsic_inline_sizes();
|
||||||
|
@ -1584,12 +1511,6 @@ impl BlockFlow {
|
||||||
left_float_width + right_float_width);
|
left_float_width + right_float_width);
|
||||||
|
|
||||||
self.base.intrinsic_inline_sizes = computation.finish();
|
self.base.intrinsic_inline_sizes = computation.finish();
|
||||||
|
|
||||||
match self.fragment.style().get_box().float {
|
|
||||||
float::T::none => {}
|
|
||||||
float::T::left => flags.insert(HAS_LEFT_FLOATED_DESCENDANTS),
|
|
||||||
float::T::right => flags.insert(HAS_RIGHT_FLOATED_DESCENDANTS),
|
|
||||||
}
|
|
||||||
self.base.flags = flags
|
self.base.flags = flags
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1668,23 +1589,15 @@ impl BlockFlow {
|
||||||
self.base.block_container_inline_size = LogicalSize::from_physical(
|
self.base.block_container_inline_size = LogicalSize::from_physical(
|
||||||
self.base.writing_mode, layout_context.shared_context().viewport_size).inline;
|
self.base.writing_mode, layout_context.shared_context().viewport_size).inline;
|
||||||
self.base.block_container_writing_mode = self.base.writing_mode;
|
self.base.block_container_writing_mode = self.base.writing_mode;
|
||||||
|
|
||||||
// The root element is never impacted by floats.
|
|
||||||
self.base.flags.remove(IMPACTED_BY_LEFT_FLOATS);
|
|
||||||
self.base.flags.remove(IMPACTED_BY_RIGHT_FLOATS);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Our inline-size was set to the inline-size of the containing block by the flow's parent.
|
// Our inline-size was set to the inline-size of the containing block by the flow's parent.
|
||||||
// Now compute the real value.
|
// Now compute the real value.
|
||||||
self.propagate_and_compute_used_inline_size(layout_context);
|
self.propagate_and_compute_used_inline_size(layout_context);
|
||||||
|
|
||||||
// Formatting contexts are never impacted by floats.
|
// Now for some speculation.
|
||||||
match self.formatting_context_type() {
|
match self.formatting_context_type() {
|
||||||
FormattingContextType::None => {}
|
|
||||||
FormattingContextType::Block => {
|
FormattingContextType::Block => {
|
||||||
self.base.flags.remove(IMPACTED_BY_LEFT_FLOATS);
|
|
||||||
self.base.flags.remove(IMPACTED_BY_RIGHT_FLOATS);
|
|
||||||
|
|
||||||
// We can't actually compute the inline-size of this block now, because floats
|
// We can't actually compute the inline-size of this block now, because floats
|
||||||
// might affect it. Speculate that its inline-size is equal to the inline-size
|
// might affect it. Speculate that its inline-size is equal to the inline-size
|
||||||
// computed above minus the inline-size of the previous left and/or right floats.
|
// computed above minus the inline-size of the previous left and/or right floats.
|
||||||
|
@ -1695,14 +1608,11 @@ impl BlockFlow {
|
||||||
if self.fragment.style.max_inline_size() == LengthOrPercentageOrNone::None {
|
if self.fragment.style.max_inline_size() == LengthOrPercentageOrNone::None {
|
||||||
self.fragment.border_box.size.inline =
|
self.fragment.border_box.size.inline =
|
||||||
self.fragment.border_box.size.inline -
|
self.fragment.border_box.size.inline -
|
||||||
self.inline_size_of_preceding_left_floats -
|
self.base.speculated_float_placement_in.left -
|
||||||
self.inline_size_of_preceding_right_floats;
|
self.base.speculated_float_placement_in.right;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
FormattingContextType::Other => {
|
FormattingContextType::None | FormattingContextType::Other => {}
|
||||||
self.base.flags.remove(IMPACTED_BY_LEFT_FLOATS);
|
|
||||||
self.base.flags.remove(IMPACTED_BY_RIGHT_FLOATS);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1786,7 +1696,7 @@ impl Flow for BlockFlow {
|
||||||
self.assign_inline_position_for_formatting_context();
|
self.assign_inline_position_for_formatting_context();
|
||||||
}
|
}
|
||||||
|
|
||||||
if self.base.flags.impacted_by_floats() {
|
if (self as &Flow).floats_might_flow_through() {
|
||||||
self.base.thread_id = parent_thread_id;
|
self.base.thread_id = parent_thread_id;
|
||||||
if self.base.restyle_damage.intersects(REFLOW_OUT_OF_FLOW | REFLOW) {
|
if self.base.restyle_damage.intersects(REFLOW_OUT_OF_FLOW | REFLOW) {
|
||||||
self.assign_block_size(layout_context);
|
self.assign_block_size(layout_context);
|
||||||
|
@ -1797,7 +1707,7 @@ impl Flow for BlockFlow {
|
||||||
}
|
}
|
||||||
|
|
||||||
if is_formatting_context {
|
if is_formatting_context {
|
||||||
// If this is a formatting context and was *not* impacted by floats, then we must
|
// If this is a formatting context and definitely did not have floats in, then we must
|
||||||
// translate the floats past us.
|
// translate the floats past us.
|
||||||
let writing_mode = self.base.floats.writing_mode;
|
let writing_mode = self.base.floats.writing_mode;
|
||||||
let delta = self.base.position.size.block;
|
let delta = self.base.position.size.block;
|
||||||
|
|
|
@ -17,7 +17,6 @@ use flow::INLINE_POSITION_IS_STATIC;
|
||||||
use flow::IS_ABSOLUTELY_POSITIONED;
|
use flow::IS_ABSOLUTELY_POSITIONED;
|
||||||
use flow::ImmutableFlowUtils;
|
use flow::ImmutableFlowUtils;
|
||||||
use flow::{Flow, FlowClass, OpaqueFlow};
|
use flow::{Flow, FlowClass, OpaqueFlow};
|
||||||
use flow::{HAS_LEFT_FLOATED_DESCENDANTS, HAS_RIGHT_FLOATED_DESCENDANTS};
|
|
||||||
use fragment::{Fragment, FragmentBorderBoxIterator, Overflow};
|
use fragment::{Fragment, FragmentBorderBoxIterator, Overflow};
|
||||||
use gfx::display_list::{StackingContext, StackingContextId};
|
use gfx::display_list::{StackingContext, StackingContextId};
|
||||||
use incremental::{REFLOW, REFLOW_OUT_OF_FLOW};
|
use incremental::{REFLOW, REFLOW_OUT_OF_FLOW};
|
||||||
|
@ -26,7 +25,7 @@ use model::MaybeAuto;
|
||||||
use model::{IntrinsicISizes};
|
use model::{IntrinsicISizes};
|
||||||
use std::cmp::max;
|
use std::cmp::max;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use style::computed_values::{flex_direction, float};
|
use style::computed_values::flex_direction;
|
||||||
use style::logical_geometry::LogicalSize;
|
use style::logical_geometry::LogicalSize;
|
||||||
use style::properties::style_structs;
|
use style::properties::style_structs;
|
||||||
use style::properties::{ComputedValues, TComputedValues};
|
use style::properties::{ComputedValues, TComputedValues};
|
||||||
|
@ -324,25 +323,10 @@ impl Flow for FlexFlow {
|
||||||
// TODO(zentner): We need to re-order the items at some point. However, all the operations
|
// TODO(zentner): We need to re-order the items at some point. However, all the operations
|
||||||
// here ignore order, so we can afford to do it later, if necessary.
|
// here ignore order, so we can afford to do it later, if necessary.
|
||||||
|
|
||||||
// `flex item`s (our children) cannot be floated. Furthermore, they all establish BFC's.
|
|
||||||
// Therefore, we do not have to handle any floats here.
|
|
||||||
|
|
||||||
let mut flags = self.block_flow.base.flags;
|
|
||||||
flags.remove(HAS_LEFT_FLOATED_DESCENDANTS);
|
|
||||||
flags.remove(HAS_RIGHT_FLOATED_DESCENDANTS);
|
|
||||||
|
|
||||||
match self.main_mode {
|
match self.main_mode {
|
||||||
Mode::Inline => self.inline_mode_bubble_inline_sizes(),
|
Mode::Inline => self.inline_mode_bubble_inline_sizes(),
|
||||||
Mode::Block => self.block_mode_bubble_inline_sizes()
|
Mode::Block => self.block_mode_bubble_inline_sizes()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Although our children can't be floated, we can.
|
|
||||||
match self.block_flow.fragment.style().get_box().float {
|
|
||||||
float::T::none => {}
|
|
||||||
float::T::left => flags.insert(HAS_LEFT_FLOATED_DESCENDANTS),
|
|
||||||
float::T::right => flags.insert(HAS_RIGHT_FLOATED_DESCENDANTS),
|
|
||||||
}
|
|
||||||
self.block_flow.base.flags = flags
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn assign_inline_sizes(&mut self, layout_context: &LayoutContext) {
|
fn assign_inline_sizes(&mut self, layout_context: &LayoutContext) {
|
||||||
|
|
|
@ -3,6 +3,8 @@
|
||||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
use app_units::Au;
|
use app_units::Au;
|
||||||
|
use block::FormattingContextType;
|
||||||
|
use flow::{self, CLEARS_LEFT, CLEARS_RIGHT, Flow, ImmutableFlowUtils};
|
||||||
use persistent_list::PersistentList;
|
use persistent_list::PersistentList;
|
||||||
use std::cmp::{max, min};
|
use std::cmp::{max, min};
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
|
@ -412,3 +414,111 @@ impl Floats {
|
||||||
clearance
|
clearance
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The speculated inline sizes of floats flowing through or around a flow (depending on whether
|
||||||
|
/// the flow is a block formatting context). These speculations are always *upper bounds*; the
|
||||||
|
/// actual inline sizes might be less. Note that this implies that a speculated value of zero is a
|
||||||
|
/// guarantee that there will be no floats on that side.
|
||||||
|
///
|
||||||
|
/// This is used for two purposes: (a) determining whether we can lay out blocks in parallel; (b)
|
||||||
|
/// guessing the inline-sizes of block formatting contexts in an effort to lay them out in
|
||||||
|
/// parallel.
|
||||||
|
#[derive(Copy, Clone)]
|
||||||
|
pub struct SpeculatedFloatPlacement {
|
||||||
|
/// The estimated inline size (an upper bound) of the left floats flowing through this flow.
|
||||||
|
pub left: Au,
|
||||||
|
/// The estimated inline size (an upper bound) of the right floats flowing through this flow.
|
||||||
|
pub right: Au,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Debug for SpeculatedFloatPlacement {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
write!(f, "L {:?} R {:?}", self.left, self.right)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SpeculatedFloatPlacement {
|
||||||
|
/// Returns a `SpeculatedFloatPlacement` objects with both left and right speculated inline
|
||||||
|
/// sizes initialized to zero.
|
||||||
|
pub fn zero() -> SpeculatedFloatPlacement {
|
||||||
|
SpeculatedFloatPlacement {
|
||||||
|
left: Au(0),
|
||||||
|
right: Au(0),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Given the speculated inline size of the floats out for the inorder predecessor of this
|
||||||
|
/// flow, computes the speculated inline size of the floats flowing in.
|
||||||
|
pub fn compute_floats_in(&mut self, flow: &mut Flow) {
|
||||||
|
let base_flow = flow::base(flow);
|
||||||
|
if base_flow.flags.contains(CLEARS_LEFT) {
|
||||||
|
self.left = Au(0)
|
||||||
|
}
|
||||||
|
if base_flow.flags.contains(CLEARS_RIGHT) {
|
||||||
|
self.right = Au(0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Given the speculated inline size of the floats in for this flow, computes the speculated
|
||||||
|
/// inline size of the floats out for this flow.
|
||||||
|
pub fn compute_floats_out(&mut self, flow: &mut Flow) {
|
||||||
|
if flow.is_block_like() {
|
||||||
|
let block_flow = flow.as_block();
|
||||||
|
if block_flow.formatting_context_type() != FormattingContextType::None {
|
||||||
|
*self = block_flow.base.speculated_float_placement_in;
|
||||||
|
|
||||||
|
if self.left > Au(0) || self.right > Au(0) {
|
||||||
|
let speculated_inline_content_edge_offsets =
|
||||||
|
block_flow.fragment.guess_inline_content_edge_offsets();
|
||||||
|
if self.left > Au(0) {
|
||||||
|
self.left = self.left + speculated_inline_content_edge_offsets.start
|
||||||
|
}
|
||||||
|
if self.right > Au(0) {
|
||||||
|
self.right = self.right + speculated_inline_content_edge_offsets.end
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let base_flow = flow::base(flow);
|
||||||
|
match base_flow.flags.float_kind() {
|
||||||
|
float::T::none => {}
|
||||||
|
float::T::left => {
|
||||||
|
self.left = self.left + base_flow.intrinsic_inline_sizes.preferred_inline_size
|
||||||
|
}
|
||||||
|
float::T::right => {
|
||||||
|
self.right = self.right + base_flow.intrinsic_inline_sizes.preferred_inline_size
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Given a flow, computes the speculated inline size of the floats in of its first child.
|
||||||
|
pub fn compute_floats_in_for_first_child(parent_flow: &mut Flow) -> SpeculatedFloatPlacement {
|
||||||
|
if !parent_flow.is_block_like() {
|
||||||
|
return flow::base(parent_flow).speculated_float_placement_in
|
||||||
|
}
|
||||||
|
|
||||||
|
let parent_block_flow = parent_flow.as_block();
|
||||||
|
if parent_block_flow.formatting_context_type() != FormattingContextType::None {
|
||||||
|
return SpeculatedFloatPlacement::zero()
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut placement = parent_block_flow.base.speculated_float_placement_in;
|
||||||
|
let speculated_inline_content_edge_offsets =
|
||||||
|
parent_block_flow.fragment.guess_inline_content_edge_offsets();
|
||||||
|
|
||||||
|
if placement.left > speculated_inline_content_edge_offsets.start {
|
||||||
|
placement.left = placement.left - speculated_inline_content_edge_offsets.start
|
||||||
|
} else {
|
||||||
|
placement.left = Au(0)
|
||||||
|
};
|
||||||
|
if placement.right > speculated_inline_content_edge_offsets.end {
|
||||||
|
placement.right = placement.right - speculated_inline_content_edge_offsets.end
|
||||||
|
} else {
|
||||||
|
placement.right = Au(0)
|
||||||
|
};
|
||||||
|
|
||||||
|
placement
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -26,11 +26,11 @@
|
||||||
//! similar methods.
|
//! similar methods.
|
||||||
|
|
||||||
use app_units::Au;
|
use app_units::Au;
|
||||||
use block::BlockFlow;
|
use block::{BlockFlow, FormattingContextType};
|
||||||
use context::LayoutContext;
|
use context::LayoutContext;
|
||||||
use display_list_builder::DisplayListBuildState;
|
use display_list_builder::DisplayListBuildState;
|
||||||
use euclid::{Point2D, Rect, Size2D};
|
use euclid::{Point2D, Rect, Size2D};
|
||||||
use floats::Floats;
|
use floats::{Floats, SpeculatedFloatPlacement};
|
||||||
use flow_list::{FlowList, FlowListIterator, MutFlowListIterator};
|
use flow_list::{FlowList, FlowListIterator, MutFlowListIterator};
|
||||||
use flow_ref::{self, FlowRef, WeakFlowRef};
|
use flow_ref::{self, FlowRef, WeakFlowRef};
|
||||||
use fragment::{Fragment, FragmentBorderBoxIterator, Overflow, SpecificFragmentInfo};
|
use fragment::{Fragment, FragmentBorderBoxIterator, Overflow, SpecificFragmentInfo};
|
||||||
|
@ -231,8 +231,8 @@ pub trait Flow: fmt::Debug + Sync + Send + 'static {
|
||||||
fn place_float_if_applicable<'a>(&mut self, _: &'a LayoutContext<'a>) {}
|
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
|
/// 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
|
/// implementation simply assigns block-sizes if this flow might have floats in. Returns true
|
||||||
/// if this child was impacted by floats or false otherwise.
|
/// if it was determined that this child might have had floats in or false otherwise.
|
||||||
///
|
///
|
||||||
/// `parent_thread_id` is the thread ID of the parent. This is used for the layout tinting
|
/// `parent_thread_id` is the thread ID of the parent. This is used for the layout tinting
|
||||||
/// debug mode; if the block size of this flow was determined by its parent, we should treat
|
/// debug mode; if the block size of this flow was determined by its parent, we should treat
|
||||||
|
@ -241,16 +241,16 @@ pub trait Flow: fmt::Debug + Sync + Send + 'static {
|
||||||
layout_context: &'a LayoutContext<'a>,
|
layout_context: &'a LayoutContext<'a>,
|
||||||
parent_thread_id: u8)
|
parent_thread_id: u8)
|
||||||
-> bool {
|
-> bool {
|
||||||
let impacted = base(self).flags.impacted_by_floats();
|
let might_have_floats_in_or_out = base(self).might_have_floats_in() ||
|
||||||
if impacted {
|
base(self).might_have_floats_out();
|
||||||
|
if might_have_floats_in_or_out {
|
||||||
mut_base(self).thread_id = parent_thread_id;
|
mut_base(self).thread_id = parent_thread_id;
|
||||||
self.assign_block_size(layout_context);
|
self.assign_block_size(layout_context);
|
||||||
mut_base(self).restyle_damage.remove(REFLOW_OUT_OF_FLOW | REFLOW);
|
mut_base(self).restyle_damage.remove(REFLOW_OUT_OF_FLOW | REFLOW);
|
||||||
}
|
}
|
||||||
impacted
|
might_have_floats_in_or_out
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Calculate and set overflow for current flow.
|
|
||||||
///
|
///
|
||||||
/// CSS Section 11.1
|
/// CSS Section 11.1
|
||||||
/// This is the union of rectangles of the flows for which we define the
|
/// This is the union of rectangles of the flows for which we define the
|
||||||
|
@ -508,6 +508,10 @@ pub trait ImmutableFlowUtils {
|
||||||
|
|
||||||
/// Dumps the flow tree for debugging into the given PrintTree.
|
/// Dumps the flow tree for debugging into the given PrintTree.
|
||||||
fn print_with_tree(self, print_tree: &mut PrintTree);
|
fn print_with_tree(self, print_tree: &mut PrintTree);
|
||||||
|
|
||||||
|
/// Returns true if floats might flow through this flow, as determined by the float placement
|
||||||
|
/// speculation pass.
|
||||||
|
fn floats_might_flow_through(self) -> bool;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait MutableFlowUtils {
|
pub trait MutableFlowUtils {
|
||||||
|
@ -559,7 +563,7 @@ pub trait MutableOwnedFlowUtils {
|
||||||
absolute_descendants: &mut AbsoluteDescendants);
|
absolute_descendants: &mut AbsoluteDescendants);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(RustcEncodable, PartialEq, Debug)]
|
#[derive(Copy, Clone, RustcEncodable, PartialEq, Debug)]
|
||||||
pub enum FlowClass {
|
pub enum FlowClass {
|
||||||
Block,
|
Block,
|
||||||
Inline,
|
Inline,
|
||||||
|
@ -576,6 +580,17 @@ pub enum FlowClass {
|
||||||
Flex,
|
Flex,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl FlowClass {
|
||||||
|
fn is_block_like(self) -> bool {
|
||||||
|
match self {
|
||||||
|
FlowClass::Block | FlowClass::ListItem | FlowClass::Table | FlowClass::TableRowGroup |
|
||||||
|
FlowClass::TableRow | FlowClass::TableCaption | FlowClass::TableCell |
|
||||||
|
FlowClass::TableWrapper => true,
|
||||||
|
_ => false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// A top-down traversal.
|
/// A top-down traversal.
|
||||||
pub trait PreorderFlowTraversal {
|
pub trait PreorderFlowTraversal {
|
||||||
/// The operation to perform. Return true to continue or false to stop.
|
/// The operation to perform. Return true to continue or false to stop.
|
||||||
|
@ -615,21 +630,6 @@ pub trait InorderFlowTraversal {
|
||||||
bitflags! {
|
bitflags! {
|
||||||
#[doc = "Flags used in flows."]
|
#[doc = "Flags used in flows."]
|
||||||
flags FlowFlags: u32 {
|
flags FlowFlags: u32 {
|
||||||
// floated descendants flags
|
|
||||||
#[doc = "Whether this flow has descendants that float left in the same block formatting"]
|
|
||||||
#[doc = "context."]
|
|
||||||
const HAS_LEFT_FLOATED_DESCENDANTS = 0b0000_0000_0000_0000_0001,
|
|
||||||
#[doc = "Whether this flow has descendants that float right in the same block formatting"]
|
|
||||||
#[doc = "context."]
|
|
||||||
const HAS_RIGHT_FLOATED_DESCENDANTS = 0b0000_0000_0000_0000_0010,
|
|
||||||
#[doc = "Whether this flow is impacted by floats to the left in the same block formatting"]
|
|
||||||
#[doc = "context (i.e. its height depends on some prior flows with `float: left`)."]
|
|
||||||
const IMPACTED_BY_LEFT_FLOATS = 0b0000_0000_0000_0000_0100,
|
|
||||||
#[doc = "Whether this flow is impacted by floats to the right in the same block"]
|
|
||||||
#[doc = "formatting context (i.e. its height depends on some prior flows with `float:"]
|
|
||||||
#[doc = "right`)."]
|
|
||||||
const IMPACTED_BY_RIGHT_FLOATS = 0b0000_0000_0000_0000_1000,
|
|
||||||
|
|
||||||
// text align flags
|
// text align flags
|
||||||
#[doc = "Whether this flow must have its own layer. Even if this flag is not set, it might"]
|
#[doc = "Whether this flow must have its own layer. Even if this flag is not set, it might"]
|
||||||
#[doc = "get its own layer if it's deemed to be likely to overlap flows with their own"]
|
#[doc = "get its own layer if it's deemed to be likely to overlap flows with their own"]
|
||||||
|
@ -704,20 +704,6 @@ impl FlowFlags {
|
||||||
self.insert(other & HAS_FLOATED_DESCENDANTS_BITMASK);
|
self.insert(other & HAS_FLOATED_DESCENDANTS_BITMASK);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
|
||||||
pub fn impacted_by_floats(&self) -> bool {
|
|
||||||
self.contains(IMPACTED_BY_LEFT_FLOATS) || self.contains(IMPACTED_BY_RIGHT_FLOATS)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
pub fn set(&mut self, flags: FlowFlags, value: bool) {
|
|
||||||
if value {
|
|
||||||
self.insert(flags);
|
|
||||||
} else {
|
|
||||||
self.remove(flags);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn float_kind(&self) -> float::T {
|
pub fn float_kind(&self) -> float::T {
|
||||||
if self.contains(FLOATS_LEFT) {
|
if self.contains(FLOATS_LEFT) {
|
||||||
|
@ -910,6 +896,12 @@ pub struct BaseFlow {
|
||||||
/// The floats next to this flow.
|
/// The floats next to this flow.
|
||||||
pub floats: Floats,
|
pub floats: Floats,
|
||||||
|
|
||||||
|
/// Metrics for floats in computed during the float metrics speculation phase.
|
||||||
|
pub speculated_float_placement_in: SpeculatedFloatPlacement,
|
||||||
|
|
||||||
|
/// Metrics for floats out computed during the float metrics speculation phase.
|
||||||
|
pub speculated_float_placement_out: SpeculatedFloatPlacement,
|
||||||
|
|
||||||
/// The collapsible margins for this flow, if any.
|
/// The collapsible margins for this flow, if any.
|
||||||
pub collapsible_margins: CollapsibleMargins,
|
pub collapsible_margins: CollapsibleMargins,
|
||||||
|
|
||||||
|
@ -994,9 +986,11 @@ impl fmt::Debug for BaseFlow {
|
||||||
};
|
};
|
||||||
|
|
||||||
write!(f,
|
write!(f,
|
||||||
"sc={:?} pos={:?}, overflow={:?}{}{}{}",
|
"sc={:?} pos={:?}, floatspec-in={:?}, floatspec-out={:?}, overflow={:?}{}{}{}",
|
||||||
self.stacking_context_id,
|
self.stacking_context_id,
|
||||||
self.position,
|
self.position,
|
||||||
|
self.speculated_float_placement_in,
|
||||||
|
self.speculated_float_placement_out,
|
||||||
self.overflow,
|
self.overflow,
|
||||||
child_count_string,
|
child_count_string,
|
||||||
absolute_descendants_string,
|
absolute_descendants_string,
|
||||||
|
@ -1122,6 +1116,8 @@ impl BaseFlow {
|
||||||
collapsible_margins: CollapsibleMargins::new(),
|
collapsible_margins: CollapsibleMargins::new(),
|
||||||
stacking_relative_position: Point2D::zero(),
|
stacking_relative_position: Point2D::zero(),
|
||||||
abs_descendants: AbsoluteDescendants::new(),
|
abs_descendants: AbsoluteDescendants::new(),
|
||||||
|
speculated_float_placement_in: SpeculatedFloatPlacement::zero(),
|
||||||
|
speculated_float_placement_out: SpeculatedFloatPlacement::zero(),
|
||||||
block_container_inline_size: Au(0),
|
block_container_inline_size: Au(0),
|
||||||
block_container_writing_mode: writing_mode,
|
block_container_writing_mode: writing_mode,
|
||||||
block_container_explicit_block_size: None,
|
block_container_explicit_block_size: None,
|
||||||
|
@ -1172,17 +1168,24 @@ impl BaseFlow {
|
||||||
kid.collect_stacking_contexts(parent_id, contexts);
|
kid.collect_stacking_contexts(parent_id, contexts);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn might_have_floats_in(&self) -> bool {
|
||||||
|
self.speculated_float_placement_in.left > Au(0) ||
|
||||||
|
self.speculated_float_placement_in.right > Au(0)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn might_have_floats_out(&self) -> bool {
|
||||||
|
self.speculated_float_placement_out.left > Au(0) ||
|
||||||
|
self.speculated_float_placement_out.right > Au(0)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> ImmutableFlowUtils for &'a Flow {
|
impl<'a> ImmutableFlowUtils for &'a Flow {
|
||||||
/// Returns true if this flow is a block flow or subclass thereof.
|
/// Returns true if this flow is a block flow or subclass thereof.
|
||||||
fn is_block_like(self) -> bool {
|
fn is_block_like(self) -> bool {
|
||||||
match self.class() {
|
self.class().is_block_like()
|
||||||
FlowClass::Block | FlowClass::ListItem | FlowClass::Table | FlowClass::TableRowGroup |
|
|
||||||
FlowClass::TableRow | FlowClass::TableCaption | FlowClass::TableCell |
|
|
||||||
FlowClass::TableWrapper => true,
|
|
||||||
_ => false,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns true if this flow is a proper table child.
|
/// Returns true if this flow is a proper table child.
|
||||||
|
@ -1378,6 +1381,19 @@ impl<'a> ImmutableFlowUtils for &'a Flow {
|
||||||
}
|
}
|
||||||
print_tree.end_level();
|
print_tree.end_level();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn floats_might_flow_through(self) -> bool {
|
||||||
|
if !base(self).might_have_floats_in() && !base(self).might_have_floats_out() {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if self.is_root() {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if !self.is_block_like() {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
self.as_block().formatting_context_type() == FormattingContextType::None
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> MutableFlowUtils for &'a mut Flow {
|
impl<'a> MutableFlowUtils for &'a mut Flow {
|
||||||
|
@ -1563,3 +1579,4 @@ impl OpaqueFlow {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1027,6 +1027,24 @@ impl Fragment {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns a guess as to the distances from the margin edge of this fragment to its content
|
||||||
|
/// in the inline direction. This will generally be correct unless percentages are involved.
|
||||||
|
///
|
||||||
|
/// This is used for the float placement speculation logic.
|
||||||
|
pub fn guess_inline_content_edge_offsets(&self) -> SpeculatedInlineContentEdgeOffsets {
|
||||||
|
let logical_margin = self.style.logical_margin();
|
||||||
|
let logical_padding = self.style.logical_padding();
|
||||||
|
let border_width = self.border_width();
|
||||||
|
SpeculatedInlineContentEdgeOffsets {
|
||||||
|
start: MaybeAuto::from_style(logical_margin.inline_start, Au(0)).specified_or_zero() +
|
||||||
|
model::specified(logical_padding.inline_start, Au(0)) +
|
||||||
|
border_width.inline_start,
|
||||||
|
end: MaybeAuto::from_style(logical_margin.inline_end, Au(0)).specified_or_zero() +
|
||||||
|
model::specified(logical_padding.inline_end, Au(0)) +
|
||||||
|
border_width.inline_end,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn calculate_line_height(&self, layout_context: &LayoutContext) -> Au {
|
pub fn calculate_line_height(&self, layout_context: &LayoutContext) -> Au {
|
||||||
let font_style = self.style.get_font_arc();
|
let font_style = self.style.get_font_arc();
|
||||||
let font_metrics = text::font_metrics_for_style(&mut layout_context.font_context(), font_style);
|
let font_metrics = text::font_metrics_for_style(&mut layout_context.font_context(), font_style);
|
||||||
|
@ -2634,3 +2652,13 @@ bitflags! {
|
||||||
const HAS_LAYER = 0x01,
|
const HAS_LAYER = 0x01,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Specified distances from the margin edge of a block to its content in the inline direction.
|
||||||
|
/// These are returned by `guess_inline_content_edge_offsets()` and are used in the float placement
|
||||||
|
/// speculation logic.
|
||||||
|
#[derive(Copy, Clone, Debug)]
|
||||||
|
pub struct SpeculatedInlineContentEdgeOffsets {
|
||||||
|
pub start: Au,
|
||||||
|
pub end: Au,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -1345,6 +1345,12 @@ impl LayoutThread {
|
||||||
self.time_profiler_chan.clone(),
|
self.time_profiler_chan.clone(),
|
||||||
|| sequential::resolve_generated_content(&mut root_flow, &layout_context));
|
|| sequential::resolve_generated_content(&mut root_flow, &layout_context));
|
||||||
|
|
||||||
|
// Guess float placement.
|
||||||
|
profile(time::ProfilerCategory::LayoutFloatPlacementSpeculation,
|
||||||
|
self.profiler_metadata(),
|
||||||
|
self.time_profiler_chan.clone(),
|
||||||
|
|| sequential::guess_float_placement(flow_ref::deref_mut(&mut root_flow)));
|
||||||
|
|
||||||
// Perform the primary layout passes over the flow tree to compute the locations of all
|
// Perform the primary layout passes over the flow tree to compute the locations of all
|
||||||
// the boxes.
|
// the boxes.
|
||||||
if flow::base(&*root_flow).restyle_damage.intersects(REFLOW | REFLOW_OUT_OF_FLOW) {
|
if flow::base(&*root_flow).restyle_damage.intersects(REFLOW | REFLOW_OUT_OF_FLOW) {
|
||||||
|
|
|
@ -8,17 +8,18 @@ use app_units::Au;
|
||||||
use context::{LayoutContext, SharedLayoutContext};
|
use context::{LayoutContext, SharedLayoutContext};
|
||||||
use display_list_builder::DisplayListBuildState;
|
use display_list_builder::DisplayListBuildState;
|
||||||
use euclid::point::Point2D;
|
use euclid::point::Point2D;
|
||||||
|
use floats::SpeculatedFloatPlacement;
|
||||||
use flow::{PostorderFlowTraversal, PreorderFlowTraversal};
|
use flow::{PostorderFlowTraversal, PreorderFlowTraversal};
|
||||||
use flow::{self, Flow, ImmutableFlowUtils, InorderFlowTraversal, MutableFlowUtils};
|
use flow::{self, Flow, ImmutableFlowUtils, InorderFlowTraversal, MutableFlowUtils};
|
||||||
use flow_ref::{self, FlowRef};
|
use flow_ref::{self, FlowRef};
|
||||||
use fragment::FragmentBorderBoxIterator;
|
use fragment::FragmentBorderBoxIterator;
|
||||||
use generated_content::ResolveGeneratedContent;
|
use generated_content::ResolveGeneratedContent;
|
||||||
use gfx::display_list::{DisplayListEntry, StackingContext};
|
use gfx::display_list::{DisplayListEntry, StackingContext};
|
||||||
use incremental::STORE_OVERFLOW;
|
use incremental::{REFLOW, STORE_OVERFLOW};
|
||||||
use style::dom::TNode;
|
use style::dom::TNode;
|
||||||
use style::traversal::DomTraversalContext;
|
use style::traversal::DomTraversalContext;
|
||||||
use traversal::{AssignBSizes, AssignISizes};
|
use traversal::{AssignBSizes, AssignISizes, BubbleISizes, BuildDisplayList};
|
||||||
use traversal::{BubbleISizes, BuildDisplayList, ComputeAbsolutePositions, PostorderNodeMutTraversal};
|
use traversal::{ComputeAbsolutePositions, PostorderNodeMutTraversal};
|
||||||
use util::opts;
|
use util::opts;
|
||||||
|
|
||||||
pub use style::sequential::traverse_dom;
|
pub use style::sequential::traverse_dom;
|
||||||
|
@ -133,3 +134,22 @@ pub fn store_overflow(layout_context: &LayoutContext, flow: &mut Flow) {
|
||||||
flow::mut_base(flow).restyle_damage.remove(STORE_OVERFLOW);
|
flow::mut_base(flow).restyle_damage.remove(STORE_OVERFLOW);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Guesses how much inline size will be taken up by floats on the left and right sides of the
|
||||||
|
/// given flow. This is needed to speculatively calculate the inline sizes of block formatting
|
||||||
|
/// contexts. The speculation typically succeeds, but if it doesn't we have to lay it out again.
|
||||||
|
pub fn guess_float_placement(flow: &mut Flow) {
|
||||||
|
if !flow::base(flow).restyle_damage.intersects(REFLOW) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut floats_in = SpeculatedFloatPlacement::compute_floats_in_for_first_child(flow);
|
||||||
|
for kid in flow::mut_base(flow).child_iter() {
|
||||||
|
floats_in.compute_floats_in(kid);
|
||||||
|
flow::mut_base(kid).speculated_float_placement_in = floats_in;
|
||||||
|
guess_float_placement(kid);
|
||||||
|
floats_in = flow::base(kid).speculated_float_placement_out;
|
||||||
|
}
|
||||||
|
floats_in.compute_floats_out(flow);
|
||||||
|
flow::mut_base(flow).speculated_float_placement_out = floats_in
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -12,8 +12,8 @@ use block::{ISizeConstraintInput, ISizeConstraintSolution};
|
||||||
use context::LayoutContext;
|
use context::LayoutContext;
|
||||||
use display_list_builder::{BlockFlowDisplayListBuilding, BorderPaintingMode, DisplayListBuildState};
|
use display_list_builder::{BlockFlowDisplayListBuilding, BorderPaintingMode, DisplayListBuildState};
|
||||||
use euclid::Point2D;
|
use euclid::Point2D;
|
||||||
use flow::{BaseFlow, IMPACTED_BY_RIGHT_FLOATS, ImmutableFlowUtils, OpaqueFlow};
|
use flow::{BaseFlow, EarlyAbsolutePositionInfo, Flow, FlowClass, ImmutableFlowUtils, OpaqueFlow};
|
||||||
use flow::{self, EarlyAbsolutePositionInfo, Flow, FlowClass, IMPACTED_BY_LEFT_FLOATS};
|
use flow::{self};
|
||||||
use flow_list::MutFlowListIterator;
|
use flow_list::MutFlowListIterator;
|
||||||
use fragment::{Fragment, FragmentBorderBoxIterator, Overflow};
|
use fragment::{Fragment, FragmentBorderBoxIterator, Overflow};
|
||||||
use gfx::display_list::{StackingContext, StackingContextId};
|
use gfx::display_list::{StackingContext, StackingContextId};
|
||||||
|
@ -392,10 +392,6 @@ impl Flow for TableFlow {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// As tables are always wrapped inside a table wrapper, they are never impacted by floats.
|
|
||||||
self.block_flow.base.flags.remove(IMPACTED_BY_LEFT_FLOATS);
|
|
||||||
self.block_flow.base.flags.remove(IMPACTED_BY_RIGHT_FLOATS);
|
|
||||||
|
|
||||||
let column_computed_inline_sizes = &self.column_computed_inline_sizes;
|
let column_computed_inline_sizes = &self.column_computed_inline_sizes;
|
||||||
let collapsed_inline_direction_border_widths_for_table =
|
let collapsed_inline_direction_border_widths_for_table =
|
||||||
&self.collapsed_inline_direction_border_widths_for_table;
|
&self.collapsed_inline_direction_border_widths_for_table;
|
||||||
|
|
|
@ -20,8 +20,7 @@ use context::LayoutContext;
|
||||||
use display_list_builder::DisplayListBuildState;
|
use display_list_builder::DisplayListBuildState;
|
||||||
use euclid::Point2D;
|
use euclid::Point2D;
|
||||||
use floats::FloatKind;
|
use floats::FloatKind;
|
||||||
use flow::{Flow, FlowClass, ImmutableFlowUtils};
|
use flow::{Flow, FlowClass, ImmutableFlowUtils, INLINE_POSITION_IS_STATIC, OpaqueFlow};
|
||||||
use flow::{IMPACTED_BY_LEFT_FLOATS, IMPACTED_BY_RIGHT_FLOATS, INLINE_POSITION_IS_STATIC, OpaqueFlow};
|
|
||||||
use fragment::{Fragment, FragmentBorderBoxIterator, Overflow};
|
use fragment::{Fragment, FragmentBorderBoxIterator, Overflow};
|
||||||
use gfx::display_list::{StackingContext, StackingContextId};
|
use gfx::display_list::{StackingContext, StackingContextId};
|
||||||
use model::MaybeAuto;
|
use model::MaybeAuto;
|
||||||
|
@ -336,11 +335,6 @@ impl Flow for TableWrapperFlow {
|
||||||
}
|
}
|
||||||
}).collect::<Vec<_>>();
|
}).collect::<Vec<_>>();
|
||||||
|
|
||||||
// Table wrappers are essentially block formatting contexts and are therefore never
|
|
||||||
// impacted by floats.
|
|
||||||
self.block_flow.base.flags.remove(IMPACTED_BY_LEFT_FLOATS);
|
|
||||||
self.block_flow.base.flags.remove(IMPACTED_BY_RIGHT_FLOATS);
|
|
||||||
|
|
||||||
// Our inline-size was set to the inline-size of the containing block by the flow's parent.
|
// Our inline-size was set to the inline-size of the containing block by the flow's parent.
|
||||||
// Now compute the real value.
|
// Now compute the real value.
|
||||||
let containing_block_inline_size = self.block_flow.base.block_container_inline_size;
|
let containing_block_inline_size = self.block_flow.base.block_container_inline_size;
|
||||||
|
|
|
@ -7,8 +7,8 @@
|
||||||
use construct::FlowConstructor;
|
use construct::FlowConstructor;
|
||||||
use context::{LayoutContext, SharedLayoutContext};
|
use context::{LayoutContext, SharedLayoutContext};
|
||||||
use display_list_builder::DisplayListBuildState;
|
use display_list_builder::DisplayListBuildState;
|
||||||
use flow::{PostorderFlowTraversal, PreorderFlowTraversal};
|
use flow::{CAN_BE_FRAGMENTED, Flow, ImmutableFlowUtils, PostorderFlowTraversal};
|
||||||
use flow::{self, Flow, CAN_BE_FRAGMENTED};
|
use flow::{PreorderFlowTraversal, self};
|
||||||
use gfx::display_list::OpaqueNode;
|
use gfx::display_list::OpaqueNode;
|
||||||
use incremental::{BUBBLE_ISIZES, REFLOW, REFLOW_OUT_OF_FLOW, REPAINT, RestyleDamage};
|
use incremental::{BUBBLE_ISIZES, REFLOW, REFLOW_OUT_OF_FLOW, REPAINT, RestyleDamage};
|
||||||
use std::mem;
|
use std::mem;
|
||||||
|
@ -179,10 +179,12 @@ pub struct AssignBSizes<'a> {
|
||||||
impl<'a> PostorderFlowTraversal for AssignBSizes<'a> {
|
impl<'a> PostorderFlowTraversal for AssignBSizes<'a> {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn process(&self, flow: &mut Flow) {
|
fn process(&self, flow: &mut Flow) {
|
||||||
// Can't do anything with flows impacted by floats until we reach their inorder parent.
|
// Can't do anything with anything that floats might flow through until we reach their
|
||||||
|
// inorder parent.
|
||||||
|
//
|
||||||
// NB: We must return without resetting the restyle bits for these, as we haven't actually
|
// NB: We must return without resetting the restyle bits for these, as we haven't actually
|
||||||
// reflowed anything!
|
// reflowed anything!
|
||||||
if flow::base(flow).flags.impacted_by_floats() {
|
if flow.floats_might_flow_through() {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -59,6 +59,7 @@ impl Formattable for ProfilerCategory {
|
||||||
ProfilerCategory::LayoutNonIncrementalReset |
|
ProfilerCategory::LayoutNonIncrementalReset |
|
||||||
ProfilerCategory::LayoutGeneratedContent |
|
ProfilerCategory::LayoutGeneratedContent |
|
||||||
ProfilerCategory::LayoutDisplayListSorting |
|
ProfilerCategory::LayoutDisplayListSorting |
|
||||||
|
ProfilerCategory::LayoutFloatPlacementSpeculation |
|
||||||
ProfilerCategory::LayoutMain |
|
ProfilerCategory::LayoutMain |
|
||||||
ProfilerCategory::LayoutStoreOverflow |
|
ProfilerCategory::LayoutStoreOverflow |
|
||||||
ProfilerCategory::LayoutDispListBuild |
|
ProfilerCategory::LayoutDispListBuild |
|
||||||
|
@ -83,6 +84,7 @@ impl Formattable for ProfilerCategory {
|
||||||
ProfilerCategory::LayoutDamagePropagate => "Damage Propagation",
|
ProfilerCategory::LayoutDamagePropagate => "Damage Propagation",
|
||||||
ProfilerCategory::LayoutDisplayListSorting => "Sorting Display List",
|
ProfilerCategory::LayoutDisplayListSorting => "Sorting Display List",
|
||||||
ProfilerCategory::LayoutGeneratedContent => "Generated Content Resolution",
|
ProfilerCategory::LayoutGeneratedContent => "Generated Content Resolution",
|
||||||
|
ProfilerCategory::LayoutFloatPlacementSpeculation => "Float Placement Speculation",
|
||||||
ProfilerCategory::LayoutMain => "Primary Layout Pass",
|
ProfilerCategory::LayoutMain => "Primary Layout Pass",
|
||||||
ProfilerCategory::LayoutStoreOverflow => "Store Overflow",
|
ProfilerCategory::LayoutStoreOverflow => "Store Overflow",
|
||||||
ProfilerCategory::LayoutParallelWarmup => "Parallel Warmup",
|
ProfilerCategory::LayoutParallelWarmup => "Parallel Warmup",
|
||||||
|
|
|
@ -49,6 +49,7 @@ pub enum ProfilerCategory {
|
||||||
LayoutDamagePropagate,
|
LayoutDamagePropagate,
|
||||||
LayoutGeneratedContent,
|
LayoutGeneratedContent,
|
||||||
LayoutDisplayListSorting,
|
LayoutDisplayListSorting,
|
||||||
|
LayoutFloatPlacementSpeculation,
|
||||||
LayoutMain,
|
LayoutMain,
|
||||||
LayoutStoreOverflow,
|
LayoutStoreOverflow,
|
||||||
LayoutParallelWarmup,
|
LayoutParallelWarmup,
|
||||||
|
|
|
@ -564,6 +564,18 @@
|
||||||
"url": "/_mozilla/css/block_formatting_context_containing_floats_a.html"
|
"url": "/_mozilla/css/block_formatting_context_containing_floats_a.html"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
"css/block_formatting_context_float_inorder_interaction_a.html": [
|
||||||
|
{
|
||||||
|
"path": "css/block_formatting_context_float_inorder_interaction_a.html",
|
||||||
|
"references": [
|
||||||
|
[
|
||||||
|
"/_mozilla/css/block_formatting_context_float_inorder_interaction_ref.html",
|
||||||
|
"=="
|
||||||
|
]
|
||||||
|
],
|
||||||
|
"url": "/_mozilla/css/block_formatting_context_float_inorder_interaction_a.html"
|
||||||
|
}
|
||||||
|
],
|
||||||
"css/block_formatting_context_float_placement_a.html": [
|
"css/block_formatting_context_float_placement_a.html": [
|
||||||
{
|
{
|
||||||
"path": "css/block_formatting_context_float_placement_a.html",
|
"path": "css/block_formatting_context_float_placement_a.html",
|
||||||
|
@ -6854,6 +6866,18 @@
|
||||||
"url": "/_mozilla/css/block_formatting_context_containing_floats_a.html"
|
"url": "/_mozilla/css/block_formatting_context_containing_floats_a.html"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
"css/block_formatting_context_float_inorder_interaction_a.html": [
|
||||||
|
{
|
||||||
|
"path": "css/block_formatting_context_float_inorder_interaction_a.html",
|
||||||
|
"references": [
|
||||||
|
[
|
||||||
|
"/_mozilla/css/block_formatting_context_float_inorder_interaction_ref.html",
|
||||||
|
"=="
|
||||||
|
]
|
||||||
|
],
|
||||||
|
"url": "/_mozilla/css/block_formatting_context_float_inorder_interaction_a.html"
|
||||||
|
}
|
||||||
|
],
|
||||||
"css/block_formatting_context_float_placement_a.html": [
|
"css/block_formatting_context_float_placement_a.html": [
|
||||||
{
|
{
|
||||||
"path": "css/block_formatting_context_float_placement_a.html",
|
"path": "css/block_formatting_context_float_placement_a.html",
|
||||||
|
|
|
@ -0,0 +1,36 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<link rel="match" href="block_formatting_context_float_inorder_interaction_ref.html">
|
||||||
|
<!-- Tests that the speculation of block formatting context inline sizes in the presence of floats
|
||||||
|
respects the inorder traversal. -->
|
||||||
|
<style>
|
||||||
|
* {
|
||||||
|
margin: 0;
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
html {
|
||||||
|
width: 300px;
|
||||||
|
border-right: solid skyblue 10px;
|
||||||
|
}
|
||||||
|
#a {
|
||||||
|
float: left;
|
||||||
|
background: forestgreen;
|
||||||
|
}
|
||||||
|
#b {
|
||||||
|
padding-bottom: 12px;
|
||||||
|
background: firebrick;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<body>
|
||||||
|
<div>
|
||||||
|
<div id=a>Mimi</div>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<div id=b>Mimi</div>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,32 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<!-- Tests that the speculation of block formatting context inline sizes in the presence of floats
|
||||||
|
respects the inorder traversal. -->
|
||||||
|
<style>
|
||||||
|
* {
|
||||||
|
margin: 0;
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
html {
|
||||||
|
width: 300px;
|
||||||
|
border-right: solid skyblue 10px;
|
||||||
|
}
|
||||||
|
#a {
|
||||||
|
float: left;
|
||||||
|
background: forestgreen;
|
||||||
|
}
|
||||||
|
#b {
|
||||||
|
padding-bottom: 12px;
|
||||||
|
background: firebrick;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<body>
|
||||||
|
<div id=a>Mimi</div>
|
||||||
|
<div id=b>Mimi</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue