Use the size of the containing block, not the size of the block formatting

context, to place floats in layout 2020.

The containing block for a float is not necessarily the same as the block
formatting context the float is in per CSS 2.1 [1]:

"For other elements, if the element’s position is relative or static, the
containing block is formed by the content edge of the nearest block container
ancestor box."

This shows up in the simplest case:

	<html>
	<body>
	<div style="float: left">Hello</div>
	</body>
	</html>

In this case, the `<html>` element is the block formatting context with inline
size equal to the width of the window, but the `<body>` element with nonzero
inline margins is the containing block for the float. The float placement must
respect the content box of the `<body>` element (i.e. floats must not overlap
the `<body>` element's margins), not that of the `<html>` element.

Because a single block formatting context may contain floats with different
containing blocks, the left and right "walls" of that containing block become
properties of individual floats at the time of placement, not properties of the
float context itself.

Additionally, this commit generalizes the float placement logic a bit to allow
the placement of arbitrary objects, not just floats. This is intended to
support inline layout and block formatting context placement.

This commit updates the `FloatContext` and associated tests only and doesn't
actually wire the context up to the rest of layout, so floats in pages still
aren't actually laid out.

[1]: https://drafts.csswg.org/css2/#containing-block-details
This commit is contained in:
Patrick Walton 2020-07-22 19:07:36 -07:00
parent 6a9aac3e65
commit 362b64aa68
3 changed files with 170 additions and 106 deletions

View file

@ -36,9 +36,6 @@ pub struct FloatContext {
/// This tree is immutable; modification operations return the new tree, which may share nodes /// This tree is immutable; modification operations return the new tree, which may share nodes
/// with previous versions of the tree. /// with previous versions of the tree.
pub bands: FloatBandTree, pub bands: FloatBandTree,
/// The logical width of this context. No floats may extend outside the width of this context
/// unless they are as far (logically) left or right as possible.
pub inline_size: Length,
/// The current (logically) vertical position. No new floats may be placed (logically) above /// The current (logically) vertical position. No new floats may be placed (logically) above
/// this line. /// this line.
pub ceiling: Length, pub ceiling: Length,
@ -47,7 +44,7 @@ pub struct FloatContext {
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(inline_size: Length) -> Self { pub fn new() -> Self {
let mut bands = FloatBandTree::new(); let mut bands = FloatBandTree::new();
bands = bands.insert(FloatBand { bands = bands.insert(FloatBand {
top: Length::zero(), top: Length::zero(),
@ -61,7 +58,6 @@ impl FloatContext {
}); });
FloatContext { FloatContext {
bands, bands,
inline_size,
ceiling: Length::zero(), ceiling: Length::zero(),
} }
} }
@ -78,25 +74,15 @@ impl FloatContext {
self.ceiling = self.ceiling.max(new_ceiling); self.ceiling = self.ceiling.max(new_ceiling);
} }
/// Returns the highest block position that is both logically below the current ceiling and /// Determines where a float with the given placement would go, but leaves the float context
/// clear of floats on the given side or sides. /// unmodified. Returns the start corner of its margin box.
pub fn clearance(&self, side: ClearSide) -> Length { ///
let mut band = self.bands.find(self.ceiling).unwrap(); /// This should be used for placing inline elements and block formatting contexts so that they
while !band.is_clear(side) { /// don't collide with floats.
let next_band = self.bands.find_next(band.top).unwrap(); pub fn place_object(&self, object: &PlacementInfo) -> Vec2<Length> {
if next_band.top.px().is_infinite() {
break;
}
band = next_band;
}
band.top.max(self.ceiling)
}
/// 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: FloatInfo) -> Vec2<Length> {
// Find the first band this float fits in. // Find the first band this float fits in.
let mut first_band = self.bands.find(self.ceiling).unwrap(); let mut first_band = self.bands.find(self.ceiling).unwrap();
while !first_band.float_fits(&new_float, self.inline_size) { while !first_band.object_fits(&object) {
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.px().is_infinite() {
break; break;
@ -104,30 +90,46 @@ impl FloatContext {
first_band = next_band; first_band = next_band;
} }
// The float fits perfectly here. Place it. // The object fits perfectly here. Place it.
let (new_float_origin, new_float_extent); match object.side {
match new_float.side {
FloatSide::Left => { FloatSide::Left => {
new_float_origin = Vec2 { let left_object_edge = match first_band.left {
inline: first_band.left.unwrap_or(Length::zero()), Some(band_left) => band_left.max(object.left_wall),
block: first_band.top.max(self.ceiling), None => object.left_wall,
}; };
new_float_extent = new_float_origin.inline + new_float.size.inline; Vec2 {
inline: left_object_edge,
block: first_band.top.max(self.ceiling),
}
}, },
FloatSide::Right => { FloatSide::Right => {
new_float_origin = Vec2 { let right_object_edge = match first_band.right {
inline: first_band.right.unwrap_or(self.inline_size) - new_float.size.inline, Some(band_right) => band_right.min(object.right_wall),
block: first_band.top.max(self.ceiling), None => object.right_wall,
}; };
new_float_extent = new_float_origin.inline; Vec2 {
inline: right_object_edge - object.size.inline,
block: first_band.top.max(self.ceiling),
}
}, },
}
}
/// 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) -> Vec2<Length> {
// Place the float.
let new_float_origin = self.place_object(new_float);
let new_float_extent = match new_float.side {
FloatSide::Left => new_float_origin.inline + new_float.size.inline,
FloatSide::Right => new_float_origin.inline,
}; };
let new_float_rect = Rect { let new_float_rect = Rect {
start_corner: new_float_origin, start_corner: new_float_origin,
size: new_float.size, size: new_float.size.clone(),
}; };
// Split the first band if necessary. // Split the first band if necessary.
let mut first_band = self.bands.find(new_float_rect.start_corner.block).unwrap();
first_band.top = new_float_rect.start_corner.block; first_band.top = new_float_rect.start_corner.block;
self.bands = self.bands.insert(first_band); self.bands = self.bands.insert(first_band);
@ -152,15 +154,21 @@ impl FloatContext {
} }
} }
/// Information needed to place a float. /// Information needed to place an object so that it doesn't collide with existing floats.
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub struct FloatInfo { pub struct PlacementInfo {
/// The *margin* box size of the float. /// The *margin* box size of the object.
pub size: Vec2<Length>, pub size: Vec2<Length>,
/// Whether the float is 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.
pub clear: ClearSide, pub clear: ClearSide,
/// The distance from the logical left side of the block formatting context to the logical
/// left side of this object's containing block.
pub left_wall: Length,
/// The distance from the logical *left* side of the block formatting context to the logical
/// right side of this object's containing block.
pub right_wall: Length,
} }
/// Whether the float is left or right. /// Whether the float is left or right.
@ -189,19 +197,20 @@ pub enum ClearSide {
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: Length,
/// The distance from the left edge to the first legal (logically) horizontal position where /// The distance from the left edge of the block formatting context to the first legal
/// floats may be placed. If `None`, there are no floats to the left; distinguishing between /// (logically) horizontal position where floats may be placed. If `None`, there are no floats
/// the cases of "a zero-width float is present" and "no floats at all are present" is /// to the left; distinguishing between the cases of "a zero-width float is present" and "no
/// 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<Length>,
/// The distance from the right edge to the first legal (logically) horizontal position where /// The distance from the *left* edge of the block formatting context to the first legal
/// floats may be placed. If `None`, there are no floats to the right; distinguishing between /// (logically) horizontal position where floats may be placed. If `None`, there are no floats
/// the cases of "a zero-width float is present" and "no floats at all are present" is /// to the right; distinguishing between the cases of "a zero-width float is present" and "no
/// 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<Length>,
} }
impl FloatBand { impl FloatBand {
// Returns true if this band is clear of floats on the given side or sides.
fn is_clear(&self, side: ClearSide) -> bool { fn is_clear(&self, side: ClearSide) -> bool {
match (side, self.left, self.right) { match (side, self.left, self.right) {
(ClearSide::Left, Some(_), _) | (ClearSide::Left, Some(_), _) |
@ -215,12 +224,56 @@ impl FloatBand {
} }
} }
fn float_fits(&self, new_float: &FloatInfo, container_inline_size: Length) -> bool { // Determines whether an object fits in a band.
let available_space = fn object_fits(&self, object: &PlacementInfo) -> bool {
self.right.unwrap_or(container_inline_size) - self.left.unwrap_or(Length::zero()); // If we must be clear on the given side and we aren't, this object doesn't fit.
self.is_clear(new_float.clear) && if !self.is_clear(object.clear) {
(new_float.size.inline <= available_space || return false;
(self.left.is_none() && self.right.is_none())) }
match object.side {
FloatSide::Left => {
// Compute a candidate left position for the object.
let candidate_left = match self.left {
None => object.left_wall,
Some(left) => left.max(object.left_wall),
};
// If this band has an existing left float in it, then make sure that the object
// doesn't stick out past the right edge (rule 7).
if self.left.is_some() && candidate_left + object.size.inline > object.right_wall {
return false;
}
// If this band has an existing right float in it, make sure we don't collide with
// it (rule 3).
match self.right {
None => true,
Some(right) => object.size.inline <= right - candidate_left,
}
},
FloatSide::Right => {
// Compute a candidate right position for the object.
let candidate_right = match self.right {
None => object.right_wall,
Some(right) => right.min(object.right_wall),
};
// If this band has an existing right float in it, then make sure that the new
// object doesn't stick out past the left edge (rule 7).
if self.right.is_some() && candidate_right - object.size.inline < object.left_wall {
return false;
}
// If this band has an existing left float in it, make sure we don't collide with
// it (rule 3).
match self.left {
None => true,
Some(left) => object.size.inline <= candidate_right - left,
}
},
}
} }
} }

View file

@ -80,7 +80,7 @@ impl BlockFormattingContext {
) -> IndependentLayout { ) -> IndependentLayout {
let mut float_context; let mut float_context;
let float_context = if self.contains_floats { let float_context = if self.contains_floats {
float_context = FloatContext::new(containing_block.inline_size); float_context = FloatContext::new();
Some(&mut float_context) Some(&mut float_context)
} else { } else {
None None

View file

@ -9,7 +9,7 @@ extern crate lazy_static;
use euclid::num::Zero; use euclid::num::Zero;
use layout::flow::float::{ClearSide, FloatBand, FloatBandNode, FloatBandTree, FloatContext}; use layout::flow::float::{ClearSide, FloatBand, FloatBandNode, FloatBandTree, FloatContext};
use layout::flow::float::{FloatInfo, FloatSide}; use layout::flow::float::{FloatSide, PlacementInfo};
use layout::geom::flow_relative::{Rect, Vec2}; use layout::geom::flow_relative::{Rect, Vec2};
use quickcheck::{Arbitrary, Gen}; use quickcheck::{Arbitrary, Gen};
use std::f32; use std::f32;
@ -337,7 +337,7 @@ fn test_tree_range_setting() {
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
struct FloatInput { struct FloatInput {
// Information needed to place the float. // Information needed to place the float.
info: FloatInfo, 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: u32,
@ -352,9 +352,11 @@ impl Arbitrary for FloatInput {
let height: u32 = Arbitrary::arbitrary(generator); let height: u32 = Arbitrary::arbitrary(generator);
let is_left: bool = Arbitrary::arbitrary(generator); let is_left: bool = Arbitrary::arbitrary(generator);
let ceiling: u32 = Arbitrary::arbitrary(generator); let ceiling: u32 = Arbitrary::arbitrary(generator);
let left_wall: u32 = Arbitrary::arbitrary(generator);
let right_wall: u32 = Arbitrary::arbitrary(generator);
let clear: u8 = Arbitrary::arbitrary(generator); let clear: u8 = Arbitrary::arbitrary(generator);
FloatInput { FloatInput {
info: FloatInfo { info: PlacementInfo {
size: Vec2 { size: Vec2 {
inline: Length::new(width as f32), inline: Length::new(width as f32),
block: Length::new(height as f32), block: Length::new(height as f32),
@ -365,6 +367,8 @@ impl Arbitrary for FloatInput {
FloatSide::Right FloatSide::Right
}, },
clear: new_clear_side(clear), clear: new_clear_side(clear),
left_wall: Length::new(left_wall as f32),
right_wall: Length::new(right_wall as f32),
}, },
ceiling, ceiling,
} }
@ -385,6 +389,14 @@ impl Arbitrary for FloatInput {
this.info.clear = new_clear_side(clear_side); this.info.clear = new_clear_side(clear_side);
shrunk = true; shrunk = true;
} }
if let Some(left_wall) = self.info.left_wall.px().shrink().next() {
this.info.left_wall = Length::new(left_wall);
shrunk = true;
}
if let Some(right_wall) = self.info.right_wall.px().shrink().next() {
this.info.right_wall = Length::new(right_wall);
shrunk = true;
}
if let Some(ceiling) = self.ceiling.shrink().next() { if let Some(ceiling) = self.ceiling.shrink().next() {
this.ceiling = ceiling; this.ceiling = ceiling;
shrunk = true; shrunk = true;
@ -416,7 +428,7 @@ struct FloatPlacement {
#[derive(Clone)] #[derive(Clone)]
struct PlacedFloat { struct PlacedFloat {
origin: Vec2<Length>, origin: Vec2<Length>,
info: FloatInfo, info: PlacementInfo,
ceiling: Length, ceiling: Length,
} }
@ -427,12 +439,12 @@ impl Drop for FloatPlacement {
} }
// Dump the float context for debugging. // Dump the float context for debugging.
eprintln!( eprintln!("Failing float placement:");
"Failing float placement (inline size: {:?}):",
self.float_context.inline_size
);
for placed_float in &self.placed_floats { for placed_float in &self.placed_floats {
eprintln!(" * {:?} @ {:?}", placed_float.info, placed_float.origin); eprintln!(
" * {:?} @ {:?}, {:?}",
placed_float.info, placed_float.origin, placed_float.ceiling
);
} }
eprintln!("Bands:\n{:?}\n", self.float_context.bands); eprintln!("Bands:\n{:?}\n", self.float_context.bands);
} }
@ -448,14 +460,14 @@ impl PlacedFloat {
} }
impl FloatPlacement { impl FloatPlacement {
fn place(inline_size: u32, floats: Vec<FloatInput>) -> FloatPlacement { fn place(floats: Vec<FloatInput>) -> FloatPlacement {
let mut float_context = FloatContext::new(Length::new(inline_size as f32)); let mut float_context = FloatContext::new();
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 = Length::new(float.ceiling as f32);
float_context.lower_ceiling(ceiling); float_context.lower_ceiling(ceiling);
placed_floats.push(PlacedFloat { placed_floats.push(PlacedFloat {
origin: float_context.add_float(float.info.clone()), origin: float_context.add_float(&float.info),
info: float.info, info: float.info,
ceiling, ceiling,
}) })
@ -476,10 +488,10 @@ impl FloatPlacement {
fn check_floats_rule_1(placement: &FloatPlacement) { fn check_floats_rule_1(placement: &FloatPlacement) {
for placed_float in &placement.placed_floats { for placed_float in &placement.placed_floats {
match placed_float.info.side { match placed_float.info.side {
FloatSide::Left => assert!(placed_float.origin.inline >= Length::zero()), FloatSide::Left => assert!(placed_float.origin.inline >= placed_float.info.left_wall),
FloatSide::Right => assert!( FloatSide::Right => {
placed_float.rect().max_inline_position() <= placement.float_context.inline_size assert!(placed_float.rect().max_inline_position() <= placed_float.info.right_wall)
), },
} }
} }
} }
@ -584,13 +596,12 @@ fn check_floats_rule_7(placement: &FloatPlacement) {
// Only consider floats that stick out. // Only consider floats that stick out.
match placed_float.info.side { match placed_float.info.side {
FloatSide::Left => { FloatSide::Left => {
if placed_float.rect().max_inline_position() <= placement.float_context.inline_size if placed_float.rect().max_inline_position() <= placed_float.info.right_wall {
{
continue; continue;
} }
}, },
FloatSide::Right => { FloatSide::Right => {
if placed_float.origin.inline >= Length::zero() { if placed_float.origin.inline >= placed_float.info.left_wall {
continue; continue;
} }
}, },
@ -608,12 +619,12 @@ fn check_floats_rule_7(placement: &FloatPlacement) {
} }
// 8. A floating box must be placed as high as possible. // 8. A floating box must be placed as high as possible.
fn check_floats_rule_8(inline_size: u32, floats_and_perturbations: Vec<(FloatInput, u32)>) { fn check_floats_rule_8(floats_and_perturbations: Vec<(FloatInput, u32)>) {
let floats = floats_and_perturbations let floats = floats_and_perturbations
.iter() .iter()
.map(|&(ref float, _)| (*float).clone()) .map(|&(ref float, _)| (*float).clone())
.collect(); .collect();
let placement = FloatPlacement::place(inline_size, floats); let placement = FloatPlacement::place(floats);
for (float_index, &(_, perturbation)) in floats_and_perturbations.iter().enumerate() { for (float_index, &(_, perturbation)) in floats_and_perturbations.iter().enumerate() {
if perturbation == 0 { if perturbation == 0 {
@ -636,12 +647,12 @@ fn check_floats_rule_8(inline_size: u32, floats_and_perturbations: Vec<(FloatInp
// 9. A left-floating box must be put as far to the left as possible, a right-floating box as far // 9. A left-floating box must be put as far to the left as possible, a right-floating box as far
// to the right as possible. A higher position is preferred over one that is further to the // to the right as possible. A higher position is preferred over one that is further to the
// left/right. // left/right.
fn check_floats_rule_9(inline_size: u32, floats_and_perturbations: Vec<(FloatInput, u32)>) { fn check_floats_rule_9(floats_and_perturbations: Vec<(FloatInput, u32)>) {
let floats = floats_and_perturbations let floats = floats_and_perturbations
.iter() .iter()
.map(|&(ref float, _)| (*float).clone()) .map(|&(ref float, _)| (*float).clone())
.collect(); .collect();
let placement = FloatPlacement::place(inline_size, floats); let placement = FloatPlacement::place(floats);
for (float_index, &(_, perturbation)) in floats_and_perturbations.iter().enumerate() { for (float_index, &(_, perturbation)) in floats_and_perturbations.iter().enumerate() {
if perturbation == 0 { if perturbation == 0 {
@ -734,90 +745,90 @@ fn check_basic_float_rules(placement: &FloatPlacement) {
#[test] #[test]
fn test_floats_rule_1() { fn test_floats_rule_1() {
let f: fn(u32, Vec<FloatInput>) = check; let f: fn(Vec<FloatInput>) = check;
quickcheck::quickcheck(f); quickcheck::quickcheck(f);
fn check(inline_size: u32, floats: Vec<FloatInput>) { fn check(floats: Vec<FloatInput>) {
check_floats_rule_1(&FloatPlacement::place(inline_size, floats)); check_floats_rule_1(&FloatPlacement::place(floats));
} }
} }
#[test] #[test]
fn test_floats_rule_2() { fn test_floats_rule_2() {
let f: fn(u32, Vec<FloatInput>) = check; let f: fn(Vec<FloatInput>) = check;
quickcheck::quickcheck(f); quickcheck::quickcheck(f);
fn check(inline_size: u32, floats: Vec<FloatInput>) { fn check(floats: Vec<FloatInput>) {
check_floats_rule_2(&FloatPlacement::place(inline_size, floats)); check_floats_rule_2(&FloatPlacement::place(floats));
} }
} }
#[test] #[test]
fn test_floats_rule_3() { fn test_floats_rule_3() {
let f: fn(u32, Vec<FloatInput>) = check; let f: fn(Vec<FloatInput>) = check;
quickcheck::quickcheck(f); quickcheck::quickcheck(f);
fn check(inline_size: u32, floats: Vec<FloatInput>) { fn check(floats: Vec<FloatInput>) {
check_floats_rule_3(&FloatPlacement::place(inline_size, floats)); check_floats_rule_3(&FloatPlacement::place(floats));
} }
} }
#[test] #[test]
fn test_floats_rule_4() { fn test_floats_rule_4() {
let f: fn(u32, Vec<FloatInput>) = check; let f: fn(Vec<FloatInput>) = check;
quickcheck::quickcheck(f); quickcheck::quickcheck(f);
fn check(inline_size: u32, floats: Vec<FloatInput>) { fn check(floats: Vec<FloatInput>) {
check_floats_rule_4(&FloatPlacement::place(inline_size, floats)); check_floats_rule_4(&FloatPlacement::place(floats));
} }
} }
#[test] #[test]
fn test_floats_rule_5() { fn test_floats_rule_5() {
let f: fn(u32, Vec<FloatInput>) = check; let f: fn(Vec<FloatInput>) = check;
quickcheck::quickcheck(f); quickcheck::quickcheck(f);
fn check(inline_size: u32, floats: Vec<FloatInput>) { fn check(floats: Vec<FloatInput>) {
check_floats_rule_5(&FloatPlacement::place(inline_size, floats)); check_floats_rule_5(&FloatPlacement::place(floats));
} }
} }
#[test] #[test]
fn test_floats_rule_6() { fn test_floats_rule_6() {
let f: fn(u32, Vec<FloatInput>) = check; let f: fn(Vec<FloatInput>) = check;
quickcheck::quickcheck(f); quickcheck::quickcheck(f);
fn check(inline_size: u32, floats: Vec<FloatInput>) { fn check(floats: Vec<FloatInput>) {
check_floats_rule_6(&FloatPlacement::place(inline_size, floats)); check_floats_rule_6(&FloatPlacement::place(floats));
} }
} }
#[test] #[test]
fn test_floats_rule_7() { fn test_floats_rule_7() {
let f: fn(u32, Vec<FloatInput>) = check; let f: fn(Vec<FloatInput>) = check;
quickcheck::quickcheck(f); quickcheck::quickcheck(f);
fn check(inline_size: u32, floats: Vec<FloatInput>) { fn check(floats: Vec<FloatInput>) {
check_floats_rule_7(&FloatPlacement::place(inline_size, floats)); check_floats_rule_7(&FloatPlacement::place(floats));
} }
} }
#[test] #[test]
fn test_floats_rule_8() { fn test_floats_rule_8() {
let f: fn(u32, Vec<(FloatInput, u32)>) = check; let f: fn(Vec<(FloatInput, u32)>) = check;
quickcheck::quickcheck(f); quickcheck::quickcheck(f);
fn check(inline_size: u32, floats: Vec<(FloatInput, u32)>) { fn check(floats: Vec<(FloatInput, u32)>) {
check_floats_rule_8(inline_size, floats); check_floats_rule_8(floats);
} }
} }
#[test] #[test]
fn test_floats_rule_9() { fn test_floats_rule_9() {
let f: fn(u32, Vec<(FloatInput, u32)>) = check; let f: fn(Vec<(FloatInput, u32)>) = check;
quickcheck::quickcheck(f); quickcheck::quickcheck(f);
fn check(inline_size: u32, floats: Vec<(FloatInput, u32)>) { fn check(floats: Vec<(FloatInput, u32)>) {
check_floats_rule_9(inline_size, floats); check_floats_rule_9(floats);
} }
} }
#[test] #[test]
fn test_floats_rule_10() { fn test_floats_rule_10() {
let f: fn(u32, Vec<FloatInput>) = check; let f: fn(Vec<FloatInput>) = check;
quickcheck::quickcheck(f); quickcheck::quickcheck(f);
fn check(inline_size: u32, floats: Vec<FloatInput>) { fn check(floats: Vec<FloatInput>) {
check_floats_rule_10(&FloatPlacement::place(inline_size, floats)); check_floats_rule_10(&FloatPlacement::place(floats));
} }
} }