summaryrefslogtreecommitdiffstats
path: root/servo/components/style/values/computed/length.rs
diff options
context:
space:
mode:
Diffstat (limited to 'servo/components/style/values/computed/length.rs')
-rw-r--r--servo/components/style/values/computed/length.rs531
1 files changed, 531 insertions, 0 deletions
diff --git a/servo/components/style/values/computed/length.rs b/servo/components/style/values/computed/length.rs
new file mode 100644
index 0000000000..e75676a76d
--- /dev/null
+++ b/servo/components/style/values/computed/length.rs
@@ -0,0 +1,531 @@
+/* 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 https://mozilla.org/MPL/2.0/. */
+
+//! `<length>` computed values, and related ones.
+
+use super::{Context, Number, ToComputedValue};
+use crate::values::animated::ToAnimatedValue;
+use crate::values::computed::NonNegativeNumber;
+use crate::values::generics::length as generics;
+use crate::values::generics::length::{
+ GenericLengthOrNumber, GenericLengthPercentageOrNormal, GenericMaxSize, GenericSize,
+};
+use crate::values::generics::NonNegative;
+use crate::values::specified::length::{AbsoluteLength, FontBaseSize, LineHeightBase};
+use crate::values::{specified, CSSFloat};
+use crate::Zero;
+use app_units::Au;
+use std::fmt::{self, Write};
+use std::ops::{Add, AddAssign, Div, Mul, MulAssign, Neg, Sub};
+use style_traits::{CSSPixel, CssWriter, ToCss};
+
+pub use super::image::Image;
+pub use super::length_percentage::{LengthPercentage, NonNegativeLengthPercentage};
+pub use crate::values::specified::url::UrlOrNone;
+pub use crate::values::specified::{Angle, BorderStyle, Time};
+
+impl ToComputedValue for specified::NoCalcLength {
+ type ComputedValue = Length;
+
+ #[inline]
+ fn to_computed_value(&self, context: &Context) -> Self::ComputedValue {
+ self.to_computed_value_with_base_size(
+ context,
+ FontBaseSize::CurrentStyle,
+ LineHeightBase::CurrentStyle,
+ )
+ }
+
+ #[inline]
+ fn from_computed_value(computed: &Self::ComputedValue) -> Self {
+ Self::Absolute(AbsoluteLength::Px(computed.px()))
+ }
+}
+
+impl specified::NoCalcLength {
+ /// Computes a length with a given font-relative base size.
+ pub fn to_computed_value_with_base_size(
+ &self,
+ context: &Context,
+ base_size: FontBaseSize,
+ line_height_base: LineHeightBase,
+ ) -> Length {
+ match *self {
+ Self::Absolute(length) => length.to_computed_value(context),
+ Self::FontRelative(length) => {
+ length.to_computed_value(context, base_size, line_height_base)
+ },
+ Self::ViewportPercentage(length) => length.to_computed_value(context),
+ Self::ContainerRelative(length) => length.to_computed_value(context),
+ Self::ServoCharacterWidth(length) => length
+ .to_computed_value(context.style().get_font().clone_font_size().computed_size()),
+ }
+ }
+}
+
+impl ToComputedValue for specified::Length {
+ type ComputedValue = Length;
+
+ #[inline]
+ fn to_computed_value(&self, context: &Context) -> Self::ComputedValue {
+ match *self {
+ Self::NoCalc(l) => l.to_computed_value(context),
+ Self::Calc(ref calc) => {
+ let result = calc.to_computed_value(context);
+ debug_assert!(
+ result.to_length().is_some(),
+ "{:?} didn't resolve to a length: {:?}",
+ calc,
+ result,
+ );
+ result.to_length().unwrap_or_else(Length::zero)
+ },
+ }
+ }
+
+ #[inline]
+ fn from_computed_value(computed: &Self::ComputedValue) -> Self {
+ Self::NoCalc(specified::NoCalcLength::from_computed_value(computed))
+ }
+}
+
+/// Some boilerplate to share between negative and non-negative
+/// length-percentage or auto.
+macro_rules! computed_length_percentage_or_auto {
+ ($inner:ty) => {
+ /// Returns the used value.
+ #[inline]
+ pub fn to_used_value(&self, percentage_basis: Au) -> Option<Au> {
+ match *self {
+ Self::Auto => None,
+ Self::LengthPercentage(ref lp) => Some(lp.to_used_value(percentage_basis)),
+ }
+ }
+
+ /// Returns true if the computed value is absolute 0 or 0%.
+ #[inline]
+ pub fn is_definitely_zero(&self) -> bool {
+ use crate::values::generics::length::LengthPercentageOrAuto::*;
+ match *self {
+ LengthPercentage(ref l) => l.is_definitely_zero(),
+ Auto => false,
+ }
+ }
+ };
+}
+
+/// A computed type for `<length-percentage> | auto`.
+pub type LengthPercentageOrAuto = generics::GenericLengthPercentageOrAuto<LengthPercentage>;
+
+impl LengthPercentageOrAuto {
+ /// Clamps the value to a non-negative value.
+ pub fn clamp_to_non_negative(self) -> Self {
+ use crate::values::generics::length::LengthPercentageOrAuto::*;
+ match self {
+ LengthPercentage(l) => LengthPercentage(l.clamp_to_non_negative()),
+ Auto => Auto,
+ }
+ }
+
+ /// Convert to have a borrow inside the enum
+ pub fn as_ref(&self) -> generics::GenericLengthPercentageOrAuto<&LengthPercentage> {
+ use crate::values::generics::length::LengthPercentageOrAuto::*;
+ match *self {
+ LengthPercentage(ref lp) => LengthPercentage(lp),
+ Auto => Auto,
+ }
+ }
+
+ computed_length_percentage_or_auto!(LengthPercentage);
+}
+
+impl generics::GenericLengthPercentageOrAuto<&LengthPercentage> {
+ /// Resolves the percentage.
+ #[inline]
+ pub fn percentage_relative_to(&self, basis: Length) -> LengthOrAuto {
+ use crate::values::generics::length::LengthPercentageOrAuto::*;
+ match self {
+ LengthPercentage(length_percentage) => {
+ LengthPercentage(length_percentage.percentage_relative_to(basis))
+ },
+ Auto => Auto,
+ }
+ }
+
+ /// Maybe resolves the percentage.
+ #[inline]
+ pub fn maybe_percentage_relative_to(&self, basis: Option<Length>) -> LengthOrAuto {
+ use crate::values::generics::length::LengthPercentageOrAuto::*;
+ match self {
+ LengthPercentage(length_percentage) => length_percentage
+ .maybe_percentage_relative_to(basis)
+ .map_or(Auto, LengthPercentage),
+ Auto => Auto,
+ }
+ }
+}
+
+/// A wrapper of LengthPercentageOrAuto, whose value must be >= 0.
+pub type NonNegativeLengthPercentageOrAuto =
+ generics::GenericLengthPercentageOrAuto<NonNegativeLengthPercentage>;
+
+impl NonNegativeLengthPercentageOrAuto {
+ computed_length_percentage_or_auto!(NonNegativeLengthPercentage);
+}
+
+#[cfg(feature = "servo")]
+impl MaxSize {
+ /// Convert the computed value into used value.
+ #[inline]
+ pub fn to_used_value(&self, percentage_basis: Au) -> Option<Au> {
+ match *self {
+ GenericMaxSize::None => None,
+ GenericMaxSize::LengthPercentage(ref lp) => Some(lp.to_used_value(percentage_basis)),
+ }
+ }
+}
+
+impl Size {
+ /// Convert the computed value into used value.
+ #[inline]
+ #[cfg(feature = "servo")]
+ pub fn to_used_value(&self, percentage_basis: Au) -> Option<Au> {
+ match *self {
+ GenericSize::Auto => None,
+ GenericSize::LengthPercentage(ref lp) => Some(lp.to_used_value(percentage_basis)),
+ }
+ }
+
+ /// Returns true if the computed value is absolute 0 or 0%.
+ #[inline]
+ pub fn is_definitely_zero(&self) -> bool {
+ match *self {
+ Self::Auto => false,
+ Self::LengthPercentage(ref lp) => lp.is_definitely_zero(),
+ #[cfg(feature = "gecko")]
+ Self::MinContent |
+ Self::MaxContent |
+ Self::FitContent |
+ Self::MozAvailable |
+ Self::FitContentFunction(_) => false,
+ }
+ }
+}
+
+/// The computed `<length>` value.
+#[derive(
+ Animate,
+ Clone,
+ ComputeSquaredDistance,
+ Copy,
+ Deserialize,
+ MallocSizeOf,
+ PartialEq,
+ PartialOrd,
+ Serialize,
+ ToAnimatedValue,
+ ToAnimatedZero,
+ ToComputedValue,
+ ToResolvedValue,
+ ToShmem,
+)]
+#[repr(C)]
+pub struct CSSPixelLength(CSSFloat);
+
+impl fmt::Debug for CSSPixelLength {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ self.0.fmt(f)?;
+ f.write_str(" px")
+ }
+}
+
+impl CSSPixelLength {
+ /// Return a new CSSPixelLength.
+ #[inline]
+ pub fn new(px: CSSFloat) -> Self {
+ CSSPixelLength(px)
+ }
+
+ /// Returns a normalized (NaN turned to zero) version of this length.
+ #[inline]
+ pub fn normalized(self) -> Self {
+ Self::new(crate::values::normalize(self.0))
+ }
+
+ /// Returns a finite (normalized and clamped to float min and max) version of this length.
+ #[inline]
+ pub fn finite(self) -> Self {
+ Self::new(crate::values::normalize(self.0).min(f32::MAX).max(f32::MIN))
+ }
+
+ /// Scale the length by a given amount.
+ #[inline]
+ pub fn scale_by(self, scale: CSSFloat) -> Self {
+ CSSPixelLength(self.0 * scale)
+ }
+
+ /// Return the containing pixel value.
+ #[inline]
+ pub fn px(self) -> CSSFloat {
+ self.0
+ }
+
+ /// Return the length with app_unit i32 type.
+ #[inline]
+ pub fn to_i32_au(self) -> i32 {
+ Au::from(self).0
+ }
+
+ /// Return the absolute value of this length.
+ #[inline]
+ pub fn abs(self) -> Self {
+ CSSPixelLength::new(self.0.abs())
+ }
+
+ /// Return the clamped value of this length.
+ #[inline]
+ pub fn clamp_to_non_negative(self) -> Self {
+ CSSPixelLength::new(self.0.max(0.))
+ }
+
+ /// Returns the minimum between `self` and `other`.
+ #[inline]
+ pub fn min(self, other: Self) -> Self {
+ CSSPixelLength::new(self.0.min(other.0))
+ }
+
+ /// Returns the maximum between `self` and `other`.
+ #[inline]
+ pub fn max(self, other: Self) -> Self {
+ CSSPixelLength::new(self.0.max(other.0))
+ }
+
+ /// Sets `self` to the maximum between `self` and `other`.
+ #[inline]
+ pub fn max_assign(&mut self, other: Self) {
+ *self = self.max(other);
+ }
+
+ /// Clamp the value to a lower bound and an optional upper bound.
+ ///
+ /// Can be used for example with `min-width` and `max-width`.
+ #[inline]
+ pub fn clamp_between_extremums(self, min_size: Self, max_size: Option<Self>) -> Self {
+ self.clamp_below_max(max_size).max(min_size)
+ }
+
+ /// Clamp the value to an optional upper bound.
+ ///
+ /// Can be used for example with `max-width`.
+ #[inline]
+ pub fn clamp_below_max(self, max_size: Option<Self>) -> Self {
+ match max_size {
+ None => self,
+ Some(max_size) => self.min(max_size),
+ }
+ }
+}
+
+impl num_traits::Zero for CSSPixelLength {
+ fn zero() -> Self {
+ CSSPixelLength::new(0.)
+ }
+
+ fn is_zero(&self) -> bool {
+ self.px() == 0.
+ }
+}
+
+impl ToCss for CSSPixelLength {
+ #[inline]
+ fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
+ where
+ W: Write,
+ {
+ self.0.to_css(dest)?;
+ dest.write_str("px")
+ }
+}
+
+impl std::iter::Sum for CSSPixelLength {
+ fn sum<I: Iterator<Item = Self>>(iter: I) -> Self {
+ iter.fold(Length::zero(), Add::add)
+ }
+}
+
+impl Add for CSSPixelLength {
+ type Output = Self;
+
+ #[inline]
+ fn add(self, other: Self) -> Self {
+ Self::new(self.px() + other.px())
+ }
+}
+
+impl AddAssign for CSSPixelLength {
+ #[inline]
+ fn add_assign(&mut self, other: Self) {
+ self.0 += other.0;
+ }
+}
+
+impl Div for CSSPixelLength {
+ type Output = CSSFloat;
+
+ #[inline]
+ fn div(self, other: Self) -> CSSFloat {
+ self.px() / other.px()
+ }
+}
+
+impl Div<CSSFloat> for CSSPixelLength {
+ type Output = Self;
+
+ #[inline]
+ fn div(self, other: CSSFloat) -> Self {
+ Self::new(self.px() / other)
+ }
+}
+
+impl MulAssign<CSSFloat> for CSSPixelLength {
+ #[inline]
+ fn mul_assign(&mut self, other: CSSFloat) {
+ self.0 *= other;
+ }
+}
+
+impl Mul<CSSFloat> for CSSPixelLength {
+ type Output = Self;
+
+ #[inline]
+ fn mul(self, other: CSSFloat) -> Self {
+ Self::new(self.px() * other)
+ }
+}
+
+impl Neg for CSSPixelLength {
+ type Output = Self;
+
+ #[inline]
+ fn neg(self) -> Self {
+ CSSPixelLength::new(-self.0)
+ }
+}
+
+impl Sub for CSSPixelLength {
+ type Output = Self;
+
+ #[inline]
+ fn sub(self, other: Self) -> Self {
+ Self::new(self.px() - other.px())
+ }
+}
+
+impl From<CSSPixelLength> for Au {
+ #[inline]
+ fn from(len: CSSPixelLength) -> Self {
+ Au::from_f32_px(len.0)
+ }
+}
+
+impl From<Au> for CSSPixelLength {
+ #[inline]
+ fn from(len: Au) -> Self {
+ CSSPixelLength::new(len.to_f32_px())
+ }
+}
+
+impl From<CSSPixelLength> for euclid::Length<CSSFloat, CSSPixel> {
+ #[inline]
+ fn from(length: CSSPixelLength) -> Self {
+ Self::new(length.0)
+ }
+}
+
+/// An alias of computed `<length>` value.
+pub type Length = CSSPixelLength;
+
+/// Either a computed `<length>` or the `auto` keyword.
+pub type LengthOrAuto = generics::GenericLengthPercentageOrAuto<Length>;
+
+/// Either a non-negative `<length>` or the `auto` keyword.
+pub type NonNegativeLengthOrAuto = generics::GenericLengthPercentageOrAuto<NonNegativeLength>;
+
+/// Either a computed `<length>` or a `<number>` value.
+pub type LengthOrNumber = GenericLengthOrNumber<Length, Number>;
+
+/// A wrapper of Length, whose value must be >= 0.
+pub type NonNegativeLength = NonNegative<Length>;
+
+impl ToAnimatedValue for NonNegativeLength {
+ type AnimatedValue = Length;
+
+ #[inline]
+ fn to_animated_value(self) -> Self::AnimatedValue {
+ self.0
+ }
+
+ #[inline]
+ fn from_animated_value(animated: Self::AnimatedValue) -> Self {
+ NonNegativeLength::new(animated.px().max(0.))
+ }
+}
+
+impl NonNegativeLength {
+ /// Create a NonNegativeLength.
+ #[inline]
+ pub fn new(px: CSSFloat) -> Self {
+ NonNegative(Length::new(px.max(0.)))
+ }
+
+ /// Return the pixel value of |NonNegativeLength|.
+ #[inline]
+ pub fn px(&self) -> CSSFloat {
+ self.0.px()
+ }
+
+ #[inline]
+ /// Ensures it is non negative
+ pub fn clamp(self) -> Self {
+ if (self.0).0 < 0. {
+ Self::zero()
+ } else {
+ self
+ }
+ }
+}
+
+impl From<Length> for NonNegativeLength {
+ #[inline]
+ fn from(len: Length) -> Self {
+ NonNegative(len)
+ }
+}
+
+impl From<Au> for NonNegativeLength {
+ #[inline]
+ fn from(au: Au) -> Self {
+ NonNegative(au.into())
+ }
+}
+
+impl From<NonNegativeLength> for Au {
+ #[inline]
+ fn from(non_negative_len: NonNegativeLength) -> Self {
+ Au::from(non_negative_len.0)
+ }
+}
+
+/// Either a computed NonNegativeLengthPercentage or the `normal` keyword.
+pub type NonNegativeLengthPercentageOrNormal =
+ GenericLengthPercentageOrNormal<NonNegativeLengthPercentage>;
+
+/// Either a non-negative `<length>` or a `<number>`.
+pub type NonNegativeLengthOrNumber = GenericLengthOrNumber<NonNegativeLength, NonNegativeNumber>;
+
+/// A computed value for `min-width`, `min-height`, `width` or `height` property.
+pub type Size = GenericSize<NonNegativeLengthPercentage>;
+
+/// A computed value for `max-width` or `min-height` property.
+pub type MaxSize = GenericMaxSize<NonNegativeLengthPercentage>;