2014-02-28 00:01:49 +04:00
|
|
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
|
|
|
|
2017-05-20 07:09:20 +03:00
|
|
|
use app_units::{Au, MAX_AU};
|
2016-03-26 04:38:41 +03:00
|
|
|
use block::FormattingContextType;
|
2017-12-15 21:44:50 +03:00
|
|
|
use flow::{Flow, FlowFlags, GetBaseFlow, ImmutableFlowUtils};
|
2016-02-20 21:45:19 +03:00
|
|
|
use persistent_list::PersistentList;
|
2015-08-20 16:43:56 +03:00
|
|
|
use std::cmp::{max, min};
|
|
|
|
use std::fmt;
|
2017-12-06 04:35:25 +03:00
|
|
|
use style::computed_values::float::T as StyleFloat;
|
2016-02-18 12:21:29 +03:00
|
|
|
use style::logical_geometry::{LogicalRect, LogicalSize, WritingMode};
|
2016-05-04 23:49:23 +03:00
|
|
|
use style::values::computed::LengthOrPercentageOrAuto;
|
2014-02-28 00:01:49 +04:00
|
|
|
|
|
|
|
/// The kind of float: left or right.
|
2017-08-24 01:18:31 +03:00
|
|
|
#[derive(Clone, Copy, Debug, Serialize)]
|
2014-02-28 00:01:49 +04:00
|
|
|
pub enum FloatKind {
|
2014-12-18 04:45:49 +03:00
|
|
|
Left,
|
|
|
|
Right
|
2014-02-28 00:01:49 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
impl FloatKind {
|
2017-12-06 04:35:25 +03:00
|
|
|
pub fn from_property(property: StyleFloat) -> Option<FloatKind> {
|
2014-02-28 00:01:49 +04:00
|
|
|
match property {
|
2017-12-06 04:35:25 +03:00
|
|
|
StyleFloat::None => None,
|
|
|
|
StyleFloat::Left => Some(FloatKind::Left),
|
|
|
|
StyleFloat::Right => Some(FloatKind::Right),
|
2014-02-28 00:01:49 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// The kind of clearance: left, right, or both.
|
2017-08-24 01:18:31 +03:00
|
|
|
#[derive(Clone, Copy)]
|
2014-02-28 00:01:49 +04:00
|
|
|
pub enum ClearType {
|
2014-12-18 04:45:49 +03:00
|
|
|
Left,
|
|
|
|
Right,
|
|
|
|
Both,
|
2014-02-28 00:01:49 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
/// Information about a single float.
|
2015-01-28 04:15:50 +03:00
|
|
|
#[derive(Clone, Copy)]
|
2014-02-28 00:01:49 +04:00
|
|
|
struct Float {
|
|
|
|
/// The boundaries of this float.
|
2014-07-19 00:27:23 +04:00
|
|
|
bounds: LogicalRect<Au>,
|
2014-02-28 00:01:49 +04:00
|
|
|
/// The kind of float: left or right.
|
|
|
|
kind: FloatKind,
|
|
|
|
}
|
|
|
|
|
2015-02-12 03:24:45 +03:00
|
|
|
impl fmt::Debug for Float {
|
2014-05-24 01:55:40 +04:00
|
|
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
2015-01-28 04:15:50 +03:00
|
|
|
write!(f, "bounds={:?} kind={:?}", self.bounds, self.kind)
|
2014-05-24 01:55:40 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-02-28 00:01:49 +04:00
|
|
|
/// Information about the floats next to a flow.
|
2015-01-28 04:15:50 +03:00
|
|
|
#[derive(Clone)]
|
2014-02-28 00:01:49 +04:00
|
|
|
struct FloatList {
|
|
|
|
/// Information about each of the floats here.
|
2014-10-31 23:00:39 +03:00
|
|
|
floats: PersistentList<Float>,
|
2014-07-19 00:27:23 +04:00
|
|
|
/// Cached copy of the maximum block-start offset of the float.
|
2016-03-26 03:18:25 +03:00
|
|
|
max_block_start: Option<Au>,
|
2014-02-28 00:01:49 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
impl FloatList {
|
|
|
|
fn new() -> FloatList {
|
|
|
|
FloatList {
|
2014-10-31 23:00:39 +03:00
|
|
|
floats: PersistentList::new(),
|
2016-03-26 03:18:25 +03:00
|
|
|
max_block_start: None,
|
2014-02-28 00:01:49 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Returns true if the list is allocated and false otherwise. If false, there are guaranteed
|
|
|
|
/// not to be any floats.
|
|
|
|
fn is_present(&self) -> bool {
|
2014-10-31 23:00:39 +03:00
|
|
|
self.floats.len() > 0
|
2014-02-28 00:01:49 +04:00
|
|
|
}
|
2014-10-31 23:00:39 +03:00
|
|
|
}
|
2014-02-28 00:01:49 +04:00
|
|
|
|
2015-02-12 03:24:45 +03:00
|
|
|
impl fmt::Debug for FloatList {
|
2014-10-31 23:00:39 +03:00
|
|
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
2017-06-18 15:55:11 +03:00
|
|
|
write!(f, "max_block_start={:?} floats={}", self.max_block_start, self.floats.len())?;
|
2016-05-04 23:49:23 +03:00
|
|
|
for float in self.floats.iter() {
|
2017-06-18 15:55:11 +03:00
|
|
|
write!(f, " {:?}", float)?;
|
2016-05-04 23:49:23 +03:00
|
|
|
}
|
|
|
|
Ok(())
|
2014-02-28 00:01:49 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// All the information necessary to place a float.
|
|
|
|
pub struct PlacementInfo {
|
|
|
|
/// The dimensions of the float.
|
2014-07-19 00:27:23 +04:00
|
|
|
pub size: LogicalSize<Au>,
|
|
|
|
/// The minimum block-start of the float, as determined by earlier elements.
|
2014-04-28 02:52:39 +04:00
|
|
|
pub ceiling: Au,
|
2014-07-19 00:27:23 +04:00
|
|
|
/// The maximum inline-end position of the float, generally determined by the containing block.
|
|
|
|
pub max_inline_size: Au,
|
2014-02-28 00:01:49 +04:00
|
|
|
/// The kind of float.
|
2014-04-28 02:52:39 +04:00
|
|
|
pub kind: FloatKind
|
2014-02-28 00:01:49 +04:00
|
|
|
}
|
|
|
|
|
2015-02-12 03:24:45 +03:00
|
|
|
impl fmt::Debug for PlacementInfo {
|
2014-05-24 01:55:40 +04:00
|
|
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
2014-10-31 23:00:39 +03:00
|
|
|
write!(f,
|
2015-01-28 04:15:50 +03:00
|
|
|
"size={:?} ceiling={:?} max_inline_size={:?} kind={:?}",
|
2014-10-31 23:00:39 +03:00
|
|
|
self.size,
|
|
|
|
self.ceiling,
|
|
|
|
self.max_inline_size,
|
|
|
|
self.kind)
|
2014-05-24 01:55:40 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-07-19 00:27:23 +04:00
|
|
|
fn range_intersect(block_start_1: Au, block_end_1: Au, block_start_2: Au, block_end_2: Au) -> (Au, Au) {
|
|
|
|
(max(block_start_1, block_start_2), min(block_end_1, block_end_2))
|
2014-02-28 00:01:49 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
/// Encapsulates information about floats. This is optimized to avoid allocation if there are
|
|
|
|
/// no floats, and to avoid copying when translating the list of floats downward.
|
2015-01-28 04:15:50 +03:00
|
|
|
#[derive(Clone)]
|
2014-02-28 00:01:49 +04:00
|
|
|
pub struct Floats {
|
|
|
|
/// The list of floats.
|
2014-10-31 23:00:39 +03:00
|
|
|
list: FloatList,
|
2014-02-28 00:01:49 +04:00
|
|
|
/// The offset of the flow relative to the first float.
|
2014-07-19 00:27:23 +04:00
|
|
|
offset: LogicalSize<Au>,
|
2014-10-31 23:00:39 +03:00
|
|
|
/// The writing mode of these floats.
|
2014-07-19 00:27:23 +04:00
|
|
|
pub writing_mode: WritingMode,
|
2014-02-28 00:01:49 +04:00
|
|
|
}
|
|
|
|
|
2015-02-12 03:24:45 +03:00
|
|
|
impl fmt::Debug for Floats {
|
2014-05-24 01:55:40 +04:00
|
|
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
2014-10-31 23:00:39 +03:00
|
|
|
if !self.list.is_present() {
|
|
|
|
write!(f, "[empty]")
|
|
|
|
} else {
|
2015-01-28 04:15:50 +03:00
|
|
|
write!(f, "offset={:?} floats={:?}", self.offset, self.list)
|
2014-05-24 01:55:40 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-02-28 00:01:49 +04:00
|
|
|
impl Floats {
|
|
|
|
/// Creates a new `Floats` object.
|
2014-07-19 00:27:23 +04:00
|
|
|
pub fn new(writing_mode: WritingMode) -> Floats {
|
2014-02-28 00:01:49 +04:00
|
|
|
Floats {
|
2014-10-31 23:00:39 +03:00
|
|
|
list: FloatList::new(),
|
2014-07-19 00:27:23 +04:00
|
|
|
offset: LogicalSize::zero(writing_mode),
|
|
|
|
writing_mode: writing_mode,
|
2014-02-28 00:01:49 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Adjusts the recorded offset of the flow relative to the first float.
|
2014-07-19 00:27:23 +04:00
|
|
|
pub fn translate(&mut self, delta: LogicalSize<Au>) {
|
2014-02-28 00:01:49 +04:00
|
|
|
self.offset = self.offset + delta
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Returns the position of the last float in flow coordinates.
|
2015-05-19 19:29:34 +03:00
|
|
|
pub fn last_float_pos(&self) -> Option<LogicalRect<Au>> {
|
2014-10-31 23:00:39 +03:00
|
|
|
match self.list.floats.front() {
|
2014-02-28 00:01:49 +04:00
|
|
|
None => None,
|
2015-05-19 19:29:34 +03:00
|
|
|
Some(float) => Some(float.bounds.translate_by_size(self.offset)),
|
2014-02-28 00:01:49 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-10-31 23:00:39 +03:00
|
|
|
/// Returns a rectangle that encloses the region from block-start to block-start + block-size,
|
|
|
|
/// with inline-size small enough that it doesn't collide with any floats. max_x is the
|
|
|
|
/// inline-size beyond which floats have no effect. (Generally this is the containing block
|
|
|
|
/// inline-size.)
|
|
|
|
pub fn available_rect(&self, block_start: Au, block_size: Au, max_x: Au)
|
|
|
|
-> Option<LogicalRect<Au>> {
|
|
|
|
let list = &self.list;
|
2014-07-19 00:27:23 +04:00
|
|
|
let block_start = block_start - self.offset.block;
|
2014-02-28 00:01:49 +04:00
|
|
|
|
2015-01-28 04:15:50 +03:00
|
|
|
debug!("available_rect: trying to find space at {:?}", block_start);
|
2014-02-28 00:01:49 +04:00
|
|
|
|
2014-07-19 00:27:23 +04:00
|
|
|
// Relevant dimensions for the inline-end-most inline-start float
|
|
|
|
let mut max_inline_start = Au(0) - self.offset.inline;
|
|
|
|
let mut l_block_start = None;
|
|
|
|
let mut l_block_end = None;
|
|
|
|
// Relevant dimensions for the inline-start-most inline-end float
|
|
|
|
let mut min_inline_end = max_x - self.offset.inline;
|
|
|
|
let mut r_block_start = None;
|
|
|
|
let mut r_block_end = None;
|
2014-02-28 00:01:49 +04:00
|
|
|
|
2014-10-29 02:21:48 +03:00
|
|
|
// Find the float collisions for the given range in the block direction.
|
2014-02-28 00:01:49 +04:00
|
|
|
for float in list.floats.iter() {
|
|
|
|
debug!("available_rect: Checking for collision against float");
|
2014-07-19 00:27:23 +04:00
|
|
|
let float_pos = float.bounds.start;
|
2014-02-28 00:01:49 +04:00
|
|
|
let float_size = float.bounds.size;
|
|
|
|
|
2015-01-28 04:15:50 +03:00
|
|
|
debug!("float_pos: {:?}, float_size: {:?}", float_pos, float_size);
|
2014-02-28 00:01:49 +04:00
|
|
|
match float.kind {
|
2014-12-18 04:45:49 +03:00
|
|
|
FloatKind::Left if float_pos.i + float_size.inline > max_inline_start &&
|
2014-10-31 23:00:39 +03:00
|
|
|
float_pos.b + float_size.block > block_start &&
|
|
|
|
float_pos.b < block_start + block_size => {
|
2014-07-19 00:27:23 +04:00
|
|
|
max_inline_start = float_pos.i + float_size.inline;
|
2014-04-07 18:52:26 +04:00
|
|
|
|
2014-07-19 00:27:23 +04:00
|
|
|
l_block_start = Some(float_pos.b);
|
|
|
|
l_block_end = Some(float_pos.b + float_size.block);
|
2014-02-28 00:01:49 +04:00
|
|
|
|
2014-10-31 23:00:39 +03:00
|
|
|
debug!("available_rect: collision with inline_start float: new \
|
2015-01-28 04:15:50 +03:00
|
|
|
max_inline_start is {:?}",
|
2014-10-31 23:00:39 +03:00
|
|
|
max_inline_start);
|
2014-02-28 00:01:49 +04:00
|
|
|
}
|
2014-12-18 04:45:49 +03:00
|
|
|
FloatKind::Right if float_pos.i < min_inline_end &&
|
2014-10-31 23:00:39 +03:00
|
|
|
float_pos.b + float_size.block > block_start &&
|
|
|
|
float_pos.b < block_start + block_size => {
|
2014-07-19 00:27:23 +04:00
|
|
|
min_inline_end = float_pos.i;
|
|
|
|
|
|
|
|
r_block_start = Some(float_pos.b);
|
|
|
|
r_block_end = Some(float_pos.b + float_size.block);
|
2014-10-31 23:00:39 +03:00
|
|
|
debug!("available_rect: collision with inline_end float: new min_inline_end \
|
2015-01-28 04:15:50 +03:00
|
|
|
is {:?}",
|
2014-07-19 00:27:23 +04:00
|
|
|
min_inline_end);
|
2014-02-28 00:01:49 +04:00
|
|
|
}
|
2014-12-18 04:45:49 +03:00
|
|
|
FloatKind::Left | FloatKind::Right => {}
|
2014-02-28 00:01:49 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Extend the vertical range of the rectangle to the closest floats.
|
|
|
|
// If there are floats on both sides, take the intersection of the
|
2014-07-19 00:27:23 +04:00
|
|
|
// two areas. Also make sure we never return a block-start smaller than the
|
2014-02-28 00:01:49 +04:00
|
|
|
// given upper bound.
|
2014-10-31 23:00:39 +03:00
|
|
|
let (block_start, block_end) = match (r_block_start,
|
|
|
|
r_block_end,
|
|
|
|
l_block_start,
|
|
|
|
l_block_end) {
|
|
|
|
(Some(r_block_start), Some(r_block_end), Some(l_block_start), Some(l_block_end)) => {
|
|
|
|
range_intersect(max(block_start, r_block_start),
|
|
|
|
r_block_end,
|
|
|
|
max(block_start, l_block_start),
|
|
|
|
l_block_end)
|
|
|
|
}
|
|
|
|
(None, None, Some(l_block_start), Some(l_block_end)) => {
|
|
|
|
(max(block_start, l_block_start), l_block_end)
|
|
|
|
}
|
|
|
|
(Some(r_block_start), Some(r_block_end), None, None) => {
|
|
|
|
(max(block_start, r_block_start), r_block_end)
|
|
|
|
}
|
2014-02-28 00:01:49 +04:00
|
|
|
(None, None, None, None) => return None,
|
2014-11-13 06:48:31 +03:00
|
|
|
_ => panic!("Reached unreachable state when computing float area")
|
2014-02-28 00:01:49 +04:00
|
|
|
};
|
|
|
|
|
|
|
|
// FIXME(eatkinson): This assertion is too strong and fails in some cases. It is OK to
|
2014-10-31 23:00:39 +03:00
|
|
|
// return negative inline-sizes since we check against that inline-end away, but we should
|
2014-12-12 12:12:51 +03:00
|
|
|
// still understand why they occur and add a stronger assertion here.
|
2014-07-19 00:27:23 +04:00
|
|
|
// assert!(max_inline-start < min_inline-end);
|
2014-04-07 18:52:26 +04:00
|
|
|
|
2014-07-19 00:27:23 +04:00
|
|
|
assert!(block_start <= block_end, "Float position error");
|
2014-02-28 00:01:49 +04:00
|
|
|
|
2014-10-31 23:00:39 +03:00
|
|
|
Some(LogicalRect::new(self.writing_mode,
|
|
|
|
max_inline_start + self.offset.inline,
|
|
|
|
block_start + self.offset.block,
|
|
|
|
min_inline_end - max_inline_start,
|
|
|
|
block_end - block_start))
|
2014-02-28 00:01:49 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
/// Adds a new float to the list.
|
|
|
|
pub fn add_float(&mut self, info: &PlacementInfo) {
|
2016-03-26 03:18:25 +03:00
|
|
|
let new_info = PlacementInfo {
|
|
|
|
size: info.size,
|
|
|
|
ceiling: match self.list.max_block_start {
|
|
|
|
None => info.ceiling,
|
|
|
|
Some(max_block_start) => max(info.ceiling, max_block_start + self.offset.block),
|
|
|
|
},
|
|
|
|
max_inline_size: info.max_inline_size,
|
|
|
|
kind: info.kind
|
|
|
|
};
|
2014-02-28 00:01:49 +04:00
|
|
|
|
2015-01-28 04:15:50 +03:00
|
|
|
debug!("add_float: added float with info {:?}", new_info);
|
2014-02-28 00:01:49 +04:00
|
|
|
|
|
|
|
let new_float = Float {
|
2014-07-19 00:27:23 +04:00
|
|
|
bounds: LogicalRect::from_point_size(
|
|
|
|
self.writing_mode,
|
|
|
|
self.place_between_floats(&new_info).start - self.offset,
|
|
|
|
info.size,
|
|
|
|
),
|
2014-02-28 00:01:49 +04:00
|
|
|
kind: info.kind
|
|
|
|
};
|
|
|
|
|
2014-10-31 23:00:39 +03:00
|
|
|
self.list.floats = self.list.floats.prepend_elem(new_float);
|
2016-03-26 03:18:25 +03:00
|
|
|
self.list.max_block_start = match self.list.max_block_start {
|
|
|
|
None => Some(new_float.bounds.start.b),
|
|
|
|
Some(max_block_start) => Some(max(max_block_start, new_float.bounds.start.b)),
|
|
|
|
}
|
2014-02-28 00:01:49 +04:00
|
|
|
}
|
|
|
|
|
2014-10-31 23:00:39 +03:00
|
|
|
/// Given the three sides of the bounding rectangle in the block-start direction, finds the
|
|
|
|
/// largest block-size that will result in the rectangle not colliding with any floats. Returns
|
|
|
|
/// `None` if that block-size is infinite.
|
|
|
|
fn max_block_size_for_bounds(&self, inline_start: Au, block_start: Au, inline_size: Au)
|
|
|
|
-> Option<Au> {
|
|
|
|
let list = &self.list;
|
2014-02-28 00:01:49 +04:00
|
|
|
|
2014-07-19 00:27:23 +04:00
|
|
|
let block_start = block_start - self.offset.block;
|
|
|
|
let inline_start = inline_start - self.offset.inline;
|
|
|
|
let mut max_block_size = None;
|
2014-02-28 00:01:49 +04:00
|
|
|
|
|
|
|
for float in list.floats.iter() {
|
2014-07-19 00:27:23 +04:00
|
|
|
if float.bounds.start.b + float.bounds.size.block > block_start &&
|
|
|
|
float.bounds.start.i + float.bounds.size.inline > inline_start &&
|
|
|
|
float.bounds.start.i < inline_start + inline_size {
|
|
|
|
let new_y = float.bounds.start.b;
|
|
|
|
max_block_size = Some(min(max_block_size.unwrap_or(new_y), new_y));
|
2014-02-28 00:01:49 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-07-19 00:27:23 +04:00
|
|
|
max_block_size.map(|h| h + self.offset.block)
|
2014-02-28 00:01:49 +04:00
|
|
|
}
|
|
|
|
|
2014-05-29 04:34:06 +04:00
|
|
|
/// Given placement information, finds the closest place a fragment can be positioned without
|
2014-02-28 00:01:49 +04:00
|
|
|
/// colliding with any floats.
|
2014-07-19 00:27:23 +04:00
|
|
|
pub fn place_between_floats(&self, info: &PlacementInfo) -> LogicalRect<Au> {
|
2015-01-28 04:15:50 +03:00
|
|
|
debug!("place_between_floats: Placing object with {:?}", info.size);
|
2014-02-28 00:01:49 +04:00
|
|
|
|
|
|
|
// If no floats, use this fast path.
|
|
|
|
if !self.list.is_present() {
|
|
|
|
match info.kind {
|
2014-12-18 04:45:49 +03:00
|
|
|
FloatKind::Left => {
|
2014-07-19 00:27:23 +04:00
|
|
|
return LogicalRect::new(
|
|
|
|
self.writing_mode,
|
|
|
|
Au(0),
|
|
|
|
info.ceiling,
|
|
|
|
info.max_inline_size,
|
2017-05-20 07:09:20 +03:00
|
|
|
MAX_AU)
|
2014-02-28 00:01:49 +04:00
|
|
|
}
|
2014-12-18 04:45:49 +03:00
|
|
|
FloatKind::Right => {
|
2014-07-19 00:27:23 +04:00
|
|
|
return LogicalRect::new(
|
|
|
|
self.writing_mode,
|
|
|
|
info.max_inline_size - info.size.inline,
|
|
|
|
info.ceiling,
|
|
|
|
info.max_inline_size,
|
2017-05-20 07:09:20 +03:00
|
|
|
MAX_AU)
|
2014-02-28 00:01:49 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Can't go any higher than previous floats or previous elements in the document.
|
2014-07-19 00:27:23 +04:00
|
|
|
let mut float_b = info.ceiling;
|
2014-02-28 00:01:49 +04:00
|
|
|
loop {
|
2014-10-31 23:00:39 +03:00
|
|
|
let maybe_location = self.available_rect(float_b,
|
|
|
|
info.size.block,
|
|
|
|
info.max_inline_size);
|
2015-04-10 00:47:03 +03:00
|
|
|
debug!("place_float: got available rect: {:?} for block-pos: {:?}",
|
|
|
|
maybe_location,
|
|
|
|
float_b);
|
2014-02-28 00:01:49 +04:00
|
|
|
match maybe_location {
|
|
|
|
// If there are no floats blocking us, return the current location
|
|
|
|
// TODO(eatkinson): integrate with overflow
|
|
|
|
None => {
|
2014-04-07 18:52:26 +04:00
|
|
|
return match info.kind {
|
2014-12-18 04:45:49 +03:00
|
|
|
FloatKind::Left => {
|
2014-07-19 00:27:23 +04:00
|
|
|
LogicalRect::new(
|
|
|
|
self.writing_mode,
|
|
|
|
Au(0),
|
|
|
|
float_b,
|
|
|
|
info.max_inline_size,
|
2017-05-20 07:09:20 +03:00
|
|
|
MAX_AU)
|
2014-02-28 00:01:49 +04:00
|
|
|
}
|
2014-12-18 04:45:49 +03:00
|
|
|
FloatKind::Right => {
|
2014-07-19 00:27:23 +04:00
|
|
|
LogicalRect::new(
|
|
|
|
self.writing_mode,
|
|
|
|
info.max_inline_size - info.size.inline,
|
|
|
|
float_b,
|
|
|
|
info.max_inline_size,
|
2017-05-20 07:09:20 +03:00
|
|
|
MAX_AU)
|
2014-02-28 00:01:49 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
Some(rect) => {
|
2018-01-26 03:06:33 +03:00
|
|
|
assert_ne!(rect.start.b + rect.size.block, float_b,
|
|
|
|
"Non-terminating float placement");
|
2014-04-07 18:52:26 +04:00
|
|
|
|
2014-02-28 00:01:49 +04:00
|
|
|
// Place here if there is enough room
|
2014-07-19 00:27:23 +04:00
|
|
|
if rect.size.inline >= info.size.inline {
|
|
|
|
let block_size = self.max_block_size_for_bounds(rect.start.i,
|
2015-04-10 00:47:03 +03:00
|
|
|
rect.start.b,
|
|
|
|
rect.size.inline);
|
2017-05-20 07:09:20 +03:00
|
|
|
let block_size = block_size.unwrap_or(MAX_AU);
|
2014-02-28 00:01:49 +04:00
|
|
|
return match info.kind {
|
2014-12-18 04:45:49 +03:00
|
|
|
FloatKind::Left => {
|
2014-07-19 00:27:23 +04:00
|
|
|
LogicalRect::new(
|
|
|
|
self.writing_mode,
|
|
|
|
rect.start.i,
|
|
|
|
float_b,
|
|
|
|
rect.size.inline,
|
|
|
|
block_size)
|
2014-02-28 00:01:49 +04:00
|
|
|
}
|
2014-12-18 04:45:49 +03:00
|
|
|
FloatKind::Right => {
|
2014-07-19 00:27:23 +04:00
|
|
|
LogicalRect::new(
|
|
|
|
self.writing_mode,
|
|
|
|
rect.start.i + rect.size.inline - info.size.inline,
|
|
|
|
float_b,
|
|
|
|
rect.size.inline,
|
|
|
|
block_size)
|
2014-02-28 00:01:49 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Try to place at the next-lowest location.
|
|
|
|
// Need to be careful of fencepost errors.
|
2014-07-19 00:27:23 +04:00
|
|
|
float_b = rect.start.b + rect.size.block;
|
2014-02-28 00:01:49 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn clearance(&self, clear: ClearType) -> Au {
|
2014-10-31 23:00:39 +03:00
|
|
|
let list = &self.list;
|
2014-02-28 00:01:49 +04:00
|
|
|
let mut clearance = Au(0);
|
|
|
|
for float in list.floats.iter() {
|
|
|
|
match (clear, float.kind) {
|
2014-12-18 04:45:49 +03:00
|
|
|
(ClearType::Left, FloatKind::Left) |
|
|
|
|
(ClearType::Right, FloatKind::Right) |
|
|
|
|
(ClearType::Both, _) => {
|
2014-07-19 00:27:23 +04:00
|
|
|
let b = self.offset.block + float.bounds.start.b + float.bounds.size.block;
|
|
|
|
clearance = max(clearance, b);
|
2014-02-28 00:01:49 +04:00
|
|
|
}
|
|
|
|
_ => {}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
clearance
|
|
|
|
}
|
2016-04-15 03:30:28 +03:00
|
|
|
|
|
|
|
pub fn is_present(&self) -> bool {
|
|
|
|
self.list.is_present()
|
|
|
|
}
|
2014-02-28 00:01:49 +04:00
|
|
|
}
|
2016-03-26 04:38:41 +03:00
|
|
|
|
|
|
|
/// The speculated inline sizes of floats flowing through or around a flow (depending on whether
|
|
|
|
/// the flow is a block formatting context). These speculations are always *upper bounds*; the
|
|
|
|
/// actual inline sizes might be less. Note that this implies that a speculated value of zero is a
|
|
|
|
/// guarantee that there will be no floats on that side.
|
|
|
|
///
|
|
|
|
/// This is used for two purposes: (a) determining whether we can lay out blocks in parallel; (b)
|
|
|
|
/// guessing the inline-sizes of block formatting contexts in an effort to lay them out in
|
|
|
|
/// parallel.
|
2017-08-24 01:18:31 +03:00
|
|
|
#[derive(Clone, Copy)]
|
2016-03-26 04:38:41 +03:00
|
|
|
pub struct SpeculatedFloatPlacement {
|
|
|
|
/// The estimated inline size (an upper bound) of the left floats flowing through this flow.
|
|
|
|
pub left: Au,
|
|
|
|
/// The estimated inline size (an upper bound) of the right floats flowing through this flow.
|
|
|
|
pub right: Au,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl fmt::Debug for SpeculatedFloatPlacement {
|
|
|
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
|
|
write!(f, "L {:?} R {:?}", self.left, self.right)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl SpeculatedFloatPlacement {
|
|
|
|
/// Returns a `SpeculatedFloatPlacement` objects with both left and right speculated inline
|
|
|
|
/// sizes initialized to zero.
|
|
|
|
pub fn zero() -> SpeculatedFloatPlacement {
|
|
|
|
SpeculatedFloatPlacement {
|
|
|
|
left: Au(0),
|
|
|
|
right: Au(0),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Given the speculated inline size of the floats out for the inorder predecessor of this
|
|
|
|
/// flow, computes the speculated inline size of the floats flowing in.
|
|
|
|
pub fn compute_floats_in(&mut self, flow: &mut Flow) {
|
2017-12-15 21:44:50 +03:00
|
|
|
let base_flow = flow.base();
|
2017-10-31 02:25:45 +03:00
|
|
|
if base_flow.flags.contains(FlowFlags::CLEARS_LEFT) {
|
2016-03-26 04:38:41 +03:00
|
|
|
self.left = Au(0)
|
|
|
|
}
|
2017-10-31 02:25:45 +03:00
|
|
|
if base_flow.flags.contains(FlowFlags::CLEARS_RIGHT) {
|
2016-03-26 04:38:41 +03:00
|
|
|
self.right = Au(0)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-03-29 13:34:01 +03:00
|
|
|
/// Given the speculated inline size of the floats out for this flow's last child, computes the
|
|
|
|
/// speculated inline size of the floats out for this flow.
|
2016-03-26 04:38:41 +03:00
|
|
|
pub fn compute_floats_out(&mut self, flow: &mut Flow) {
|
|
|
|
if flow.is_block_like() {
|
|
|
|
let block_flow = flow.as_block();
|
|
|
|
if block_flow.formatting_context_type() != FormattingContextType::None {
|
|
|
|
*self = block_flow.base.speculated_float_placement_in;
|
2016-05-11 10:41:00 +03:00
|
|
|
} else {
|
|
|
|
if self.left > Au(0) || self.right > Au(0) {
|
|
|
|
let speculated_inline_content_edge_offsets =
|
|
|
|
block_flow.fragment.guess_inline_content_edge_offsets();
|
|
|
|
if self.left > Au(0) && speculated_inline_content_edge_offsets.start > Au(0) {
|
|
|
|
self.left = self.left + speculated_inline_content_edge_offsets.start
|
|
|
|
}
|
|
|
|
if self.right > Au(0) && speculated_inline_content_edge_offsets.end > Au(0) {
|
|
|
|
self.right = self.right + speculated_inline_content_edge_offsets.end
|
|
|
|
}
|
2016-04-28 20:24:38 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
self.left = max(self.left, block_flow.base.speculated_float_placement_in.left);
|
|
|
|
self.right = max(self.right, block_flow.base.speculated_float_placement_in.right);
|
2016-03-26 04:38:41 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-12-15 21:44:50 +03:00
|
|
|
let base_flow = flow.base();
|
2016-05-04 23:49:23 +03:00
|
|
|
if !base_flow.flags.is_float() {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
let mut float_inline_size = base_flow.intrinsic_inline_sizes.preferred_inline_size;
|
|
|
|
if float_inline_size == Au(0) {
|
|
|
|
if flow.is_block_like() {
|
|
|
|
// Hack: If the size of the float is a percentage, then there's no way we can guess
|
|
|
|
// at its size now. So just pick an arbitrary nonzero value (in this case, 1px) so
|
|
|
|
// that the layout traversal logic will know that objects later in the document
|
|
|
|
// might flow around this float.
|
|
|
|
if let LengthOrPercentageOrAuto::Percentage(percentage) =
|
|
|
|
flow.as_block().fragment.style.content_inline_size() {
|
2017-06-15 23:37:04 +03:00
|
|
|
if percentage.0 > 0.0 {
|
2016-05-04 23:49:23 +03:00
|
|
|
float_inline_size = Au::from_px(1)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-03-26 04:38:41 +03:00
|
|
|
match base_flow.flags.float_kind() {
|
2017-12-06 04:35:25 +03:00
|
|
|
StyleFloat::None => {}
|
|
|
|
StyleFloat::Left => self.left = self.left + float_inline_size,
|
|
|
|
StyleFloat::Right => self.right = self.right + float_inline_size,
|
2016-03-26 04:38:41 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Given a flow, computes the speculated inline size of the floats in of its first child.
|
|
|
|
pub fn compute_floats_in_for_first_child(parent_flow: &mut Flow) -> SpeculatedFloatPlacement {
|
|
|
|
if !parent_flow.is_block_like() {
|
2017-12-15 21:44:50 +03:00
|
|
|
return parent_flow.base().speculated_float_placement_in
|
2016-03-26 04:38:41 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
let parent_block_flow = parent_flow.as_block();
|
|
|
|
if parent_block_flow.formatting_context_type() != FormattingContextType::None {
|
|
|
|
return SpeculatedFloatPlacement::zero()
|
|
|
|
}
|
|
|
|
|
|
|
|
let mut placement = parent_block_flow.base.speculated_float_placement_in;
|
|
|
|
let speculated_inline_content_edge_offsets =
|
|
|
|
parent_block_flow.fragment.guess_inline_content_edge_offsets();
|
|
|
|
|
2016-03-29 13:34:01 +03:00
|
|
|
if speculated_inline_content_edge_offsets.start > Au(0) {
|
|
|
|
placement.left = if placement.left > speculated_inline_content_edge_offsets.start {
|
|
|
|
placement.left - speculated_inline_content_edge_offsets.start
|
|
|
|
} else {
|
|
|
|
Au(0)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if speculated_inline_content_edge_offsets.end > Au(0) {
|
|
|
|
placement.right = if placement.right > speculated_inline_content_edge_offsets.end {
|
|
|
|
placement.right - speculated_inline_content_edge_offsets.end
|
|
|
|
} else {
|
|
|
|
Au(0)
|
|
|
|
}
|
|
|
|
}
|
2016-03-26 04:38:41 +03:00
|
|
|
|
|
|
|
placement
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|