Use App units in flow layout (#30894)

* use app_unit in flow layout

* fmt

* Avoid crash

* Drop assert that doesn't hold anymore

* update expectation

---------

Co-authored-by: Oriol Brufau <obrufau@igalia.com>
This commit is contained in:
atbrakhi 2024-01-19 14:20:01 +01:00 committed by GitHub
parent 734eb46954
commit 3d520f2668
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
9 changed files with 313 additions and 225 deletions

View file

@ -8,15 +8,16 @@
use std::collections::VecDeque; use std::collections::VecDeque;
use std::fmt::{Debug, Formatter, Result as FmtResult}; use std::fmt::{Debug, Formatter, Result as FmtResult};
use std::mem;
use std::ops::Range; use std::ops::Range;
use std::{f32, mem};
use app_units::{Au, MAX_AU, MIN_AU};
use euclid::num::Zero; use euclid::num::Zero;
use serde::Serialize; use serde::Serialize;
use servo_arc::Arc; use servo_arc::Arc;
use style::computed_values::float::T as FloatProperty; use style::computed_values::float::T as FloatProperty;
use style::properties::ComputedValues; use style::properties::ComputedValues;
use style::values::computed::{CSSPixelLength, Clear, Length}; use style::values::computed::{Clear, Length};
use style::values::specified::text::TextDecorationLine; use style::values::specified::text::TextDecorationLine;
use crate::context::LayoutContext; use crate::context::LayoutContext;
@ -24,7 +25,7 @@ use crate::dom::NodeExt;
use crate::dom_traversal::{Contents, NodeAndStyleInfo}; use crate::dom_traversal::{Contents, NodeAndStyleInfo};
use crate::formatting_contexts::IndependentFormattingContext; use crate::formatting_contexts::IndependentFormattingContext;
use crate::fragment_tree::{BoxFragment, CollapsedBlockMargins, CollapsedMargin, FloatFragment}; use crate::fragment_tree::{BoxFragment, CollapsedBlockMargins, CollapsedMargin, FloatFragment};
use crate::geom::{LogicalRect, LogicalVec2}; use crate::geom::{LogicalRect, LogicalSides, LogicalVec2};
use crate::positioned::PositioningContext; use crate::positioned::PositioningContext;
use crate::style_ext::{ComputedValuesExt, DisplayInside, PaddingBorderMargin}; use crate::style_ext::{ComputedValuesExt, DisplayInside, PaddingBorderMargin};
use crate::ContainingBlock; use crate::ContainingBlock;
@ -47,7 +48,7 @@ pub struct ContainingBlockPositionInfo {
/// containing block, excluding uncollapsed block start margins. Note that /// containing block, excluding uncollapsed block start margins. Note that
/// this does not include uncollapsed block start margins because we don't /// this does not include uncollapsed block start margins because we don't
/// know the value of collapsed margins until we lay out children. /// know the value of collapsed margins until we lay out children.
pub(crate) block_start: Length, pub(crate) block_start: Au,
/// Any uncollapsed block start margins that we have collected between the /// Any uncollapsed block start margins that we have collected between the
/// block start of the float containing independent block formatting context /// block start of the float containing independent block formatting context
/// and this containing block, including for this containing block. /// and this containing block, including for this containing block.
@ -55,17 +56,17 @@ pub struct ContainingBlockPositionInfo {
/// The distance from the inline start position of the float containing /// The distance from the inline start position of the float containing
/// independent formatting context and the inline start of this containing /// independent formatting context and the inline start of this containing
/// block. /// block.
pub inline_start: Length, pub inline_start: Au,
/// The offset from the inline start position of the float containing /// The offset from the inline start position of the float containing
/// independent formatting context to the inline end of this containing /// independent formatting context to the inline end of this containing
/// block. /// block.
pub inline_end: Length, pub inline_end: Au,
} }
impl ContainingBlockPositionInfo { impl ContainingBlockPositionInfo {
pub fn new_with_inline_offsets(inline_start: Length, inline_end: Length) -> Self { pub fn new_with_inline_offsets(inline_start: Au, inline_end: Au) -> Self {
Self { Self {
block_start: Length::zero(), block_start: Au::zero(),
block_start_margins_not_collapsed: CollapsedMargin::zero(), block_start_margins_not_collapsed: CollapsedMargin::zero(),
inline_start, inline_start,
inline_end, inline_end,
@ -84,33 +85,37 @@ pub(crate) struct PlacementAmongFloats<'a> {
/// The next band, needed to know the height of the last band in current_bands. /// The next band, needed to know the height of the last band in current_bands.
next_band: FloatBand, next_band: FloatBand,
/// The size of the object to place. /// The size of the object to place.
object_size: LogicalVec2<Length>, object_size: LogicalVec2<Au>,
/// The minimum position in the block direction for the placement. Objects should not /// The minimum position in the block direction for the placement. Objects should not
/// be placed before this point. /// be placed before this point.
ceiling: Length, ceiling: Au,
/// The inline position where the object would be if there were no floats. The object /// The inline position where the object would be if there were no floats. The object
/// can be placed after it due to floats, but not before it. /// can be placed after it due to floats, but not before it.
min_inline_start: Length, min_inline_start: Au,
/// The maximum inline position that the object can attain when avoiding floats. /// The maximum inline position that the object can attain when avoiding floats.
max_inline_end: Length, max_inline_end: Au,
} }
impl<'a> PlacementAmongFloats<'a> { impl<'a> PlacementAmongFloats<'a> {
pub(crate) fn new( pub(crate) fn new(
float_context: &'a FloatContext, float_context: &'a FloatContext,
ceiling: Length, ceiling: Au,
object_size: LogicalVec2<Length>, object_size: LogicalVec2<Au>,
pbm: &PaddingBorderMargin, pbm: &PaddingBorderMargin,
) -> Self { ) -> Self {
assert!(!ceiling.px().is_infinite()); let mut ceiling_band = float_context.bands.find(ceiling).unwrap();
let mut current_band = float_context.bands.find(ceiling).unwrap(); let (current_bands, next_band) = if ceiling == MAX_AU {
current_band.top = ceiling; (VecDeque::new(), ceiling_band)
let current_bands = VecDeque::from([current_band]); } else {
ceiling_band.top = ceiling;
let current_bands = VecDeque::from([ceiling_band]);
let next_band = float_context.bands.find_next(ceiling).unwrap(); let next_band = float_context.bands.find_next(ceiling).unwrap();
(current_bands, next_band)
};
let min_inline_start = float_context.containing_block_info.inline_start + let min_inline_start = float_context.containing_block_info.inline_start +
pbm.margin.inline_start.auto_is(Length::zero); pbm.margin.inline_start.auto_is(Length::zero).into();
let max_inline_end = (float_context.containing_block_info.inline_end - let max_inline_end = (float_context.containing_block_info.inline_end -
pbm.margin.inline_end.auto_is(Length::zero)) pbm.margin.inline_end.auto_is(Length::zero).into())
.max(min_inline_start + object_size.inline); .max(min_inline_start + object_size.inline);
PlacementAmongFloats { PlacementAmongFloats {
float_context, float_context,
@ -126,24 +131,27 @@ impl<'a> PlacementAmongFloats<'a> {
/// The top of the bands under consideration. This is initially the ceiling provided /// The top of the bands under consideration. This is initially the ceiling provided
/// during creation of this [`PlacementAmongFloats`], but may be larger if the top /// during creation of this [`PlacementAmongFloats`], but may be larger if the top
/// band is discarded. /// band is discarded.
fn top_of_bands(&self) -> Option<Length> { fn top_of_bands(&self) -> Option<Au> {
self.current_bands.front().map(|band| band.top) self.current_bands.front().map(|band| band.top)
} }
/// The height of the bands under consideration. /// The height of the bands under consideration.
fn current_bands_height(&self) -> Length { fn current_bands_height(&self) -> Au {
if let Some(top) = self.top_of_bands() { if self.next_band.top == MAX_AU {
self.next_band.top - top // Treat MAX_AU as infinity.
MAX_AU
} else { } else {
assert!(self.next_band.top.px().is_infinite()); let top = self
self.next_band.top .top_of_bands()
.expect("Should have bands before reaching the end");
self.next_band.top - top
} }
} }
/// Add a single band to the bands under consideration and calculate the new /// Add a single band to the bands under consideration and calculate the new
/// [`PlacementAmongFloats::next_band`]. /// [`PlacementAmongFloats::next_band`].
fn add_one_band(&mut self) { fn add_one_band(&mut self) {
assert!(!self.next_band.top.px().is_infinite()); assert!(self.next_band.top != MAX_AU);
self.current_bands.push_back(self.next_band); self.current_bands.push_back(self.next_band);
self.next_band = self self.next_band = self
.float_context .float_context
@ -162,7 +170,7 @@ impl<'a> PlacementAmongFloats<'a> {
/// Find the start and end of the inline space provided by the current set of bands /// Find the start and end of the inline space provided by the current set of bands
/// under consideration. /// under consideration.
fn calculate_inline_start_and_end(&self) -> (Length, Length) { fn calculate_inline_start_and_end(&self) -> (Au, Au) {
let mut max_inline_start = self.min_inline_start; let mut max_inline_start = self.min_inline_start;
let mut min_inline_end = self.max_inline_end; let mut min_inline_end = self.max_inline_end;
for band in self.current_bands.iter() { for band in self.current_bands.iter() {
@ -177,12 +185,12 @@ impl<'a> PlacementAmongFloats<'a> {
} }
/// Find the total inline size provided by the current set of bands under consideration. /// Find the total inline size provided by the current set of bands under consideration.
fn calculate_viable_inline_size(&self) -> Length { fn calculate_viable_inline_size(&self) -> Au {
let (inline_start, inline_end) = self.calculate_inline_start_and_end(); let (inline_start, inline_end) = self.calculate_inline_start_and_end();
inline_end - inline_start inline_end - inline_start
} }
fn try_place_once(&mut self) -> Option<LogicalRect<Length>> { fn try_place_once(&mut self) -> Option<LogicalRect<Au>> {
assert!(!self.current_bands.is_empty()); assert!(!self.current_bands.is_empty());
self.accumulate_enough_bands_for_block_size(); self.accumulate_enough_bands_for_block_size();
let (inline_start, inline_end) = self.calculate_inline_start_and_end(); let (inline_start, inline_end) = self.calculate_inline_start_and_end();
@ -190,15 +198,14 @@ impl<'a> PlacementAmongFloats<'a> {
if available_inline_size < self.object_size.inline { if available_inline_size < self.object_size.inline {
return None; return None;
} }
let top = self.top_of_bands().unwrap();
Some(LogicalRect { Some(LogicalRect {
start_corner: LogicalVec2 { start_corner: LogicalVec2 {
inline: inline_start, inline: inline_start,
block: top, block: self.top_of_bands().unwrap(),
}, },
size: LogicalVec2 { size: LogicalVec2 {
inline: available_inline_size, inline: available_inline_size,
block: self.next_band.top - top, block: self.current_bands_height(),
}, },
}) })
} }
@ -206,7 +213,7 @@ impl<'a> PlacementAmongFloats<'a> {
/// Checks if we either have bands or we have gone past all of them. /// Checks if we either have bands or we have gone past all of them.
/// This is an invariant that should hold, otherwise we are in a broken state. /// This is an invariant that should hold, otherwise we are in a broken state.
fn has_bands_or_at_end(&self) -> bool { fn has_bands_or_at_end(&self) -> bool {
!self.current_bands.is_empty() || self.next_band.top.px().is_infinite() !self.current_bands.is_empty() || self.next_band.top == MAX_AU
} }
fn pop_front_band_ensuring_has_bands_or_at_end(&mut self) { fn pop_front_band_ensuring_has_bands_or_at_end(&mut self) {
@ -217,7 +224,7 @@ impl<'a> PlacementAmongFloats<'a> {
} }
/// Run the placement algorithm for this [PlacementAmongFloats]. /// Run the placement algorithm for this [PlacementAmongFloats].
pub(crate) fn place(&mut self) -> LogicalRect<Length> { pub(crate) fn place(&mut self) -> LogicalRect<Au> {
debug_assert!(self.has_bands_or_at_end()); debug_assert!(self.has_bands_or_at_end());
while !self.current_bands.is_empty() { while !self.current_bands.is_empty() {
if let Some(result) = self.try_place_once() { if let Some(result) = self.try_place_once() {
@ -239,7 +246,7 @@ impl<'a> PlacementAmongFloats<'a> {
}, },
size: LogicalVec2 { size: LogicalVec2 {
inline: self.max_inline_end - self.min_inline_start, inline: self.max_inline_end - self.min_inline_start,
block: Length::new(f32::INFINITY), block: MAX_AU,
}, },
} }
} }
@ -252,8 +259,8 @@ impl<'a> PlacementAmongFloats<'a> {
/// (with this [PlacementAmongFloats]). /// (with this [PlacementAmongFloats]).
pub(crate) fn try_to_expand_for_auto_block_size( pub(crate) fn try_to_expand_for_auto_block_size(
&mut self, &mut self,
block_size_after_layout: Length, block_size_after_layout: Au,
size_from_placement: &LogicalVec2<Length>, size_from_placement: &LogicalVec2<Au>,
) -> bool { ) -> bool {
debug_assert!(self.has_bands_or_at_end()); debug_assert!(self.has_bands_or_at_end());
debug_assert_eq!(size_from_placement.block, self.current_bands_height()); debug_assert_eq!(size_from_placement.block, self.current_bands_height());
@ -309,59 +316,59 @@ pub struct FloatContext {
pub bands: FloatBandTree, pub bands: FloatBandTree,
/// The block-direction "ceiling" defined by the placement of other floated content of /// The block-direction "ceiling" defined by the placement of other floated content of
/// this FloatContext. No new floats can be placed at a lower block start than this value. /// this FloatContext. No new floats can be placed at a lower block start than this value.
pub ceiling_from_floats: Length, pub ceiling_from_floats: Au,
/// The block-direction "ceiling" defined by the placement of non-floated content that /// The block-direction "ceiling" defined by the placement of non-floated content that
/// precedes floated content in the document. Note that this may actually decrease as /// precedes floated content in the document. Note that this may actually decrease as
/// content is laid out in the case that content overflows its container. /// content is laid out in the case that content overflows its container.
pub ceiling_from_non_floats: Length, pub ceiling_from_non_floats: Au,
/// Details about the position of the containing block relative to the /// Details about the position of the containing block relative to the
/// independent block formatting context that contains all of the floats /// independent block formatting context that contains all of the floats
/// this `FloatContext` positions. /// this `FloatContext` positions.
pub containing_block_info: ContainingBlockPositionInfo, pub containing_block_info: ContainingBlockPositionInfo,
/// The (logically) lowest margin edge of the last left float. /// The (logically) lowest margin edge of the last left float.
pub clear_left_position: Length, pub clear_left_position: Au,
/// The (logically) lowest margin edge of the last right float. /// The (logically) lowest margin edge of the last right float.
pub clear_right_position: Length, pub clear_right_position: Au,
} }
impl FloatContext { impl FloatContext {
/// Returns a new float context representing a containing block with the given content /// Returns a new float context representing a containing block with the given content
/// inline-size. /// inline-size.
pub fn new(max_inline_size: Length) -> Self { pub fn new(max_inline_size: Au) -> Self {
let mut bands = FloatBandTree::new(); let mut bands = FloatBandTree::new();
bands = bands.insert(FloatBand { bands = bands.insert(FloatBand {
top: Length::new(-f32::INFINITY), top: MIN_AU,
left: None, left: None,
right: None, right: None,
}); });
bands = bands.insert(FloatBand { bands = bands.insert(FloatBand {
top: Length::new(f32::INFINITY), top: MAX_AU,
left: None, left: None,
right: None, right: None,
}); });
FloatContext { FloatContext {
bands, bands,
ceiling_from_floats: Length::zero(), ceiling_from_floats: Au::zero(),
ceiling_from_non_floats: Length::zero(), ceiling_from_non_floats: Au::zero(),
containing_block_info: ContainingBlockPositionInfo::new_with_inline_offsets( containing_block_info: ContainingBlockPositionInfo::new_with_inline_offsets(
Length::zero(), Au::zero(),
max_inline_size, max_inline_size,
), ),
clear_left_position: Length::zero(), clear_left_position: Au::zero(),
clear_right_position: Length::zero(), clear_right_position: Au::zero(),
} }
} }
/// (Logically) lowers the ceiling to at least `new_ceiling` units. /// (Logically) lowers the ceiling to at least `new_ceiling` units.
/// ///
/// If the ceiling is already logically lower (i.e. larger) than this, does nothing. /// If the ceiling is already logically lower (i.e. larger) than this, does nothing.
pub fn set_ceiling_from_non_floats(&mut self, new_ceiling: Length) { pub fn set_ceiling_from_non_floats(&mut self, new_ceiling: Au) {
self.ceiling_from_non_floats = new_ceiling; self.ceiling_from_non_floats = new_ceiling;
} }
/// The "ceiling" used for float placement. This is the minimum block position value /// The "ceiling" used for float placement. This is the minimum block position value
/// that should be used for placing any new float. /// that should be used for placing any new float.
fn ceiling(&mut self) -> Length { fn ceiling(&mut self) -> Au {
self.ceiling_from_floats.max(self.ceiling_from_non_floats) self.ceiling_from_floats.max(self.ceiling_from_non_floats)
} }
@ -370,11 +377,7 @@ impl FloatContext {
/// ///
/// This should be used for placing inline elements and block formatting contexts so that they /// This should be used for placing inline elements and block formatting contexts so that they
/// don't collide with floats. /// don't collide with floats.
pub(crate) fn place_object( pub(crate) fn place_object(&self, object: &PlacementInfo, ceiling: Au) -> LogicalVec2<Au> {
&self,
object: &PlacementInfo,
ceiling: Length,
) -> LogicalVec2<Length> {
let ceiling = match object.clear { let ceiling = match object.clear {
Clear::None => ceiling, Clear::None => ceiling,
Clear::Left => ceiling.max(self.clear_left_position), Clear::Left => ceiling.max(self.clear_left_position),
@ -388,7 +391,7 @@ impl FloatContext {
let mut first_band = self.bands.find(ceiling).unwrap(); let mut first_band = self.bands.find(ceiling).unwrap();
while !first_band.object_fits(&object, &self.containing_block_info) { while !first_band.object_fits(&object, &self.containing_block_info) {
let next_band = self.bands.find_next(first_band.top).unwrap(); let next_band = self.bands.find_next(first_band.top).unwrap();
if next_band.top.px().is_infinite() { if next_band.top == MAX_AU {
break; break;
} }
first_band = next_band; first_band = next_band;
@ -420,7 +423,7 @@ impl FloatContext {
} }
/// Places a new float and adds it to the list. Returns the start corner of its margin box. /// Places a new float and adds it to the list. Returns the start corner of its margin box.
pub fn add_float(&mut self, new_float: &PlacementInfo) -> LogicalVec2<Length> { pub fn add_float(&mut self, new_float: &PlacementInfo) -> LogicalVec2<Au> {
// Place the float. // Place the float.
let ceiling = self.ceiling(); let ceiling = self.ceiling();
let new_float_origin = self.place_object(&new_float, ceiling); let new_float_origin = self.place_object(&new_float, ceiling);
@ -436,8 +439,8 @@ impl FloatContext {
// so negative that it's placed completely above the current float ceiling, then // so negative that it's placed completely above the current float ceiling, then
// we should position it as if it had zero block size. // we should position it as if it had zero block size.
size: LogicalVec2 { size: LogicalVec2 {
inline: new_float.size.inline.max(CSSPixelLength::zero()), inline: new_float.size.inline.max(Au::zero()),
block: new_float.size.block.max(CSSPixelLength::zero()), block: new_float.size.block.max(Au::zero()),
}, },
}; };
@ -476,17 +479,25 @@ impl FloatContext {
// CSS 2.1 § 9.5.1 rule 6: The outer top of a floating box may not be higher than the outer // CSS 2.1 § 9.5.1 rule 6: The outer top of a floating box may not be higher than the outer
// top of any block or floated box generated by an element earlier in the source document. // top of any block or floated box generated by an element earlier in the source document.
self.ceiling_from_floats max_assign_au(
.max_assign(new_float_rect.start_corner.block); &mut self.ceiling_from_floats,
new_float_rect.start_corner.block,
);
new_float_rect.start_corner new_float_rect.start_corner
} }
} }
fn max_assign_au(current: &mut Au, other: Au) {
let max_value = std::cmp::max(current.0, other.0);
*current = Au(max_value);
}
/// Information needed to place an object so that it doesn't collide with existing floats. /// Information needed to place an object so that it doesn't collide with existing floats.
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub struct PlacementInfo { pub struct PlacementInfo {
/// The *margin* box size of the object. /// The *margin* box size of the object.
pub size: LogicalVec2<Length>, pub size: LogicalVec2<Au>,
/// Whether the object is (logically) aligned to the left or right. /// Whether the object is (logically) aligned to the left or right.
pub side: FloatSide, pub side: FloatSide,
/// Which side or sides to clear floats on. /// Which side or sides to clear floats on.
@ -507,17 +518,17 @@ pub enum FloatSide {
#[derive(Clone, Copy, Debug, PartialEq)] #[derive(Clone, Copy, Debug, PartialEq)]
pub struct FloatBand { pub struct FloatBand {
/// The logical vertical position of the top of this band. /// The logical vertical position of the top of this band.
pub top: Length, pub top: Au,
/// The distance from the left edge of the block formatting context to the first legal /// The distance from the left edge of the block formatting context to the first legal
/// (logically) horizontal position where floats may be placed. If `None`, there are no floats /// (logically) horizontal position where floats may be placed. If `None`, there are no floats
/// to the left; distinguishing between the cases of "a zero-width float is present" and "no /// to the left; distinguishing between the cases of "a zero-width float is present" and "no
/// floats at all are present" is necessary to, for example, clear past zero-width floats. /// floats at all are present" is necessary to, for example, clear past zero-width floats.
pub left: Option<Length>, pub left: Option<Au>,
/// The distance from the *left* edge of the block formatting context to the first legal /// The distance from the *left* edge of the block formatting context to the first legal
/// (logically) horizontal position where floats may be placed. If `None`, there are no floats /// (logically) horizontal position where floats may be placed. If `None`, there are no floats
/// to the right; distinguishing between the cases of "a zero-width float is present" and "no /// to the right; distinguishing between the cases of "a zero-width float is present" and "no
/// floats at all are present" is necessary to, for example, clear past zero-width floats. /// floats at all are present" is necessary to, for example, clear past zero-width floats.
pub right: Option<Length>, pub right: Option<Au>,
} }
impl FloatSide { impl FloatSide {
@ -624,24 +635,19 @@ impl FloatBandTree {
} }
/// Returns the first band whose top is less than or equal to the given `block_position`. /// Returns the first band whose top is less than or equal to the given `block_position`.
pub fn find(&self, block_position: Length) -> Option<FloatBand> { pub fn find(&self, block_position: Au) -> Option<FloatBand> {
self.root.find(block_position) self.root.find(block_position)
} }
/// Returns the first band whose top is strictly greater than to the given `block_position`. /// Returns the first band whose top is strictly greater than to the given `block_position`.
pub fn find_next(&self, block_position: Length) -> Option<FloatBand> { pub fn find_next(&self, block_position: Au) -> Option<FloatBand> {
self.root.find_next(block_position) self.root.find_next(block_position)
} }
/// Sets the side values of all bands within the given half-open range to be at least /// Sets the side values of all bands within the given half-open range to be at least
/// `new_value`. /// `new_value`.
#[must_use] #[must_use]
pub fn set_range( pub fn set_range(&self, range: &Range<Au>, side: FloatSide, new_value: Au) -> FloatBandTree {
&self,
range: &Range<Length>,
side: FloatSide,
new_value: Length,
) -> FloatBandTree {
FloatBandTree { FloatBandTree {
root: FloatBandLink( root: FloatBandLink(
self.root self.root
@ -674,22 +680,21 @@ impl FloatBandNode {
/// Sets the side values of all bands within the given half-open range to be at least /// Sets the side values of all bands within the given half-open range to be at least
/// `new_value`. /// `new_value`.
fn set_range( fn set_range(&self, range: &Range<Au>, side: FloatSide, new_value: Au) -> Arc<FloatBandNode> {
&self,
range: &Range<Length>,
side: FloatSide,
new_value: Length,
) -> Arc<FloatBandNode> {
let mut new_band = self.band.clone(); let mut new_band = self.band.clone();
if self.band.top >= range.start && self.band.top < range.end { if self.band.top >= range.start && self.band.top < range.end {
match side { match side {
FloatSide::Left => match new_band.left { FloatSide::Left => {
None => new_band.left = Some(new_value), new_band.left = match new_band.left {
Some(ref mut old_value) => *old_value = old_value.max(new_value), Some(old_value) => Some(std::cmp::max(old_value, new_value)),
None => Some(new_value),
};
}, },
FloatSide::Right => match new_band.right { FloatSide::Right => {
None => new_band.right = Some(new_value), new_band.right = match new_band.right {
Some(ref mut old_value) => *old_value = old_value.min(new_value), Some(old_value) => Some(std::cmp::min(old_value, new_value)),
None => Some(new_value),
};
}, },
} }
} }
@ -721,7 +726,7 @@ impl FloatBandNode {
impl FloatBandLink { impl FloatBandLink {
/// Returns the first band whose top is less than or equal to the given `block_position`. /// Returns the first band whose top is less than or equal to the given `block_position`.
fn find(&self, block_position: Length) -> Option<FloatBand> { fn find(&self, block_position: Au) -> Option<FloatBand> {
let this = match self.0 { let this = match self.0 {
None => return None, None => return None,
Some(ref node) => node, Some(ref node) => node,
@ -741,7 +746,7 @@ impl FloatBandLink {
} }
/// Returns the first band whose top is strictly greater than the given `block_position`. /// Returns the first band whose top is strictly greater than the given `block_position`.
fn find_next(&self, block_position: Length) -> Option<FloatBand> { fn find_next(&self, block_position: Au) -> Option<FloatBand> {
let this = match self.0 { let this = match self.0 {
None => return None, None => return None,
Some(ref node) => node, Some(ref node) => node,
@ -886,7 +891,7 @@ impl FloatBox {
// Margin is computed this way regardless of whether the element is replaced // Margin is computed this way regardless of whether the element is replaced
// or non-replaced. // or non-replaced.
let pbm = style.padding_border_margin(containing_block); let pbm = style.padding_border_margin(containing_block);
let margin = pbm.margin.auto_is(|| Length::zero()); let margin = pbm.margin.auto_is(Length::zero);
let pbm_sums = &(&pbm.padding + &pbm.border) + &margin; let pbm_sums = &(&pbm.padding + &pbm.border) + &margin;
let (content_size, children); let (content_size, children);
@ -993,18 +998,18 @@ pub(crate) struct SequentialLayoutState {
/// This is often, but not always, the same as the float ceiling. The float ceiling can be lower /// This is often, but not always, the same as the float ceiling. The float ceiling can be lower
/// than this value because this value is calculated based on in-flow boxes only, while /// than this value because this value is calculated based on in-flow boxes only, while
/// out-of-flow floats can affect the ceiling as well (see CSS 2.1 § 9.5.1 rule 6). /// out-of-flow floats can affect the ceiling as well (see CSS 2.1 § 9.5.1 rule 6).
pub(crate) bfc_relative_block_position: Length, pub(crate) bfc_relative_block_position: Au,
/// Any collapsible margins that we've encountered after `bfc_relative_block_position`. /// Any collapsible margins that we've encountered after `bfc_relative_block_position`.
pub(crate) current_margin: CollapsedMargin, pub(crate) current_margin: CollapsedMargin,
} }
impl SequentialLayoutState { impl SequentialLayoutState {
/// Creates a new empty `SequentialLayoutState`. /// Creates a new empty `SequentialLayoutState`.
pub(crate) fn new(max_inline_size: Length) -> SequentialLayoutState { pub(crate) fn new(max_inline_size: Au) -> SequentialLayoutState {
SequentialLayoutState { SequentialLayoutState {
floats: FloatContext::new(max_inline_size), floats: FloatContext::new(max_inline_size),
current_margin: CollapsedMargin::zero(), current_margin: CollapsedMargin::zero(),
bfc_relative_block_position: Length::zero(), bfc_relative_block_position: Au::zero(),
} }
} }
@ -1014,7 +1019,7 @@ impl SequentialLayoutState {
/// [`SequentialLayoutState`] after processing its overflowing content. /// [`SequentialLayoutState`] after processing its overflowing content.
/// ///
/// Floats may not be placed higher than the current block position. /// Floats may not be placed higher than the current block position.
pub(crate) fn advance_block_position(&mut self, block_distance: Length) { pub(crate) fn advance_block_position(&mut self, block_distance: Au) {
self.bfc_relative_block_position += block_distance; self.bfc_relative_block_position += block_distance;
self.floats self.floats
.set_ceiling_from_non_floats(self.bfc_relative_block_position); .set_ceiling_from_non_floats(self.bfc_relative_block_position);
@ -1032,8 +1037,8 @@ impl SequentialLayoutState {
/// Return the current block position in the float containing block formatting /// Return the current block position in the float containing block formatting
/// context and any uncollapsed block margins. /// context and any uncollapsed block margins.
pub(crate) fn current_block_position_including_margins(&self) -> Length { pub(crate) fn current_block_position_including_margins(&self) -> Au {
self.bfc_relative_block_position + self.current_margin.solve() self.bfc_relative_block_position + self.current_margin.solve().into()
} }
/// Collapses margins, moving the block position down by the collapsed value of `current_margin` /// Collapses margins, moving the block position down by the collapsed value of `current_margin`
@ -1042,29 +1047,29 @@ impl SequentialLayoutState {
/// Call this method before laying out children when it is known that the start margin of the /// Call this method before laying out children when it is known that the start margin of the
/// current fragment can't collapse with the margins of any of its children. /// current fragment can't collapse with the margins of any of its children.
pub(crate) fn collapse_margins(&mut self) { pub(crate) fn collapse_margins(&mut self) {
self.advance_block_position(self.current_margin.solve()); self.advance_block_position(self.current_margin.solve().into());
self.current_margin = CollapsedMargin::zero(); self.current_margin = CollapsedMargin::zero();
} }
/// Computes the position of the block-start border edge of an element /// Computes the position of the block-start border edge of an element
/// with the provided `block_start_margin`, assuming no clearance. /// with the provided `block_start_margin`, assuming no clearance.
pub(crate) fn position_without_clearance( pub(crate) fn position_without_clearance(&self, block_start_margin: &CollapsedMargin) -> Au {
&self,
block_start_margin: &CollapsedMargin,
) -> Length {
// Adjoin `current_margin` and `block_start_margin` since there is no clearance. // Adjoin `current_margin` and `block_start_margin` since there is no clearance.
self.bfc_relative_block_position + self.current_margin.adjoin(&block_start_margin).solve() self.bfc_relative_block_position +
self.current_margin
.adjoin(&block_start_margin)
.solve()
.into()
} }
/// Computes the position of the block-start border edge of an element /// Computes the position of the block-start border edge of an element
/// with the provided `block_start_margin`, assuming a clearance of 0px. /// with the provided `block_start_margin`, assuming a clearance of 0px.
pub(crate) fn position_with_zero_clearance( pub(crate) fn position_with_zero_clearance(&self, block_start_margin: &CollapsedMargin) -> Au {
&self,
block_start_margin: &CollapsedMargin,
) -> Length {
// Clearance prevents `current_margin` and `block_start_margin` from being // Clearance prevents `current_margin` and `block_start_margin` from being
// adjoining, so we need to solve them separately and then sum. // adjoining, so we need to solve them separately and then sum.
self.bfc_relative_block_position + self.current_margin.solve() + block_start_margin.solve() self.bfc_relative_block_position +
self.current_margin.solve().into() +
block_start_margin.solve().into()
} }
/// Returns the block-end outer edge of the lowest float that is to be cleared (if any) /// Returns the block-end outer edge of the lowest float that is to be cleared (if any)
@ -1073,7 +1078,7 @@ impl SequentialLayoutState {
&self, &self,
clear: Clear, clear: Clear,
block_start_margin: &CollapsedMargin, block_start_margin: &CollapsedMargin,
) -> Option<Length> { ) -> Option<Au> {
if clear == Clear::None { if clear == Clear::None {
return None; return None;
} }
@ -1112,7 +1117,7 @@ impl SequentialLayoutState {
&self, &self,
clear: Clear, clear: Clear,
block_start_margin: &CollapsedMargin, block_start_margin: &CollapsedMargin,
) -> Option<Length> { ) -> Option<Au> {
return self return self
.calculate_clear_position(clear, &block_start_margin) .calculate_clear_position(clear, &block_start_margin)
.map(|offset| offset - self.position_with_zero_clearance(&block_start_margin)); .map(|offset| offset - self.position_with_zero_clearance(&block_start_margin));
@ -1131,8 +1136,8 @@ impl SequentialLayoutState {
clear: Clear, clear: Clear,
block_start_margin: &CollapsedMargin, block_start_margin: &CollapsedMargin,
pbm: &PaddingBorderMargin, pbm: &PaddingBorderMargin,
object_size: LogicalVec2<Length>, object_size: LogicalVec2<Au>,
) -> (Option<Length>, LogicalRect<Length>) { ) -> (Option<Au>, LogicalRect<Au>) {
// First compute the clear position required by the 'clear' property. // First compute the clear position required by the 'clear' property.
// The code below may then add extra clearance when the element can't fit // The code below may then add extra clearance when the element can't fit
// next to floats not covered by 'clear'. // next to floats not covered by 'clear'.
@ -1157,12 +1162,13 @@ impl SequentialLayoutState {
} }
/// Get the offset of the current containing block and any uncollapsed margins. /// Get the offset of the current containing block and any uncollapsed margins.
pub(crate) fn current_containing_block_offset(&self) -> CSSPixelLength { pub(crate) fn current_containing_block_offset(&self) -> Au {
self.floats.containing_block_info.block_start + self.floats.containing_block_info.block_start +
self.floats self.floats
.containing_block_info .containing_block_info
.block_start_margins_not_collapsed .block_start_margins_not_collapsed
.solve() .solve()
.into()
} }
/// This function places a Fragment that has been created for a FloatBox. /// This function places a Fragment that has been created for a FloatBox.
@ -1170,30 +1176,33 @@ impl SequentialLayoutState {
&mut self, &mut self,
box_fragment: &mut BoxFragment, box_fragment: &mut BoxFragment,
margins_collapsing_with_parent_containing_block: CollapsedMargin, margins_collapsing_with_parent_containing_block: CollapsedMargin,
block_offset_from_containing_block_top: Length, block_offset_from_containing_block_top: Au,
) { ) {
let block_start_of_containing_block_in_bfc = self.floats.containing_block_info.block_start + let block_start_of_containing_block_in_bfc = self.floats.containing_block_info.block_start +
self.floats self.floats
.containing_block_info .containing_block_info
.block_start_margins_not_collapsed .block_start_margins_not_collapsed
.adjoin(&margins_collapsing_with_parent_containing_block) .adjoin(&margins_collapsing_with_parent_containing_block)
.solve(); .solve()
.into();
self.floats.set_ceiling_from_non_floats( self.floats.set_ceiling_from_non_floats(
block_start_of_containing_block_in_bfc + block_offset_from_containing_block_top, block_start_of_containing_block_in_bfc + block_offset_from_containing_block_top,
); );
let pbm_sums = &(&box_fragment.padding + &box_fragment.border) + &box_fragment.margin; let pbm_sums = &(&box_fragment.padding + &box_fragment.border) + &box_fragment.margin;
let content_rect: LogicalRect<Au> = box_fragment.content_rect.clone().into();
let pbm_sums_all: LogicalSides<Au> = pbm_sums.map(|length| (*length).into());
let margin_box_start_corner = self.floats.add_float(&PlacementInfo { let margin_box_start_corner = self.floats.add_float(&PlacementInfo {
size: &box_fragment.content_rect.size + &pbm_sums.sum(), size: &content_rect.size + &pbm_sums_all.sum(),
side: FloatSide::from_style(&box_fragment.style).expect("Float box wasn't floated!"), side: FloatSide::from_style(&box_fragment.style).expect("Float box wasn't floated!"),
clear: box_fragment.style.get_box().clear, clear: box_fragment.style.get_box().clear,
}); });
// This is the position of the float in the float-containing block formatting context. We add the // This is the position of the float in the float-containing block formatting context. We add the
// existing start corner here because we may have already gotten some relative positioning offset. // existing start corner here because we may have already gotten some relative positioning offset.
let new_position_in_bfc = &(&margin_box_start_corner + &pbm_sums.start_offset()) + let new_position_in_bfc =
&box_fragment.content_rect.start_corner; &(&margin_box_start_corner + &pbm_sums_all.start_offset()) + &content_rect.start_corner;
// This is the position of the float relative to the containing block start. // This is the position of the float relative to the containing block start.
let new_position_in_containing_block = LogicalVec2 { let new_position_in_containing_block = LogicalVec2 {
@ -1201,6 +1210,6 @@ impl SequentialLayoutState {
block: new_position_in_bfc.block - block_start_of_containing_block_in_bfc, block: new_position_in_bfc.block - block_start_of_containing_block_in_bfc,
}; };
box_fragment.content_rect.start_corner = new_position_in_containing_block; box_fragment.content_rect.start_corner = new_position_in_containing_block.into();
} }
} }

View file

@ -160,10 +160,10 @@ impl LineUnderConstruction {
} }
} }
fn line_block_start_considering_placement_among_floats(&self) -> Length { fn line_block_start_considering_placement_among_floats(&self) -> Au {
match self.placement_among_floats.get() { match self.placement_among_floats.get() {
Some(placement_among_floats) => placement_among_floats.start_corner.block, Some(placement_among_floats) => placement_among_floats.start_corner.block.into(),
None => self.start_position.block, None => self.start_position.block.into(),
} }
} }
@ -730,12 +730,12 @@ impl<'a, 'b> InlineFormattingContextState<'a, 'b> {
LineBlockSizes::zero() LineBlockSizes::zero()
}; };
let block_end_position = block_start_position + effective_block_advance.resolve(); let block_end_position = block_start_position + effective_block_advance.resolve().into();
if let Some(sequential_layout_state) = self.sequential_layout_state.as_mut() { if let Some(sequential_layout_state) = self.sequential_layout_state.as_mut() {
// This amount includes both the block size of the line and any extra space // This amount includes both the block size of the line and any extra space
// added to move the line down in order to avoid overlapping floats. // added to move the line down in order to avoid overlapping floats.
let increment = block_end_position - self.current_line.start_position.block; let increment = block_end_position - self.current_line.start_position.block.into();
sequential_layout_state.advance_block_position(increment); sequential_layout_state.advance_block_position(increment.into());
} }
let mut line_items = std::mem::take(&mut self.current_line.line_items); let mut line_items = std::mem::take(&mut self.current_line.line_items);
@ -746,7 +746,7 @@ impl<'a, 'b> InlineFormattingContextState<'a, 'b> {
// Set up the new line now that we no longer need the old one. // Set up the new line now that we no longer need the old one.
self.current_line = LineUnderConstruction::new(LogicalVec2 { self.current_line = LineUnderConstruction::new(LogicalVec2 {
inline: Length::zero(), inline: Length::zero(),
block: block_end_position, block: block_end_position.into(),
}); });
let baseline_offset = effective_block_advance.find_baseline_offset(); let baseline_offset = effective_block_advance.find_baseline_offset();
@ -759,7 +759,7 @@ impl<'a, 'b> InlineFormattingContextState<'a, 'b> {
positioning_context: &mut self.positioning_context, positioning_context: &mut self.positioning_context,
justification_adjustment, justification_adjustment,
line_metrics: &LineMetrics { line_metrics: &LineMetrics {
block_offset: block_start_position, block_offset: block_start_position.into(),
block_size: effective_block_advance.resolve(), block_size: effective_block_advance.resolve(),
baseline_block_offset: baseline_offset, baseline_block_offset: baseline_offset,
}, },
@ -782,14 +782,14 @@ impl<'a, 'b> InlineFormattingContextState<'a, 'b> {
return; return;
} }
self.last_baseline_offset = Some(baseline_offset + block_start_position); self.last_baseline_offset = Some(baseline_offset + block_start_position.into());
let line_rect = LogicalRect { let line_rect = LogicalRect {
// The inline part of this start offset was taken into account when determining // The inline part of this start offset was taken into account when determining
// the inline start of the line in `calculate_inline_start_for_current_line` so // the inline start of the line in `calculate_inline_start_for_current_line` so
// we do not need to include it in the `start_corner` of the line's main Fragment. // we do not need to include it in the `start_corner` of the line's main Fragment.
start_corner: LogicalVec2 { start_corner: LogicalVec2 {
inline: Length::zero(), inline: Length::zero(),
block: block_start_position, block: block_start_position.into(),
}, },
size: LogicalVec2 { size: LogicalVec2 {
inline: self.containing_block.inline_size, inline: self.containing_block.inline_size,
@ -1000,7 +1000,9 @@ impl<'a, 'b> InlineFormattingContextState<'a, 'b> {
.floats .floats
.containing_block_info .containing_block_info
.inline_start, .inline_start,
block: sequential_layout_state.current_containing_block_offset(), block: sequential_layout_state
.current_containing_block_offset()
.into(),
}; };
let ceiling = self let ceiling = self
@ -1008,14 +1010,17 @@ impl<'a, 'b> InlineFormattingContextState<'a, 'b> {
.line_block_start_considering_placement_among_floats(); .line_block_start_considering_placement_among_floats();
let mut placement = PlacementAmongFloats::new( let mut placement = PlacementAmongFloats::new(
&sequential_layout_state.floats, &sequential_layout_state.floats,
ceiling + ifc_offset_in_float_container.block, ceiling + ifc_offset_in_float_container.block.into(),
potential_line_size.clone(), LogicalVec2 {
inline: potential_line_size.inline.into(),
block: potential_line_size.block.into(),
},
&PaddingBorderMargin::zero(), &PaddingBorderMargin::zero(),
); );
let mut placement_rect = placement.place(); let mut placement_rect = placement.place();
placement_rect.start_corner = &placement_rect.start_corner - &ifc_offset_in_float_container; placement_rect.start_corner = &placement_rect.start_corner - &ifc_offset_in_float_container;
placement_rect placement_rect.into()
} }
/// Returns true if a new potential line size for the current line would require a line /// Returns true if a new potential line size for the current line would require a line
@ -1083,6 +1088,7 @@ impl<'a, 'b> InlineFormattingContextState<'a, 'b> {
if new_placement.start_corner.block != if new_placement.start_corner.block !=
self.current_line self.current_line
.line_block_start_considering_placement_among_floats() .line_block_start_considering_placement_among_floats()
.into()
{ {
return true; return true;
} else { } else {

View file

@ -4,6 +4,7 @@
//! Flow layout, also known as block-and-inline layout. //! Flow layout, also known as block-and-inline layout.
use app_units::Au;
use rayon::iter::{IntoParallelRefIterator, ParallelIterator}; use rayon::iter::{IntoParallelRefIterator, ParallelIterator};
use serde::Serialize; use serde::Serialize;
use servo_arc::Arc; use servo_arc::Arc;
@ -213,7 +214,9 @@ impl BlockFormattingContext {
containing_block: &ContainingBlock, containing_block: &ContainingBlock,
) -> IndependentLayout { ) -> IndependentLayout {
let mut sequential_layout_state = if self.contains_floats || !layout_context.use_rayon { let mut sequential_layout_state = if self.contains_floats || !layout_context.use_rayon {
Some(SequentialLayoutState::new(containing_block.inline_size)) Some(SequentialLayoutState::new(
containing_block.inline_size.into(),
))
} else { } else {
None None
}; };
@ -242,7 +245,7 @@ impl BlockFormattingContext {
fragments: flow_layout.fragments, fragments: flow_layout.fragments,
content_block_size: (flow_layout.content_block_size + content_block_size: (flow_layout.content_block_size +
flow_layout.collapsible_margins_in_children.end.solve() + flow_layout.collapsible_margins_in_children.end.solve() +
clearance.unwrap_or_else(Length::zero)) clearance.unwrap_or_else(Au::zero).into())
.into(), .into(),
last_inflow_baseline_offset: flow_layout.last_inflow_baseline_offset.map(|t| t.into()), last_inflow_baseline_offset: flow_layout.last_inflow_baseline_offset.map(|t| t.into()),
} }
@ -692,9 +695,10 @@ fn layout_in_flow_non_replaced_block_level_same_formatting_context(
// NB: This will be a no-op if we're collapsing margins with our children since that // NB: This will be a no-op if we're collapsing margins with our children since that
// can only happen if we have no block-start padding and border. // can only happen if we have no block-start padding and border.
sequential_layout_state.advance_block_position( sequential_layout_state.advance_block_position(
pbm.padding.block_start + (pbm.padding.block_start +
pbm.border.block_start + pbm.border.block_start +
clearance.unwrap_or_else(Length::zero), clearance.unwrap_or_else(Au::zero).into())
.into(),
); );
// We are about to lay out children. Update the offset between the block formatting // We are about to lay out children. Update the offset between the block formatting
@ -706,14 +710,14 @@ fn layout_in_flow_non_replaced_block_level_same_formatting_context(
.floats .floats
.containing_block_info .containing_block_info
.inline_start + .inline_start +
pbm.padding.inline_start + pbm.padding.inline_start.into() +
pbm.border.inline_start + pbm.border.inline_start.into() +
margin.inline_start; margin.inline_start.into();
let new_cb_offsets = ContainingBlockPositionInfo { let new_cb_offsets = ContainingBlockPositionInfo {
block_start: sequential_layout_state.bfc_relative_block_position, block_start: sequential_layout_state.bfc_relative_block_position,
block_start_margins_not_collapsed: sequential_layout_state.current_margin, block_start_margins_not_collapsed: sequential_layout_state.current_margin,
inline_start, inline_start,
inline_end: inline_start + containing_block_for_children.inline_size, inline_end: inline_start + containing_block_for_children.inline_size.into(),
}; };
parent_containing_block_position_info = Some( parent_containing_block_position_info = Some(
sequential_layout_state.replace_containing_block_position_info(new_cb_offsets), sequential_layout_state.replace_containing_block_position_info(new_cb_offsets),
@ -781,7 +785,7 @@ fn layout_in_flow_non_replaced_block_level_same_formatting_context(
// the block direction. In that case, the ceiling for floats is effectively raised // the block direction. In that case, the ceiling for floats is effectively raised
// as long as no floats in the overflowing content lowered it. // as long as no floats in the overflowing content lowered it.
sequential_layout_state.advance_block_position( sequential_layout_state.advance_block_position(
(block_size - content_block_size) + pbm.padding.block_end + pbm.border.block_end, (block_size - content_block_size + pbm.padding.block_end + pbm.border.block_end).into(),
); );
if !end_margin_can_collapse_with_children { if !end_margin_can_collapse_with_children {
@ -792,9 +796,10 @@ fn layout_in_flow_non_replaced_block_level_same_formatting_context(
let content_rect = LogicalRect { let content_rect = LogicalRect {
start_corner: LogicalVec2 { start_corner: LogicalVec2 {
block: pbm.padding.block_start + block: (pbm.padding.block_start +
pbm.border.block_start + pbm.border.block_start +
clearance.unwrap_or_else(Length::zero), clearance.unwrap_or_else(Au::zero).into())
.into(),
inline: pbm.padding.inline_start + pbm.border.inline_start + margin.inline_start, inline: pbm.padding.inline_start + pbm.border.inline_start + margin.inline_start,
}, },
size: LogicalVec2 { size: LogicalVec2 {
@ -811,7 +816,7 @@ fn layout_in_flow_non_replaced_block_level_same_formatting_context(
pbm.padding, pbm.padding,
pbm.border, pbm.border,
margin, margin,
clearance, clearance.map(|t| t.into()),
flow_layout.last_inflow_baseline_offset, flow_layout.last_inflow_baseline_offset,
block_margins_collapsed_with_children, block_margins_collapsed_with_children,
) )
@ -987,7 +992,7 @@ impl NonReplacedFormattingContext {
let mut placement = PlacementAmongFloats::new( let mut placement = PlacementAmongFloats::new(
&sequential_layout_state.floats, &sequential_layout_state.floats,
ceiling, ceiling,
minimum_size_of_block, minimum_size_of_block.into(),
&pbm, &pbm,
); );
let mut placement_rect; let mut placement_rect;
@ -995,8 +1000,9 @@ impl NonReplacedFormattingContext {
loop { loop {
// First try to place the block using the minimum size as the object size. // First try to place the block using the minimum size as the object size.
placement_rect = placement.place(); placement_rect = placement.place();
let proposed_inline_size = (placement_rect.size.inline - let proposed_inline_size = Length::from(
pbm.padding_border_sums.inline) placement_rect.size.inline - pbm.padding_border_sums.inline.into(),
)
.clamp_between_extremums(min_box_size.inline, max_box_size.inline); .clamp_between_extremums(min_box_size.inline, max_box_size.inline);
// Now lay out the block using the inline size we calculated from the placement. // Now lay out the block using the inline size we calculated from the placement.
@ -1029,7 +1035,7 @@ impl NonReplacedFormattingContext {
// size of auto. Try to fit it into our precalculated placement among the // size of auto. Try to fit it into our precalculated placement among the
// floats. If it fits, then we can stop trying layout candidates. // floats. If it fits, then we can stop trying layout candidates.
if placement.try_to_expand_for_auto_block_size( if placement.try_to_expand_for_auto_block_size(
content_size.block + pbm.padding_border_sums.block, (content_size.block + pbm.padding_border_sums.block).into(),
&placement_rect.size, &placement_rect.size,
) { ) {
break; break;
@ -1046,9 +1052,10 @@ impl NonReplacedFormattingContext {
// prevent margin collapse. // prevent margin collapse.
clearance = if clear_position.is_some() || placement_rect.start_corner.block > ceiling { clearance = if clear_position.is_some() || placement_rect.start_corner.block > ceiling {
Some( Some(
placement_rect.start_corner.block - (placement_rect.start_corner.block -
sequential_layout_state sequential_layout_state
.position_with_zero_clearance(&collapsed_margin_block_start), .position_with_zero_clearance(&collapsed_margin_block_start))
.into(),
) )
} else { } else {
None None
@ -1059,7 +1066,7 @@ impl NonReplacedFormattingContext {
&containing_block, &containing_block,
&pbm, &pbm,
content_size.inline + pbm.padding_border_sums.inline, content_size.inline + pbm.padding_border_sums.inline,
placement_rect, placement_rect.into(),
); );
} }
@ -1080,9 +1087,10 @@ impl NonReplacedFormattingContext {
// Margins can never collapse into independent formatting contexts. // Margins can never collapse into independent formatting contexts.
sequential_layout_state.collapse_margins(); sequential_layout_state.collapse_margins();
sequential_layout_state.advance_block_position( sequential_layout_state.advance_block_position(
pbm.padding_border_sums.block + (pbm.padding_border_sums.block +
content_size.block + content_size.block +
clearance.unwrap_or_else(Length::zero), clearance.unwrap_or_else(Length::zero))
.into(),
); );
sequential_layout_state.adjoin_assign(&CollapsedMargin::new(margin.block_end)); sequential_layout_state.adjoin_assign(&CollapsedMargin::new(margin.block_end));
@ -1163,7 +1171,7 @@ fn layout_in_flow_replaced_block_level<'a>(
// Margins can never collapse into replaced elements. // Margins can never collapse into replaced elements.
sequential_layout_state.collapse_margins(); sequential_layout_state.collapse_margins();
sequential_layout_state sequential_layout_state
.advance_block_position(size.block + clearance.unwrap_or_else(Length::zero)); .advance_block_position((size.block + clearance.unwrap_or_else(Length::zero)).into());
sequential_layout_state.adjoin_assign(&CollapsedMargin::new(margin_block_end)); sequential_layout_state.adjoin_assign(&CollapsedMargin::new(margin_block_end));
} else { } else {
clearance = None; clearance = None;
@ -1299,16 +1307,16 @@ fn solve_clearance_and_inline_margins_avoiding_floats(
style.get_box().clear, style.get_box().clear,
&block_start_margin, &block_start_margin,
&pbm, &pbm,
size.clone(), size.clone().into(),
); );
let inline_margins = solve_inline_margins_avoiding_floats( let inline_margins = solve_inline_margins_avoiding_floats(
&sequential_layout_state, &sequential_layout_state,
&containing_block, &containing_block,
&pbm, &pbm,
size.inline, size.inline,
placement_rect, placement_rect.into(),
); );
(clearance, inline_margins) (clearance.map(|t| t.into()), inline_margins)
} }
/// Resolves the margins of an in-flow block-level box in the inline axis /// Resolves the margins of an in-flow block-level box in the inline axis
@ -1325,7 +1333,8 @@ fn solve_inline_margins_avoiding_floats(
sequential_layout_state sequential_layout_state
.floats .floats
.containing_block_info .containing_block_info
.inline_start; .inline_start
.into();
assert!(placement_rect.size.inline >= inline_size); assert!(placement_rect.size.inline >= inline_size);
let free_space = placement_rect.size.inline - inline_size; let free_space = placement_rect.size.inline - inline_size;
let margin_inline_start = match (pbm.margin.inline_start, pbm.margin.inline_end) { let margin_inline_start = match (pbm.margin.inline_start, pbm.margin.inline_end) {
@ -1493,7 +1502,7 @@ impl PlacementState {
sequential_layout_state.place_float_fragment( sequential_layout_state.place_float_fragment(
box_fragment, box_fragment,
self.start_margin, self.start_margin,
block_offset_from_containing_block_top, block_offset_from_containing_block_top.into(),
); );
}, },
Fragment::Anonymous(_) => {}, Fragment::Anonymous(_) => {},

View file

@ -2,6 +2,7 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this * License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
use std::convert::From;
use std::fmt; use std::fmt;
use std::ops::{Add, AddAssign, Sub}; use std::ops::{Add, AddAssign, Sub};
@ -10,7 +11,7 @@ use serde::Serialize;
use style::logical_geometry::{ use style::logical_geometry::{
BlockFlowDirection, InlineBaseDirection, PhysicalCorner, WritingMode, BlockFlowDirection, InlineBaseDirection, PhysicalCorner, WritingMode,
}; };
use style::values::computed::{Length, LengthPercentage}; use style::values::computed::{CSSPixelLength, Length, LengthPercentage};
use style::values::generics::length::GenericLengthPercentageOrAuto as AutoOr; use style::values::generics::length::GenericLengthPercentageOrAuto as AutoOr;
use style::Zero; use style::Zero;
use style_traits::CSSPixel; use style_traits::CSSPixel;
@ -415,3 +416,51 @@ impl<T> LogicalRect<T> {
) )
} }
} }
impl From<LogicalVec2<CSSPixelLength>> for LogicalVec2<Au> {
fn from(value: LogicalVec2<CSSPixelLength>) -> Self {
LogicalVec2 {
inline: value.inline.into(),
block: value.block.into(),
}
}
}
impl From<LogicalVec2<Au>> for LogicalVec2<CSSPixelLength> {
fn from(value: LogicalVec2<Au>) -> Self {
LogicalVec2 {
inline: value.inline.into(),
block: value.block.into(),
}
}
}
impl From<LogicalRect<Au>> for LogicalRect<CSSPixelLength> {
fn from(value: LogicalRect<Au>) -> Self {
LogicalRect {
start_corner: LogicalVec2 {
inline: value.start_corner.inline.into(),
block: value.start_corner.block.into(),
},
size: LogicalVec2 {
inline: value.size.inline.into(),
block: value.size.block.into(),
},
}
}
}
impl From<LogicalRect<CSSPixelLength>> for LogicalRect<Au> {
fn from(value: LogicalRect<CSSPixelLength>) -> Self {
LogicalRect {
start_corner: LogicalVec2 {
inline: value.start_corner.inline.into(),
block: value.start_corner.block.into(),
},
size: LogicalVec2 {
inline: value.size.inline.into(),
block: value.size.block.into(),
},
}
}
}

View file

@ -4,11 +4,13 @@
//! Property-based randomized testing for the core float layout algorithm. //! Property-based randomized testing for the core float layout algorithm.
use std::f32::INFINITY;
use std::ops::Range; use std::ops::Range;
use std::panic::{self, PanicInfo}; use std::panic::{self, PanicInfo};
use std::sync::{Mutex, MutexGuard}; use std::sync::{Mutex, MutexGuard};
use std::{f32, thread, u32}; use std::{thread, u32};
use app_units::Au;
use euclid::num::Zero; use euclid::num::Zero;
use layout_2020::flow::float::{ use layout_2020::flow::float::{
ContainingBlockPositionInfo, FloatBand, FloatBandNode, FloatBandTree, FloatContext, FloatSide, ContainingBlockPositionInfo, FloatBand, FloatBandNode, FloatBandTree, FloatContext, FloatSide,
@ -17,7 +19,7 @@ use layout_2020::flow::float::{
use layout_2020::geom::{LogicalRect, LogicalVec2}; use layout_2020::geom::{LogicalRect, LogicalVec2};
use lazy_static::lazy_static; use lazy_static::lazy_static;
use quickcheck::{Arbitrary, Gen}; use quickcheck::{Arbitrary, Gen};
use style::values::computed::{Clear, Length}; use style::values::computed::Clear;
lazy_static! { lazy_static! {
static ref PANIC_HOOK_MUTEX: Mutex<()> = Mutex::new(()); static ref PANIC_HOOK_MUTEX: Mutex<()> = Mutex::new(());
@ -57,13 +59,14 @@ struct FloatBandWrapper(FloatBand);
impl Arbitrary for FloatBandWrapper { impl Arbitrary for FloatBandWrapper {
fn arbitrary(generator: &mut Gen) -> FloatBandWrapper { fn arbitrary(generator: &mut Gen) -> FloatBandWrapper {
let top: u32 = Arbitrary::arbitrary(generator); let top: u32 = u32::arbitrary(generator);
let left: Option<u32> = Arbitrary::arbitrary(generator); let left: Option<u32> = Some(u32::arbitrary(generator));
let right: Option<u32> = Arbitrary::arbitrary(generator); let right: Option<u32> = Some(u32::arbitrary(generator));
FloatBandWrapper(FloatBand { FloatBandWrapper(FloatBand {
top: Length::new(top as f32), top: Au::from_f32_px(top as f32),
left: left.map(|value| Length::new(value as f32)), left: left.map(|value| Au::from_f32_px(value as f32)),
right: right.map(|value| Length::new(value as f32)), right: right.map(|value| Au::from_f32_px(value as f32)),
}) })
} }
} }
@ -148,7 +151,7 @@ fn check_tree_balance(tree: FloatBandTree) {
} }
} }
fn check_tree_find(tree: &FloatBandTree, block_position: Length, sorted_bands: &[FloatBand]) { fn check_tree_find(tree: &FloatBandTree, block_position: Au, sorted_bands: &[FloatBand]) {
let found_band = tree let found_band = tree
.find(block_position) .find(block_position)
.expect("Couldn't find the band in the tree!"); .expect("Couldn't find the band in the tree!");
@ -163,7 +166,7 @@ fn check_tree_find(tree: &FloatBandTree, block_position: Length, sorted_bands: &
assert_eq!(found_band.right, reference_band.right); assert_eq!(found_band.right, reference_band.right);
} }
fn check_tree_find_next(tree: &FloatBandTree, block_position: Length, sorted_bands: &[FloatBand]) { fn check_tree_find_next(tree: &FloatBandTree, block_position: Au, sorted_bands: &[FloatBand]) {
let found_band = tree let found_band = tree
.find_next(block_position) .find_next(block_position)
.expect("Couldn't find the band in the tree!"); .expect("Couldn't find the band in the tree!");
@ -179,9 +182,9 @@ fn check_tree_find_next(tree: &FloatBandTree, block_position: Length, sorted_ban
fn check_node_range_setting( fn check_node_range_setting(
node: &FloatBandNode, node: &FloatBandNode,
block_range: &Range<Length>, block_range: &Range<Au>,
side: FloatSide, side: FloatSide,
value: Length, value: Au,
) { ) {
if node.band.top >= block_range.start && node.band.top < block_range.end { if node.band.top >= block_range.start && node.band.top < block_range.end {
match side { match side {
@ -200,9 +203,9 @@ fn check_node_range_setting(
fn check_tree_range_setting( fn check_tree_range_setting(
tree: &FloatBandTree, tree: &FloatBandTree,
block_range: &Range<Length>, block_range: &Range<Au>,
side: FloatSide, side: FloatSide,
value: Length, value: Au,
) { ) {
if let Some(ref root) = tree.root.0 { if let Some(ref root) = tree.root.0 {
check_node_range_setting(root, block_range, side, value) check_node_range_setting(root, block_range, side, value)
@ -242,17 +245,17 @@ fn test_tree_balance() {
// Tests that the `find()` method works. // Tests that the `find()` method works.
#[test] #[test]
fn test_tree_find() { fn test_tree_find() {
let f: fn(Vec<FloatBandWrapper>, Vec<u32>) = check; let f: fn(Vec<FloatBandWrapper>, Vec<u16>) = check;
quickcheck::quickcheck(f); quickcheck::quickcheck(f);
fn check(bands: Vec<FloatBandWrapper>, lookups: Vec<u32>) { fn check(bands: Vec<FloatBandWrapper>, lookups: Vec<u16>) {
let mut bands: Vec<FloatBand> = bands.into_iter().map(|band| band.0).collect(); let mut bands: Vec<FloatBand> = bands.into_iter().map(|band| band.0).collect();
bands.push(FloatBand { bands.push(FloatBand {
top: Length::zero(), top: Au::zero(),
left: None, left: None,
right: None, right: None,
}); });
bands.push(FloatBand { bands.push(FloatBand {
top: Length::new(f32::INFINITY), top: Au::from_f32_px(INFINITY),
left: None, left: None,
right: None, right: None,
}); });
@ -262,7 +265,7 @@ fn test_tree_find() {
} }
bands.sort_by(|a, b| a.top.partial_cmp(&b.top).unwrap()); bands.sort_by(|a, b| a.top.partial_cmp(&b.top).unwrap());
for lookup in lookups { for lookup in lookups {
check_tree_find(&tree, Length::new(lookup as f32), &bands); check_tree_find(&tree, Au::from_f32_px(lookup as f32), &bands);
} }
} }
} }
@ -270,17 +273,17 @@ fn test_tree_find() {
// Tests that the `find_next()` method works. // Tests that the `find_next()` method works.
#[test] #[test]
fn test_tree_find_next() { fn test_tree_find_next() {
let f: fn(Vec<FloatBandWrapper>, Vec<u32>) = check; let f: fn(Vec<FloatBandWrapper>, Vec<u16>) = check;
quickcheck::quickcheck(f); quickcheck::quickcheck(f);
fn check(bands: Vec<FloatBandWrapper>, lookups: Vec<u32>) { fn check(bands: Vec<FloatBandWrapper>, lookups: Vec<u16>) {
let mut bands: Vec<FloatBand> = bands.into_iter().map(|band| band.0).collect(); let mut bands: Vec<FloatBand> = bands.into_iter().map(|band| band.0).collect();
bands.push(FloatBand { bands.push(FloatBand {
top: Length::zero(), top: Au::zero(),
left: None, left: None,
right: None, right: None,
}); });
bands.push(FloatBand { bands.push(FloatBand {
top: Length::new(f32::INFINITY), top: Au::from_f32_px(INFINITY),
left: None, left: None,
right: None, right: None,
}); });
@ -291,7 +294,7 @@ fn test_tree_find_next() {
tree = tree.insert((*band).clone()); tree = tree.insert((*band).clone());
} }
for lookup in lookups { for lookup in lookups {
check_tree_find_next(&tree, Length::new(lookup as f32), &bands); check_tree_find_next(&tree, Au::from_f32_px(lookup as f32), &bands);
} }
} }
} }
@ -307,15 +310,15 @@ fn test_tree_range_setting() {
tree = tree.insert((*band).clone()); tree = tree.insert((*band).clone());
} }
let mut tops: Vec<Length> = bands.iter().map(|band| band.0.top).collect(); let mut tops: Vec<Au> = bands.iter().map(|band| band.0.top).collect();
tops.push(Length::new(f32::INFINITY)); tops.push(Au::from_f32_px(INFINITY));
tops.sort_by(|a, b| a.px().partial_cmp(&b.px()).unwrap()); tops.sort_by(|a, b| a.to_px().partial_cmp(&b.to_px()).unwrap());
for range in ranges { for range in ranges {
let start = range.start_index.min(tops.len() as u32 - 1); let start = range.start_index.min(tops.len() as u32 - 1);
let end = (range.start_index as u64 + range.length as u64).min(tops.len() as u64 - 1); let end = (range.start_index as u64 + range.length as u64).min(tops.len() as u64 - 1);
let block_range = tops[start as usize]..tops[end as usize]; let block_range = tops[start as usize]..tops[end as usize];
let length = Length::new(range.length as f32); let length = Au::from_px(range.length as i32);
let new_tree = tree.set_range(&block_range, range.side, length); let new_tree = tree.set_range(&block_range, range.side, length);
check_tree_range_setting(&new_tree, &block_range, range.side, length); check_tree_range_setting(&new_tree, &block_range, range.side, length);
} }
@ -330,7 +333,7 @@ struct FloatInput {
info: PlacementInfo, info: PlacementInfo,
// The float may be placed no higher than this line. This simulates the effect of line boxes // The float may be placed no higher than this line. This simulates the effect of line boxes
// per CSS 2.1 § 9.5.1 rule 6. // per CSS 2.1 § 9.5.1 rule 6.
ceiling: u32, ceiling: Au,
/// Containing block positioning information, which is used to track the current offsets /// Containing block positioning information, which is used to track the current offsets
/// from the float containing block formatting context to the current containing block. /// from the float containing block formatting context to the current containing block.
containing_block_info: ContainingBlockPositionInfo, containing_block_info: ContainingBlockPositionInfo,
@ -353,8 +356,8 @@ impl Arbitrary for FloatInput {
FloatInput { FloatInput {
info: PlacementInfo { info: PlacementInfo {
size: LogicalVec2 { size: LogicalVec2 {
inline: Length::new(width as f32), inline: Au::from_f32_px(width as f32),
block: Length::new(height as f32), block: Au::from_f32_px(height as f32),
}, },
side: if is_left { side: if is_left {
FloatSide::Left FloatSide::Left
@ -363,10 +366,10 @@ impl Arbitrary for FloatInput {
}, },
clear: new_clear(clear), clear: new_clear(clear),
}, },
ceiling, ceiling: Au::from_f32_px(ceiling as f32),
containing_block_info: ContainingBlockPositionInfo::new_with_inline_offsets( containing_block_info: ContainingBlockPositionInfo::new_with_inline_offsets(
Length::new(left as f32), Au::from_f32_px(left as f32),
Length::new(left as f32 + containing_block_width as f32), Au::from_f32_px(left as f32 + containing_block_width as f32),
), ),
} }
} }
@ -374,28 +377,40 @@ impl Arbitrary for FloatInput {
fn shrink(&self) -> Box<dyn Iterator<Item = FloatInput>> { fn shrink(&self) -> Box<dyn Iterator<Item = FloatInput>> {
let mut this = (*self).clone(); let mut this = (*self).clone();
let mut shrunk = false; let mut shrunk = false;
if let Some(inline_size) = self.info.size.inline.px().shrink().next() { if let Some(inline_size) = self.info.size.inline.to_px().shrink().next() {
this.info.size.inline = Length::new(inline_size); this.info.size.inline = Au::from_px(inline_size);
shrunk = true; shrunk = true;
} }
if let Some(block_size) = self.info.size.block.px().shrink().next() { if let Some(block_size) = self.info.size.block.to_px().shrink().next() {
this.info.size.block = Length::new(block_size); this.info.size.block = Au::from_px(block_size);
shrunk = true; shrunk = true;
} }
if let Some(clear) = (self.info.clear as u8).shrink().next() { if let Some(clear) = (self.info.clear as u8).shrink().next() {
this.info.clear = new_clear(clear); this.info.clear = new_clear(clear);
shrunk = true; shrunk = true;
} }
if let Some(left) = self.containing_block_info.inline_start.px().shrink().next() { if let Some(left) = self
this.containing_block_info.inline_start = Length::new(left); .containing_block_info
.inline_start
.to_px()
.shrink()
.next()
{
this.containing_block_info.inline_start = Au::from_px(left);
shrunk = true; shrunk = true;
} }
if let Some(right) = self.containing_block_info.inline_end.px().shrink().next() { if let Some(right) = self
this.containing_block_info.inline_end = Length::new(right); .containing_block_info
.inline_end
.to_px()
.shrink()
.next()
{
this.containing_block_info.inline_end = Au::from_px(right);
shrunk = true; shrunk = true;
} }
if let Some(ceiling) = self.ceiling.shrink().next() { if let Some(ceiling) = self.ceiling.to_px().shrink().next() {
this.ceiling = ceiling; this.ceiling = Au::from_px(ceiling);
shrunk = true; shrunk = true;
} }
if shrunk { if shrunk {
@ -424,9 +439,9 @@ struct FloatPlacement {
// Information about the placement of a float. // Information about the placement of a float.
#[derive(Clone)] #[derive(Clone)]
struct PlacedFloat { struct PlacedFloat {
origin: LogicalVec2<Length>, origin: LogicalVec2<Au>,
info: PlacementInfo, info: PlacementInfo,
ceiling: Length, ceiling: Au,
containing_block_info: ContainingBlockPositionInfo, containing_block_info: ContainingBlockPositionInfo,
} }
@ -453,7 +468,7 @@ impl Drop for FloatPlacement {
} }
impl PlacedFloat { impl PlacedFloat {
fn rect(&self) -> LogicalRect<Length> { fn rect(&self) -> LogicalRect<Au> {
LogicalRect { LogicalRect {
start_corner: self.origin.clone(), start_corner: self.origin.clone(),
size: self.info.size.clone(), size: self.info.size.clone(),
@ -463,10 +478,10 @@ impl PlacedFloat {
impl FloatPlacement { impl FloatPlacement {
fn place(floats: Vec<FloatInput>) -> FloatPlacement { fn place(floats: Vec<FloatInput>) -> FloatPlacement {
let mut float_context = FloatContext::new(Length::new(f32::INFINITY)); let mut float_context = FloatContext::new(Au::from_f32_px(INFINITY));
let mut placed_floats = vec![]; let mut placed_floats = vec![];
for float in floats { for float in floats {
let ceiling = Length::new(float.ceiling as f32); let ceiling = float.ceiling;
float_context.set_ceiling_from_non_floats(ceiling); float_context.set_ceiling_from_non_floats(ceiling);
float_context.containing_block_info = float.containing_block_info; float_context.containing_block_info = float.containing_block_info;
placed_floats.push(PlacedFloat { placed_floats.push(PlacedFloat {
@ -547,9 +562,9 @@ fn check_floats_rule_3(placement: &FloatPlacement) {
// Where the top of `b` should probably be 32px per Rule 3, but unless this distinction // Where the top of `b` should probably be 32px per Rule 3, but unless this distinction
// is made the top of `b` could legally be 0px. // is made the top of `b` could legally be 0px.
if this_float.origin.block >= other_float.rect().max_block_position() || if this_float.origin.block >= other_float.rect().max_block_position() ||
(this_float.info.size.block == Length::zero() && (this_float.info.size.block == Au::zero() &&
this_float.rect().max_block_position() < other_float.origin.block) || this_float.rect().max_block_position() < other_float.origin.block) ||
(this_float.info.size.block > Length::zero() && (this_float.info.size.block > Au::zero() &&
this_float.rect().max_block_position() <= other_float.origin.block) this_float.rect().max_block_position() <= other_float.origin.block)
{ {
continue; continue;
@ -574,14 +589,14 @@ fn check_floats_rule_3(placement: &FloatPlacement) {
// is defined by the rules in the section on margin collapsing. // is defined by the rules in the section on margin collapsing.
fn check_floats_rule_4(placement: &FloatPlacement) { fn check_floats_rule_4(placement: &FloatPlacement) {
for placed_float in &placement.placed_floats { for placed_float in &placement.placed_floats {
assert!(placed_float.origin.block >= Length::zero()); assert!(placed_float.origin.block >= Au::zero());
} }
} }
// 5. The outer top of a floating box may not be higher than the outer top of any block or floated // 5. The outer top of a floating box may not be higher than the outer top of any block or floated
// box generated by an element earlier in the source document. // box generated by an element earlier in the source document.
fn check_floats_rule_5(placement: &FloatPlacement) { fn check_floats_rule_5(placement: &FloatPlacement) {
let mut block_position = Length::zero(); let mut block_position = Au::zero();
for placed_float in &placement.placed_floats { for placed_float in &placement.placed_floats {
assert!(placed_float.origin.block >= block_position); assert!(placed_float.origin.block >= block_position);
block_position = placed_float.origin.block; block_position = placed_float.origin.block;
@ -644,7 +659,8 @@ fn check_floats_rule_8(floats_and_perturbations: Vec<(FloatInput, u32)>) {
let mut placement = placement.clone(); let mut placement = placement.clone();
placement.placed_floats[float_index].origin.block = placement.placed_floats[float_index].origin.block =
placement.placed_floats[float_index].origin.block - Length::new(perturbation as f32); placement.placed_floats[float_index].origin.block -
Au::from_f32_px(perturbation as f32);
let result = { let result = {
let mutex_guard = PANIC_HOOK_MUTEX.lock().unwrap(); let mutex_guard = PANIC_HOOK_MUTEX.lock().unwrap();
@ -673,7 +689,7 @@ fn check_floats_rule_9(floats_and_perturbations: Vec<(FloatInput, u32)>) {
let mut placement = placement.clone(); let mut placement = placement.clone();
{ {
let placed_float = &mut placement.placed_floats[float_index]; let placed_float = &mut placement.placed_floats[float_index];
let perturbation = Length::new(perturbation as f32); let perturbation = Au::from_f32_px(perturbation as f32);
match placed_float.info.side { match placed_float.info.side {
FloatSide::Left => { FloatSide::Left => {
placed_float.origin.inline = placed_float.origin.inline - perturbation placed_float.origin.inline = placed_float.origin.inline - perturbation
@ -699,7 +715,7 @@ fn check_floats_rule_9(floats_and_perturbations: Vec<(FloatInput, u32)>) {
// left-floating boxes (in the case of 'clear: left'), or all earlier right-floating boxes (in // left-floating boxes (in the case of 'clear: left'), or all earlier right-floating boxes (in
// the case of 'clear: right'), or both ('clear: both'). // the case of 'clear: right'), or both ('clear: both').
fn check_floats_rule_10(placement: &FloatPlacement) { fn check_floats_rule_10(placement: &FloatPlacement) {
let mut block_position = Length::zero(); let mut block_position = Au::zero();
for placed_float in &placement.placed_floats { for placed_float in &placement.placed_floats {
assert!(placed_float.origin.block >= block_position); assert!(placed_float.origin.block >= block_position);
block_position = placed_float.origin.block; block_position = placed_float.origin.block;
@ -721,9 +737,9 @@ fn check_floats_rule_10(placement: &FloatPlacement) {
// Where the top of `b` should probably be 32px per Rule 3, but unless this distinction // Where the top of `b` should probably be 32px per Rule 3, but unless this distinction
// is made the top of `b` could legally be 0px. // is made the top of `b` could legally be 0px.
if this_float.origin.block >= other_float.rect().max_block_position() || if this_float.origin.block >= other_float.rect().max_block_position() ||
(this_float.info.size.block == Length::zero() && (this_float.info.size.block == Au::zero() &&
this_float.rect().max_block_position() < other_float.origin.block) || this_float.rect().max_block_position() < other_float.origin.block) ||
(this_float.info.size.block > Length::zero() && (this_float.info.size.block > Au::zero() &&
this_float.rect().max_block_position() <= other_float.origin.block) this_float.rect().max_block_position() <= other_float.origin.block)
{ {
continue; continue;

View file

@ -1,2 +0,0 @@
[c414-flt-fit-004.xht]
expected: FAIL

View file

@ -0,0 +1,2 @@
[font-weight-applies-to-005.xht]
expected: FAIL

View file

@ -0,0 +1,2 @@
[flexbox_item-clear.html]
expected: FAIL