aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorYuki Izumi <kivikakk@github.com>2016-11-05 17:41:50 +1100
committerYuki Izumi <kivikakk@github.com>2016-11-06 14:11:37 +1100
commitf33f5605ba4a6684ac4af61b5d2d1d75ddfdb6d2 (patch)
tree03a32b66077ec4a1231c545f530ec1a64fca1857
parent465619ca37c2a6bc7f60d25bf8bbd064e6c79ac0 (diff)
downloadservo-f33f5605ba4a6684ac4af61b5d2d1d75ddfdb6d2.tar.gz
servo-f33f5605ba4a6684ac4af61b5d2d1d75ddfdb6d2.zip
Refactor style lengths per #13584
-rw-r--r--components/style/values/computed/length.rs508
-rw-r--r--components/style/values/computed/mod.rs499
-rw-r--r--components/style/values/specified/length.rs1004
-rw-r--r--components/style/values/specified/mod.rs998
4 files changed, 1524 insertions, 1485 deletions
diff --git a/components/style/values/computed/length.rs b/components/style/values/computed/length.rs
new file mode 100644
index 00000000000..72056f0bbdd
--- /dev/null
+++ b/components/style/values/computed/length.rs
@@ -0,0 +1,508 @@
+/* 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/. */
+
+use app_units::Au;
+use ordered_float::NotNaN;
+use std::fmt;
+use super::{ToComputedValue, Context};
+use values::{CSSFloat, LocalToCss, specified};
+
+pub use cssparser::Color as CSSColor;
+pub use super::image::{EndingShape as GradientShape, Gradient, GradientKind, Image};
+pub use super::image::{LengthOrKeyword, LengthOrPercentageOrKeyword};
+pub use values::specified::{Angle, BorderStyle, Time, UrlExtraData, UrlOrNone};
+
+#[derive(Clone, PartialEq, Copy, Debug)]
+#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
+pub struct CalcLengthOrPercentage {
+ pub length: Option<Au>,
+ pub percentage: Option<CSSFloat>,
+}
+
+impl CalcLengthOrPercentage {
+ #[inline]
+ pub fn length(&self) -> Au {
+ self.length.unwrap_or(Au(0))
+ }
+
+ #[inline]
+ pub fn percentage(&self) -> CSSFloat {
+ self.percentage.unwrap_or(0.)
+ }
+}
+
+impl From<LengthOrPercentage> for CalcLengthOrPercentage {
+ fn from(len: LengthOrPercentage) -> CalcLengthOrPercentage {
+ match len {
+ LengthOrPercentage::Percentage(this) => {
+ CalcLengthOrPercentage {
+ length: None,
+ percentage: Some(this),
+ }
+ }
+ LengthOrPercentage::Length(this) => {
+ CalcLengthOrPercentage {
+ length: Some(this),
+ percentage: None,
+ }
+ }
+ LengthOrPercentage::Calc(this) => {
+ this
+ }
+ }
+ }
+}
+
+impl From<LengthOrPercentageOrAuto> for Option<CalcLengthOrPercentage> {
+ fn from(len: LengthOrPercentageOrAuto) -> Option<CalcLengthOrPercentage> {
+ match len {
+ LengthOrPercentageOrAuto::Percentage(this) => {
+ Some(CalcLengthOrPercentage {
+ length: None,
+ percentage: Some(this),
+ })
+ }
+ LengthOrPercentageOrAuto::Length(this) => {
+ Some(CalcLengthOrPercentage {
+ length: Some(this),
+ percentage: None,
+ })
+ }
+ LengthOrPercentageOrAuto::Calc(this) => {
+ Some(this)
+ }
+ LengthOrPercentageOrAuto::Auto => {
+ None
+ }
+ }
+ }
+}
+
+impl ::cssparser::ToCss for CalcLengthOrPercentage {
+ fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
+ match (self.length, self.percentage) {
+ (None, Some(p)) => write!(dest, "{}%", p * 100.),
+ (Some(l), None) => write!(dest, "{}px", Au::to_px(l)),
+ (Some(l), Some(p)) => write!(dest, "calc({}px + {}%)", Au::to_px(l), p * 100.),
+ _ => unreachable!()
+ }
+ }
+}
+
+impl ToComputedValue for specified::CalcLengthOrPercentage {
+ type ComputedValue = CalcLengthOrPercentage;
+
+ fn to_computed_value(&self, context: &Context) -> CalcLengthOrPercentage {
+ self.compute_from_viewport_and_font_size(context.viewport_size(),
+ context.style().get_font().clone_font_size(),
+ context.style().root_font_size())
+
+ }
+
+ #[inline]
+ fn from_computed_value(computed: &CalcLengthOrPercentage) -> Self {
+ specified::CalcLengthOrPercentage {
+ absolute: computed.length,
+ percentage: computed.percentage.map(specified::Percentage),
+ ..Default::default()
+ }
+ }
+}
+
+#[derive(PartialEq, Clone, Copy)]
+#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
+pub enum LengthOrPercentage {
+ Length(Au),
+ Percentage(CSSFloat),
+ Calc(CalcLengthOrPercentage),
+}
+
+impl LengthOrPercentage {
+ #[inline]
+ pub fn zero() -> LengthOrPercentage {
+ LengthOrPercentage::Length(Au(0))
+ }
+
+ /// Returns true if the computed value is absolute 0 or 0%.
+ ///
+ /// (Returns false for calc() values, even if ones that may resolve to zero.)
+ #[inline]
+ pub fn is_definitely_zero(&self) -> bool {
+ use self::LengthOrPercentage::*;
+ match *self {
+ Length(Au(0)) | Percentage(0.0) => true,
+ Length(_) | Percentage(_) | Calc(_) => false
+ }
+ }
+
+ pub fn to_hash_key(&self) -> (Au, NotNaN<f32>) {
+ use self::LengthOrPercentage::*;
+ match *self {
+ Length(l) => (l, NotNaN::new(0.0).unwrap()),
+ Percentage(p) => (Au(0), NotNaN::new(p).unwrap()),
+ Calc(c) => (c.length(), NotNaN::new(c.percentage()).unwrap()),
+ }
+ }
+}
+
+impl fmt::Debug for LengthOrPercentage {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ match *self {
+ LengthOrPercentage::Length(length) => write!(f, "{:?}", length),
+ LengthOrPercentage::Percentage(percentage) => write!(f, "{}%", percentage * 100.),
+ LengthOrPercentage::Calc(calc) => write!(f, "{:?}", calc),
+ }
+ }
+}
+
+impl ToComputedValue for specified::LengthOrPercentage {
+ type ComputedValue = LengthOrPercentage;
+
+ fn to_computed_value(&self, context: &Context) -> LengthOrPercentage {
+ match *self {
+ specified::LengthOrPercentage::Length(value) => {
+ LengthOrPercentage::Length(value.to_computed_value(context))
+ }
+ specified::LengthOrPercentage::Percentage(value) => {
+ LengthOrPercentage::Percentage(value.0)
+ }
+ specified::LengthOrPercentage::Calc(calc) => {
+ LengthOrPercentage::Calc(calc.to_computed_value(context))
+ }
+ }
+ }
+
+ fn from_computed_value(computed: &LengthOrPercentage) -> Self {
+ match *computed {
+ LengthOrPercentage::Length(value) => {
+ specified::LengthOrPercentage::Length(
+ ToComputedValue::from_computed_value(&value)
+ )
+ }
+ LengthOrPercentage::Percentage(value) => {
+ specified::LengthOrPercentage::Percentage(specified::Percentage(value))
+ }
+ LengthOrPercentage::Calc(calc) => {
+ specified::LengthOrPercentage::Calc(
+ ToComputedValue::from_computed_value(&calc)
+ )
+ }
+ }
+ }
+}
+
+impl ::cssparser::ToCss for LengthOrPercentage {
+ fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
+ match *self {
+ LengthOrPercentage::Length(length) => length.to_css(dest),
+ LengthOrPercentage::Percentage(percentage)
+ => write!(dest, "{}%", percentage * 100.),
+ LengthOrPercentage::Calc(calc) => calc.to_css(dest),
+ }
+ }
+}
+
+#[derive(PartialEq, Clone, Copy)]
+#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
+pub enum LengthOrPercentageOrAuto {
+ Length(Au),
+ Percentage(CSSFloat),
+ Auto,
+ Calc(CalcLengthOrPercentage),
+}
+
+impl LengthOrPercentageOrAuto {
+ /// Returns true if the computed value is absolute 0 or 0%.
+ ///
+ /// (Returns false for calc() values, even if ones that may resolve to zero.)
+ #[inline]
+ pub fn is_definitely_zero(&self) -> bool {
+ use self::LengthOrPercentageOrAuto::*;
+ match *self {
+ Length(Au(0)) | Percentage(0.0) => true,
+ Length(_) | Percentage(_) | Calc(_) | Auto => false
+ }
+ }
+}
+
+impl fmt::Debug for LengthOrPercentageOrAuto {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ match *self {
+ LengthOrPercentageOrAuto::Length(length) => write!(f, "{:?}", length),
+ LengthOrPercentageOrAuto::Percentage(percentage) => write!(f, "{}%", percentage * 100.),
+ LengthOrPercentageOrAuto::Auto => write!(f, "auto"),
+ LengthOrPercentageOrAuto::Calc(calc) => write!(f, "{:?}", calc),
+ }
+ }
+}
+
+impl ToComputedValue for specified::LengthOrPercentageOrAuto {
+ type ComputedValue = LengthOrPercentageOrAuto;
+
+ #[inline]
+ fn to_computed_value(&self, context: &Context) -> LengthOrPercentageOrAuto {
+ match *self {
+ specified::LengthOrPercentageOrAuto::Length(value) => {
+ LengthOrPercentageOrAuto::Length(value.to_computed_value(context))
+ }
+ specified::LengthOrPercentageOrAuto::Percentage(value) => {
+ LengthOrPercentageOrAuto::Percentage(value.0)
+ }
+ specified::LengthOrPercentageOrAuto::Auto => {
+ LengthOrPercentageOrAuto::Auto
+ }
+ specified::LengthOrPercentageOrAuto::Calc(calc) => {
+ LengthOrPercentageOrAuto::Calc(calc.to_computed_value(context))
+ }
+ }
+ }
+
+ #[inline]
+ fn from_computed_value(computed: &LengthOrPercentageOrAuto) -> Self {
+ match *computed {
+ LengthOrPercentageOrAuto::Auto => specified::LengthOrPercentageOrAuto::Auto,
+ LengthOrPercentageOrAuto::Length(value) => {
+ specified::LengthOrPercentageOrAuto::Length(
+ ToComputedValue::from_computed_value(&value)
+ )
+ }
+ LengthOrPercentageOrAuto::Percentage(value) => {
+ specified::LengthOrPercentageOrAuto::Percentage(specified::Percentage(value))
+ }
+ LengthOrPercentageOrAuto::Calc(calc) => {
+ specified::LengthOrPercentageOrAuto::Calc(
+ ToComputedValue::from_computed_value(&calc)
+ )
+ }
+ }
+ }
+}
+
+impl ::cssparser::ToCss for LengthOrPercentageOrAuto {
+ fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
+ match *self {
+ LengthOrPercentageOrAuto::Length(length) => length.to_css(dest),
+ LengthOrPercentageOrAuto::Percentage(percentage)
+ => write!(dest, "{}%", percentage * 100.),
+ LengthOrPercentageOrAuto::Auto => dest.write_str("auto"),
+ LengthOrPercentageOrAuto::Calc(calc) => calc.to_css(dest),
+ }
+ }
+}
+
+#[derive(PartialEq, Clone, Copy)]
+#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
+pub enum LengthOrPercentageOrAutoOrContent {
+ Length(Au),
+ Percentage(CSSFloat),
+ Calc(CalcLengthOrPercentage),
+ Auto,
+ Content
+}
+
+impl fmt::Debug for LengthOrPercentageOrAutoOrContent {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ match *self {
+ LengthOrPercentageOrAutoOrContent::Length(length) => write!(f, "{:?}", length),
+ LengthOrPercentageOrAutoOrContent::Percentage(percentage) => write!(f, "{}%", percentage * 100.),
+ LengthOrPercentageOrAutoOrContent::Calc(calc) => write!(f, "{:?}", calc),
+ LengthOrPercentageOrAutoOrContent::Auto => write!(f, "auto"),
+ LengthOrPercentageOrAutoOrContent::Content => write!(f, "content")
+ }
+ }
+}
+
+impl ToComputedValue for specified::LengthOrPercentageOrAutoOrContent {
+ type ComputedValue = LengthOrPercentageOrAutoOrContent;
+
+ #[inline]
+ fn to_computed_value(&self, context: &Context) -> LengthOrPercentageOrAutoOrContent {
+ match *self {
+ specified::LengthOrPercentageOrAutoOrContent::Length(value) => {
+ LengthOrPercentageOrAutoOrContent::Length(value.to_computed_value(context))
+ },
+ specified::LengthOrPercentageOrAutoOrContent::Percentage(value) => {
+ LengthOrPercentageOrAutoOrContent::Percentage(value.0)
+ },
+ specified::LengthOrPercentageOrAutoOrContent::Calc(calc) => {
+ LengthOrPercentageOrAutoOrContent::Calc(calc.to_computed_value(context))
+ },
+ specified::LengthOrPercentageOrAutoOrContent::Auto => {
+ LengthOrPercentageOrAutoOrContent::Auto
+ },
+ specified::LengthOrPercentageOrAutoOrContent::Content => {
+ LengthOrPercentageOrAutoOrContent::Content
+ }
+ }
+ }
+
+
+ #[inline]
+ fn from_computed_value(computed: &LengthOrPercentageOrAutoOrContent) -> Self {
+ match *computed {
+ LengthOrPercentageOrAutoOrContent::Auto => {
+ specified::LengthOrPercentageOrAutoOrContent::Auto
+ }
+ LengthOrPercentageOrAutoOrContent::Content => {
+ specified::LengthOrPercentageOrAutoOrContent::Content
+ }
+ LengthOrPercentageOrAutoOrContent::Length(value) => {
+ specified::LengthOrPercentageOrAutoOrContent::Length(
+ ToComputedValue::from_computed_value(&value)
+ )
+ }
+ LengthOrPercentageOrAutoOrContent::Percentage(value) => {
+ specified::LengthOrPercentageOrAutoOrContent::Percentage(specified::Percentage(value))
+ }
+ LengthOrPercentageOrAutoOrContent::Calc(calc) => {
+ specified::LengthOrPercentageOrAutoOrContent::Calc(
+ ToComputedValue::from_computed_value(&calc)
+ )
+ }
+ }
+ }
+}
+
+impl ::cssparser::ToCss for LengthOrPercentageOrAutoOrContent {
+ fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
+ match *self {
+ LengthOrPercentageOrAutoOrContent::Length(length) => length.to_css(dest),
+ LengthOrPercentageOrAutoOrContent::Percentage(percentage)
+ => write!(dest, "{}%", percentage * 100.),
+ LengthOrPercentageOrAutoOrContent::Calc(calc) => calc.to_css(dest),
+ LengthOrPercentageOrAutoOrContent::Auto => dest.write_str("auto"),
+ LengthOrPercentageOrAutoOrContent::Content => dest.write_str("content")
+ }
+ }
+}
+
+#[derive(PartialEq, Clone, Copy)]
+#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
+pub enum LengthOrPercentageOrNone {
+ Length(Au),
+ Percentage(CSSFloat),
+ Calc(CalcLengthOrPercentage),
+ None,
+}
+
+impl fmt::Debug for LengthOrPercentageOrNone {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ match *self {
+ LengthOrPercentageOrNone::Length(length) => write!(f, "{:?}", length),
+ LengthOrPercentageOrNone::Percentage(percentage) => write!(f, "{}%", percentage * 100.),
+ LengthOrPercentageOrNone::Calc(calc) => write!(f, "{:?}", calc),
+ LengthOrPercentageOrNone::None => write!(f, "none"),
+ }
+ }
+}
+
+impl ToComputedValue for specified::LengthOrPercentageOrNone {
+ type ComputedValue = LengthOrPercentageOrNone;
+
+ #[inline]
+ fn to_computed_value(&self, context: &Context) -> LengthOrPercentageOrNone {
+ match *self {
+ specified::LengthOrPercentageOrNone::Length(value) => {
+ LengthOrPercentageOrNone::Length(value.to_computed_value(context))
+ }
+ specified::LengthOrPercentageOrNone::Percentage(value) => {
+ LengthOrPercentageOrNone::Percentage(value.0)
+ }
+ specified::LengthOrPercentageOrNone::Calc(calc) => {
+ LengthOrPercentageOrNone::Calc(calc.to_computed_value(context))
+ }
+ specified::LengthOrPercentageOrNone::None => {
+ LengthOrPercentageOrNone::None
+ }
+ }
+ }
+
+ #[inline]
+ fn from_computed_value(computed: &LengthOrPercentageOrNone) -> Self {
+ match *computed {
+ LengthOrPercentageOrNone::None => specified::LengthOrPercentageOrNone::None,
+ LengthOrPercentageOrNone::Length(value) => {
+ specified::LengthOrPercentageOrNone::Length(
+ ToComputedValue::from_computed_value(&value)
+ )
+ }
+ LengthOrPercentageOrNone::Percentage(value) => {
+ specified::LengthOrPercentageOrNone::Percentage(specified::Percentage(value))
+ }
+ LengthOrPercentageOrNone::Calc(calc) => {
+ specified::LengthOrPercentageOrNone::Calc(
+ ToComputedValue::from_computed_value(&calc)
+ )
+ }
+ }
+ }
+}
+
+impl ::cssparser::ToCss for LengthOrPercentageOrNone {
+ fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
+ match *self {
+ LengthOrPercentageOrNone::Length(length) => length.to_css(dest),
+ LengthOrPercentageOrNone::Percentage(percentage) =>
+ write!(dest, "{}%", percentage * 100.),
+ LengthOrPercentageOrNone::Calc(calc) => calc.to_css(dest),
+ LengthOrPercentageOrNone::None => dest.write_str("none"),
+ }
+ }
+}
+
+#[derive(PartialEq, Clone, Copy)]
+#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
+pub enum LengthOrNone {
+ Length(Au),
+ None,
+}
+
+impl fmt::Debug for LengthOrNone {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ match *self {
+ LengthOrNone::Length(length) => write!(f, "{:?}", length),
+ LengthOrNone::None => write!(f, "none"),
+ }
+ }
+}
+
+impl ToComputedValue for specified::LengthOrNone {
+ type ComputedValue = LengthOrNone;
+
+ #[inline]
+ fn to_computed_value(&self, context: &Context) -> LengthOrNone {
+ match *self {
+ specified::LengthOrNone::Length(specified::Length::Calc(calc, range)) => {
+ LengthOrNone::Length(range.clamp(calc.to_computed_value(context).length()))
+ }
+ specified::LengthOrNone::Length(value) => {
+ LengthOrNone::Length(value.to_computed_value(context))
+ }
+ specified::LengthOrNone::None => {
+ LengthOrNone::None
+ }
+ }
+ }
+
+ #[inline]
+ fn from_computed_value(computed: &LengthOrNone) -> Self {
+ match *computed {
+ LengthOrNone::Length(au) => {
+ specified::LengthOrNone::Length(ToComputedValue::from_computed_value(&au))
+ }
+ LengthOrNone::None => {
+ specified::LengthOrNone::None
+ }
+ }
+ }
+}
+
+impl ::cssparser::ToCss for LengthOrNone {
+ fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
+ match *self {
+ LengthOrNone::Length(length) => length.to_css(dest),
+ LengthOrNone::None => dest.write_str("none"),
+ }
+ }
+}
diff --git a/components/style/values/computed/mod.rs b/components/style/values/computed/mod.rs
index 42abdf5b933..de5dfa76844 100644
--- a/components/style/values/computed/mod.rs
+++ b/components/style/values/computed/mod.rs
@@ -4,19 +4,20 @@
use app_units::Au;
use euclid::size::Size2D;
-use ordered_float::NotNaN;
use properties::ComputedValues;
use std::fmt;
use super::{CSSFloat, specified};
-use super::LocalToCss;
pub use cssparser::Color as CSSColor;
pub use self::image::{EndingShape as GradientShape, Gradient, GradientKind, Image};
pub use self::image::{LengthOrKeyword, LengthOrPercentageOrKeyword};
pub use super::specified::{Angle, BorderStyle, Time, UrlExtraData, UrlOrNone};
+pub use self::length::{CalcLengthOrPercentage, LengthOrPercentage, LengthOrPercentageOrAuto};
+pub use self::length::{LengthOrPercentageOrAutoOrContent, LengthOrPercentageOrNone, LengthOrNone};
pub mod basic_shape;
pub mod image;
+pub mod length;
pub mod position;
pub struct Context<'a> {
@@ -110,104 +111,6 @@ impl ToComputedValue for specified::Length {
}
}
-#[derive(Clone, PartialEq, Copy, Debug)]
-#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
-pub struct CalcLengthOrPercentage {
- pub length: Option<Au>,
- pub percentage: Option<CSSFloat>,
-}
-
-impl CalcLengthOrPercentage {
- #[inline]
- pub fn length(&self) -> Au {
- self.length.unwrap_or(Au(0))
- }
-
- #[inline]
- pub fn percentage(&self) -> CSSFloat {
- self.percentage.unwrap_or(0.)
- }
-}
-
-impl From<LengthOrPercentage> for CalcLengthOrPercentage {
- fn from(len: LengthOrPercentage) -> CalcLengthOrPercentage {
- match len {
- LengthOrPercentage::Percentage(this) => {
- CalcLengthOrPercentage {
- length: None,
- percentage: Some(this),
- }
- }
- LengthOrPercentage::Length(this) => {
- CalcLengthOrPercentage {
- length: Some(this),
- percentage: None,
- }
- }
- LengthOrPercentage::Calc(this) => {
- this
- }
- }
- }
-}
-
-impl From<LengthOrPercentageOrAuto> for Option<CalcLengthOrPercentage> {
- fn from(len: LengthOrPercentageOrAuto) -> Option<CalcLengthOrPercentage> {
- match len {
- LengthOrPercentageOrAuto::Percentage(this) => {
- Some(CalcLengthOrPercentage {
- length: None,
- percentage: Some(this),
- })
- }
- LengthOrPercentageOrAuto::Length(this) => {
- Some(CalcLengthOrPercentage {
- length: Some(this),
- percentage: None,
- })
- }
- LengthOrPercentageOrAuto::Calc(this) => {
- Some(this)
- }
- LengthOrPercentageOrAuto::Auto => {
- None
- }
- }
- }
-}
-
-impl ::cssparser::ToCss for CalcLengthOrPercentage {
- fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
- match (self.length, self.percentage) {
- (None, Some(p)) => write!(dest, "{}%", p * 100.),
- (Some(l), None) => write!(dest, "{}px", Au::to_px(l)),
- (Some(l), Some(p)) => write!(dest, "calc({}px + {}%)", Au::to_px(l), p * 100.),
- _ => unreachable!()
- }
- }
-}
-
-impl ToComputedValue for specified::CalcLengthOrPercentage {
- type ComputedValue = CalcLengthOrPercentage;
-
- fn to_computed_value(&self, context: &Context) -> CalcLengthOrPercentage {
- self.compute_from_viewport_and_font_size(context.viewport_size(),
- context.style().get_font().clone_font_size(),
- context.style().root_font_size())
-
- }
-
- #[inline]
- fn from_computed_value(computed: &CalcLengthOrPercentage) -> Self {
- specified::CalcLengthOrPercentage {
- absolute: computed.length,
- percentage: computed.percentage.map(specified::Percentage),
- ..Default::default()
- }
- }
-}
-
-
#[derive(Debug, PartialEq, Clone, Copy)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
pub struct BorderRadiusSize(pub Size2D<LengthOrPercentage>);
@@ -244,402 +147,6 @@ impl ::cssparser::ToCss for BorderRadiusSize {
}
}
-#[derive(PartialEq, Clone, Copy)]
-#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
-pub enum LengthOrPercentage {
- Length(Au),
- Percentage(CSSFloat),
- Calc(CalcLengthOrPercentage),
-}
-
-impl LengthOrPercentage {
- #[inline]
- pub fn zero() -> LengthOrPercentage {
- LengthOrPercentage::Length(Au(0))
- }
-
- /// Returns true if the computed value is absolute 0 or 0%.
- ///
- /// (Returns false for calc() values, even if ones that may resolve to zero.)
- #[inline]
- pub fn is_definitely_zero(&self) -> bool {
- use self::LengthOrPercentage::*;
- match *self {
- Length(Au(0)) | Percentage(0.0) => true,
- Length(_) | Percentage(_) | Calc(_) => false
- }
- }
-
- pub fn to_hash_key(&self) -> (Au, NotNaN<f32>) {
- use self::LengthOrPercentage::*;
- match *self {
- Length(l) => (l, NotNaN::new(0.0).unwrap()),
- Percentage(p) => (Au(0), NotNaN::new(p).unwrap()),
- Calc(c) => (c.length(), NotNaN::new(c.percentage()).unwrap()),
- }
- }
-}
-
-impl fmt::Debug for LengthOrPercentage {
- fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- match *self {
- LengthOrPercentage::Length(length) => write!(f, "{:?}", length),
- LengthOrPercentage::Percentage(percentage) => write!(f, "{}%", percentage * 100.),
- LengthOrPercentage::Calc(calc) => write!(f, "{:?}", calc),
- }
- }
-}
-
-impl ToComputedValue for specified::LengthOrPercentage {
- type ComputedValue = LengthOrPercentage;
-
- fn to_computed_value(&self, context: &Context) -> LengthOrPercentage {
- match *self {
- specified::LengthOrPercentage::Length(value) => {
- LengthOrPercentage::Length(value.to_computed_value(context))
- }
- specified::LengthOrPercentage::Percentage(value) => {
- LengthOrPercentage::Percentage(value.0)
- }
- specified::LengthOrPercentage::Calc(calc) => {
- LengthOrPercentage::Calc(calc.to_computed_value(context))
- }
- }
- }
-
- fn from_computed_value(computed: &LengthOrPercentage) -> Self {
- match *computed {
- LengthOrPercentage::Length(value) => {
- specified::LengthOrPercentage::Length(
- ToComputedValue::from_computed_value(&value)
- )
- }
- LengthOrPercentage::Percentage(value) => {
- specified::LengthOrPercentage::Percentage(specified::Percentage(value))
- }
- LengthOrPercentage::Calc(calc) => {
- specified::LengthOrPercentage::Calc(
- ToComputedValue::from_computed_value(&calc)
- )
- }
- }
- }
-}
-
-impl ::cssparser::ToCss for LengthOrPercentage {
- fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
- match *self {
- LengthOrPercentage::Length(length) => length.to_css(dest),
- LengthOrPercentage::Percentage(percentage)
- => write!(dest, "{}%", percentage * 100.),
- LengthOrPercentage::Calc(calc) => calc.to_css(dest),
- }
- }
-}
-
-#[derive(PartialEq, Clone, Copy)]
-#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
-pub enum LengthOrPercentageOrAuto {
- Length(Au),
- Percentage(CSSFloat),
- Auto,
- Calc(CalcLengthOrPercentage),
-}
-
-impl LengthOrPercentageOrAuto {
- /// Returns true if the computed value is absolute 0 or 0%.
- ///
- /// (Returns false for calc() values, even if ones that may resolve to zero.)
- #[inline]
- pub fn is_definitely_zero(&self) -> bool {
- use self::LengthOrPercentageOrAuto::*;
- match *self {
- Length(Au(0)) | Percentage(0.0) => true,
- Length(_) | Percentage(_) | Calc(_) | Auto => false
- }
- }
-}
-
-impl fmt::Debug for LengthOrPercentageOrAuto {
- fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- match *self {
- LengthOrPercentageOrAuto::Length(length) => write!(f, "{:?}", length),
- LengthOrPercentageOrAuto::Percentage(percentage) => write!(f, "{}%", percentage * 100.),
- LengthOrPercentageOrAuto::Auto => write!(f, "auto"),
- LengthOrPercentageOrAuto::Calc(calc) => write!(f, "{:?}", calc),
- }
- }
-}
-
-impl ToComputedValue for specified::LengthOrPercentageOrAuto {
- type ComputedValue = LengthOrPercentageOrAuto;
-
- #[inline]
- fn to_computed_value(&self, context: &Context) -> LengthOrPercentageOrAuto {
- match *self {
- specified::LengthOrPercentageOrAuto::Length(value) => {
- LengthOrPercentageOrAuto::Length(value.to_computed_value(context))
- }
- specified::LengthOrPercentageOrAuto::Percentage(value) => {
- LengthOrPercentageOrAuto::Percentage(value.0)
- }
- specified::LengthOrPercentageOrAuto::Auto => {
- LengthOrPercentageOrAuto::Auto
- }
- specified::LengthOrPercentageOrAuto::Calc(calc) => {
- LengthOrPercentageOrAuto::Calc(calc.to_computed_value(context))
- }
- }
- }
-
- #[inline]
- fn from_computed_value(computed: &LengthOrPercentageOrAuto) -> Self {
- match *computed {
- LengthOrPercentageOrAuto::Auto => specified::LengthOrPercentageOrAuto::Auto,
- LengthOrPercentageOrAuto::Length(value) => {
- specified::LengthOrPercentageOrAuto::Length(
- ToComputedValue::from_computed_value(&value)
- )
- }
- LengthOrPercentageOrAuto::Percentage(value) => {
- specified::LengthOrPercentageOrAuto::Percentage(specified::Percentage(value))
- }
- LengthOrPercentageOrAuto::Calc(calc) => {
- specified::LengthOrPercentageOrAuto::Calc(
- ToComputedValue::from_computed_value(&calc)
- )
- }
- }
- }
-}
-
-impl ::cssparser::ToCss for LengthOrPercentageOrAuto {
- fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
- match *self {
- LengthOrPercentageOrAuto::Length(length) => length.to_css(dest),
- LengthOrPercentageOrAuto::Percentage(percentage)
- => write!(dest, "{}%", percentage * 100.),
- LengthOrPercentageOrAuto::Auto => dest.write_str("auto"),
- LengthOrPercentageOrAuto::Calc(calc) => calc.to_css(dest),
- }
- }
-}
-
-#[derive(PartialEq, Clone, Copy)]
-#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
-pub enum LengthOrPercentageOrAutoOrContent {
- Length(Au),
- Percentage(CSSFloat),
- Calc(CalcLengthOrPercentage),
- Auto,
- Content
-}
-
-impl fmt::Debug for LengthOrPercentageOrAutoOrContent {
- fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- match *self {
- LengthOrPercentageOrAutoOrContent::Length(length) => write!(f, "{:?}", length),
- LengthOrPercentageOrAutoOrContent::Percentage(percentage) => write!(f, "{}%", percentage * 100.),
- LengthOrPercentageOrAutoOrContent::Calc(calc) => write!(f, "{:?}", calc),
- LengthOrPercentageOrAutoOrContent::Auto => write!(f, "auto"),
- LengthOrPercentageOrAutoOrContent::Content => write!(f, "content")
- }
- }
-}
-
-impl ToComputedValue for specified::LengthOrPercentageOrAutoOrContent {
- type ComputedValue = LengthOrPercentageOrAutoOrContent;
-
- #[inline]
- fn to_computed_value(&self, context: &Context) -> LengthOrPercentageOrAutoOrContent {
- match *self {
- specified::LengthOrPercentageOrAutoOrContent::Length(value) => {
- LengthOrPercentageOrAutoOrContent::Length(value.to_computed_value(context))
- },
- specified::LengthOrPercentageOrAutoOrContent::Percentage(value) => {
- LengthOrPercentageOrAutoOrContent::Percentage(value.0)
- },
- specified::LengthOrPercentageOrAutoOrContent::Calc(calc) => {
- LengthOrPercentageOrAutoOrContent::Calc(calc.to_computed_value(context))
- },
- specified::LengthOrPercentageOrAutoOrContent::Auto => {
- LengthOrPercentageOrAutoOrContent::Auto
- },
- specified::LengthOrPercentageOrAutoOrContent::Content => {
- LengthOrPercentageOrAutoOrContent::Content
- }
- }
- }
-
-
- #[inline]
- fn from_computed_value(computed: &LengthOrPercentageOrAutoOrContent) -> Self {
- match *computed {
- LengthOrPercentageOrAutoOrContent::Auto => {
- specified::LengthOrPercentageOrAutoOrContent::Auto
- }
- LengthOrPercentageOrAutoOrContent::Content => {
- specified::LengthOrPercentageOrAutoOrContent::Content
- }
- LengthOrPercentageOrAutoOrContent::Length(value) => {
- specified::LengthOrPercentageOrAutoOrContent::Length(
- ToComputedValue::from_computed_value(&value)
- )
- }
- LengthOrPercentageOrAutoOrContent::Percentage(value) => {
- specified::LengthOrPercentageOrAutoOrContent::Percentage(specified::Percentage(value))
- }
- LengthOrPercentageOrAutoOrContent::Calc(calc) => {
- specified::LengthOrPercentageOrAutoOrContent::Calc(
- ToComputedValue::from_computed_value(&calc)
- )
- }
- }
- }
-}
-
-impl ::cssparser::ToCss for LengthOrPercentageOrAutoOrContent {
- fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
- match *self {
- LengthOrPercentageOrAutoOrContent::Length(length) => length.to_css(dest),
- LengthOrPercentageOrAutoOrContent::Percentage(percentage)
- => write!(dest, "{}%", percentage * 100.),
- LengthOrPercentageOrAutoOrContent::Calc(calc) => calc.to_css(dest),
- LengthOrPercentageOrAutoOrContent::Auto => dest.write_str("auto"),
- LengthOrPercentageOrAutoOrContent::Content => dest.write_str("content")
- }
- }
-}
-
-#[derive(PartialEq, Clone, Copy)]
-#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
-pub enum LengthOrPercentageOrNone {
- Length(Au),
- Percentage(CSSFloat),
- Calc(CalcLengthOrPercentage),
- None,
-}
-
-impl fmt::Debug for LengthOrPercentageOrNone {
- fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- match *self {
- LengthOrPercentageOrNone::Length(length) => write!(f, "{:?}", length),
- LengthOrPercentageOrNone::Percentage(percentage) => write!(f, "{}%", percentage * 100.),
- LengthOrPercentageOrNone::Calc(calc) => write!(f, "{:?}", calc),
- LengthOrPercentageOrNone::None => write!(f, "none"),
- }
- }
-}
-
-impl ToComputedValue for specified::LengthOrPercentageOrNone {
- type ComputedValue = LengthOrPercentageOrNone;
-
- #[inline]
- fn to_computed_value(&self, context: &Context) -> LengthOrPercentageOrNone {
- match *self {
- specified::LengthOrPercentageOrNone::Length(value) => {
- LengthOrPercentageOrNone::Length(value.to_computed_value(context))
- }
- specified::LengthOrPercentageOrNone::Percentage(value) => {
- LengthOrPercentageOrNone::Percentage(value.0)
- }
- specified::LengthOrPercentageOrNone::Calc(calc) => {
- LengthOrPercentageOrNone::Calc(calc.to_computed_value(context))
- }
- specified::LengthOrPercentageOrNone::None => {
- LengthOrPercentageOrNone::None
- }
- }
- }
-
- #[inline]
- fn from_computed_value(computed: &LengthOrPercentageOrNone) -> Self {
- match *computed {
- LengthOrPercentageOrNone::None => specified::LengthOrPercentageOrNone::None,
- LengthOrPercentageOrNone::Length(value) => {
- specified::LengthOrPercentageOrNone::Length(
- ToComputedValue::from_computed_value(&value)
- )
- }
- LengthOrPercentageOrNone::Percentage(value) => {
- specified::LengthOrPercentageOrNone::Percentage(specified::Percentage(value))
- }
- LengthOrPercentageOrNone::Calc(calc) => {
- specified::LengthOrPercentageOrNone::Calc(
- ToComputedValue::from_computed_value(&calc)
- )
- }
- }
- }
-}
-
-impl ::cssparser::ToCss for LengthOrPercentageOrNone {
- fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
- match *self {
- LengthOrPercentageOrNone::Length(length) => length.to_css(dest),
- LengthOrPercentageOrNone::Percentage(percentage) =>
- write!(dest, "{}%", percentage * 100.),
- LengthOrPercentageOrNone::Calc(calc) => calc.to_css(dest),
- LengthOrPercentageOrNone::None => dest.write_str("none"),
- }
- }
-}
-
-#[derive(PartialEq, Clone, Copy)]
-#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
-pub enum LengthOrNone {
- Length(Au),
- None,
-}
-
-impl fmt::Debug for LengthOrNone {
- fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- match *self {
- LengthOrNone::Length(length) => write!(f, "{:?}", length),
- LengthOrNone::None => write!(f, "none"),
- }
- }
-}
-
-impl ToComputedValue for specified::LengthOrNone {
- type ComputedValue = LengthOrNone;
-
- #[inline]
- fn to_computed_value(&self, context: &Context) -> LengthOrNone {
- match *self {
- specified::LengthOrNone::Length(specified::Length::Calc(calc, range)) => {
- LengthOrNone::Length(range.clamp(calc.to_computed_value(context).length()))
- }
- specified::LengthOrNone::Length(value) => {
- LengthOrNone::Length(value.to_computed_value(context))
- }
- specified::LengthOrNone::None => {
- LengthOrNone::None
- }
- }
- }
-
- #[inline]
- fn from_computed_value(computed: &LengthOrNone) -> Self {
- match *computed {
- LengthOrNone::Length(au) => {
- specified::LengthOrNone::Length(ToComputedValue::from_computed_value(&au))
- }
- LengthOrNone::None => {
- specified::LengthOrNone::None
- }
- }
- }
-}
-
-impl ::cssparser::ToCss for LengthOrNone {
- fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
- match *self {
- LengthOrNone::Length(length) => length.to_css(dest),
- LengthOrNone::None => dest.write_str("none"),
- }
- }
-}
pub type Length = Au;
pub type Number = CSSFloat;
diff --git a/components/style/values/specified/length.rs b/components/style/values/specified/length.rs
new file mode 100644
index 00000000000..0eca7c16ac2
--- /dev/null
+++ b/components/style/values/specified/length.rs
@@ -0,0 +1,1004 @@
+/* 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/. */
+
+use app_units::Au;
+use cssparser::{Parser, ToCss, Token};
+use euclid::size::Size2D;
+use parser::Parse;
+use std::ascii::AsciiExt;
+use std::cmp;
+use std::fmt;
+use std::ops::Mul;
+use style_traits::values::specified::AllowedNumericType;
+use super::{Angle, SimplifiedValueNode, SimplifiedSumNode, Time};
+use values::{CSSFloat, FONT_MEDIUM_PX, HasViewportPercentage, LocalToCss, computed};
+
+pub use super::image::{AngleOrCorner, ColorStop, EndingShape as GradientEndingShape, Gradient};
+pub use super::image::{GradientKind, HorizontalDirection, Image, LengthOrKeyword, LengthOrPercentageOrKeyword};
+pub use super::image::{SizeKeyword, VerticalDirection};
+
+#[derive(Clone, PartialEq, Copy, Debug)]
+#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
+pub enum FontRelativeLength {
+ Em(CSSFloat),
+ Ex(CSSFloat),
+ Ch(CSSFloat),
+ Rem(CSSFloat)
+}
+
+impl ToCss for FontRelativeLength {
+ fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
+ match *self {
+ FontRelativeLength::Em(length) => write!(dest, "{}em", length),
+ FontRelativeLength::Ex(length) => write!(dest, "{}ex", length),
+ FontRelativeLength::Ch(length) => write!(dest, "{}ch", length),
+ FontRelativeLength::Rem(length) => write!(dest, "{}rem", length)
+ }
+ }
+}
+
+impl FontRelativeLength {
+ pub fn to_computed_value(&self,
+ reference_font_size: Au,
+ root_font_size: Au)
+ -> Au
+ {
+ match *self {
+ FontRelativeLength::Em(length) => reference_font_size.scale_by(length),
+ FontRelativeLength::Ex(length) | FontRelativeLength::Ch(length) => {
+ // https://github.com/servo/servo/issues/7462
+ let em_factor = 0.5;
+ reference_font_size.scale_by(length * em_factor)
+ },
+ FontRelativeLength::Rem(length) => root_font_size.scale_by(length)
+ }
+ }
+}
+
+#[derive(Clone, PartialEq, Copy, Debug)]
+#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
+pub enum ViewportPercentageLength {
+ Vw(CSSFloat),
+ Vh(CSSFloat),
+ Vmin(CSSFloat),
+ Vmax(CSSFloat)
+}
+
+impl HasViewportPercentage for ViewportPercentageLength {
+ fn has_viewport_percentage(&self) -> bool {
+ true
+ }
+}
+
+impl ToCss for ViewportPercentageLength {
+ fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
+ match *self {
+ ViewportPercentageLength::Vw(length) => write!(dest, "{}vw", length),
+ ViewportPercentageLength::Vh(length) => write!(dest, "{}vh", length),
+ ViewportPercentageLength::Vmin(length) => write!(dest, "{}vmin", length),
+ ViewportPercentageLength::Vmax(length) => write!(dest, "{}vmax", length)
+ }
+ }
+}
+
+impl ViewportPercentageLength {
+ pub fn to_computed_value(&self, viewport_size: Size2D<Au>) -> Au {
+ macro_rules! to_unit {
+ ($viewport_dimension:expr) => {
+ $viewport_dimension.to_f32_px() / 100.0
+ }
+ }
+
+ let value = match *self {
+ ViewportPercentageLength::Vw(length) =>
+ length * to_unit!(viewport_size.width),
+ ViewportPercentageLength::Vh(length) =>
+ length * to_unit!(viewport_size.height),
+ ViewportPercentageLength::Vmin(length) =>
+ length * to_unit!(cmp::min(viewport_size.width, viewport_size.height)),
+ ViewportPercentageLength::Vmax(length) =>
+ length * to_unit!(cmp::max(viewport_size.width, viewport_size.height)),
+ };
+ Au::from_f32_px(value)
+ }
+}
+
+#[derive(Clone, PartialEq, Copy, Debug)]
+#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
+pub struct CharacterWidth(pub i32);
+
+impl CharacterWidth {
+ pub fn to_computed_value(&self, reference_font_size: Au) -> Au {
+ // This applies the *converting a character width to pixels* algorithm as specified
+ // in HTML5 § 14.5.4.
+ //
+ // TODO(pcwalton): Find these from the font.
+ let average_advance = reference_font_size.scale_by(0.5);
+ let max_advance = reference_font_size;
+ average_advance.scale_by(self.0 as CSSFloat - 1.0) + max_advance
+ }
+}
+
+#[derive(Clone, PartialEq, Copy, Debug)]
+#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
+pub enum Length {
+ Absolute(Au), // application units
+ FontRelative(FontRelativeLength),
+ ViewportPercentage(ViewportPercentageLength),
+
+ /// HTML5 "character width", as defined in HTML5 § 14.5.4.
+ ///
+ /// This cannot be specified by the user directly and is only generated by
+ /// `Stylist::synthesize_rules_for_legacy_attributes()`.
+ ServoCharacterWidth(CharacterWidth),
+
+ Calc(CalcLengthOrPercentage, AllowedNumericType),
+}
+
+impl HasViewportPercentage for Length {
+ fn has_viewport_percentage(&self) -> bool {
+ match *self {
+ Length::ViewportPercentage(_) => true,
+ Length::Calc(ref calc, _) => calc.has_viewport_percentage(),
+ _ => false
+ }
+ }
+}
+
+impl ToCss for Length {
+ fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
+ match *self {
+ Length::Absolute(length) => write!(dest, "{}px", length.to_f32_px()),
+ Length::FontRelative(length) => length.to_css(dest),
+ Length::ViewportPercentage(length) => length.to_css(dest),
+ Length::Calc(ref calc, _) => calc.to_css(dest),
+ /* This should only be reached from style dumping code */
+ Length::ServoCharacterWidth(CharacterWidth(i)) => write!(dest, "CharWidth({})", i),
+ }
+ }
+}
+
+impl Mul<CSSFloat> for Length {
+ type Output = Length;
+
+ #[inline]
+ fn mul(self, scalar: CSSFloat) -> Length {
+ match self {
+ Length::Absolute(Au(v)) => Length::Absolute(Au(((v as f32) * scalar) as i32)),
+ Length::FontRelative(v) => Length::FontRelative(v * scalar),
+ Length::ViewportPercentage(v) => Length::ViewportPercentage(v * scalar),
+ Length::Calc(..) => panic!("Can't multiply Calc!"),
+ Length::ServoCharacterWidth(_) => panic!("Can't multiply ServoCharacterWidth!"),
+ }
+ }
+}
+
+impl Mul<CSSFloat> for FontRelativeLength {
+ type Output = FontRelativeLength;
+
+ #[inline]
+ fn mul(self, scalar: CSSFloat) -> FontRelativeLength {
+ match self {
+ FontRelativeLength::Em(v) => FontRelativeLength::Em(v * scalar),
+ FontRelativeLength::Ex(v) => FontRelativeLength::Ex(v * scalar),
+ FontRelativeLength::Ch(v) => FontRelativeLength::Ch(v * scalar),
+ FontRelativeLength::Rem(v) => FontRelativeLength::Rem(v * scalar),
+ }
+ }
+}
+
+impl Mul<CSSFloat> for ViewportPercentageLength {
+ type Output = ViewportPercentageLength;
+
+ #[inline]
+ fn mul(self, scalar: CSSFloat) -> ViewportPercentageLength {
+ match self {
+ ViewportPercentageLength::Vw(v) => ViewportPercentageLength::Vw(v * scalar),
+ ViewportPercentageLength::Vh(v) => ViewportPercentageLength::Vh(v * scalar),
+ ViewportPercentageLength::Vmin(v) => ViewportPercentageLength::Vmin(v * scalar),
+ ViewportPercentageLength::Vmax(v) => ViewportPercentageLength::Vmax(v * scalar),
+ }
+ }
+}
+
+const AU_PER_PX: CSSFloat = 60.;
+const AU_PER_IN: CSSFloat = AU_PER_PX * 96.;
+const AU_PER_CM: CSSFloat = AU_PER_IN / 2.54;
+const AU_PER_MM: CSSFloat = AU_PER_IN / 25.4;
+const AU_PER_Q: CSSFloat = AU_PER_MM / 4.;
+const AU_PER_PT: CSSFloat = AU_PER_IN / 72.;
+const AU_PER_PC: CSSFloat = AU_PER_PT * 12.;
+
+impl Length {
+ // https://drafts.csswg.org/css-fonts-3/#font-size-prop
+ pub fn from_str(s: &str) -> Option<Length> {
+ Some(match_ignore_ascii_case! { s,
+ "xx-small" => Length::Absolute(Au::from_px(FONT_MEDIUM_PX) * 3 / 5),
+ "x-small" => Length::Absolute(Au::from_px(FONT_MEDIUM_PX) * 3 / 4),
+ "small" => Length::Absolute(Au::from_px(FONT_MEDIUM_PX) * 8 / 9),
+ "medium" => Length::Absolute(Au::from_px(FONT_MEDIUM_PX)),
+ "large" => Length::Absolute(Au::from_px(FONT_MEDIUM_PX) * 6 / 5),
+ "x-large" => Length::Absolute(Au::from_px(FONT_MEDIUM_PX) * 3 / 2),
+ "xx-large" => Length::Absolute(Au::from_px(FONT_MEDIUM_PX) * 2),
+
+ // https://github.com/servo/servo/issues/3423#issuecomment-56321664
+ "smaller" => Length::FontRelative(FontRelativeLength::Em(0.85)),
+ "larger" => Length::FontRelative(FontRelativeLength::Em(1.2)),
+ _ => return None
+ })
+ }
+
+ #[inline]
+ fn parse_internal(input: &mut Parser, context: AllowedNumericType) -> Result<Length, ()> {
+ match try!(input.next()) {
+ Token::Dimension(ref value, ref unit) if context.is_ok(value.value) =>
+ Length::parse_dimension(value.value, unit),
+ Token::Number(ref value) if value.value == 0. =>
+ Ok(Length::Absolute(Au(0))),
+ Token::Function(ref name) if name.eq_ignore_ascii_case("calc") =>
+ input.parse_nested_block(|input| {
+ CalcLengthOrPercentage::parse_length(input, context)
+ }),
+ _ => Err(())
+ }
+ }
+ pub fn parse_non_negative(input: &mut Parser) -> Result<Length, ()> {
+ Length::parse_internal(input, AllowedNumericType::NonNegative)
+ }
+ pub fn parse_dimension(value: CSSFloat, unit: &str) -> Result<Length, ()> {
+ match_ignore_ascii_case! { unit,
+ "px" => Ok(Length::from_px(value)),
+ "in" => Ok(Length::Absolute(Au((value * AU_PER_IN) as i32))),
+ "cm" => Ok(Length::Absolute(Au((value * AU_PER_CM) as i32))),
+ "mm" => Ok(Length::Absolute(Au((value * AU_PER_MM) as i32))),
+ "q" => Ok(Length::Absolute(Au((value * AU_PER_Q) as i32))),
+ "pt" => Ok(Length::Absolute(Au((value * AU_PER_PT) as i32))),
+ "pc" => Ok(Length::Absolute(Au((value * AU_PER_PC) as i32))),
+ // font-relative
+ "em" => Ok(Length::FontRelative(FontRelativeLength::Em(value))),
+ "ex" => Ok(Length::FontRelative(FontRelativeLength::Ex(value))),
+ "ch" => Ok(Length::FontRelative(FontRelativeLength::Ch(value))),
+ "rem" => Ok(Length::FontRelative(FontRelativeLength::Rem(value))),
+ // viewport percentages
+ "vw" => Ok(Length::ViewportPercentage(ViewportPercentageLength::Vw(value))),
+ "vh" => Ok(Length::ViewportPercentage(ViewportPercentageLength::Vh(value))),
+ "vmin" => Ok(Length::ViewportPercentage(ViewportPercentageLength::Vmin(value))),
+ "vmax" => Ok(Length::ViewportPercentage(ViewportPercentageLength::Vmax(value))),
+ _ => Err(())
+ }
+ }
+ #[inline]
+ pub fn from_px(px_value: CSSFloat) -> Length {
+ Length::Absolute(Au((px_value * AU_PER_PX) as i32))
+ }
+}
+
+impl Parse for Length {
+ fn parse(input: &mut Parser) -> Result<Self, ()> {
+ Length::parse_internal(input, AllowedNumericType::All)
+ }
+}
+
+#[derive(Clone, Debug)]
+pub struct CalcSumNode {
+ pub products: Vec<CalcProductNode>,
+}
+
+#[derive(Clone, Debug)]
+pub struct CalcProductNode {
+ values: Vec<CalcValueNode>
+}
+
+#[derive(Clone, Debug)]
+pub enum CalcValueNode {
+ Length(Length),
+ Angle(Angle),
+ Time(Time),
+ Percentage(CSSFloat),
+ Number(CSSFloat),
+ Sum(Box<CalcSumNode>),
+}
+
+#[derive(Clone, Copy, PartialEq)]
+pub enum CalcUnit {
+ Number,
+ Integer,
+ Length,
+ LengthOrPercentage,
+ Angle,
+ Time,
+}
+
+#[derive(Clone, PartialEq, Copy, Debug, Default)]
+#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
+pub struct CalcLengthOrPercentage {
+ pub absolute: Option<Au>,
+ pub vw: Option<ViewportPercentageLength>,
+ pub vh: Option<ViewportPercentageLength>,
+ pub vmin: Option<ViewportPercentageLength>,
+ pub vmax: Option<ViewportPercentageLength>,
+ pub em: Option<FontRelativeLength>,
+ pub ex: Option<FontRelativeLength>,
+ pub ch: Option<FontRelativeLength>,
+ pub rem: Option<FontRelativeLength>,
+ pub percentage: Option<Percentage>,
+}
+
+impl CalcLengthOrPercentage {
+ pub fn parse_sum(input: &mut Parser, expected_unit: CalcUnit) -> Result<CalcSumNode, ()> {
+ let mut products = Vec::new();
+ products.push(try!(CalcLengthOrPercentage::parse_product(input, expected_unit)));
+
+ while let Ok(token) = input.next() {
+ match token {
+ Token::Delim('+') => {
+ products.push(try!(CalcLengthOrPercentage::parse_product(input, expected_unit)));
+ }
+ Token::Delim('-') => {
+ let mut right = try!(CalcLengthOrPercentage::parse_product(input, expected_unit));
+ right.values.push(CalcValueNode::Number(-1.));
+ products.push(right);
+ }
+ _ => return Err(())
+ }
+ }
+
+ Ok(CalcSumNode { products: products })
+ }
+
+ fn parse_product(input: &mut Parser, expected_unit: CalcUnit) -> Result<CalcProductNode, ()> {
+ let mut values = Vec::new();
+ values.push(try!(CalcLengthOrPercentage::parse_value(input, expected_unit)));
+
+ loop {
+ let position = input.position();
+ match input.next() {
+ Ok(Token::Delim('*')) => {
+ values.push(try!(CalcLengthOrPercentage::parse_value(input, expected_unit)));
+ }
+ Ok(Token::Delim('/')) if expected_unit != CalcUnit::Integer => {
+ if let Ok(Token::Number(ref value)) = input.next() {
+ if value.value == 0. {
+ return Err(());
+ }
+ values.push(CalcValueNode::Number(1. / value.value));
+ } else {
+ return Err(());
+ }
+ }
+ _ => {
+ input.reset(position);
+ break
+ }
+ }
+ }
+
+ Ok(CalcProductNode { values: values })
+ }
+
+ fn parse_value(input: &mut Parser, expected_unit: CalcUnit) -> Result<CalcValueNode, ()> {
+ match (try!(input.next()), expected_unit) {
+ (Token::Number(ref value), _) => Ok(CalcValueNode::Number(value.value)),
+ (Token::Dimension(ref value, ref unit), CalcUnit::Length) |
+ (Token::Dimension(ref value, ref unit), CalcUnit::LengthOrPercentage) => {
+ Length::parse_dimension(value.value, unit).map(CalcValueNode::Length)
+ }
+ (Token::Dimension(ref value, ref unit), CalcUnit::Angle) => {
+ Angle::parse_dimension(value.value, unit).map(CalcValueNode::Angle)
+ }
+ (Token::Dimension(ref value, ref unit), CalcUnit::Time) => {
+ Time::parse_dimension(value.value, unit).map(CalcValueNode::Time)
+ }
+ (Token::Percentage(ref value), CalcUnit::LengthOrPercentage) =>
+ Ok(CalcValueNode::Percentage(value.unit_value)),
+ (Token::ParenthesisBlock, _) => {
+ input.parse_nested_block(|i| CalcLengthOrPercentage::parse_sum(i, expected_unit))
+ .map(|result| CalcValueNode::Sum(Box::new(result)))
+ },
+ _ => Err(())
+ }
+ }
+
+ fn simplify_value_to_number(node: &CalcValueNode) -> Option<CSSFloat> {
+ match *node {
+ CalcValueNode::Number(number) => Some(number),
+ CalcValueNode::Sum(ref sum) => CalcLengthOrPercentage::simplify_sum_to_number(sum),
+ _ => None
+ }
+ }
+
+ fn simplify_sum_to_number(node: &CalcSumNode) -> Option<CSSFloat> {
+ let mut sum = 0.;
+ for ref product in &node.products {
+ match CalcLengthOrPercentage::simplify_product_to_number(product) {
+ Some(number) => sum += number,
+ _ => return None
+ }
+ }
+ Some(sum)
+ }
+
+ fn simplify_product_to_number(node: &CalcProductNode) -> Option<CSSFloat> {
+ let mut product = 1.;
+ for ref value in &node.values {
+ match CalcLengthOrPercentage::simplify_value_to_number(value) {
+ Some(number) => product *= number,
+ _ => return None
+ }
+ }
+ Some(product)
+ }
+
+ fn simplify_products_in_sum(node: &CalcSumNode) -> Result<SimplifiedValueNode, ()> {
+ let mut simplified = Vec::new();
+ for product in &node.products {
+ match try!(CalcLengthOrPercentage::simplify_product(product)) {
+ SimplifiedValueNode::Sum(ref sum) => simplified.extend_from_slice(&sum.values),
+ val => simplified.push(val),
+ }
+ }
+
+ if simplified.len() == 1 {
+ Ok(simplified[0].clone())
+ } else {
+ Ok(SimplifiedValueNode::Sum(Box::new(SimplifiedSumNode { values: simplified })))
+ }
+ }
+
+ pub fn simplify_product(node: &CalcProductNode) -> Result<SimplifiedValueNode, ()> {
+ let mut multiplier = 1.;
+ let mut node_with_unit = None;
+ for node in &node.values {
+ match CalcLengthOrPercentage::simplify_value_to_number(&node) {
+ Some(number) => multiplier *= number,
+ _ if node_with_unit.is_none() => {
+ node_with_unit = Some(match *node {
+ CalcValueNode::Sum(ref sum) =>
+ try!(CalcLengthOrPercentage::simplify_products_in_sum(sum)),
+ CalcValueNode::Length(l) => SimplifiedValueNode::Length(l),
+ CalcValueNode::Angle(a) => SimplifiedValueNode::Angle(a),
+ CalcValueNode::Time(t) => SimplifiedValueNode::Time(t),
+ CalcValueNode::Percentage(p) => SimplifiedValueNode::Percentage(p),
+ _ => unreachable!("Numbers should have been handled by simplify_value_to_nubmer")
+ })
+ },
+ _ => return Err(()),
+ }
+ }
+
+ match node_with_unit {
+ None => Ok(SimplifiedValueNode::Number(multiplier)),
+ Some(ref value) => Ok(value * multiplier)
+ }
+ }
+
+ fn parse_length(input: &mut Parser,
+ context: AllowedNumericType) -> Result<Length, ()> {
+ CalcLengthOrPercentage::parse(input, CalcUnit::Length).map(|calc| {
+ Length::Calc(calc, context)
+ })
+ }
+
+ fn parse_length_or_percentage(input: &mut Parser) -> Result<CalcLengthOrPercentage, ()> {
+ CalcLengthOrPercentage::parse(input, CalcUnit::LengthOrPercentage)
+ }
+
+ fn parse(input: &mut Parser,
+ expected_unit: CalcUnit) -> Result<CalcLengthOrPercentage, ()> {
+ let ast = try!(CalcLengthOrPercentage::parse_sum(input, expected_unit));
+
+ let mut simplified = Vec::new();
+ for ref node in ast.products {
+ match try!(CalcLengthOrPercentage::simplify_product(node)) {
+ SimplifiedValueNode::Sum(sum) => simplified.extend_from_slice(&sum.values),
+ value => simplified.push(value),
+ }
+ }
+
+ let mut absolute = None;
+ let mut vw = None;
+ let mut vh = None;
+ let mut vmax = None;
+ let mut vmin = None;
+ let mut em = None;
+ let mut ex = None;
+ let mut ch = None;
+ let mut rem = None;
+ let mut percentage = None;
+ let mut number = None;
+
+ for value in simplified {
+ match value {
+ SimplifiedValueNode::Percentage(p) =>
+ percentage = Some(percentage.unwrap_or(0.) + p),
+ SimplifiedValueNode::Length(Length::Absolute(Au(au))) =>
+ absolute = Some(absolute.unwrap_or(0) + au),
+ SimplifiedValueNode::Length(Length::ViewportPercentage(v)) =>
+ match v {
+ ViewportPercentageLength::Vw(val) =>
+ vw = Some(vw.unwrap_or(0.) + val),
+ ViewportPercentageLength::Vh(val) =>
+ vh = Some(vh.unwrap_or(0.) + val),
+ ViewportPercentageLength::Vmin(val) =>
+ vmin = Some(vmin.unwrap_or(0.) + val),
+ ViewportPercentageLength::Vmax(val) =>
+ vmax = Some(vmax.unwrap_or(0.) + val),
+ },
+ SimplifiedValueNode::Length(Length::FontRelative(f)) =>
+ match f {
+ FontRelativeLength::Em(val) =>
+ em = Some(em.unwrap_or(0.) + val),
+ FontRelativeLength::Ex(val) =>
+ ex = Some(ex.unwrap_or(0.) + val),
+ FontRelativeLength::Ch(val) =>
+ ch = Some(ch.unwrap_or(0.) + val),
+ FontRelativeLength::Rem(val) =>
+ rem = Some(rem.unwrap_or(0.) + val),
+ },
+ SimplifiedValueNode::Number(val) => number = Some(number.unwrap_or(0.) + val),
+ _ => return Err(()),
+ }
+ }
+
+ Ok(CalcLengthOrPercentage {
+ absolute: absolute.map(Au),
+ vw: vw.map(ViewportPercentageLength::Vw),
+ vh: vh.map(ViewportPercentageLength::Vh),
+ vmax: vmax.map(ViewportPercentageLength::Vmax),
+ vmin: vmin.map(ViewportPercentageLength::Vmin),
+ em: em.map(FontRelativeLength::Em),
+ ex: ex.map(FontRelativeLength::Ex),
+ ch: ch.map(FontRelativeLength::Ch),
+ rem: rem.map(FontRelativeLength::Rem),
+ percentage: percentage.map(Percentage),
+ })
+ }
+
+ pub fn parse_time(input: &mut Parser) -> Result<Time, ()> {
+ let ast = try!(CalcLengthOrPercentage::parse_sum(input, CalcUnit::Time));
+
+ let mut simplified = Vec::new();
+ for ref node in ast.products {
+ match try!(CalcLengthOrPercentage::simplify_product(node)) {
+ SimplifiedValueNode::Sum(sum) => simplified.extend_from_slice(&sum.values),
+ value => simplified.push(value),
+ }
+ }
+
+ let mut time = None;
+
+ for value in simplified {
+ match value {
+ SimplifiedValueNode::Time(Time(val)) =>
+ time = Some(time.unwrap_or(0.) + val),
+ _ => return Err(()),
+ }
+ }
+
+ match time {
+ Some(time) => Ok(Time(time)),
+ _ => Err(())
+ }
+ }
+
+ pub fn parse_angle(input: &mut Parser) -> Result<Angle, ()> {
+ let ast = try!(CalcLengthOrPercentage::parse_sum(input, CalcUnit::Angle));
+
+ let mut simplified = Vec::new();
+ for ref node in ast.products {
+ match try!(CalcLengthOrPercentage::simplify_product(node)) {
+ SimplifiedValueNode::Sum(sum) => simplified.extend_from_slice(&sum.values),
+ value => simplified.push(value),
+ }
+ }
+
+ let mut angle = None;
+ let mut number = None;
+
+ for value in simplified {
+ match value {
+ SimplifiedValueNode::Angle(Angle(val)) =>
+ angle = Some(angle.unwrap_or(0.) + val),
+ SimplifiedValueNode::Number(val) => number = Some(number.unwrap_or(0.) + val),
+ _ => unreachable!()
+ }
+ }
+
+ match (angle, number) {
+ (Some(angle), None) => Ok(Angle(angle)),
+ (None, Some(value)) if value == 0. => Ok(Angle(0.)),
+ _ => Err(())
+ }
+ }
+
+ pub fn compute_from_viewport_and_font_size(&self,
+ viewport_size: Size2D<Au>,
+ font_size: Au,
+ root_font_size: Au)
+ -> computed::CalcLengthOrPercentage
+ {
+ let mut length = None;
+
+ if let Some(absolute) = self.absolute {
+ length = Some(length.unwrap_or(Au(0)) + absolute);
+ }
+
+ for val in &[self.vw, self.vh, self.vmin, self.vmax] {
+ if let Some(val) = *val {
+ length = Some(length.unwrap_or(Au(0)) +
+ val.to_computed_value(viewport_size));
+ }
+ }
+
+ for val in &[self.ch, self.em, self.ex, self.rem] {
+ if let Some(val) = *val {
+ length = Some(length.unwrap_or(Au(0)) + val.to_computed_value(
+ font_size, root_font_size));
+ }
+ }
+
+ computed::CalcLengthOrPercentage {
+ length: length,
+ percentage: self.percentage.map(|p| p.0),
+ }
+ }
+}
+
+impl HasViewportPercentage for CalcLengthOrPercentage {
+ fn has_viewport_percentage(&self) -> bool {
+ self.vw.is_some() || self.vh.is_some() ||
+ self.vmin.is_some() || self.vmax.is_some()
+ }
+}
+
+impl ToCss for CalcLengthOrPercentage {
+ #[allow(unused_assignments)]
+ fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
+ macro_rules! count {
+ ( $( $val:ident ),* ) => {
+ {
+ let mut count = 0;
+ $(
+ if let Some(_) = self.$val {
+ count += 1;
+ }
+ )*
+ count
+ }
+ };
+ }
+
+ macro_rules! serialize {
+ ( $( $val:ident ),* ) => {
+ {
+ let mut first_value = true;
+ $(
+ if let Some(val) = self.$val {
+ if !first_value {
+ try!(write!(dest, " + "));
+ } else {
+ first_value = false;
+ }
+ try!(val.to_css(dest));
+ }
+ )*
+ }
+ };
+ }
+
+ let count = count!(ch, em, ex, absolute, rem, vh, vmax, vmin, vw, percentage);
+ assert!(count > 0);
+
+ if count > 1 {
+ try!(write!(dest, "calc("));
+ }
+
+ serialize!(ch, em, ex, absolute, rem, vh, vmax, vmin, vw, percentage);
+
+ if count > 1 {
+ try!(write!(dest, ")"));
+ }
+ Ok(())
+ }
+}
+
+#[derive(Clone, PartialEq, Copy, Debug)]
+#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
+pub struct Percentage(pub CSSFloat); // [0 .. 100%] maps to [0.0 .. 1.0]
+
+impl ToCss for Percentage {
+ fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
+ write!(dest, "{}%", self.0 * 100.)
+ }
+}
+
+#[derive(Clone, PartialEq, Copy, Debug)]
+#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
+pub enum LengthOrPercentage {
+ Length(Length),
+ Percentage(Percentage),
+ Calc(CalcLengthOrPercentage),
+}
+
+impl HasViewportPercentage for LengthOrPercentage {
+ fn has_viewport_percentage(&self) -> bool {
+ match *self {
+ LengthOrPercentage::Length(ref length) => length.has_viewport_percentage(),
+ LengthOrPercentage::Calc(ref calc) => calc.has_viewport_percentage(),
+ _ => false
+ }
+ }
+}
+
+impl ToCss for LengthOrPercentage {
+ fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
+ match *self {
+ LengthOrPercentage::Length(length) => length.to_css(dest),
+ LengthOrPercentage::Percentage(percentage) => percentage.to_css(dest),
+ LengthOrPercentage::Calc(calc) => calc.to_css(dest),
+ }
+ }
+}
+impl LengthOrPercentage {
+ pub fn zero() -> LengthOrPercentage {
+ LengthOrPercentage::Length(Length::Absolute(Au(0)))
+ }
+
+ fn parse_internal(input: &mut Parser, context: AllowedNumericType)
+ -> Result<LengthOrPercentage, ()>
+ {
+ match try!(input.next()) {
+ Token::Dimension(ref value, ref unit) if context.is_ok(value.value) =>
+ Length::parse_dimension(value.value, unit).map(LengthOrPercentage::Length),
+ Token::Percentage(ref value) if context.is_ok(value.unit_value) =>
+ Ok(LengthOrPercentage::Percentage(Percentage(value.unit_value))),
+ Token::Number(ref value) if value.value == 0. =>
+ Ok(LengthOrPercentage::Length(Length::Absolute(Au(0)))),
+ Token::Function(ref name) if name.eq_ignore_ascii_case("calc") => {
+ let calc = try!(input.parse_nested_block(CalcLengthOrPercentage::parse_length_or_percentage));
+ Ok(LengthOrPercentage::Calc(calc))
+ },
+ _ => Err(())
+ }
+ }
+
+ #[inline]
+ pub fn parse_non_negative(input: &mut Parser) -> Result<LengthOrPercentage, ()> {
+ LengthOrPercentage::parse_internal(input, AllowedNumericType::NonNegative)
+ }
+}
+
+impl Parse for LengthOrPercentage {
+ #[inline]
+ fn parse(input: &mut Parser) -> Result<Self, ()> {
+ LengthOrPercentage::parse_internal(input, AllowedNumericType::All)
+ }
+}
+
+#[derive(Clone, PartialEq, Copy, Debug)]
+#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
+pub enum LengthOrPercentageOrAuto {
+ Length(Length),
+ Percentage(Percentage),
+ Auto,
+ Calc(CalcLengthOrPercentage),
+}
+
+impl HasViewportPercentage for LengthOrPercentageOrAuto {
+ fn has_viewport_percentage(&self) -> bool {
+ match *self {
+ LengthOrPercentageOrAuto::Length(ref length) => length.has_viewport_percentage(),
+ LengthOrPercentageOrAuto::Calc(ref calc) => calc.has_viewport_percentage(),
+ _ => false
+ }
+ }
+}
+
+impl ToCss for LengthOrPercentageOrAuto {
+ fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
+ match *self {
+ LengthOrPercentageOrAuto::Length(length) => length.to_css(dest),
+ LengthOrPercentageOrAuto::Percentage(percentage) => percentage.to_css(dest),
+ LengthOrPercentageOrAuto::Auto => dest.write_str("auto"),
+ LengthOrPercentageOrAuto::Calc(calc) => calc.to_css(dest),
+ }
+ }
+}
+
+impl LengthOrPercentageOrAuto {
+ fn parse_internal(input: &mut Parser, context: AllowedNumericType)
+ -> Result<LengthOrPercentageOrAuto, ()>
+ {
+ match try!(input.next()) {
+ Token::Dimension(ref value, ref unit) if context.is_ok(value.value) =>
+ Length::parse_dimension(value.value, unit).map(LengthOrPercentageOrAuto::Length),
+ Token::Percentage(ref value) if context.is_ok(value.unit_value) =>
+ Ok(LengthOrPercentageOrAuto::Percentage(Percentage(value.unit_value))),
+ Token::Number(ref value) if value.value == 0. =>
+ Ok(LengthOrPercentageOrAuto::Length(Length::Absolute(Au(0)))),
+ Token::Ident(ref value) if value.eq_ignore_ascii_case("auto") =>
+ Ok(LengthOrPercentageOrAuto::Auto),
+ Token::Function(ref name) if name.eq_ignore_ascii_case("calc") => {
+ let calc = try!(input.parse_nested_block(CalcLengthOrPercentage::parse_length_or_percentage));
+ Ok(LengthOrPercentageOrAuto::Calc(calc))
+ },
+ _ => Err(())
+ }
+ }
+ #[inline]
+ pub fn parse(input: &mut Parser) -> Result<LengthOrPercentageOrAuto, ()> {
+ LengthOrPercentageOrAuto::parse_internal(input, AllowedNumericType::All)
+ }
+ #[inline]
+ pub fn parse_non_negative(input: &mut Parser) -> Result<LengthOrPercentageOrAuto, ()> {
+ LengthOrPercentageOrAuto::parse_internal(input, AllowedNumericType::NonNegative)
+ }
+}
+
+#[derive(Clone, PartialEq, Copy, Debug)]
+#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
+pub enum LengthOrPercentageOrNone {
+ Length(Length),
+ Percentage(Percentage),
+ Calc(CalcLengthOrPercentage),
+ None,
+}
+
+impl HasViewportPercentage for LengthOrPercentageOrNone {
+ fn has_viewport_percentage(&self) -> bool {
+ match *self {
+ LengthOrPercentageOrNone::Length(ref length) => length.has_viewport_percentage(),
+ LengthOrPercentageOrNone::Calc(ref calc) => calc.has_viewport_percentage(),
+ _ => false
+ }
+ }
+}
+
+impl ToCss for LengthOrPercentageOrNone {
+ fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
+ match *self {
+ LengthOrPercentageOrNone::Length(ref length) => length.to_css(dest),
+ LengthOrPercentageOrNone::Percentage(ref percentage) => percentage.to_css(dest),
+ LengthOrPercentageOrNone::Calc(ref calc) => calc.to_css(dest),
+ LengthOrPercentageOrNone::None => dest.write_str("none"),
+ }
+ }
+}
+impl LengthOrPercentageOrNone {
+ fn parse_internal(input: &mut Parser, context: AllowedNumericType)
+ -> Result<LengthOrPercentageOrNone, ()>
+ {
+ match try!(input.next()) {
+ Token::Dimension(ref value, ref unit) if context.is_ok(value.value) =>
+ Length::parse_dimension(value.value, unit).map(LengthOrPercentageOrNone::Length),
+ Token::Percentage(ref value) if context.is_ok(value.unit_value) =>
+ Ok(LengthOrPercentageOrNone::Percentage(Percentage(value.unit_value))),
+ Token::Number(ref value) if value.value == 0. =>
+ Ok(LengthOrPercentageOrNone::Length(Length::Absolute(Au(0)))),
+ Token::Function(ref name) if name.eq_ignore_ascii_case("calc") => {
+ let calc = try!(input.parse_nested_block(CalcLengthOrPercentage::parse_length_or_percentage));
+ Ok(LengthOrPercentageOrNone::Calc(calc))
+ },
+ Token::Ident(ref value) if value.eq_ignore_ascii_case("none") =>
+ Ok(LengthOrPercentageOrNone::None),
+ _ => Err(())
+ }
+ }
+ #[inline]
+ pub fn parse(input: &mut Parser) -> Result<LengthOrPercentageOrNone, ()> {
+ LengthOrPercentageOrNone::parse_internal(input, AllowedNumericType::All)
+ }
+ #[inline]
+ pub fn parse_non_negative(input: &mut Parser) -> Result<LengthOrPercentageOrNone, ()> {
+ LengthOrPercentageOrNone::parse_internal(input, AllowedNumericType::NonNegative)
+ }
+}
+
+#[derive(Clone, PartialEq, Copy, Debug)]
+#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
+pub enum LengthOrNone {
+ Length(Length),
+ None,
+}
+
+impl HasViewportPercentage for LengthOrNone {
+ fn has_viewport_percentage(&self) -> bool {
+ match *self {
+ LengthOrNone::Length(ref length) => length.has_viewport_percentage(),
+ _ => false
+ }
+ }
+}
+
+impl ToCss for LengthOrNone {
+ fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
+ match *self {
+ LengthOrNone::Length(length) => length.to_css(dest),
+ LengthOrNone::None => dest.write_str("none"),
+ }
+ }
+}
+impl LengthOrNone {
+ fn parse_internal(input: &mut Parser, context: AllowedNumericType)
+ -> Result<LengthOrNone, ()>
+ {
+ match try!(input.next()) {
+ Token::Dimension(ref value, ref unit) if context.is_ok(value.value) =>
+ Length::parse_dimension(value.value, unit).map(LengthOrNone::Length),
+ Token::Number(ref value) if value.value == 0. =>
+ Ok(LengthOrNone::Length(Length::Absolute(Au(0)))),
+ Token::Function(ref name) if name.eq_ignore_ascii_case("calc") =>
+ input.parse_nested_block(|input| {
+ CalcLengthOrPercentage::parse_length(input, context)
+ }).map(LengthOrNone::Length),
+ Token::Ident(ref value) if value.eq_ignore_ascii_case("none") =>
+ Ok(LengthOrNone::None),
+ _ => Err(())
+ }
+ }
+ #[inline]
+ pub fn parse(input: &mut Parser) -> Result<LengthOrNone, ()> {
+ LengthOrNone::parse_internal(input, AllowedNumericType::All)
+ }
+ #[inline]
+ pub fn parse_non_negative(input: &mut Parser) -> Result<LengthOrNone, ()> {
+ LengthOrNone::parse_internal(input, AllowedNumericType::NonNegative)
+ }
+}
+
+#[derive(Clone, PartialEq, Copy, Debug)]
+#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
+pub enum LengthOrPercentageOrAutoOrContent {
+ Length(Length),
+ Percentage(Percentage),
+ Calc(CalcLengthOrPercentage),
+ Auto,
+ Content
+}
+
+impl HasViewportPercentage for LengthOrPercentageOrAutoOrContent {
+ fn has_viewport_percentage(&self) -> bool {
+ match *self {
+ LengthOrPercentageOrAutoOrContent::Length(length) => length.has_viewport_percentage(),
+ LengthOrPercentageOrAutoOrContent::Calc(ref calc) => calc.has_viewport_percentage(),
+ _ => false
+ }
+ }
+}
+
+impl ToCss for LengthOrPercentageOrAutoOrContent {
+ fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
+ match *self {
+ LengthOrPercentageOrAutoOrContent::Length(len) => len.to_css(dest),
+ LengthOrPercentageOrAutoOrContent::Percentage(perc) => perc.to_css(dest),
+ LengthOrPercentageOrAutoOrContent::Auto => dest.write_str("auto"),
+ LengthOrPercentageOrAutoOrContent::Content => dest.write_str("content"),
+ LengthOrPercentageOrAutoOrContent::Calc(calc) => calc.to_css(dest),
+ }
+ }
+}
+
+impl LengthOrPercentageOrAutoOrContent {
+ pub fn parse(input: &mut Parser) -> Result<LengthOrPercentageOrAutoOrContent, ()> {
+ let context = AllowedNumericType::NonNegative;
+ match try!(input.next()) {
+ Token::Dimension(ref value, ref unit) if context.is_ok(value.value) =>
+ Length::parse_dimension(value.value, unit).map(LengthOrPercentageOrAutoOrContent::Length),
+ Token::Percentage(ref value) if context.is_ok(value.unit_value) =>
+ Ok(LengthOrPercentageOrAutoOrContent::Percentage(Percentage(value.unit_value))),
+ Token::Number(ref value) if value.value == 0. =>
+ Ok(LengthOrPercentageOrAutoOrContent::Length(Length::Absolute(Au(0)))),
+ Token::Ident(ref value) if value.eq_ignore_ascii_case("auto") =>
+ Ok(LengthOrPercentageOrAutoOrContent::Auto),
+ Token::Ident(ref value) if value.eq_ignore_ascii_case("content") =>
+ Ok(LengthOrPercentageOrAutoOrContent::Content),
+ Token::Function(ref name) if name.eq_ignore_ascii_case("calc") => {
+ let calc = try!(input.parse_nested_block(CalcLengthOrPercentage::parse_length_or_percentage));
+ Ok(LengthOrPercentageOrAutoOrContent::Calc(calc))
+ },
+ _ => Err(())
+ }
+ }
+}
+
diff --git a/components/style/values/specified/mod.rs b/components/style/values/specified/mod.rs
index 124acadad5a..30ca7266185 100644
--- a/components/style/values/specified/mod.rs
+++ b/components/style/values/specified/mod.rs
@@ -7,25 +7,27 @@ use cssparser::{self, Parser, ToCss, Token};
use euclid::size::Size2D;
#[cfg(feature = "gecko")]
use gecko_bindings::sugar::refptr::{GeckoArcPrincipal, GeckoArcURI};
-use parser::{Parse, ParserContext};
+use parser::ParserContext;
#[cfg(feature = "gecko")]
use parser::ParserContextExtraData;
use std::ascii::AsciiExt;
-use std::cmp;
use std::f32::consts::PI;
use std::fmt;
use std::ops::Mul;
-use style_traits::values::specified::AllowedNumericType;
-use super::{CSSFloat, FONT_MEDIUM_PX, HasViewportPercentage, LocalToCss, NoViewportPercentage};
-use super::computed::{self, ComputedValueAsSpecified, Context, ToComputedValue};
+use super::{CSSFloat, HasViewportPercentage, NoViewportPercentage};
+use super::computed::{ComputedValueAsSpecified, Context, ToComputedValue};
use url::Url;
pub use self::image::{AngleOrCorner, ColorStop, EndingShape as GradientEndingShape, Gradient};
pub use self::image::{GradientKind, HorizontalDirection, Image, LengthOrKeyword, LengthOrPercentageOrKeyword};
pub use self::image::{SizeKeyword, VerticalDirection};
+pub use self::length::{FontRelativeLength, ViewportPercentageLength, CharacterWidth, Length, CalcLengthOrPercentage};
+pub use self::length::{Percentage, LengthOrPercentage, LengthOrPercentageOrAuto, LengthOrPercentageOrNone};
+pub use self::length::{LengthOrNone, LengthOrPercentageOrAutoOrContent, CalcUnit};
pub mod basic_shape;
pub mod image;
+pub mod length;
pub mod position;
impl NoViewportPercentage for i32 {} // For PropertyDeclaration::Order
@@ -80,289 +82,9 @@ impl ToCss for CSSRGBA {
}
}
-#[derive(Clone, PartialEq, Copy, Debug)]
-#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
-pub enum FontRelativeLength {
- Em(CSSFloat),
- Ex(CSSFloat),
- Ch(CSSFloat),
- Rem(CSSFloat)
-}
-
-impl ToCss for FontRelativeLength {
- fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
- match *self {
- FontRelativeLength::Em(length) => write!(dest, "{}em", length),
- FontRelativeLength::Ex(length) => write!(dest, "{}ex", length),
- FontRelativeLength::Ch(length) => write!(dest, "{}ch", length),
- FontRelativeLength::Rem(length) => write!(dest, "{}rem", length)
- }
- }
-}
-
-impl FontRelativeLength {
- pub fn to_computed_value(&self,
- reference_font_size: Au,
- root_font_size: Au)
- -> Au
- {
- match *self {
- FontRelativeLength::Em(length) => reference_font_size.scale_by(length),
- FontRelativeLength::Ex(length) | FontRelativeLength::Ch(length) => {
- // https://github.com/servo/servo/issues/7462
- let em_factor = 0.5;
- reference_font_size.scale_by(length * em_factor)
- },
- FontRelativeLength::Rem(length) => root_font_size.scale_by(length)
- }
- }
-}
-
-#[derive(Clone, PartialEq, Copy, Debug)]
-#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
-pub enum ViewportPercentageLength {
- Vw(CSSFloat),
- Vh(CSSFloat),
- Vmin(CSSFloat),
- Vmax(CSSFloat)
-}
-
-impl HasViewportPercentage for ViewportPercentageLength {
- fn has_viewport_percentage(&self) -> bool {
- true
- }
-}
-
-impl ToCss for ViewportPercentageLength {
- fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
- match *self {
- ViewportPercentageLength::Vw(length) => write!(dest, "{}vw", length),
- ViewportPercentageLength::Vh(length) => write!(dest, "{}vh", length),
- ViewportPercentageLength::Vmin(length) => write!(dest, "{}vmin", length),
- ViewportPercentageLength::Vmax(length) => write!(dest, "{}vmax", length)
- }
- }
-}
-
-impl ViewportPercentageLength {
- pub fn to_computed_value(&self, viewport_size: Size2D<Au>) -> Au {
- macro_rules! to_unit {
- ($viewport_dimension:expr) => {
- $viewport_dimension.to_f32_px() / 100.0
- }
- }
-
- let value = match *self {
- ViewportPercentageLength::Vw(length) =>
- length * to_unit!(viewport_size.width),
- ViewportPercentageLength::Vh(length) =>
- length * to_unit!(viewport_size.height),
- ViewportPercentageLength::Vmin(length) =>
- length * to_unit!(cmp::min(viewport_size.width, viewport_size.height)),
- ViewportPercentageLength::Vmax(length) =>
- length * to_unit!(cmp::max(viewport_size.width, viewport_size.height)),
- };
- Au::from_f32_px(value)
- }
-}
-
-#[derive(Clone, PartialEq, Copy, Debug)]
-#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
-pub struct CharacterWidth(pub i32);
-
-impl CharacterWidth {
- pub fn to_computed_value(&self, reference_font_size: Au) -> Au {
- // This applies the *converting a character width to pixels* algorithm as specified
- // in HTML5 § 14.5.4.
- //
- // TODO(pcwalton): Find these from the font.
- let average_advance = reference_font_size.scale_by(0.5);
- let max_advance = reference_font_size;
- average_advance.scale_by(self.0 as CSSFloat - 1.0) + max_advance
- }
-}
-
-#[derive(Clone, PartialEq, Copy, Debug)]
-#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
-pub enum Length {
- Absolute(Au), // application units
- FontRelative(FontRelativeLength),
- ViewportPercentage(ViewportPercentageLength),
-
- /// HTML5 "character width", as defined in HTML5 § 14.5.4.
- ///
- /// This cannot be specified by the user directly and is only generated by
- /// `Stylist::synthesize_rules_for_legacy_attributes()`.
- ServoCharacterWidth(CharacterWidth),
-
- Calc(CalcLengthOrPercentage, AllowedNumericType),
-}
-
-impl HasViewportPercentage for Length {
- fn has_viewport_percentage(&self) -> bool {
- match *self {
- Length::ViewportPercentage(_) => true,
- Length::Calc(ref calc, _) => calc.has_viewport_percentage(),
- _ => false
- }
- }
-}
-
-impl ToCss for Length {
- fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
- match *self {
- Length::Absolute(length) => write!(dest, "{}px", length.to_f32_px()),
- Length::FontRelative(length) => length.to_css(dest),
- Length::ViewportPercentage(length) => length.to_css(dest),
- Length::Calc(ref calc, _) => calc.to_css(dest),
- /* This should only be reached from style dumping code */
- Length::ServoCharacterWidth(CharacterWidth(i)) => write!(dest, "CharWidth({})", i),
- }
- }
-}
-
-impl Mul<CSSFloat> for Length {
- type Output = Length;
-
- #[inline]
- fn mul(self, scalar: CSSFloat) -> Length {
- match self {
- Length::Absolute(Au(v)) => Length::Absolute(Au(((v as f32) * scalar) as i32)),
- Length::FontRelative(v) => Length::FontRelative(v * scalar),
- Length::ViewportPercentage(v) => Length::ViewportPercentage(v * scalar),
- Length::Calc(..) => panic!("Can't multiply Calc!"),
- Length::ServoCharacterWidth(_) => panic!("Can't multiply ServoCharacterWidth!"),
- }
- }
-}
-
-impl Mul<CSSFloat> for FontRelativeLength {
- type Output = FontRelativeLength;
-
- #[inline]
- fn mul(self, scalar: CSSFloat) -> FontRelativeLength {
- match self {
- FontRelativeLength::Em(v) => FontRelativeLength::Em(v * scalar),
- FontRelativeLength::Ex(v) => FontRelativeLength::Ex(v * scalar),
- FontRelativeLength::Ch(v) => FontRelativeLength::Ch(v * scalar),
- FontRelativeLength::Rem(v) => FontRelativeLength::Rem(v * scalar),
- }
- }
-}
-
-impl Mul<CSSFloat> for ViewportPercentageLength {
- type Output = ViewportPercentageLength;
-
- #[inline]
- fn mul(self, scalar: CSSFloat) -> ViewportPercentageLength {
- match self {
- ViewportPercentageLength::Vw(v) => ViewportPercentageLength::Vw(v * scalar),
- ViewportPercentageLength::Vh(v) => ViewportPercentageLength::Vh(v * scalar),
- ViewportPercentageLength::Vmin(v) => ViewportPercentageLength::Vmin(v * scalar),
- ViewportPercentageLength::Vmax(v) => ViewportPercentageLength::Vmax(v * scalar),
- }
- }
-}
-
-const AU_PER_PX: CSSFloat = 60.;
-const AU_PER_IN: CSSFloat = AU_PER_PX * 96.;
-const AU_PER_CM: CSSFloat = AU_PER_IN / 2.54;
-const AU_PER_MM: CSSFloat = AU_PER_IN / 25.4;
-const AU_PER_Q: CSSFloat = AU_PER_MM / 4.;
-const AU_PER_PT: CSSFloat = AU_PER_IN / 72.;
-const AU_PER_PC: CSSFloat = AU_PER_PT * 12.;
-impl Length {
- // https://drafts.csswg.org/css-fonts-3/#font-size-prop
- pub fn from_str(s: &str) -> Option<Length> {
- Some(match_ignore_ascii_case! { s,
- "xx-small" => Length::Absolute(Au::from_px(FONT_MEDIUM_PX) * 3 / 5),
- "x-small" => Length::Absolute(Au::from_px(FONT_MEDIUM_PX) * 3 / 4),
- "small" => Length::Absolute(Au::from_px(FONT_MEDIUM_PX) * 8 / 9),
- "medium" => Length::Absolute(Au::from_px(FONT_MEDIUM_PX)),
- "large" => Length::Absolute(Au::from_px(FONT_MEDIUM_PX) * 6 / 5),
- "x-large" => Length::Absolute(Au::from_px(FONT_MEDIUM_PX) * 3 / 2),
- "xx-large" => Length::Absolute(Au::from_px(FONT_MEDIUM_PX) * 2),
-
- // https://github.com/servo/servo/issues/3423#issuecomment-56321664
- "smaller" => Length::FontRelative(FontRelativeLength::Em(0.85)),
- "larger" => Length::FontRelative(FontRelativeLength::Em(1.2)),
- _ => return None
- })
- }
-
- #[inline]
- fn parse_internal(input: &mut Parser, context: AllowedNumericType) -> Result<Length, ()> {
- match try!(input.next()) {
- Token::Dimension(ref value, ref unit) if context.is_ok(value.value) =>
- Length::parse_dimension(value.value, unit),
- Token::Number(ref value) if value.value == 0. =>
- Ok(Length::Absolute(Au(0))),
- Token::Function(ref name) if name.eq_ignore_ascii_case("calc") =>
- input.parse_nested_block(|input| {
- CalcLengthOrPercentage::parse_length(input, context)
- }),
- _ => Err(())
- }
- }
- pub fn parse_non_negative(input: &mut Parser) -> Result<Length, ()> {
- Length::parse_internal(input, AllowedNumericType::NonNegative)
- }
- pub fn parse_dimension(value: CSSFloat, unit: &str) -> Result<Length, ()> {
- match_ignore_ascii_case! { unit,
- "px" => Ok(Length::from_px(value)),
- "in" => Ok(Length::Absolute(Au((value * AU_PER_IN) as i32))),
- "cm" => Ok(Length::Absolute(Au((value * AU_PER_CM) as i32))),
- "mm" => Ok(Length::Absolute(Au((value * AU_PER_MM) as i32))),
- "q" => Ok(Length::Absolute(Au((value * AU_PER_Q) as i32))),
- "pt" => Ok(Length::Absolute(Au((value * AU_PER_PT) as i32))),
- "pc" => Ok(Length::Absolute(Au((value * AU_PER_PC) as i32))),
- // font-relative
- "em" => Ok(Length::FontRelative(FontRelativeLength::Em(value))),
- "ex" => Ok(Length::FontRelative(FontRelativeLength::Ex(value))),
- "ch" => Ok(Length::FontRelative(FontRelativeLength::Ch(value))),
- "rem" => Ok(Length::FontRelative(FontRelativeLength::Rem(value))),
- // viewport percentages
- "vw" => Ok(Length::ViewportPercentage(ViewportPercentageLength::Vw(value))),
- "vh" => Ok(Length::ViewportPercentage(ViewportPercentageLength::Vh(value))),
- "vmin" => Ok(Length::ViewportPercentage(ViewportPercentageLength::Vmin(value))),
- "vmax" => Ok(Length::ViewportPercentage(ViewportPercentageLength::Vmax(value))),
- _ => Err(())
- }
- }
- #[inline]
- pub fn from_px(px_value: CSSFloat) -> Length {
- Length::Absolute(Au((px_value * AU_PER_PX) as i32))
- }
-}
-
-impl Parse for Length {
- fn parse(input: &mut Parser) -> Result<Self, ()> {
- Length::parse_internal(input, AllowedNumericType::All)
- }
-}
#[derive(Clone, Debug)]
-struct CalcSumNode {
- products: Vec<CalcProductNode>,
-}
-
-#[derive(Clone, Debug)]
-struct CalcProductNode {
- values: Vec<CalcValueNode>
-}
-
-#[derive(Clone, Debug)]
-enum CalcValueNode {
- Length(Length),
- Angle(Angle),
- Time(Time),
- Percentage(CSSFloat),
- Number(CSSFloat),
- Sum(Box<CalcSumNode>),
-}
-
-#[derive(Clone, Debug)]
-struct SimplifiedSumNode {
+pub struct SimplifiedSumNode {
values: Vec<SimplifiedValueNode>,
}
impl<'a> Mul<CSSFloat> for &'a SimplifiedSumNode {
@@ -377,7 +99,7 @@ impl<'a> Mul<CSSFloat> for &'a SimplifiedSumNode {
}
#[derive(Clone, Debug)]
-enum SimplifiedValueNode {
+pub enum SimplifiedValueNode {
Length(Length),
Angle(Angle),
Time(Time),
@@ -454,708 +176,6 @@ pub fn parse_number(input: &mut Parser) -> Result<f32, ()> {
}
}
-#[derive(Clone, Copy, PartialEq)]
-enum CalcUnit {
- Number,
- Integer,
- Length,
- LengthOrPercentage,
- Angle,
- Time,
-}
-
-#[derive(Clone, PartialEq, Copy, Debug, Default)]
-#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
-pub struct CalcLengthOrPercentage {
- pub absolute: Option<Au>,
- pub vw: Option<ViewportPercentageLength>,
- pub vh: Option<ViewportPercentageLength>,
- pub vmin: Option<ViewportPercentageLength>,
- pub vmax: Option<ViewportPercentageLength>,
- pub em: Option<FontRelativeLength>,
- pub ex: Option<FontRelativeLength>,
- pub ch: Option<FontRelativeLength>,
- pub rem: Option<FontRelativeLength>,
- pub percentage: Option<Percentage>,
-}
-
-impl CalcLengthOrPercentage {
- fn parse_sum(input: &mut Parser, expected_unit: CalcUnit) -> Result<CalcSumNode, ()> {
- let mut products = Vec::new();
- products.push(try!(CalcLengthOrPercentage::parse_product(input, expected_unit)));
-
- while let Ok(token) = input.next() {
- match token {
- Token::Delim('+') => {
- products.push(try!(CalcLengthOrPercentage::parse_product(input, expected_unit)));
- }
- Token::Delim('-') => {
- let mut right = try!(CalcLengthOrPercentage::parse_product(input, expected_unit));
- right.values.push(CalcValueNode::Number(-1.));
- products.push(right);
- }
- _ => return Err(())
- }
- }
-
- Ok(CalcSumNode { products: products })
- }
-
- fn parse_product(input: &mut Parser, expected_unit: CalcUnit) -> Result<CalcProductNode, ()> {
- let mut values = Vec::new();
- values.push(try!(CalcLengthOrPercentage::parse_value(input, expected_unit)));
-
- loop {
- let position = input.position();
- match input.next() {
- Ok(Token::Delim('*')) => {
- values.push(try!(CalcLengthOrPercentage::parse_value(input, expected_unit)));
- }
- Ok(Token::Delim('/')) if expected_unit != CalcUnit::Integer => {
- if let Ok(Token::Number(ref value)) = input.next() {
- if value.value == 0. {
- return Err(());
- }
- values.push(CalcValueNode::Number(1. / value.value));
- } else {
- return Err(());
- }
- }
- _ => {
- input.reset(position);
- break
- }
- }
- }
-
- Ok(CalcProductNode { values: values })
- }
-
- fn parse_value(input: &mut Parser, expected_unit: CalcUnit) -> Result<CalcValueNode, ()> {
- match (try!(input.next()), expected_unit) {
- (Token::Number(ref value), _) => Ok(CalcValueNode::Number(value.value)),
- (Token::Dimension(ref value, ref unit), CalcUnit::Length) |
- (Token::Dimension(ref value, ref unit), CalcUnit::LengthOrPercentage) => {
- Length::parse_dimension(value.value, unit).map(CalcValueNode::Length)
- }
- (Token::Dimension(ref value, ref unit), CalcUnit::Angle) => {
- Angle::parse_dimension(value.value, unit).map(CalcValueNode::Angle)
- }
- (Token::Dimension(ref value, ref unit), CalcUnit::Time) => {
- Time::parse_dimension(value.value, unit).map(CalcValueNode::Time)
- }
- (Token::Percentage(ref value), CalcUnit::LengthOrPercentage) =>
- Ok(CalcValueNode::Percentage(value.unit_value)),
- (Token::ParenthesisBlock, _) => {
- input.parse_nested_block(|i| CalcLengthOrPercentage::parse_sum(i, expected_unit))
- .map(|result| CalcValueNode::Sum(Box::new(result)))
- },
- _ => Err(())
- }
- }
-
- fn simplify_value_to_number(node: &CalcValueNode) -> Option<CSSFloat> {
- match *node {
- CalcValueNode::Number(number) => Some(number),
- CalcValueNode::Sum(ref sum) => CalcLengthOrPercentage::simplify_sum_to_number(sum),
- _ => None
- }
- }
-
- fn simplify_sum_to_number(node: &CalcSumNode) -> Option<CSSFloat> {
- let mut sum = 0.;
- for ref product in &node.products {
- match CalcLengthOrPercentage::simplify_product_to_number(product) {
- Some(number) => sum += number,
- _ => return None
- }
- }
- Some(sum)
- }
-
- fn simplify_product_to_number(node: &CalcProductNode) -> Option<CSSFloat> {
- let mut product = 1.;
- for ref value in &node.values {
- match CalcLengthOrPercentage::simplify_value_to_number(value) {
- Some(number) => product *= number,
- _ => return None
- }
- }
- Some(product)
- }
-
- fn simplify_products_in_sum(node: &CalcSumNode) -> Result<SimplifiedValueNode, ()> {
- let mut simplified = Vec::new();
- for product in &node.products {
- match try!(CalcLengthOrPercentage::simplify_product(product)) {
- SimplifiedValueNode::Sum(ref sum) => simplified.extend_from_slice(&sum.values),
- val => simplified.push(val),
- }
- }
-
- if simplified.len() == 1 {
- Ok(simplified[0].clone())
- } else {
- Ok(SimplifiedValueNode::Sum(Box::new(SimplifiedSumNode { values: simplified })))
- }
- }
-
- fn simplify_product(node: &CalcProductNode) -> Result<SimplifiedValueNode, ()> {
- let mut multiplier = 1.;
- let mut node_with_unit = None;
- for node in &node.values {
- match CalcLengthOrPercentage::simplify_value_to_number(&node) {
- Some(number) => multiplier *= number,
- _ if node_with_unit.is_none() => {
- node_with_unit = Some(match *node {
- CalcValueNode::Sum(ref sum) =>
- try!(CalcLengthOrPercentage::simplify_products_in_sum(sum)),
- CalcValueNode::Length(l) => SimplifiedValueNode::Length(l),
- CalcValueNode::Angle(a) => SimplifiedValueNode::Angle(a),
- CalcValueNode::Time(t) => SimplifiedValueNode::Time(t),
- CalcValueNode::Percentage(p) => SimplifiedValueNode::Percentage(p),
- _ => unreachable!("Numbers should have been handled by simplify_value_to_nubmer")
- })
- },
- _ => return Err(()),
- }
- }
-
- match node_with_unit {
- None => Ok(SimplifiedValueNode::Number(multiplier)),
- Some(ref value) => Ok(value * multiplier)
- }
- }
-
- fn parse_length(input: &mut Parser,
- context: AllowedNumericType) -> Result<Length, ()> {
- CalcLengthOrPercentage::parse(input, CalcUnit::Length).map(|calc| {
- Length::Calc(calc, context)
- })
- }
-
- fn parse_length_or_percentage(input: &mut Parser) -> Result<CalcLengthOrPercentage, ()> {
- CalcLengthOrPercentage::parse(input, CalcUnit::LengthOrPercentage)
- }
-
- fn parse(input: &mut Parser,
- expected_unit: CalcUnit) -> Result<CalcLengthOrPercentage, ()> {
- let ast = try!(CalcLengthOrPercentage::parse_sum(input, expected_unit));
-
- let mut simplified = Vec::new();
- for ref node in ast.products {
- match try!(CalcLengthOrPercentage::simplify_product(node)) {
- SimplifiedValueNode::Sum(sum) => simplified.extend_from_slice(&sum.values),
- value => simplified.push(value),
- }
- }
-
- let mut absolute = None;
- let mut vw = None;
- let mut vh = None;
- let mut vmax = None;
- let mut vmin = None;
- let mut em = None;
- let mut ex = None;
- let mut ch = None;
- let mut rem = None;
- let mut percentage = None;
- let mut number = None;
-
- for value in simplified {
- match value {
- SimplifiedValueNode::Percentage(p) =>
- percentage = Some(percentage.unwrap_or(0.) + p),
- SimplifiedValueNode::Length(Length::Absolute(Au(au))) =>
- absolute = Some(absolute.unwrap_or(0) + au),
- SimplifiedValueNode::Length(Length::ViewportPercentage(v)) =>
- match v {
- ViewportPercentageLength::Vw(val) =>
- vw = Some(vw.unwrap_or(0.) + val),
- ViewportPercentageLength::Vh(val) =>
- vh = Some(vh.unwrap_or(0.) + val),
- ViewportPercentageLength::Vmin(val) =>
- vmin = Some(vmin.unwrap_or(0.) + val),
- ViewportPercentageLength::Vmax(val) =>
- vmax = Some(vmax.unwrap_or(0.) + val),
- },
- SimplifiedValueNode::Length(Length::FontRelative(f)) =>
- match f {
- FontRelativeLength::Em(val) =>
- em = Some(em.unwrap_or(0.) + val),
- FontRelativeLength::Ex(val) =>
- ex = Some(ex.unwrap_or(0.) + val),
- FontRelativeLength::Ch(val) =>
- ch = Some(ch.unwrap_or(0.) + val),
- FontRelativeLength::Rem(val) =>
- rem = Some(rem.unwrap_or(0.) + val),
- },
- SimplifiedValueNode::Number(val) => number = Some(number.unwrap_or(0.) + val),
- _ => return Err(()),
- }
- }
-
- Ok(CalcLengthOrPercentage {
- absolute: absolute.map(Au),
- vw: vw.map(ViewportPercentageLength::Vw),
- vh: vh.map(ViewportPercentageLength::Vh),
- vmax: vmax.map(ViewportPercentageLength::Vmax),
- vmin: vmin.map(ViewportPercentageLength::Vmin),
- em: em.map(FontRelativeLength::Em),
- ex: ex.map(FontRelativeLength::Ex),
- ch: ch.map(FontRelativeLength::Ch),
- rem: rem.map(FontRelativeLength::Rem),
- percentage: percentage.map(Percentage),
- })
- }
-
- pub fn parse_time(input: &mut Parser) -> Result<Time, ()> {
- let ast = try!(CalcLengthOrPercentage::parse_sum(input, CalcUnit::Time));
-
- let mut simplified = Vec::new();
- for ref node in ast.products {
- match try!(CalcLengthOrPercentage::simplify_product(node)) {
- SimplifiedValueNode::Sum(sum) => simplified.extend_from_slice(&sum.values),
- value => simplified.push(value),
- }
- }
-
- let mut time = None;
-
- for value in simplified {
- match value {
- SimplifiedValueNode::Time(Time(val)) =>
- time = Some(time.unwrap_or(0.) + val),
- _ => return Err(()),
- }
- }
-
- match time {
- Some(time) => Ok(Time(time)),
- _ => Err(())
- }
- }
-
- pub fn parse_angle(input: &mut Parser) -> Result<Angle, ()> {
- let ast = try!(CalcLengthOrPercentage::parse_sum(input, CalcUnit::Angle));
-
- let mut simplified = Vec::new();
- for ref node in ast.products {
- match try!(CalcLengthOrPercentage::simplify_product(node)) {
- SimplifiedValueNode::Sum(sum) => simplified.extend_from_slice(&sum.values),
- value => simplified.push(value),
- }
- }
-
- let mut angle = None;
- let mut number = None;
-
- for value in simplified {
- match value {
- SimplifiedValueNode::Angle(Angle(val)) =>
- angle = Some(angle.unwrap_or(0.) + val),
- SimplifiedValueNode::Number(val) => number = Some(number.unwrap_or(0.) + val),
- _ => unreachable!()
- }
- }
-
- match (angle, number) {
- (Some(angle), None) => Ok(Angle(angle)),
- (None, Some(value)) if value == 0. => Ok(Angle(0.)),
- _ => Err(())
- }
- }
-
- pub fn compute_from_viewport_and_font_size(&self,
- viewport_size: Size2D<Au>,
- font_size: Au,
- root_font_size: Au)
- -> computed::CalcLengthOrPercentage
- {
- let mut length = None;
-
- if let Some(absolute) = self.absolute {
- length = Some(length.unwrap_or(Au(0)) + absolute);
- }
-
- for val in &[self.vw, self.vh, self.vmin, self.vmax] {
- if let Some(val) = *val {
- length = Some(length.unwrap_or(Au(0)) +
- val.to_computed_value(viewport_size));
- }
- }
-
- for val in &[self.ch, self.em, self.ex, self.rem] {
- if let Some(val) = *val {
- length = Some(length.unwrap_or(Au(0)) + val.to_computed_value(
- font_size, root_font_size));
- }
- }
-
- computed::CalcLengthOrPercentage {
- length: length,
- percentage: self.percentage.map(|p| p.0),
- }
- }
-}
-
-impl HasViewportPercentage for CalcLengthOrPercentage {
- fn has_viewport_percentage(&self) -> bool {
- self.vw.is_some() || self.vh.is_some() ||
- self.vmin.is_some() || self.vmax.is_some()
- }
-}
-
-impl ToCss for CalcLengthOrPercentage {
- #[allow(unused_assignments)]
- fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
- macro_rules! count {
- ( $( $val:ident ),* ) => {
- {
- let mut count = 0;
- $(
- if let Some(_) = self.$val {
- count += 1;
- }
- )*
- count
- }
- };
- }
-
- macro_rules! serialize {
- ( $( $val:ident ),* ) => {
- {
- let mut first_value = true;
- $(
- if let Some(val) = self.$val {
- if !first_value {
- try!(write!(dest, " + "));
- } else {
- first_value = false;
- }
- try!(val.to_css(dest));
- }
- )*
- }
- };
- }
-
- let count = count!(ch, em, ex, absolute, rem, vh, vmax, vmin, vw, percentage);
- assert!(count > 0);
-
- if count > 1 {
- try!(write!(dest, "calc("));
- }
-
- serialize!(ch, em, ex, absolute, rem, vh, vmax, vmin, vw, percentage);
-
- if count > 1 {
- try!(write!(dest, ")"));
- }
- Ok(())
- }
-}
-
-#[derive(Clone, PartialEq, Copy, Debug)]
-#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
-pub struct Percentage(pub CSSFloat); // [0 .. 100%] maps to [0.0 .. 1.0]
-
-impl ToCss for Percentage {
- fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
- write!(dest, "{}%", self.0 * 100.)
- }
-}
-
-#[derive(Clone, PartialEq, Copy, Debug)]
-#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
-pub enum LengthOrPercentage {
- Length(Length),
- Percentage(Percentage),
- Calc(CalcLengthOrPercentage),
-}
-
-impl HasViewportPercentage for LengthOrPercentage {
- fn has_viewport_percentage(&self) -> bool {
- match *self {
- LengthOrPercentage::Length(ref length) => length.has_viewport_percentage(),
- LengthOrPercentage::Calc(ref calc) => calc.has_viewport_percentage(),
- _ => false
- }
- }
-}
-
-impl ToCss for LengthOrPercentage {
- fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
- match *self {
- LengthOrPercentage::Length(length) => length.to_css(dest),
- LengthOrPercentage::Percentage(percentage) => percentage.to_css(dest),
- LengthOrPercentage::Calc(calc) => calc.to_css(dest),
- }
- }
-}
-impl LengthOrPercentage {
- pub fn zero() -> LengthOrPercentage {
- LengthOrPercentage::Length(Length::Absolute(Au(0)))
- }
-
- fn parse_internal(input: &mut Parser, context: AllowedNumericType)
- -> Result<LengthOrPercentage, ()>
- {
- match try!(input.next()) {
- Token::Dimension(ref value, ref unit) if context.is_ok(value.value) =>
- Length::parse_dimension(value.value, unit).map(LengthOrPercentage::Length),
- Token::Percentage(ref value) if context.is_ok(value.unit_value) =>
- Ok(LengthOrPercentage::Percentage(Percentage(value.unit_value))),
- Token::Number(ref value) if value.value == 0. =>
- Ok(LengthOrPercentage::Length(Length::Absolute(Au(0)))),
- Token::Function(ref name) if name.eq_ignore_ascii_case("calc") => {
- let calc = try!(input.parse_nested_block(CalcLengthOrPercentage::parse_length_or_percentage));
- Ok(LengthOrPercentage::Calc(calc))
- },
- _ => Err(())
- }
- }
-
- #[inline]
- pub fn parse_non_negative(input: &mut Parser) -> Result<LengthOrPercentage, ()> {
- LengthOrPercentage::parse_internal(input, AllowedNumericType::NonNegative)
- }
-}
-
-impl Parse for LengthOrPercentage {
- #[inline]
- fn parse(input: &mut Parser) -> Result<Self, ()> {
- LengthOrPercentage::parse_internal(input, AllowedNumericType::All)
- }
-}
-
-#[derive(Clone, PartialEq, Copy, Debug)]
-#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
-pub enum LengthOrPercentageOrAuto {
- Length(Length),
- Percentage(Percentage),
- Auto,
- Calc(CalcLengthOrPercentage),
-}
-
-impl HasViewportPercentage for LengthOrPercentageOrAuto {
- fn has_viewport_percentage(&self) -> bool {
- match *self {
- LengthOrPercentageOrAuto::Length(ref length) => length.has_viewport_percentage(),
- LengthOrPercentageOrAuto::Calc(ref calc) => calc.has_viewport_percentage(),
- _ => false
- }
- }
-}
-
-impl ToCss for LengthOrPercentageOrAuto {
- fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
- match *self {
- LengthOrPercentageOrAuto::Length(length) => length.to_css(dest),
- LengthOrPercentageOrAuto::Percentage(percentage) => percentage.to_css(dest),
- LengthOrPercentageOrAuto::Auto => dest.write_str("auto"),
- LengthOrPercentageOrAuto::Calc(calc) => calc.to_css(dest),
- }
- }
-}
-
-impl LengthOrPercentageOrAuto {
- fn parse_internal(input: &mut Parser, context: AllowedNumericType)
- -> Result<LengthOrPercentageOrAuto, ()>
- {
- match try!(input.next()) {
- Token::Dimension(ref value, ref unit) if context.is_ok(value.value) =>
- Length::parse_dimension(value.value, unit).map(LengthOrPercentageOrAuto::Length),
- Token::Percentage(ref value) if context.is_ok(value.unit_value) =>
- Ok(LengthOrPercentageOrAuto::Percentage(Percentage(value.unit_value))),
- Token::Number(ref value) if value.value == 0. =>
- Ok(LengthOrPercentageOrAuto::Length(Length::Absolute(Au(0)))),
- Token::Ident(ref value) if value.eq_ignore_ascii_case("auto") =>
- Ok(LengthOrPercentageOrAuto::Auto),
- Token::Function(ref name) if name.eq_ignore_ascii_case("calc") => {
- let calc = try!(input.parse_nested_block(CalcLengthOrPercentage::parse_length_or_percentage));
- Ok(LengthOrPercentageOrAuto::Calc(calc))
- },
- _ => Err(())
- }
- }
- #[inline]
- pub fn parse(input: &mut Parser) -> Result<LengthOrPercentageOrAuto, ()> {
- LengthOrPercentageOrAuto::parse_internal(input, AllowedNumericType::All)
- }
- #[inline]
- pub fn parse_non_negative(input: &mut Parser) -> Result<LengthOrPercentageOrAuto, ()> {
- LengthOrPercentageOrAuto::parse_internal(input, AllowedNumericType::NonNegative)
- }
-}
-
-#[derive(Clone, PartialEq, Copy, Debug)]
-#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
-pub enum LengthOrPercentageOrNone {
- Length(Length),
- Percentage(Percentage),
- Calc(CalcLengthOrPercentage),
- None,
-}
-
-impl HasViewportPercentage for LengthOrPercentageOrNone {
- fn has_viewport_percentage(&self) -> bool {
- match *self {
- LengthOrPercentageOrNone::Length(ref length) => length.has_viewport_percentage(),
- LengthOrPercentageOrNone::Calc(ref calc) => calc.has_viewport_percentage(),
- _ => false
- }
- }
-}
-
-impl ToCss for LengthOrPercentageOrNone {
- fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
- match *self {
- LengthOrPercentageOrNone::Length(ref length) => length.to_css(dest),
- LengthOrPercentageOrNone::Percentage(ref percentage) => percentage.to_css(dest),
- LengthOrPercentageOrNone::Calc(ref calc) => calc.to_css(dest),
- LengthOrPercentageOrNone::None => dest.write_str("none"),
- }
- }
-}
-impl LengthOrPercentageOrNone {
- fn parse_internal(input: &mut Parser, context: AllowedNumericType)
- -> Result<LengthOrPercentageOrNone, ()>
- {
- match try!(input.next()) {
- Token::Dimension(ref value, ref unit) if context.is_ok(value.value) =>
- Length::parse_dimension(value.value, unit).map(LengthOrPercentageOrNone::Length),
- Token::Percentage(ref value) if context.is_ok(value.unit_value) =>
- Ok(LengthOrPercentageOrNone::Percentage(Percentage(value.unit_value))),
- Token::Number(ref value) if value.value == 0. =>
- Ok(LengthOrPercentageOrNone::Length(Length::Absolute(Au(0)))),
- Token::Function(ref name) if name.eq_ignore_ascii_case("calc") => {
- let calc = try!(input.parse_nested_block(CalcLengthOrPercentage::parse_length_or_percentage));
- Ok(LengthOrPercentageOrNone::Calc(calc))
- },
- Token::Ident(ref value) if value.eq_ignore_ascii_case("none") =>
- Ok(LengthOrPercentageOrNone::None),
- _ => Err(())
- }
- }
- #[inline]
- pub fn parse(input: &mut Parser) -> Result<LengthOrPercentageOrNone, ()> {
- LengthOrPercentageOrNone::parse_internal(input, AllowedNumericType::All)
- }
- #[inline]
- pub fn parse_non_negative(input: &mut Parser) -> Result<LengthOrPercentageOrNone, ()> {
- LengthOrPercentageOrNone::parse_internal(input, AllowedNumericType::NonNegative)
- }
-}
-
-#[derive(Clone, PartialEq, Copy, Debug)]
-#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
-pub enum LengthOrNone {
- Length(Length),
- None,
-}
-
-impl HasViewportPercentage for LengthOrNone {
- fn has_viewport_percentage(&self) -> bool {
- match *self {
- LengthOrNone::Length(ref length) => length.has_viewport_percentage(),
- _ => false
- }
- }
-}
-
-impl ToCss for LengthOrNone {
- fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
- match *self {
- LengthOrNone::Length(length) => length.to_css(dest),
- LengthOrNone::None => dest.write_str("none"),
- }
- }
-}
-impl LengthOrNone {
- fn parse_internal(input: &mut Parser, context: AllowedNumericType)
- -> Result<LengthOrNone, ()>
- {
- match try!(input.next()) {
- Token::Dimension(ref value, ref unit) if context.is_ok(value.value) =>
- Length::parse_dimension(value.value, unit).map(LengthOrNone::Length),
- Token::Number(ref value) if value.value == 0. =>
- Ok(LengthOrNone::Length(Length::Absolute(Au(0)))),
- Token::Function(ref name) if name.eq_ignore_ascii_case("calc") =>
- input.parse_nested_block(|input| {
- CalcLengthOrPercentage::parse_length(input, context)
- }).map(LengthOrNone::Length),
- Token::Ident(ref value) if value.eq_ignore_ascii_case("none") =>
- Ok(LengthOrNone::None),
- _ => Err(())
- }
- }
- #[inline]
- pub fn parse(input: &mut Parser) -> Result<LengthOrNone, ()> {
- LengthOrNone::parse_internal(input, AllowedNumericType::All)
- }
- #[inline]
- pub fn parse_non_negative(input: &mut Parser) -> Result<LengthOrNone, ()> {
- LengthOrNone::parse_internal(input, AllowedNumericType::NonNegative)
- }
-}
-
-#[derive(Clone, PartialEq, Copy, Debug)]
-#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
-pub enum LengthOrPercentageOrAutoOrContent {
- Length(Length),
- Percentage(Percentage),
- Calc(CalcLengthOrPercentage),
- Auto,
- Content
-}
-
-impl HasViewportPercentage for LengthOrPercentageOrAutoOrContent {
- fn has_viewport_percentage(&self) -> bool {
- match *self {
- LengthOrPercentageOrAutoOrContent::Length(length) => length.has_viewport_percentage(),
- LengthOrPercentageOrAutoOrContent::Calc(ref calc) => calc.has_viewport_percentage(),
- _ => false
- }
- }
-}
-
-impl ToCss for LengthOrPercentageOrAutoOrContent {
- fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
- match *self {
- LengthOrPercentageOrAutoOrContent::Length(len) => len.to_css(dest),
- LengthOrPercentageOrAutoOrContent::Percentage(perc) => perc.to_css(dest),
- LengthOrPercentageOrAutoOrContent::Auto => dest.write_str("auto"),
- LengthOrPercentageOrAutoOrContent::Content => dest.write_str("content"),
- LengthOrPercentageOrAutoOrContent::Calc(calc) => calc.to_css(dest),
- }
- }
-}
-
-impl LengthOrPercentageOrAutoOrContent {
- pub fn parse(input: &mut Parser) -> Result<LengthOrPercentageOrAutoOrContent, ()> {
- let context = AllowedNumericType::NonNegative;
- match try!(input.next()) {
- Token::Dimension(ref value, ref unit) if context.is_ok(value.value) =>
- Length::parse_dimension(value.value, unit).map(LengthOrPercentageOrAutoOrContent::Length),
- Token::Percentage(ref value) if context.is_ok(value.unit_value) =>
- Ok(LengthOrPercentageOrAutoOrContent::Percentage(Percentage(value.unit_value))),
- Token::Number(ref value) if value.value == 0. =>
- Ok(LengthOrPercentageOrAutoOrContent::Length(Length::Absolute(Au(0)))),
- Token::Ident(ref value) if value.eq_ignore_ascii_case("auto") =>
- Ok(LengthOrPercentageOrAutoOrContent::Auto),
- Token::Ident(ref value) if value.eq_ignore_ascii_case("content") =>
- Ok(LengthOrPercentageOrAutoOrContent::Content),
- Token::Function(ref name) if name.eq_ignore_ascii_case("calc") => {
- let calc = try!(input.parse_nested_block(CalcLengthOrPercentage::parse_length_or_percentage));
- Ok(LengthOrPercentageOrAutoOrContent::Calc(calc))
- },
- _ => Err(())
- }
- }
-}
-
#[derive(Clone, PartialEq, Copy, Debug)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
pub struct BorderRadiusSize(pub Size2D<LengthOrPercentage>);