From 39780e894b10928db798db7509a6da3e0a1afd67 Mon Sep 17 00:00:00 2001 From: Pu Xingyu Date: Sun, 11 Dec 2016 00:54:00 +0800 Subject: [PATCH] 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`. --- components/layout/flex.rs | 6 +-- components/layout/fragment.rs | 23 +++++++++- components/layout/model.rs | 86 +++++++++++++++++------------------ 3 files changed, 66 insertions(+), 49 deletions(-) diff --git a/components/layout/flex.rs b/components/layout/flex.rs index d84373a7c21..7b169674363 100644 --- a/components/layout/flex.rs +++ b/components/layout/flex.rs @@ -19,7 +19,7 @@ use fragment::{Fragment, FragmentBorderBoxIterator, Overflow}; use gfx::display_list::StackingContext; use gfx_traits::ScrollRootId; use layout_debug; -use model::{IntrinsicISizes, MaybeAuto, MinMaxConstraint}; +use model::{IntrinsicISizes, MaybeAuto, SizeConstraint}; use model::{specified, specified_or_none}; use std::cmp::{max, min}; use std::ops::Range; @@ -38,7 +38,7 @@ use style::values::computed::{LengthOrPercentageOrAutoOrContent, LengthOrPercent #[derive(Debug)] enum AxisSize { Definite(Au), - MinMax(MinMaxConstraint), + MinMax(SizeConstraint), Infinite, } @@ -62,7 +62,7 @@ impl AxisSize { } } LengthOrPercentageOrAuto::Auto => { - AxisSize::MinMax(MinMaxConstraint::new(content_size, min, max)) + AxisSize::MinMax(SizeConstraint::new(content_size, min, max, None)) } } } diff --git a/components/layout/fragment.rs b/components/layout/fragment.rs index f2ba5e83916..742da56a0b5 100644 --- a/components/layout/fragment.rs +++ b/components/layout/fragment.rs @@ -23,7 +23,7 @@ use inline::{InlineMetrics, LAST_FRAGMENT_OF_ELEMENT, LineMetrics}; use ipc_channel::ipc::IpcSender; #[cfg(debug_assertions)] use layout_debug; -use model::{self, IntrinsicISizes, IntrinsicISizesContribution, MaybeAuto}; +use model::{self, IntrinsicISizes, IntrinsicISizesContribution, MaybeAuto, SizeConstraint}; use msg::constellation_msg::PipelineId; use net_traits::image::base::{Image, ImageMetadata}; 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, 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 /// in the inline direction. This will generally be correct unless percentages are involved. /// diff --git a/components/layout/model.rs b/components/layout/model.rs index a0693e0d8f8..dd5d3435c75 100644 --- a/components/layout/model.rs +++ b/components/layout/model.rs @@ -504,64 +504,60 @@ impl ToGfxMatrix for ComputedMatrix { } } -// https://drafts.csswg.org/css2/visudet.html#min-max-widths -// https://drafts.csswg.org/css2/visudet.html#min-max-heights -/// A min or max constraint -/// -/// A `max` of `None` is equivalent to no limmit for the size in the given -/// dimension. The `min` is >= 0, as negative values are illegal and by -/// default `min` is 0. -#[derive(Debug)] -pub struct MinMaxConstraint { - min: Au, - max: Option +/// A min-size and max-size constraint. The constructor has a optional `border` +/// parameter, and when it is present the constraint will be subtracted. This is +/// 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. +#[derive(Clone, Copy, Debug)] +pub struct SizeConstraint { + min_size: Au, + max_size: Option, } -impl MinMaxConstraint { - /// Create a `MinMaxConstraint` for a dimension given the min, max, and content box size for - /// an axis - pub fn new(content_size: Option, min: LengthOrPercentage, - max: LengthOrPercentageOrNone) -> MinMaxConstraint { - let min = match min { - LengthOrPercentage::Length(length) => length, - LengthOrPercentage::Percentage(percent) => { - match content_size { - Some(size) => size.scale_by(percent), - None => Au(0), - } - }, - LengthOrPercentage::Calc(calc) => { - match content_size { - Some(size) => size.scale_by(calc.percentage()), - None => Au(0), - } +impl SizeConstraint { + /// Create a `SizeConstraint` for an axis. + pub fn new(container_size: Option, + min_size: LengthOrPercentage, + max_size: LengthOrPercentageOrNone, + border: Option) -> SizeConstraint { + let mut min_size = match container_size { + Some(container_size) => specified(min_size, container_size), + None => if let LengthOrPercentage::Length(length) = min_size { + length + } else { + Au(0) } }; - let max = match max { - LengthOrPercentageOrNone::Length(length) => Some(length), - LengthOrPercentageOrNone::Percentage(percent) => { - content_size.map(|size| size.scale_by(percent)) - }, - LengthOrPercentageOrNone::Calc(calc) => { - content_size.map(|size| size.scale_by(calc.percentage())) + let mut max_size = match container_size { + Some(container_size) => specified_or_none(max_size, container_size), + None => if let LengthOrPercentageOrNone::Length(length) = max_size { + Some(length) + } else { + None } - LengthOrPercentageOrNone::None => None, }; + // Make sure max size is not smaller than min size. + max_size = max_size.map(|x| max(x, min_size)); - MinMaxConstraint { - min: min, - max: max + if let Some(border) = border { + min_size = max((min_size - border), Au(0)); + 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 { - if other < self.min { - self.min + if other < self.min_size { + self.min_size } else { - match self.max { - Some(max) if max < other => max, + match self.max_size { + Some(max_size) if max_size < other => max_size, _ => other } }