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::fmt::{Debug, Formatter, Result as FmtResult};
use std::mem;
use std::ops::Range;
use std::{f32, mem};
use app_units::{Au, MAX_AU, MIN_AU};
use euclid::num::Zero;
use serde::Serialize;
use servo_arc::Arc;
use style::computed_values::float::T as FloatProperty;
use style::properties::ComputedValues;
use style::values::computed::{CSSPixelLength, Clear, Length};
use style::values::computed::{Clear, Length};
use style::values::specified::text::TextDecorationLine;
use crate::context::LayoutContext;
@ -24,7 +25,7 @@ use crate::dom::NodeExt;
use crate::dom_traversal::{Contents, NodeAndStyleInfo};
use crate::formatting_contexts::IndependentFormattingContext;
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::style_ext::{ComputedValuesExt, DisplayInside, PaddingBorderMargin};
use crate::ContainingBlock;
@ -47,7 +48,7 @@ pub struct ContainingBlockPositionInfo {
/// containing block, excluding uncollapsed block start margins. Note that
/// this does not include uncollapsed block start margins because we don't
/// 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
/// block start of the float containing independent block formatting context
/// 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
/// independent formatting context and the inline start of this containing
/// block.
pub inline_start: Length,
pub inline_start: Au,
/// The offset from the inline start position of the float containing
/// independent formatting context to the inline end of this containing
/// block.
pub inline_end: Length,
pub inline_end: Au,
}
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 {
block_start: Length::zero(),
block_start: Au::zero(),
block_start_margins_not_collapsed: CollapsedMargin::zero(),
inline_start,
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.
next_band: FloatBand,
/// 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
/// be placed before this point.
ceiling: Length,
ceiling: Au,
/// 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.
min_inline_start: Length,
min_inline_start: Au,
/// The maximum inline position that the object can attain when avoiding floats.
max_inline_end: Length,
max_inline_end: Au,
}
impl<'a> PlacementAmongFloats<'a> {
pub(crate) fn new(
float_context: &'a FloatContext,
ceiling: Length,
object_size: LogicalVec2<Length>,
ceiling: Au,
object_size: LogicalVec2<Au>,
pbm: &PaddingBorderMargin,
) -> Self {
assert!(!ceiling.px().is_infinite());
let mut current_band = float_context.bands.find(ceiling).unwrap();
current_band.top = ceiling;
let current_bands = VecDeque::from([current_band]);
let mut ceiling_band = float_context.bands.find(ceiling).unwrap();
let (current_bands, next_band) = if ceiling == MAX_AU {
(VecDeque::new(), ceiling_band)
} else {
ceiling_band.top = ceiling;
let current_bands = VecDeque::from([ceiling_band]);
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 +
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 -
pbm.margin.inline_end.auto_is(Length::zero))
pbm.margin.inline_end.auto_is(Length::zero).into())
.max(min_inline_start + object_size.inline);
PlacementAmongFloats {
float_context,
@ -126,24 +131,27 @@ impl<'a> PlacementAmongFloats<'a> {
/// 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
/// 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)
}
/// The height of the bands under consideration.
fn current_bands_height(&self) -> Length {
if let Some(top) = self.top_of_bands() {
self.next_band.top - top
fn current_bands_height(&self) -> Au {
if self.next_band.top == MAX_AU {
// Treat MAX_AU as infinity.
MAX_AU
} else {
assert!(self.next_band.top.px().is_infinite());
self.next_band.top
let top = self
.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
/// [`PlacementAmongFloats::next_band`].
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.next_band = self
.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
/// 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 min_inline_end = self.max_inline_end;
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.
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();
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());
self.accumulate_enough_bands_for_block_size();
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 {
return None;
}
let top = self.top_of_bands().unwrap();
Some(LogicalRect {
start_corner: LogicalVec2 {
inline: inline_start,
block: top,
block: self.top_of_bands().unwrap(),
},
size: LogicalVec2 {
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.
/// This is an invariant that should hold, otherwise we are in a broken state.
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) {
@ -217,7 +224,7 @@ impl<'a> PlacementAmongFloats<'a> {
}
/// 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());
while !self.current_bands.is_empty() {
if let Some(result) = self.try_place_once() {
@ -239,7 +246,7 @@ impl<'a> PlacementAmongFloats<'a> {
},
size: LogicalVec2 {
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]).
pub(crate) fn try_to_expand_for_auto_block_size(
&mut self,
block_size_after_layout: Length,
size_from_placement: &LogicalVec2<Length>,
block_size_after_layout: Au,
size_from_placement: &LogicalVec2<Au>,
) -> bool {
debug_assert!(self.has_bands_or_at_end());
debug_assert_eq!(size_from_placement.block, self.current_bands_height());
@ -309,59 +316,59 @@ pub struct FloatContext {
pub bands: FloatBandTree,
/// 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.
pub ceiling_from_floats: Length,
pub ceiling_from_floats: Au,
/// 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
/// 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
/// independent block formatting context that contains all of the floats
/// this `FloatContext` positions.
pub containing_block_info: ContainingBlockPositionInfo,
/// 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.
pub clear_right_position: Length,
pub clear_right_position: Au,
}
impl FloatContext {
/// Returns a new float context representing a containing block with the given content
/// inline-size.
pub fn new(max_inline_size: Length) -> Self {
pub fn new(max_inline_size: Au) -> Self {
let mut bands = FloatBandTree::new();
bands = bands.insert(FloatBand {
top: Length::new(-f32::INFINITY),
top: MIN_AU,
left: None,
right: None,
});
bands = bands.insert(FloatBand {
top: Length::new(f32::INFINITY),
top: MAX_AU,
left: None,
right: None,
});
FloatContext {
bands,
ceiling_from_floats: Length::zero(),
ceiling_from_non_floats: Length::zero(),
ceiling_from_floats: Au::zero(),
ceiling_from_non_floats: Au::zero(),
containing_block_info: ContainingBlockPositionInfo::new_with_inline_offsets(
Length::zero(),
Au::zero(),
max_inline_size,
),
clear_left_position: Length::zero(),
clear_right_position: Length::zero(),
clear_left_position: Au::zero(),
clear_right_position: Au::zero(),
}
}
/// (Logically) lowers the ceiling to at least `new_ceiling` units.
///
/// 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;
}
/// The "ceiling" used for float placement. This is the minimum block position value
/// 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)
}
@ -370,11 +377,7 @@ impl FloatContext {
///
/// This should be used for placing inline elements and block formatting contexts so that they
/// don't collide with floats.
pub(crate) fn place_object(
&self,
object: &PlacementInfo,
ceiling: Length,
) -> LogicalVec2<Length> {
pub(crate) fn place_object(&self, object: &PlacementInfo, ceiling: Au) -> LogicalVec2<Au> {
let ceiling = match object.clear {
Clear::None => ceiling,
Clear::Left => ceiling.max(self.clear_left_position),
@ -388,7 +391,7 @@ impl FloatContext {
let mut first_band = self.bands.find(ceiling).unwrap();
while !first_band.object_fits(&object, &self.containing_block_info) {
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;
}
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.
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.
let ceiling = self.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
// we should position it as if it had zero block size.
size: LogicalVec2 {
inline: new_float.size.inline.max(CSSPixelLength::zero()),
block: new_float.size.block.max(CSSPixelLength::zero()),
inline: new_float.size.inline.max(Au::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
// top of any block or floated box generated by an element earlier in the source document.
self.ceiling_from_floats
.max_assign(new_float_rect.start_corner.block);
max_assign_au(
&mut self.ceiling_from_floats,
new_float_rect.start_corner.block,
);
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.
#[derive(Clone, Debug)]
pub struct PlacementInfo {
/// 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.
pub side: FloatSide,
/// Which side or sides to clear floats on.
@ -507,17 +518,17 @@ pub enum FloatSide {
#[derive(Clone, Copy, Debug, PartialEq)]
pub struct FloatBand {
/// 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
/// (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
/// 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
/// (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
/// 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 {
@ -624,24 +635,19 @@ impl FloatBandTree {
}
/// 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)
}
/// 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)
}
/// Sets the side values of all bands within the given half-open range to be at least
/// `new_value`.
#[must_use]
pub fn set_range(
&self,
range: &Range<Length>,
side: FloatSide,
new_value: Length,
) -> FloatBandTree {
pub fn set_range(&self, range: &Range<Au>, side: FloatSide, new_value: Au) -> FloatBandTree {
FloatBandTree {
root: FloatBandLink(
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
/// `new_value`.
fn set_range(
&self,
range: &Range<Length>,
side: FloatSide,
new_value: Length,
) -> Arc<FloatBandNode> {
fn set_range(&self, range: &Range<Au>, side: FloatSide, new_value: Au) -> Arc<FloatBandNode> {
let mut new_band = self.band.clone();
if self.band.top >= range.start && self.band.top < range.end {
match side {
FloatSide::Left => match new_band.left {
None => new_band.left = Some(new_value),
Some(ref mut old_value) => *old_value = old_value.max(new_value),
FloatSide::Left => {
new_band.left = match new_band.left {
Some(old_value) => Some(std::cmp::max(old_value, new_value)),
None => Some(new_value),
};
},
FloatSide::Right => match new_band.right {
None => new_band.right = Some(new_value),
Some(ref mut old_value) => *old_value = old_value.min(new_value),
FloatSide::Right => {
new_band.right = match new_band.right {
Some(old_value) => Some(std::cmp::min(old_value, new_value)),
None => Some(new_value),
};
},
}
}
@ -721,7 +726,7 @@ impl FloatBandNode {
impl FloatBandLink {
/// 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 {
None => return None,
Some(ref node) => node,
@ -741,7 +746,7 @@ impl FloatBandLink {
}
/// 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 {
None => return None,
Some(ref node) => node,
@ -886,7 +891,7 @@ impl FloatBox {
// Margin is computed this way regardless of whether the element is replaced
// or non-replaced.
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 (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
/// 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).
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`.
pub(crate) current_margin: CollapsedMargin,
}
impl 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 {
floats: FloatContext::new(max_inline_size),
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.
///
/// 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.floats
.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
/// context and any uncollapsed block margins.
pub(crate) fn current_block_position_including_margins(&self) -> Length {
self.bfc_relative_block_position + self.current_margin.solve()
pub(crate) fn current_block_position_including_margins(&self) -> Au {
self.bfc_relative_block_position + self.current_margin.solve().into()
}
/// 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
/// current fragment can't collapse with the margins of any of its children.
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();
}
/// Computes the position of the block-start border edge of an element
/// with the provided `block_start_margin`, assuming no clearance.
pub(crate) fn position_without_clearance(
&self,
block_start_margin: &CollapsedMargin,
) -> Length {
pub(crate) fn position_without_clearance(&self, block_start_margin: &CollapsedMargin) -> Au {
// 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
/// with the provided `block_start_margin`, assuming a clearance of 0px.
pub(crate) fn position_with_zero_clearance(
&self,
block_start_margin: &CollapsedMargin,
) -> Length {
pub(crate) fn position_with_zero_clearance(&self, block_start_margin: &CollapsedMargin) -> Au {
// Clearance prevents `current_margin` and `block_start_margin` from being
// 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)
@ -1073,7 +1078,7 @@ impl SequentialLayoutState {
&self,
clear: Clear,
block_start_margin: &CollapsedMargin,
) -> Option<Length> {
) -> Option<Au> {
if clear == Clear::None {
return None;
}
@ -1112,7 +1117,7 @@ impl SequentialLayoutState {
&self,
clear: Clear,
block_start_margin: &CollapsedMargin,
) -> Option<Length> {
) -> Option<Au> {
return self
.calculate_clear_position(clear, &block_start_margin)
.map(|offset| offset - self.position_with_zero_clearance(&block_start_margin));
@ -1131,8 +1136,8 @@ impl SequentialLayoutState {
clear: Clear,
block_start_margin: &CollapsedMargin,
pbm: &PaddingBorderMargin,
object_size: LogicalVec2<Length>,
) -> (Option<Length>, LogicalRect<Length>) {
object_size: LogicalVec2<Au>,
) -> (Option<Au>, LogicalRect<Au>) {
// First compute the clear position required by the 'clear' property.
// The code below may then add extra clearance when the element can't fit
// 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.
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_margins_not_collapsed
.solve()
.into()
}
/// This function places a Fragment that has been created for a FloatBox.
@ -1170,30 +1176,33 @@ impl SequentialLayoutState {
&mut self,
box_fragment: &mut BoxFragment,
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 +
self.floats
.containing_block_info
.block_start_margins_not_collapsed
.adjoin(&margins_collapsing_with_parent_containing_block)
.solve();
.solve()
.into();
self.floats.set_ceiling_from_non_floats(
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 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 {
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!"),
clear: box_fragment.style.get_box().clear,
});
// 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.
let new_position_in_bfc = &(&margin_box_start_corner + &pbm_sums.start_offset()) +
&box_fragment.content_rect.start_corner;
let new_position_in_bfc =
&(&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.
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,
};
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() {
Some(placement_among_floats) => placement_among_floats.start_corner.block,
None => self.start_position.block,
Some(placement_among_floats) => placement_among_floats.start_corner.block.into(),
None => self.start_position.block.into(),
}
}
@ -730,12 +730,12 @@ impl<'a, 'b> InlineFormattingContextState<'a, 'b> {
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() {
// 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.
let increment = block_end_position - self.current_line.start_position.block;
sequential_layout_state.advance_block_position(increment);
let increment = block_end_position - self.current_line.start_position.block.into();
sequential_layout_state.advance_block_position(increment.into());
}
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.
self.current_line = LineUnderConstruction::new(LogicalVec2 {
inline: Length::zero(),
block: block_end_position,
block: block_end_position.into(),
});
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,
justification_adjustment,
line_metrics: &LineMetrics {
block_offset: block_start_position,
block_offset: block_start_position.into(),
block_size: effective_block_advance.resolve(),
baseline_block_offset: baseline_offset,
},
@ -782,14 +782,14 @@ impl<'a, 'b> InlineFormattingContextState<'a, 'b> {
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 {
// 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
// we do not need to include it in the `start_corner` of the line's main Fragment.
start_corner: LogicalVec2 {
inline: Length::zero(),
block: block_start_position,
block: block_start_position.into(),
},
size: LogicalVec2 {
inline: self.containing_block.inline_size,
@ -1000,7 +1000,9 @@ impl<'a, 'b> InlineFormattingContextState<'a, 'b> {
.floats
.containing_block_info
.inline_start,
block: sequential_layout_state.current_containing_block_offset(),
block: sequential_layout_state
.current_containing_block_offset()
.into(),
};
let ceiling = self
@ -1008,14 +1010,17 @@ impl<'a, 'b> InlineFormattingContextState<'a, 'b> {
.line_block_start_considering_placement_among_floats();
let mut placement = PlacementAmongFloats::new(
&sequential_layout_state.floats,
ceiling + ifc_offset_in_float_container.block,
potential_line_size.clone(),
ceiling + ifc_offset_in_float_container.block.into(),
LogicalVec2 {
inline: potential_line_size.inline.into(),
block: potential_line_size.block.into(),
},
&PaddingBorderMargin::zero(),
);
let mut placement_rect = placement.place();
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
@ -1083,6 +1088,7 @@ impl<'a, 'b> InlineFormattingContextState<'a, 'b> {
if new_placement.start_corner.block !=
self.current_line
.line_block_start_considering_placement_among_floats()
.into()
{
return true;
} else {

View file

@ -4,6 +4,7 @@
//! Flow layout, also known as block-and-inline layout.
use app_units::Au;
use rayon::iter::{IntoParallelRefIterator, ParallelIterator};
use serde::Serialize;
use servo_arc::Arc;
@ -213,7 +214,9 @@ impl BlockFormattingContext {
containing_block: &ContainingBlock,
) -> IndependentLayout {
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 {
None
};
@ -242,7 +245,7 @@ impl BlockFormattingContext {
fragments: flow_layout.fragments,
content_block_size: (flow_layout.content_block_size +
flow_layout.collapsible_margins_in_children.end.solve() +
clearance.unwrap_or_else(Length::zero))
clearance.unwrap_or_else(Au::zero).into())
.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
// can only happen if we have no block-start padding and border.
sequential_layout_state.advance_block_position(
pbm.padding.block_start +
(pbm.padding.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
@ -706,14 +710,14 @@ fn layout_in_flow_non_replaced_block_level_same_formatting_context(
.floats
.containing_block_info
.inline_start +
pbm.padding.inline_start +
pbm.border.inline_start +
margin.inline_start;
pbm.padding.inline_start.into() +
pbm.border.inline_start.into() +
margin.inline_start.into();
let new_cb_offsets = ContainingBlockPositionInfo {
block_start: sequential_layout_state.bfc_relative_block_position,
block_start_margins_not_collapsed: sequential_layout_state.current_margin,
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(
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
// as long as no floats in the overflowing content lowered it.
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 {
@ -792,9 +796,10 @@ fn layout_in_flow_non_replaced_block_level_same_formatting_context(
let content_rect = LogicalRect {
start_corner: LogicalVec2 {
block: pbm.padding.block_start +
block: (pbm.padding.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,
},
size: LogicalVec2 {
@ -811,7 +816,7 @@ fn layout_in_flow_non_replaced_block_level_same_formatting_context(
pbm.padding,
pbm.border,
margin,
clearance,
clearance.map(|t| t.into()),
flow_layout.last_inflow_baseline_offset,
block_margins_collapsed_with_children,
)
@ -987,7 +992,7 @@ impl NonReplacedFormattingContext {
let mut placement = PlacementAmongFloats::new(
&sequential_layout_state.floats,
ceiling,
minimum_size_of_block,
minimum_size_of_block.into(),
&pbm,
);
let mut placement_rect;
@ -995,8 +1000,9 @@ impl NonReplacedFormattingContext {
loop {
// First try to place the block using the minimum size as the object size.
placement_rect = placement.place();
let proposed_inline_size = (placement_rect.size.inline -
pbm.padding_border_sums.inline)
let proposed_inline_size = Length::from(
placement_rect.size.inline - pbm.padding_border_sums.inline.into(),
)
.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.
@ -1029,7 +1035,7 @@ impl NonReplacedFormattingContext {
// size of auto. Try to fit it into our precalculated placement among the
// floats. If it fits, then we can stop trying layout candidates.
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,
) {
break;
@ -1046,9 +1052,10 @@ impl NonReplacedFormattingContext {
// prevent margin collapse.
clearance = if clear_position.is_some() || placement_rect.start_corner.block > ceiling {
Some(
placement_rect.start_corner.block -
(placement_rect.start_corner.block -
sequential_layout_state
.position_with_zero_clearance(&collapsed_margin_block_start),
.position_with_zero_clearance(&collapsed_margin_block_start))
.into(),
)
} else {
None
@ -1059,7 +1066,7 @@ impl NonReplacedFormattingContext {
&containing_block,
&pbm,
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.
sequential_layout_state.collapse_margins();
sequential_layout_state.advance_block_position(
pbm.padding_border_sums.block +
(pbm.padding_border_sums.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));
@ -1163,7 +1171,7 @@ fn layout_in_flow_replaced_block_level<'a>(
// Margins can never collapse into replaced elements.
sequential_layout_state.collapse_margins();
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));
} else {
clearance = None;
@ -1299,16 +1307,16 @@ fn solve_clearance_and_inline_margins_avoiding_floats(
style.get_box().clear,
&block_start_margin,
&pbm,
size.clone(),
size.clone().into(),
);
let inline_margins = solve_inline_margins_avoiding_floats(
&sequential_layout_state,
&containing_block,
&pbm,
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
@ -1325,7 +1333,8 @@ fn solve_inline_margins_avoiding_floats(
sequential_layout_state
.floats
.containing_block_info
.inline_start;
.inline_start
.into();
assert!(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) {
@ -1493,7 +1502,7 @@ impl PlacementState {
sequential_layout_state.place_float_fragment(
box_fragment,
self.start_margin,
block_offset_from_containing_block_top,
block_offset_from_containing_block_top.into(),
);
},
Fragment::Anonymous(_) => {},

View file

@ -2,6 +2,7 @@
* 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/. */
use std::convert::From;
use std::fmt;
use std::ops::{Add, AddAssign, Sub};
@ -10,7 +11,7 @@ use serde::Serialize;
use style::logical_geometry::{
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::Zero;
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.
use std::f32::INFINITY;
use std::ops::Range;
use std::panic::{self, PanicInfo};
use std::sync::{Mutex, MutexGuard};
use std::{f32, thread, u32};
use std::{thread, u32};
use app_units::Au;
use euclid::num::Zero;
use layout_2020::flow::float::{
ContainingBlockPositionInfo, FloatBand, FloatBandNode, FloatBandTree, FloatContext, FloatSide,
@ -17,7 +19,7 @@ use layout_2020::flow::float::{
use layout_2020::geom::{LogicalRect, LogicalVec2};
use lazy_static::lazy_static;
use quickcheck::{Arbitrary, Gen};
use style::values::computed::{Clear, Length};
use style::values::computed::Clear;
lazy_static! {
static ref PANIC_HOOK_MUTEX: Mutex<()> = Mutex::new(());
@ -57,13 +59,14 @@ struct FloatBandWrapper(FloatBand);
impl Arbitrary for FloatBandWrapper {
fn arbitrary(generator: &mut Gen) -> FloatBandWrapper {
let top: u32 = Arbitrary::arbitrary(generator);
let left: Option<u32> = Arbitrary::arbitrary(generator);
let right: Option<u32> = Arbitrary::arbitrary(generator);
let top: u32 = u32::arbitrary(generator);
let left: Option<u32> = Some(u32::arbitrary(generator));
let right: Option<u32> = Some(u32::arbitrary(generator));
FloatBandWrapper(FloatBand {
top: Length::new(top as f32),
left: left.map(|value| Length::new(value as f32)),
right: right.map(|value| Length::new(value as f32)),
top: Au::from_f32_px(top as f32),
left: left.map(|value| Au::from_f32_px(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
.find(block_position)
.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);
}
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
.find_next(block_position)
.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(
node: &FloatBandNode,
block_range: &Range<Length>,
block_range: &Range<Au>,
side: FloatSide,
value: Length,
value: Au,
) {
if node.band.top >= block_range.start && node.band.top < block_range.end {
match side {
@ -200,9 +203,9 @@ fn check_node_range_setting(
fn check_tree_range_setting(
tree: &FloatBandTree,
block_range: &Range<Length>,
block_range: &Range<Au>,
side: FloatSide,
value: Length,
value: Au,
) {
if let Some(ref root) = tree.root.0 {
check_node_range_setting(root, block_range, side, value)
@ -242,17 +245,17 @@ fn test_tree_balance() {
// Tests that the `find()` method works.
#[test]
fn test_tree_find() {
let f: fn(Vec<FloatBandWrapper>, Vec<u32>) = check;
let f: fn(Vec<FloatBandWrapper>, Vec<u16>) = check;
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();
bands.push(FloatBand {
top: Length::zero(),
top: Au::zero(),
left: None,
right: None,
});
bands.push(FloatBand {
top: Length::new(f32::INFINITY),
top: Au::from_f32_px(INFINITY),
left: None,
right: None,
});
@ -262,7 +265,7 @@ fn test_tree_find() {
}
bands.sort_by(|a, b| a.top.partial_cmp(&b.top).unwrap());
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.
#[test]
fn test_tree_find_next() {
let f: fn(Vec<FloatBandWrapper>, Vec<u32>) = check;
let f: fn(Vec<FloatBandWrapper>, Vec<u16>) = check;
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();
bands.push(FloatBand {
top: Length::zero(),
top: Au::zero(),
left: None,
right: None,
});
bands.push(FloatBand {
top: Length::new(f32::INFINITY),
top: Au::from_f32_px(INFINITY),
left: None,
right: None,
});
@ -291,7 +294,7 @@ fn test_tree_find_next() {
tree = tree.insert((*band).clone());
}
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());
}
let mut tops: Vec<Length> = bands.iter().map(|band| band.0.top).collect();
tops.push(Length::new(f32::INFINITY));
tops.sort_by(|a, b| a.px().partial_cmp(&b.px()).unwrap());
let mut tops: Vec<Au> = bands.iter().map(|band| band.0.top).collect();
tops.push(Au::from_f32_px(INFINITY));
tops.sort_by(|a, b| a.to_px().partial_cmp(&b.to_px()).unwrap());
for range in ranges {
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 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);
check_tree_range_setting(&new_tree, &block_range, range.side, length);
}
@ -330,7 +333,7 @@ struct FloatInput {
info: PlacementInfo,
// 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.
ceiling: u32,
ceiling: Au,
/// Containing block positioning information, which is used to track the current offsets
/// from the float containing block formatting context to the current containing block.
containing_block_info: ContainingBlockPositionInfo,
@ -353,8 +356,8 @@ impl Arbitrary for FloatInput {
FloatInput {
info: PlacementInfo {
size: LogicalVec2 {
inline: Length::new(width as f32),
block: Length::new(height as f32),
inline: Au::from_f32_px(width as f32),
block: Au::from_f32_px(height as f32),
},
side: if is_left {
FloatSide::Left
@ -363,10 +366,10 @@ impl Arbitrary for FloatInput {
},
clear: new_clear(clear),
},
ceiling,
ceiling: Au::from_f32_px(ceiling as f32),
containing_block_info: ContainingBlockPositionInfo::new_with_inline_offsets(
Length::new(left as f32),
Length::new(left as f32 + containing_block_width as f32),
Au::from_f32_px(left 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>> {
let mut this = (*self).clone();
let mut shrunk = false;
if let Some(inline_size) = self.info.size.inline.px().shrink().next() {
this.info.size.inline = Length::new(inline_size);
if let Some(inline_size) = self.info.size.inline.to_px().shrink().next() {
this.info.size.inline = Au::from_px(inline_size);
shrunk = true;
}
if let Some(block_size) = self.info.size.block.px().shrink().next() {
this.info.size.block = Length::new(block_size);
if let Some(block_size) = self.info.size.block.to_px().shrink().next() {
this.info.size.block = Au::from_px(block_size);
shrunk = true;
}
if let Some(clear) = (self.info.clear as u8).shrink().next() {
this.info.clear = new_clear(clear);
shrunk = true;
}
if let Some(left) = self.containing_block_info.inline_start.px().shrink().next() {
this.containing_block_info.inline_start = Length::new(left);
if let Some(left) = self
.containing_block_info
.inline_start
.to_px()
.shrink()
.next()
{
this.containing_block_info.inline_start = Au::from_px(left);
shrunk = true;
}
if let Some(right) = self.containing_block_info.inline_end.px().shrink().next() {
this.containing_block_info.inline_end = Length::new(right);
if let Some(right) = self
.containing_block_info
.inline_end
.to_px()
.shrink()
.next()
{
this.containing_block_info.inline_end = Au::from_px(right);
shrunk = true;
}
if let Some(ceiling) = self.ceiling.shrink().next() {
this.ceiling = ceiling;
if let Some(ceiling) = self.ceiling.to_px().shrink().next() {
this.ceiling = Au::from_px(ceiling);
shrunk = true;
}
if shrunk {
@ -424,9 +439,9 @@ struct FloatPlacement {
// Information about the placement of a float.
#[derive(Clone)]
struct PlacedFloat {
origin: LogicalVec2<Length>,
origin: LogicalVec2<Au>,
info: PlacementInfo,
ceiling: Length,
ceiling: Au,
containing_block_info: ContainingBlockPositionInfo,
}
@ -453,7 +468,7 @@ impl Drop for FloatPlacement {
}
impl PlacedFloat {
fn rect(&self) -> LogicalRect<Length> {
fn rect(&self) -> LogicalRect<Au> {
LogicalRect {
start_corner: self.origin.clone(),
size: self.info.size.clone(),
@ -463,10 +478,10 @@ impl PlacedFloat {
impl 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![];
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.containing_block_info = float.containing_block_info;
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
// is made the top of `b` could legally be 0px.
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.info.size.block > Length::zero() &&
(this_float.info.size.block > Au::zero() &&
this_float.rect().max_block_position() <= other_float.origin.block)
{
continue;
@ -574,14 +589,14 @@ fn check_floats_rule_3(placement: &FloatPlacement) {
// is defined by the rules in the section on margin collapsing.
fn check_floats_rule_4(placement: &FloatPlacement) {
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
// box generated by an element earlier in the source document.
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 {
assert!(placed_float.origin.block >= block_position);
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();
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 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 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 {
FloatSide::Left => {
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
// the case of 'clear: right'), or both ('clear: both').
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 {
assert!(placed_float.origin.block >= block_position);
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
// is made the top of `b` could legally be 0px.
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.info.size.block > Length::zero() &&
(this_float.info.size.block > Au::zero() &&
this_float.rect().max_block_position() <= other_float.origin.block)
{
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