Place floats in layout 2020, but don't flow text around the floats yet.

This commit puts floats behind the `layout.floats.enabled` pref, because of the
following issues and unimplemented features:

* Inline formatting contexts don't take floats into account, so text doesn't
  flow around the floats yet.

* Non-floated block formatting contexts don't take floats into account, so BFCs
  can overlap floats.

* Block formatting contexts that contain floats don't expand vertically to
  contain all the floats. That is, floats can stick out the bottom of BFCs,
  contra spec.
This commit is contained in:
Patrick Walton 2020-07-22 10:52:11 -07:00 committed by Oriol Brufau
parent 053a0aa4fd
commit cdec48328e
235 changed files with 1018 additions and 623 deletions

View file

@ -9,7 +9,7 @@ extern crate lazy_static;
use euclid::num::Zero;
use layout::flow::float::{ClearSide, FloatBand, FloatBandNode, FloatBandTree, FloatContext};
use layout::flow::float::{FloatSide, PlacementInfo};
use layout::flow::float::{FloatSide, InlineWalls, PlacementInfo};
use layout::geom::flow_relative::{Rect, Vec2};
use quickcheck::{Arbitrary, Gen};
use std::f32;
@ -57,9 +57,7 @@ impl<'a> Drop for PanicMsgSuppressor<'a> {
struct FloatBandWrapper(FloatBand);
impl Arbitrary for FloatBandWrapper {
fn arbitrary<G>(generator: &mut G) -> FloatBandWrapper
where
G: Gen,
fn arbitrary(generator: &mut Gen) -> FloatBandWrapper
{
let top: u32 = Arbitrary::arbitrary(generator);
let left: Option<u32> = Arbitrary::arbitrary(generator);
@ -81,9 +79,7 @@ struct FloatRangeInput {
}
impl Arbitrary for FloatRangeInput {
fn arbitrary<G>(generator: &mut G) -> FloatRangeInput
where
G: Gen,
fn arbitrary(generator: &mut Gen) -> FloatRangeInput
{
let start_index: u32 = Arbitrary::arbitrary(generator);
let band_count: u32 = Arbitrary::arbitrary(generator);
@ -341,19 +337,20 @@ struct FloatInput {
// 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,
/// Distances from the logical left side of the block formatting context to the logical sides
/// of the current containing block.
walls: InlineWalls,
}
impl Arbitrary for FloatInput {
fn arbitrary<G>(generator: &mut G) -> FloatInput
where
G: Gen,
fn arbitrary(generator: &mut Gen) -> FloatInput
{
let width: u32 = Arbitrary::arbitrary(generator);
let height: u32 = Arbitrary::arbitrary(generator);
let is_left: bool = Arbitrary::arbitrary(generator);
let ceiling: u32 = Arbitrary::arbitrary(generator);
let left_wall: u32 = Arbitrary::arbitrary(generator);
let right_wall: u32 = Arbitrary::arbitrary(generator);
let left: u32 = Arbitrary::arbitrary(generator);
let right: u32 = Arbitrary::arbitrary(generator);
let clear: u8 = Arbitrary::arbitrary(generator);
FloatInput {
info: PlacementInfo {
@ -367,10 +364,12 @@ impl Arbitrary for FloatInput {
FloatSide::Right
},
clear: new_clear_side(clear),
left_wall: Length::new(left_wall as f32),
right_wall: Length::new(right_wall as f32),
},
ceiling,
walls: InlineWalls {
left: Length::new(left as f32),
right: Length::new(right as f32),
},
}
}
@ -389,12 +388,12 @@ impl Arbitrary for FloatInput {
this.info.clear = new_clear_side(clear_side);
shrunk = true;
}
if let Some(left_wall) = self.info.left_wall.px().shrink().next() {
this.info.left_wall = Length::new(left_wall);
if let Some(left) = self.walls.left.px().shrink().next() {
this.walls.left = Length::new(left);
shrunk = true;
}
if let Some(right_wall) = self.info.right_wall.px().shrink().next() {
this.info.right_wall = Length::new(right_wall);
if let Some(right) = self.walls.right.px().shrink().next() {
this.walls.right = Length::new(right);
shrunk = true;
}
if let Some(ceiling) = self.ceiling.shrink().next() {
@ -430,6 +429,7 @@ struct PlacedFloat {
origin: Vec2<Length>,
info: PlacementInfo,
ceiling: Length,
walls: InlineWalls,
}
impl Drop for FloatPlacement {
@ -442,8 +442,12 @@ impl Drop for FloatPlacement {
eprintln!("Failing float placement:");
for placed_float in &self.placed_floats {
eprintln!(
" * {:?} @ {:?}, {:?}",
placed_float.info, placed_float.origin, placed_float.ceiling
" * {:?} @ {:?}, T {:?} L {:?} R {:?}",
placed_float.info,
placed_float.origin,
placed_float.ceiling,
placed_float.walls.left,
placed_float.walls.right,
);
}
eprintln!("Bands:\n{:?}\n", self.float_context.bands);
@ -466,10 +470,12 @@ impl FloatPlacement {
for float in floats {
let ceiling = Length::new(float.ceiling as f32);
float_context.lower_ceiling(ceiling);
float_context.walls = float.walls;
placed_floats.push(PlacedFloat {
origin: float_context.add_float(&float.info),
info: float.info,
ceiling,
walls: float.walls,
})
}
FloatPlacement {
@ -488,9 +494,9 @@ impl FloatPlacement {
fn check_floats_rule_1(placement: &FloatPlacement) {
for placed_float in &placement.placed_floats {
match placed_float.info.side {
FloatSide::Left => assert!(placed_float.origin.inline >= placed_float.info.left_wall),
FloatSide::Left => assert!(placed_float.origin.inline >= placed_float.walls.left),
FloatSide::Right => {
assert!(placed_float.rect().max_inline_position() <= placed_float.info.right_wall)
assert!(placed_float.rect().max_inline_position() <= placed_float.walls.right)
},
}
}
@ -596,12 +602,12 @@ fn check_floats_rule_7(placement: &FloatPlacement) {
// Only consider floats that stick out.
match placed_float.info.side {
FloatSide::Left => {
if placed_float.rect().max_inline_position() <= placed_float.info.right_wall {
if placed_float.rect().max_inline_position() <= placed_float.walls.right {
continue;
}
},
FloatSide::Right => {
if placed_float.origin.inline >= placed_float.info.left_wall {
if placed_float.origin.inline >= placed_float.walls.left {
continue;
}
},