Rename the MinMaxConstraint to SizeConstraint and enhancement

Renamed to `SizeConstraint`, add an optional `border` parameter to
deal with `box-sizing: border-box`, and fix its bug when involving
with `calc`.
This commit is contained in:
Pu Xingyu 2016-12-11 00:54:00 +08:00
parent b9a8ccd775
commit 39780e894b
3 changed files with 66 additions and 49 deletions

View file

@ -19,7 +19,7 @@ use fragment::{Fragment, FragmentBorderBoxIterator, Overflow};
use gfx::display_list::StackingContext; use gfx::display_list::StackingContext;
use gfx_traits::ScrollRootId; use gfx_traits::ScrollRootId;
use layout_debug; use layout_debug;
use model::{IntrinsicISizes, MaybeAuto, MinMaxConstraint}; use model::{IntrinsicISizes, MaybeAuto, SizeConstraint};
use model::{specified, specified_or_none}; use model::{specified, specified_or_none};
use std::cmp::{max, min}; use std::cmp::{max, min};
use std::ops::Range; use std::ops::Range;
@ -38,7 +38,7 @@ use style::values::computed::{LengthOrPercentageOrAutoOrContent, LengthOrPercent
#[derive(Debug)] #[derive(Debug)]
enum AxisSize { enum AxisSize {
Definite(Au), Definite(Au),
MinMax(MinMaxConstraint), MinMax(SizeConstraint),
Infinite, Infinite,
} }
@ -62,7 +62,7 @@ impl AxisSize {
} }
} }
LengthOrPercentageOrAuto::Auto => { LengthOrPercentageOrAuto::Auto => {
AxisSize::MinMax(MinMaxConstraint::new(content_size, min, max)) AxisSize::MinMax(SizeConstraint::new(content_size, min, max, None))
} }
} }
} }

View file

@ -23,7 +23,7 @@ use inline::{InlineMetrics, LAST_FRAGMENT_OF_ELEMENT, LineMetrics};
use ipc_channel::ipc::IpcSender; use ipc_channel::ipc::IpcSender;
#[cfg(debug_assertions)] #[cfg(debug_assertions)]
use layout_debug; use layout_debug;
use model::{self, IntrinsicISizes, IntrinsicISizesContribution, MaybeAuto}; use model::{self, IntrinsicISizes, IntrinsicISizesContribution, MaybeAuto, SizeConstraint};
use msg::constellation_msg::PipelineId; use msg::constellation_msg::PipelineId;
use net_traits::image::base::{Image, ImageMetadata}; use net_traits::image::base::{Image, ImageMetadata};
use net_traits::image_cache_thread::{ImageOrMetadataAvailable, UsePlaceholder}; use net_traits::image_cache_thread::{ImageOrMetadataAvailable, UsePlaceholder};
@ -1202,6 +1202,27 @@ impl Fragment {
} }
} }
/// Return a size constraint that can be used the clamp size in given direction.
/// To take `box-sizing: border-box` into account, the `border_padding` field
/// must be initialized first.
///
/// TODO(stshine): Maybe there is a more convenient way.
pub fn size_constraint(&self, containing_size: Option<Au>, direction: Direction) -> SizeConstraint {
let (style_min_size, style_max_size) = match direction {
Direction::Inline => (self.style.min_inline_size(), self.style.max_inline_size()),
Direction::Block => (self.style.min_block_size(), self.style.max_block_size())
};
let border = if self.style().get_position().box_sizing == box_sizing::T::border_box {
Some(self.border_padding.start_end(direction))
} else {
None
};
SizeConstraint::new(containing_size, style_min_size, style_max_size, border)
}
/// Returns a guess as to the distances from the margin edge of this fragment to its content /// Returns a guess as to the distances from the margin edge of this fragment to its content
/// in the inline direction. This will generally be correct unless percentages are involved. /// in the inline direction. This will generally be correct unless percentages are involved.
/// ///

View file

@ -504,64 +504,60 @@ impl ToGfxMatrix for ComputedMatrix {
} }
} }
// https://drafts.csswg.org/css2/visudet.html#min-max-widths /// A min-size and max-size constraint. The constructor has a optional `border`
// https://drafts.csswg.org/css2/visudet.html#min-max-heights /// parameter, and when it is present the constraint will be subtracted. This is
/// A min or max constraint /// used to adjust the constraint for `box-sizing: border-box`, and when you do so
/// /// make sure the size you want to clamp is intended to be used for content box.
/// A `max` of `None` is equivalent to no limmit for the size in the given #[derive(Clone, Copy, Debug)]
/// dimension. The `min` is >= 0, as negative values are illegal and by pub struct SizeConstraint {
/// default `min` is 0. min_size: Au,
#[derive(Debug)] max_size: Option<Au>,
pub struct MinMaxConstraint {
min: Au,
max: Option<Au>
} }
impl MinMaxConstraint { impl SizeConstraint {
/// Create a `MinMaxConstraint` for a dimension given the min, max, and content box size for /// Create a `SizeConstraint` for an axis.
/// an axis pub fn new(container_size: Option<Au>,
pub fn new(content_size: Option<Au>, min: LengthOrPercentage, min_size: LengthOrPercentage,
max: LengthOrPercentageOrNone) -> MinMaxConstraint { max_size: LengthOrPercentageOrNone,
let min = match min { border: Option<Au>) -> SizeConstraint {
LengthOrPercentage::Length(length) => length, let mut min_size = match container_size {
LengthOrPercentage::Percentage(percent) => { Some(container_size) => specified(min_size, container_size),
match content_size { None => if let LengthOrPercentage::Length(length) = min_size {
Some(size) => size.scale_by(percent), length
None => Au(0), } else {
} Au(0)
},
LengthOrPercentage::Calc(calc) => {
match content_size {
Some(size) => size.scale_by(calc.percentage()),
None => Au(0),
}
} }
}; };
let max = match max { let mut max_size = match container_size {
LengthOrPercentageOrNone::Length(length) => Some(length), Some(container_size) => specified_or_none(max_size, container_size),
LengthOrPercentageOrNone::Percentage(percent) => { None => if let LengthOrPercentageOrNone::Length(length) = max_size {
content_size.map(|size| size.scale_by(percent)) Some(length)
}, } else {
LengthOrPercentageOrNone::Calc(calc) => { None
content_size.map(|size| size.scale_by(calc.percentage()))
} }
LengthOrPercentageOrNone::None => None,
}; };
// Make sure max size is not smaller than min size.
max_size = max_size.map(|x| max(x, min_size));
MinMaxConstraint { if let Some(border) = border {
min: min, min_size = max((min_size - border), Au(0));
max: max max_size = max_size.map(|x| max(x - border, Au(0)));
}
SizeConstraint {
min_size: min_size,
max_size: max_size
} }
} }
/// Clamp the given size by the given `min` and `max` constraints. /// Clamp the given size by the given min size and max size constraint.
pub fn clamp(&self, other: Au) -> Au { pub fn clamp(&self, other: Au) -> Au {
if other < self.min { if other < self.min_size {
self.min self.min_size
} else { } else {
match self.max { match self.max_size {
Some(max) if max < other => max, Some(max_size) if max_size < other => max_size,
_ => other _ => other
} }
} }