From 4e8831457aab1f16e43b60374e921f03f4339b5f Mon Sep 17 00:00:00 2001 From: Per Lundberg Date: Sat, 23 Apr 2016 00:35:13 +0300 Subject: [PATCH] Moved the rest of the longhand structs to separate files. Sorry for the bulk size of this; I know already it's not going to be a fun thing to review. Nevertheless, it should be done so we finalize the split of this huge file into smaller, more maintable parts. The content of stuff being moved to separate files is unchanged. Only some minor formatting changes have been made and similar, but nothing of particular interest. IMHO it should be safe to merge if all the tests are fine. --- components/style/properties/data.py | 7 - .../properties/longhand/background.mako.rs | 327 ++ .../style/properties/longhand/border.mako.rs | 3 +- .../style/properties/longhand/box.mako.rs | 710 ++- .../style/properties/longhand/color.mako.rs | 43 + .../style/properties/longhand/column.mako.rs | 196 + .../properties/longhand/counters.mako.rs | 248 + .../style/properties/longhand/effects.mako.rs | 1343 +++++ .../style/properties/longhand/font.mako.rs | 312 ++ .../properties/longhand/inherited_box.mako.rs | 90 + .../longhand/inherited_table.mako.rs | 100 + .../longhand/inherited_text.mako.rs | 613 +++ .../style/properties/longhand/list.mako.rs | 153 + .../style/properties/longhand/outline.mako.rs | 1 - .../properties/longhand/pointing.mako.rs | 56 + .../properties/longhand/position.mako.rs | 59 + .../style/properties/longhand/svg.mako.rs | 18 + .../properties/longhand/svg_inherited.mako.rs | 38 + .../style/properties/longhand/table.mako.rs | 9 + .../style/properties/longhand/text.mako.rs | 109 + .../style/properties/properties.mako.rs | 4366 +---------------- 21 files changed, 4440 insertions(+), 4361 deletions(-) create mode 100644 components/style/properties/longhand/background.mako.rs create mode 100644 components/style/properties/longhand/color.mako.rs create mode 100644 components/style/properties/longhand/column.mako.rs create mode 100644 components/style/properties/longhand/counters.mako.rs create mode 100644 components/style/properties/longhand/effects.mako.rs create mode 100644 components/style/properties/longhand/font.mako.rs create mode 100644 components/style/properties/longhand/inherited_box.mako.rs create mode 100644 components/style/properties/longhand/inherited_table.mako.rs create mode 100644 components/style/properties/longhand/inherited_text.mako.rs create mode 100644 components/style/properties/longhand/list.mako.rs create mode 100644 components/style/properties/longhand/pointing.mako.rs create mode 100644 components/style/properties/longhand/svg.mako.rs create mode 100644 components/style/properties/longhand/svg_inherited.mako.rs create mode 100644 components/style/properties/longhand/table.mako.rs create mode 100644 components/style/properties/longhand/text.mako.rs diff --git a/components/style/properties/data.py b/components/style/properties/data.py index fd741f9713a..14ec494bfba 100644 --- a/components/style/properties/data.py +++ b/components/style/properties/data.py @@ -128,13 +128,6 @@ class PropertiesData(object): def active_style_structs(self): return [s for s in self.style_structs if s.additional_methods or s.longhands] - def switch_to_style_struct(self, name): - for style_struct in self.style_structs: - if style_struct.trait_name == name: - self.current_style_struct = style_struct - return - raise Exception("Failed to find the struct named " + name) - def declare_longhand(self, name, products="gecko servo", **kwargs): products = products.split() if self.product not in products: diff --git a/components/style/properties/longhand/background.mako.rs b/components/style/properties/longhand/background.mako.rs new file mode 100644 index 00000000000..65a2e857db7 --- /dev/null +++ b/components/style/properties/longhand/background.mako.rs @@ -0,0 +1,327 @@ +/* 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/. */ + +<%namespace name="helpers" file="/helpers.mako.rs" /> + +<% data.new_style_struct("Background", inherited=False, gecko_ffi_name="nsStyleBackground") %> +${helpers.predefined_type( + "background-color", "CSSColor", + "::cssparser::Color::RGBA(::cssparser::RGBA { red: 0., green: 0., blue: 0., alpha: 0. }) /* transparent */")} + +<%helpers:longhand name="background-image"> + use cssparser::ToCss; + use std::fmt; + use values::specified::Image; + use values::LocalToCss; + + pub mod computed_value { + use values::computed; + #[derive(Debug, Clone, PartialEq, HeapSizeOf)] + pub struct T(pub Option); + } + + impl ToCss for computed_value::T { + fn to_css(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { + match self.0 { + None => dest.write_str("none"), + Some(computed::Image::Url(ref url)) => url.to_css(dest), + Some(computed::Image::LinearGradient(ref gradient)) => + gradient.to_css(dest) + } + } + } + + #[derive(Debug, Clone, PartialEq, HeapSizeOf)] + pub struct SpecifiedValue(pub Option); + + impl ToCss for SpecifiedValue { + fn to_css(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { + match *self { + SpecifiedValue(Some(ref image)) => image.to_css(dest), + SpecifiedValue(None) => dest.write_str("none"), + } + } + } + + #[inline] + pub fn get_initial_value() -> computed_value::T { + computed_value::T(None) + } + pub fn parse(context: &ParserContext, input: &mut Parser) -> Result { + if input.try(|input| input.expect_ident_matching("none")).is_ok() { + Ok(SpecifiedValue(None)) + } else { + Ok(SpecifiedValue(Some(try!(Image::parse(context, input))))) + } + } + impl ToComputedValue for SpecifiedValue { + type ComputedValue = computed_value::T; + + #[inline] + fn to_computed_value(&self, context: &Cx) -> computed_value::T { + match *self { + SpecifiedValue(None) => computed_value::T(None), + SpecifiedValue(Some(ref image)) => + computed_value::T(Some(image.to_computed_value(context))), + } + } + } + + +<%helpers:longhand name="background-position"> + use cssparser::ToCss; + use std::fmt; + use values::AuExtensionMethods; + + pub mod computed_value { + use values::computed::LengthOrPercentage; + + #[derive(PartialEq, Copy, Clone, Debug, HeapSizeOf)] + pub struct T { + pub horizontal: LengthOrPercentage, + pub vertical: LengthOrPercentage, + } + } + + #[derive(Debug, Clone, PartialEq, Copy, HeapSizeOf)] + pub struct SpecifiedValue { + pub horizontal: specified::LengthOrPercentage, + pub vertical: specified::LengthOrPercentage, + } + + impl ToCss for SpecifiedValue { + fn to_css(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { + try!(self.horizontal.to_css(dest)); + try!(dest.write_str(" ")); + try!(self.vertical.to_css(dest)); + Ok(()) + } + } + + impl ToCss for computed_value::T { + fn to_css(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { + try!(self.horizontal.to_css(dest)); + try!(dest.write_str(" ")); + try!(self.vertical.to_css(dest)); + Ok(()) + } + } + + impl SpecifiedValue { + fn new(first: specified::PositionComponent, second: specified::PositionComponent) + -> Result { + let (horiz, vert) = match (category(first), category(second)) { + // Don't allow two vertical keywords or two horizontal keywords. + (PositionCategory::HorizontalKeyword, PositionCategory::HorizontalKeyword) | + (PositionCategory::VerticalKeyword, PositionCategory::VerticalKeyword) => return Err(()), + + // Swap if both are keywords and vertical precedes horizontal. + (PositionCategory::VerticalKeyword, PositionCategory::HorizontalKeyword) | + (PositionCategory::VerticalKeyword, PositionCategory::OtherKeyword) | + (PositionCategory::OtherKeyword, PositionCategory::HorizontalKeyword) => (second, first), + + // By default, horizontal is first. + _ => (first, second), + }; + Ok(SpecifiedValue { + horizontal: horiz.to_length_or_percentage(), + vertical: vert.to_length_or_percentage(), + }) + } + } + + // Collapse `Position` into a few categories to simplify the above `match` expression. + enum PositionCategory { + HorizontalKeyword, + VerticalKeyword, + OtherKeyword, + LengthOrPercentage, + } + fn category(p: specified::PositionComponent) -> PositionCategory { + match p { + specified::PositionComponent::Left | + specified::PositionComponent::Right => + PositionCategory::HorizontalKeyword, + specified::PositionComponent::Top | + specified::PositionComponent::Bottom => + PositionCategory::VerticalKeyword, + specified::PositionComponent::Center => + PositionCategory::OtherKeyword, + specified::PositionComponent::LengthOrPercentage(_) => + PositionCategory::LengthOrPercentage, + } + } + + impl ToComputedValue for SpecifiedValue { + type ComputedValue = computed_value::T; + + #[inline] + fn to_computed_value(&self, context: &Cx) -> computed_value::T { + computed_value::T { + horizontal: self.horizontal.to_computed_value(context), + vertical: self.vertical.to_computed_value(context), + } + } + } + + #[inline] + pub fn get_initial_value() -> computed_value::T { + computed_value::T { + horizontal: computed::LengthOrPercentage::Percentage(0.0), + vertical: computed::LengthOrPercentage::Percentage(0.0), + } + } + + pub fn parse(_context: &ParserContext, input: &mut Parser) + -> Result { + let first = try!(specified::PositionComponent::parse(input)); + let second = input.try(specified::PositionComponent::parse) + .unwrap_or(specified::PositionComponent::Center); + SpecifiedValue::new(first, second) + } + + +${helpers.single_keyword("background-repeat", "repeat repeat-x repeat-y no-repeat")} + +${helpers.single_keyword("background-attachment", "scroll fixed")} + +${helpers.single_keyword("background-clip", "border-box padding-box content-box")} + +${helpers.single_keyword("background-origin", "padding-box border-box content-box")} + +<%helpers:longhand name="background-size"> + use cssparser::{ToCss, Token}; + use std::ascii::AsciiExt; + use std::fmt; + + pub mod computed_value { + use values::computed::LengthOrPercentageOrAuto; + + #[derive(PartialEq, Clone, Debug, HeapSizeOf)] + pub struct ExplicitSize { + pub width: LengthOrPercentageOrAuto, + pub height: LengthOrPercentageOrAuto, + } + + #[derive(PartialEq, Clone, Debug, HeapSizeOf)] + pub enum T { + Explicit(ExplicitSize), + Cover, + Contain, + } + } + + impl ToCss for computed_value::T { + fn to_css(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { + match *self { + computed_value::T::Explicit(ref size) => size.to_css(dest), + computed_value::T::Cover => dest.write_str("cover"), + computed_value::T::Contain => dest.write_str("contain"), + } + } + } + + #[derive(Clone, PartialEq, Debug, HeapSizeOf)] + pub struct SpecifiedExplicitSize { + pub width: specified::LengthOrPercentageOrAuto, + pub height: specified::LengthOrPercentageOrAuto, + } + + impl ToCss for SpecifiedExplicitSize { + fn to_css(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { + try!(self.width.to_css(dest)); + try!(dest.write_str(" ")); + self.height.to_css(dest) + } + } + + impl ToCss for computed_value::ExplicitSize { + fn to_css(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { + try!(self.width.to_css(dest)); + try!(dest.write_str(" ")); + self.height.to_css(dest) + } + } + + + #[derive(Clone, PartialEq, Debug, HeapSizeOf)] + pub enum SpecifiedValue { + Explicit(SpecifiedExplicitSize), + Cover, + Contain, + } + + impl ToCss for SpecifiedValue { + fn to_css(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { + match *self { + SpecifiedValue::Explicit(ref size) => size.to_css(dest), + SpecifiedValue::Cover => dest.write_str("cover"), + SpecifiedValue::Contain => dest.write_str("contain"), + } + } + } + + impl ToComputedValue for SpecifiedValue { + type ComputedValue = computed_value::T; + + #[inline] + fn to_computed_value(&self, context: &Cx) -> computed_value::T { + match *self { + SpecifiedValue::Explicit(ref size) => { + computed_value::T::Explicit(computed_value::ExplicitSize { + width: size.width.to_computed_value(context), + height: size.height.to_computed_value(context), + }) + } + SpecifiedValue::Cover => computed_value::T::Cover, + SpecifiedValue::Contain => computed_value::T::Contain, + } + } + } + + #[inline] + pub fn get_initial_value() -> computed_value::T { + computed_value::T::Explicit(computed_value::ExplicitSize { + width: computed::LengthOrPercentageOrAuto::Auto, + height: computed::LengthOrPercentageOrAuto::Auto, + }) + } + + pub fn parse(_: &ParserContext, input: &mut Parser) -> Result { + let width; + if let Ok(value) = input.try(|input| { + match input.next() { + Err(_) => Err(()), + Ok(Token::Ident(ref ident)) if ident.eq_ignore_ascii_case("cover") => { + Ok(SpecifiedValue::Cover) + } + Ok(Token::Ident(ref ident)) if ident.eq_ignore_ascii_case("contain") => { + Ok(SpecifiedValue::Contain) + } + Ok(_) => Err(()), + } + }) { + return Ok(value) + } else { + width = try!(specified::LengthOrPercentageOrAuto::parse(input)) + } + + let height; + if let Ok(value) = input.try(|input| { + match input.next() { + Err(_) => Ok(specified::LengthOrPercentageOrAuto::Auto), + Ok(_) => Err(()), + } + }) { + height = value + } else { + height = try!(specified::LengthOrPercentageOrAuto::parse(input)); + } + + Ok(SpecifiedValue::Explicit(SpecifiedExplicitSize { + width: width, + height: height, + })) + } + diff --git a/components/style/properties/longhand/border.mako.rs b/components/style/properties/longhand/border.mako.rs index 16e8bc7a6eb..e36266b2a3c 100644 --- a/components/style/properties/longhand/border.mako.rs +++ b/components/style/properties/longhand/border.mako.rs @@ -3,7 +3,6 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ <%namespace name="helpers" file="/helpers.mako.rs" /> - <% from data import Method %> <% data.new_style_struct("Border", inherited=False, gecko_ffi_name="nsStyleBorder", @@ -62,3 +61,5 @@ "computed::BorderRadiusSize::zero()", "parse")} % endfor + +${helpers.single_keyword("box-decoration-break", "slice clone", products="gecko")} diff --git a/components/style/properties/longhand/box.mako.rs b/components/style/properties/longhand/box.mako.rs index 34d425ec16e..ec158c0d9fa 100644 --- a/components/style/properties/longhand/box.mako.rs +++ b/components/style/properties/longhand/box.mako.rs @@ -3,7 +3,6 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ <%namespace name="helpers" file="/helpers.mako.rs" /> - <% from data import Method, to_rust_ident %> <% data.new_style_struct("Box", @@ -122,3 +121,712 @@ ${helpers.single_keyword("clear", "none left right both", gecko_ffi_name="mBreak } + +${helpers.predefined_type("width", + "LengthOrPercentageOrAuto", + "computed::LengthOrPercentageOrAuto::Auto", + "parse_non_negative")} + +${helpers.predefined_type("height", + "LengthOrPercentageOrAuto", + "computed::LengthOrPercentageOrAuto::Auto", + "parse_non_negative")} + +<%helpers:longhand name="vertical-align"> + use cssparser::ToCss; + use std::fmt; + + <% vertical_align_keywords = ( + "baseline sub super top text-top middle bottom text-bottom".split()) %> + #[allow(non_camel_case_types)] + #[derive(Debug, Clone, PartialEq, Copy, HeapSizeOf)] + pub enum SpecifiedValue { + % for keyword in vertical_align_keywords: + ${to_rust_ident(keyword)}, + % endfor + LengthOrPercentage(specified::LengthOrPercentage), + } + + impl ToCss for SpecifiedValue { + fn to_css(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { + match *self { + % for keyword in vertical_align_keywords: + SpecifiedValue::${to_rust_ident(keyword)} => dest.write_str("${keyword}"), + % endfor + SpecifiedValue::LengthOrPercentage(value) => value.to_css(dest), + } + } + } + /// baseline | sub | super | top | text-top | middle | bottom | text-bottom + /// | | + pub fn parse(_context: &ParserContext, input: &mut Parser) -> Result { + input.try(specified::LengthOrPercentage::parse) + .map(SpecifiedValue::LengthOrPercentage) + .or_else(|()| { + match_ignore_ascii_case! { try!(input.expect_ident()), + % for keyword in vertical_align_keywords: + "${keyword}" => Ok(SpecifiedValue::${to_rust_ident(keyword)}), + % endfor + _ => Err(()) + } + }) + } + pub mod computed_value { + use app_units::Au; + use std::fmt; + use values::AuExtensionMethods; + use values::{CSSFloat, computed}; + #[allow(non_camel_case_types)] + #[derive(PartialEq, Copy, Clone, HeapSizeOf, Debug)] + pub enum T { + % for keyword in vertical_align_keywords: + ${to_rust_ident(keyword)}, + % endfor + LengthOrPercentage(computed::LengthOrPercentage), + } + impl ::cssparser::ToCss for T { + fn to_css(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { + match *self { + % for keyword in vertical_align_keywords: + T::${to_rust_ident(keyword)} => dest.write_str("${keyword}"), + % endfor + T::LengthOrPercentage(value) => value.to_css(dest), + } + } + } + } + #[inline] + pub fn get_initial_value() -> computed_value::T { computed_value::T::baseline } + + impl ToComputedValue for SpecifiedValue { + type ComputedValue = computed_value::T; + + #[inline] + fn to_computed_value(&self, context: &Cx) -> computed_value::T { + match *self { + % for keyword in vertical_align_keywords: + SpecifiedValue::${to_rust_ident(keyword)} => { + computed_value::T::${to_rust_ident(keyword)} + } + % endfor + SpecifiedValue::LengthOrPercentage(value) => + computed_value::T::LengthOrPercentage(value.to_computed_value(context)), + } + } + } + + + +// CSS 2.1, Section 11 - Visual effects + +// Non-standard, see https://developer.mozilla.org/en-US/docs/Web/CSS/overflow-clip-box#Specifications +${helpers.single_keyword("-servo-overflow-clip-box", "padding-box content-box", products="servo", + internal=True)} + +${helpers.single_keyword("overflow-clip-box", "padding-box content-box", products="gecko", + internal=True)} + +// FIXME(pcwalton, #2742): Implement scrolling for `scroll` and `auto`. +${helpers.single_keyword("overflow-x", "visible hidden scroll auto", need_clone=True, + gecko_constant_prefix="NS_STYLE_OVERFLOW")} + +// FIXME(pcwalton, #2742): Implement scrolling for `scroll` and `auto`. +<%helpers:longhand name="overflow-y" need_clone="True"> + use super::overflow_x; + + use cssparser::ToCss; + use std::fmt; + + pub use self::computed_value::T as SpecifiedValue; + + impl ToCss for SpecifiedValue { + fn to_css(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { + self.0.to_css(dest) + } + } + + pub mod computed_value { + #[derive(Debug, Clone, Copy, PartialEq, HeapSizeOf)] + pub struct T(pub super::super::overflow_x::computed_value::T); + } + + impl ToComputedValue for SpecifiedValue { + type ComputedValue = computed_value::T; + + #[inline] + fn to_computed_value(&self, context: &Cx) -> computed_value::T { + computed_value::T(self.0.to_computed_value(context)) + } + } + + pub fn get_initial_value() -> computed_value::T { + computed_value::T(overflow_x::get_initial_value()) + } + + pub fn parse(context: &ParserContext, input: &mut Parser) -> Result { + overflow_x::parse(context, input).map(SpecifiedValue) + } + + +// TODO(pcwalton): Multiple transitions. +<%helpers:longhand name="transition-duration"> + use values::specified::Time; + + pub use self::computed_value::T as SpecifiedValue; + pub use values::specified::Time as SingleSpecifiedValue; + + pub mod computed_value { + use cssparser::ToCss; + use std::fmt; + use values::computed::{TContext, ToComputedValue}; + + pub use values::computed::Time as SingleComputedValue; + + #[derive(Debug, Clone, PartialEq, HeapSizeOf)] + pub struct T(pub Vec); + + impl ToComputedValue for T { + type ComputedValue = T; + + #[inline] + fn to_computed_value(&self, _: &Cx) -> T { + (*self).clone() + } + } + + impl ToCss for T { + fn to_css(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { + if self.0.is_empty() { + return dest.write_str("none") + } + for (i, value) in self.0.iter().enumerate() { + if i != 0 { + try!(dest.write_str(", ")) + } + try!(value.to_css(dest)) + } + Ok(()) + } + } + } + + #[inline] + pub fn parse_one(input: &mut Parser) -> Result { + Time::parse(input) + } + + #[inline] + pub fn get_initial_value() -> computed_value::T { + computed_value::T(vec![get_initial_single_value()]) + } + + #[inline] + pub fn get_initial_single_value() -> Time { + Time(0.0) + } + + pub fn parse(_: &ParserContext, input: &mut Parser) -> Result { + Ok(SpecifiedValue(try!(input.parse_comma_separated(parse_one)))) + } + + +// TODO(pcwalton): Lots more timing functions. +// TODO(pcwalton): Multiple transitions. +<%helpers:longhand name="transition-timing-function"> + use self::computed_value::{StartEnd, TransitionTimingFunction}; + + use euclid::point::Point2D; + + pub use self::computed_value::SingleComputedValue as SingleSpecifiedValue; + pub use self::computed_value::T as SpecifiedValue; + + static EASE: TransitionTimingFunction = TransitionTimingFunction::CubicBezier(Point2D { + x: 0.25, + y: 0.1, + }, Point2D { + x: 0.25, + y: 1.0, + }); + static LINEAR: TransitionTimingFunction = TransitionTimingFunction::CubicBezier(Point2D { + x: 0.0, + y: 0.0, + }, Point2D { + x: 1.0, + y: 1.0, + }); + static EASE_IN: TransitionTimingFunction = TransitionTimingFunction::CubicBezier(Point2D { + x: 0.42, + y: 0.0, + }, Point2D { + x: 1.0, + y: 1.0, + }); + static EASE_OUT: TransitionTimingFunction = TransitionTimingFunction::CubicBezier(Point2D { + x: 0.0, + y: 0.0, + }, Point2D { + x: 0.58, + y: 1.0, + }); + static EASE_IN_OUT: TransitionTimingFunction = + TransitionTimingFunction::CubicBezier(Point2D { + x: 0.42, + y: 0.0, + }, Point2D { + x: 0.58, + y: 1.0, + }); + static STEP_START: TransitionTimingFunction = + TransitionTimingFunction::Steps(1, StartEnd::Start); + static STEP_END: TransitionTimingFunction = + TransitionTimingFunction::Steps(1, StartEnd::End); + + pub mod computed_value { + use cssparser::ToCss; + use euclid::point::Point2D; + use std::fmt; + + pub use self::TransitionTimingFunction as SingleComputedValue; + + #[derive(Copy, Clone, Debug, PartialEq, HeapSizeOf)] + pub enum TransitionTimingFunction { + CubicBezier(Point2D, Point2D), + Steps(u32, StartEnd), + } + + impl ToCss for TransitionTimingFunction { + fn to_css(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { + match *self { + TransitionTimingFunction::CubicBezier(p1, p2) => { + try!(dest.write_str("cubic-bezier(")); + try!(p1.x.to_css(dest)); + try!(dest.write_str(", ")); + try!(p1.y.to_css(dest)); + try!(dest.write_str(", ")); + try!(p2.x.to_css(dest)); + try!(dest.write_str(", ")); + try!(p2.y.to_css(dest)); + dest.write_str(")") + } + TransitionTimingFunction::Steps(steps, start_end) => { + try!(dest.write_str("steps(")); + try!(steps.to_css(dest)); + try!(dest.write_str(", ")); + try!(start_end.to_css(dest)); + dest.write_str(")") + } + } + } + } + + #[derive(Copy, Clone, Debug, PartialEq, HeapSizeOf)] + pub enum StartEnd { + Start, + End, + } + + impl ToCss for StartEnd { + fn to_css(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { + match *self { + StartEnd::Start => dest.write_str("start"), + StartEnd::End => dest.write_str("end"), + } + } + } + + #[derive(Clone, Debug, PartialEq, HeapSizeOf)] + pub struct T(pub Vec); + + impl ToCss for T { + fn to_css(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { + if self.0.is_empty() { + return dest.write_str("none") + } + for (i, value) in self.0.iter().enumerate() { + if i != 0 { + try!(dest.write_str(", ")) + } + try!(value.to_css(dest)) + } + Ok(()) + } + } + } + + impl ToComputedValue for SpecifiedValue { + type ComputedValue = computed_value::T; + + #[inline] + fn to_computed_value(&self, _: &Cx) -> computed_value::T { + (*self).clone() + } + } + + #[inline] + pub fn get_initial_value() -> computed_value::T { + computed_value::T(vec![get_initial_single_value()]) + } + + #[inline] + pub fn get_initial_single_value() -> TransitionTimingFunction { + EASE + } + + pub fn parse_one(input: &mut Parser) -> Result { + if let Ok(function_name) = input.try(|input| input.expect_function()) { + return match_ignore_ascii_case! { + function_name, + "cubic-bezier" => { + let (mut p1x, mut p1y, mut p2x, mut p2y) = (0.0, 0.0, 0.0, 0.0); + try!(input.parse_nested_block(|input| { + p1x = try!(specified::parse_number(input)); + try!(input.expect_comma()); + p1y = try!(specified::parse_number(input)); + try!(input.expect_comma()); + p2x = try!(specified::parse_number(input)); + try!(input.expect_comma()); + p2y = try!(specified::parse_number(input)); + Ok(()) + })); + let (p1, p2) = (Point2D::new(p1x, p1y), Point2D::new(p2x, p2y)); + Ok(TransitionTimingFunction::CubicBezier(p1, p2)) + }, + "steps" => { + let (mut step_count, mut start_end) = (0, computed_value::StartEnd::Start); + try!(input.parse_nested_block(|input| { + step_count = try!(specified::parse_integer(input)); + try!(input.expect_comma()); + start_end = try!(match_ignore_ascii_case! { + try!(input.expect_ident()), + "start" => Ok(computed_value::StartEnd::Start), + "end" => Ok(computed_value::StartEnd::End), + _ => Err(()) + }); + Ok(()) + })); + Ok(TransitionTimingFunction::Steps(step_count as u32, start_end)) + }, + _ => Err(()) + } + } + match_ignore_ascii_case! { + try!(input.expect_ident()), + "ease" => Ok(EASE), + "linear" => Ok(LINEAR), + "ease-in" => Ok(EASE_IN), + "ease-out" => Ok(EASE_OUT), + "ease-in-out" => Ok(EASE_IN_OUT), + "step-start" => Ok(STEP_START), + "step-end" => Ok(STEP_END), + _ => Err(()) + } + } + + pub fn parse(_: &ParserContext, input: &mut Parser) -> Result { + Ok(SpecifiedValue(try!(input.parse_comma_separated(parse_one)))) + } + + +// TODO(pcwalton): Lots more properties. +<%helpers:longhand name="transition-property"> + use self::computed_value::TransitionProperty; + + pub use self::computed_value::SingleComputedValue as SingleSpecifiedValue; + pub use self::computed_value::T as SpecifiedValue; + + pub mod computed_value { + use cssparser::ToCss; + use std::fmt; + + pub use self::TransitionProperty as SingleComputedValue; + + #[derive(Copy, Clone, Debug, PartialEq, HeapSizeOf)] + pub enum TransitionProperty { + All, + BackgroundColor, + BackgroundPosition, + BorderBottomColor, + BorderBottomWidth, + BorderLeftColor, + BorderLeftWidth, + BorderRightColor, + BorderRightWidth, + BorderSpacing, + BorderTopColor, + BorderTopWidth, + Bottom, + Color, + Clip, + FontSize, + FontWeight, + Height, + Left, + LetterSpacing, + LineHeight, + MarginBottom, + MarginLeft, + MarginRight, + MarginTop, + MaxHeight, + MaxWidth, + MinHeight, + MinWidth, + Opacity, + OutlineColor, + OutlineWidth, + PaddingBottom, + PaddingLeft, + PaddingRight, + PaddingTop, + Right, + TextIndent, + TextShadow, + Top, + Transform, + VerticalAlign, + Visibility, + Width, + WordSpacing, + ZIndex, + } + + pub static ALL_TRANSITION_PROPERTIES: [TransitionProperty; 45] = [ + TransitionProperty::BackgroundColor, + TransitionProperty::BackgroundPosition, + TransitionProperty::BorderBottomColor, + TransitionProperty::BorderBottomWidth, + TransitionProperty::BorderLeftColor, + TransitionProperty::BorderLeftWidth, + TransitionProperty::BorderRightColor, + TransitionProperty::BorderRightWidth, + TransitionProperty::BorderSpacing, + TransitionProperty::BorderTopColor, + TransitionProperty::BorderTopWidth, + TransitionProperty::Bottom, + TransitionProperty::Color, + TransitionProperty::Clip, + TransitionProperty::FontSize, + TransitionProperty::FontWeight, + TransitionProperty::Height, + TransitionProperty::Left, + TransitionProperty::LetterSpacing, + TransitionProperty::LineHeight, + TransitionProperty::MarginBottom, + TransitionProperty::MarginLeft, + TransitionProperty::MarginRight, + TransitionProperty::MarginTop, + TransitionProperty::MaxHeight, + TransitionProperty::MaxWidth, + TransitionProperty::MinHeight, + TransitionProperty::MinWidth, + TransitionProperty::Opacity, + TransitionProperty::OutlineColor, + TransitionProperty::OutlineWidth, + TransitionProperty::PaddingBottom, + TransitionProperty::PaddingLeft, + TransitionProperty::PaddingRight, + TransitionProperty::PaddingTop, + TransitionProperty::Right, + TransitionProperty::TextIndent, + TransitionProperty::TextShadow, + TransitionProperty::Top, + TransitionProperty::Transform, + TransitionProperty::VerticalAlign, + TransitionProperty::Visibility, + TransitionProperty::Width, + TransitionProperty::WordSpacing, + TransitionProperty::ZIndex, + ]; + + impl ToCss for TransitionProperty { + fn to_css(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { + match *self { + TransitionProperty::All => dest.write_str("all"), + TransitionProperty::BackgroundColor => dest.write_str("background-color"), + TransitionProperty::BackgroundPosition => dest.write_str("background-position"), + TransitionProperty::BorderBottomColor => dest.write_str("border-bottom-color"), + TransitionProperty::BorderBottomWidth => dest.write_str("border-bottom-width"), + TransitionProperty::BorderLeftColor => dest.write_str("border-left-color"), + TransitionProperty::BorderLeftWidth => dest.write_str("border-left-width"), + TransitionProperty::BorderRightColor => dest.write_str("border-right-color"), + TransitionProperty::BorderRightWidth => dest.write_str("border-right-width"), + TransitionProperty::BorderSpacing => dest.write_str("border-spacing"), + TransitionProperty::BorderTopColor => dest.write_str("border-top-color"), + TransitionProperty::BorderTopWidth => dest.write_str("border-top-width"), + TransitionProperty::Bottom => dest.write_str("bottom"), + TransitionProperty::Color => dest.write_str("color"), + TransitionProperty::Clip => dest.write_str("clip"), + TransitionProperty::FontSize => dest.write_str("font-size"), + TransitionProperty::FontWeight => dest.write_str("font-weight"), + TransitionProperty::Height => dest.write_str("height"), + TransitionProperty::Left => dest.write_str("left"), + TransitionProperty::LetterSpacing => dest.write_str("letter-spacing"), + TransitionProperty::LineHeight => dest.write_str("line-height"), + TransitionProperty::MarginBottom => dest.write_str("margin-bottom"), + TransitionProperty::MarginLeft => dest.write_str("margin-left"), + TransitionProperty::MarginRight => dest.write_str("margin-right"), + TransitionProperty::MarginTop => dest.write_str("margin-top"), + TransitionProperty::MaxHeight => dest.write_str("max-height"), + TransitionProperty::MaxWidth => dest.write_str("max-width"), + TransitionProperty::MinHeight => dest.write_str("min-height"), + TransitionProperty::MinWidth => dest.write_str("min-width"), + TransitionProperty::Opacity => dest.write_str("opacity"), + TransitionProperty::OutlineColor => dest.write_str("outline-color"), + TransitionProperty::OutlineWidth => dest.write_str("outline-width"), + TransitionProperty::PaddingBottom => dest.write_str("padding-bottom"), + TransitionProperty::PaddingLeft => dest.write_str("padding-left"), + TransitionProperty::PaddingRight => dest.write_str("padding-right"), + TransitionProperty::PaddingTop => dest.write_str("padding-top"), + TransitionProperty::Right => dest.write_str("right"), + TransitionProperty::TextIndent => dest.write_str("text-indent"), + TransitionProperty::TextShadow => dest.write_str("text-shadow"), + TransitionProperty::Top => dest.write_str("top"), + TransitionProperty::Transform => dest.write_str("transform"), + TransitionProperty::VerticalAlign => dest.write_str("vertical-align"), + TransitionProperty::Visibility => dest.write_str("visibility"), + TransitionProperty::Width => dest.write_str("width"), + TransitionProperty::WordSpacing => dest.write_str("word-spacing"), + TransitionProperty::ZIndex => dest.write_str("z-index"), + } + } + } + + #[derive(Clone, Debug, PartialEq, HeapSizeOf)] + pub struct T(pub Vec); + + impl ToCss for T { + fn to_css(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { + if self.0.is_empty() { + return dest.write_str("none") + } + for (i, value) in self.0.iter().enumerate() { + if i != 0 { + try!(dest.write_str(", ")) + } + try!(value.to_css(dest)) + } + Ok(()) + } + } + } + + #[inline] + pub fn get_initial_value() -> computed_value::T { + computed_value::T(Vec::new()) + } + + pub fn parse_one(input: &mut Parser) -> Result { + match_ignore_ascii_case! { + try!(input.expect_ident()), + "all" => Ok(TransitionProperty::All), + "background-color" => Ok(TransitionProperty::BackgroundColor), + "background-position" => Ok(TransitionProperty::BackgroundPosition), + "border-bottom-color" => Ok(TransitionProperty::BorderBottomColor), + "border-bottom-width" => Ok(TransitionProperty::BorderBottomWidth), + "border-left-color" => Ok(TransitionProperty::BorderLeftColor), + "border-left-width" => Ok(TransitionProperty::BorderLeftWidth), + "border-right-color" => Ok(TransitionProperty::BorderRightColor), + "border-right-width" => Ok(TransitionProperty::BorderRightWidth), + "border-spacing" => Ok(TransitionProperty::BorderSpacing), + "border-top-color" => Ok(TransitionProperty::BorderTopColor), + "border-top-width" => Ok(TransitionProperty::BorderTopWidth), + "bottom" => Ok(TransitionProperty::Bottom), + "color" => Ok(TransitionProperty::Color), + "clip" => Ok(TransitionProperty::Clip), + "font-size" => Ok(TransitionProperty::FontSize), + "font-weight" => Ok(TransitionProperty::FontWeight), + "height" => Ok(TransitionProperty::Height), + "left" => Ok(TransitionProperty::Left), + "letter-spacing" => Ok(TransitionProperty::LetterSpacing), + "line-height" => Ok(TransitionProperty::LineHeight), + "margin-bottom" => Ok(TransitionProperty::MarginBottom), + "margin-left" => Ok(TransitionProperty::MarginLeft), + "margin-right" => Ok(TransitionProperty::MarginRight), + "margin-top" => Ok(TransitionProperty::MarginTop), + "max-height" => Ok(TransitionProperty::MaxHeight), + "max-width" => Ok(TransitionProperty::MaxWidth), + "min-height" => Ok(TransitionProperty::MinHeight), + "min-width" => Ok(TransitionProperty::MinWidth), + "opacity" => Ok(TransitionProperty::Opacity), + "outline-color" => Ok(TransitionProperty::OutlineColor), + "outline-width" => Ok(TransitionProperty::OutlineWidth), + "padding-bottom" => Ok(TransitionProperty::PaddingBottom), + "padding-left" => Ok(TransitionProperty::PaddingLeft), + "padding-right" => Ok(TransitionProperty::PaddingRight), + "padding-top" => Ok(TransitionProperty::PaddingTop), + "right" => Ok(TransitionProperty::Right), + "text-indent" => Ok(TransitionProperty::TextIndent), + "text-shadow" => Ok(TransitionProperty::TextShadow), + "top" => Ok(TransitionProperty::Top), + "transform" => Ok(TransitionProperty::Transform), + "vertical-align" => Ok(TransitionProperty::VerticalAlign), + "visibility" => Ok(TransitionProperty::Visibility), + "width" => Ok(TransitionProperty::Width), + "word-spacing" => Ok(TransitionProperty::WordSpacing), + "z-index" => Ok(TransitionProperty::ZIndex), + _ => Err(()) + } + } + + pub fn parse(_: &ParserContext, input: &mut Parser) -> Result { + Ok(SpecifiedValue(try!(input.parse_comma_separated(parse_one)))) + } + + impl ToComputedValue for SpecifiedValue { + type ComputedValue = computed_value::T; + + #[inline] + fn to_computed_value(&self, _: &Cx) -> computed_value::T { + (*self).clone() + } + } + + +<%helpers:longhand name="transition-delay"> + pub use properties::longhands::transition_duration::{SingleSpecifiedValue, SpecifiedValue}; + pub use properties::longhands::transition_duration::{computed_value}; + pub use properties::longhands::transition_duration::{get_initial_single_value}; + pub use properties::longhands::transition_duration::{get_initial_value, parse, parse_one}; + + +// CSSOM View Module +// https://www.w3.org/TR/cssom-view-1/ +${helpers.single_keyword("scroll-behavior", + "auto smooth", + products="gecko")} + +// Non-standard: https://developer.mozilla.org/en-US/docs/Web/CSS/scroll-snap-type-x +${helpers.single_keyword("scroll-snap-type-x", + "none mandatory proximity", + products="gecko", + gecko_constant_prefix="NS_STYLE_SCROLL_SNAP_TYPE")} + +// Non-standard: https://developer.mozilla.org/en-US/docs/Web/CSS/scroll-snap-type-y +${helpers.single_keyword("scroll-snap-type-y", + "none mandatory proximity", + products="gecko", + gecko_constant_prefix="NS_STYLE_SCROLL_SNAP_TYPE")} + +// Compositing and Blending Level 1 +// http://www.w3.org/TR/compositing-1/ +${helpers.single_keyword("isolation", + "auto isolate", + products="gecko")} + +${helpers.single_keyword("page-break-after", + "auto always avoid left right", + products="gecko")} +${helpers.single_keyword("page-break-before", + "auto always avoid left right", + products="gecko")} +${helpers.single_keyword("page-break-inside", + "auto avoid", + products="gecko", + gecko_ffi_name="mBreakInside", + gecko_constant_prefix="NS_STYLE_PAGE_BREAK")} + +// CSS Basic User Interface Module Level 3 +// http://dev.w3.org/csswg/css-ui/ +${helpers.single_keyword("resize", + "none both horizontal vertical", + products="gecko")} diff --git a/components/style/properties/longhand/color.mako.rs b/components/style/properties/longhand/color.mako.rs new file mode 100644 index 00000000000..dc9555e7999 --- /dev/null +++ b/components/style/properties/longhand/color.mako.rs @@ -0,0 +1,43 @@ +/* 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/. */ + +<%namespace name="helpers" file="/helpers.mako.rs" /> + +<% data.new_style_struct("Color", inherited=True, gecko_ffi_name="nsStyleColor") %> + +<%helpers:raw_longhand name="color" need_clone="True"> + use cssparser::Color as CSSParserColor; + use cssparser::RGBA; + use values::specified::{CSSColor, CSSRGBA}; + + impl ToComputedValue for SpecifiedValue { + type ComputedValue = computed_value::T; + + #[inline] + fn to_computed_value(&self, _context: &Cx) -> computed_value::T { + self.parsed + } + } + + pub type SpecifiedValue = CSSRGBA; + pub mod computed_value { + use cssparser; + pub type T = cssparser::RGBA; + } + #[inline] pub fn get_initial_value() -> computed_value::T { + RGBA { red: 0., green: 0., blue: 0., alpha: 1. } /* black */ + } + pub fn parse_specified(_context: &ParserContext, input: &mut Parser) + -> Result, ()> { + let value = try!(CSSColor::parse(input)); + let rgba = match value.parsed { + CSSParserColor::RGBA(rgba) => rgba, + CSSParserColor::CurrentColor => return Ok(DeclaredValue::Inherit) + }; + Ok(DeclaredValue::Value(CSSRGBA { + parsed: rgba, + authored: value.authored, + })) + } + diff --git a/components/style/properties/longhand/column.mako.rs b/components/style/properties/longhand/column.mako.rs new file mode 100644 index 00000000000..2e6618e3745 --- /dev/null +++ b/components/style/properties/longhand/column.mako.rs @@ -0,0 +1,196 @@ +/* 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/. */ + +<%namespace name="helpers" file="/helpers.mako.rs" /> + +<% data.new_style_struct("Column", inherited=False, gecko_ffi_name="nsStyleColumn") %> + +<%helpers:longhand name="column-width" experimental="True"> + use cssparser::ToCss; + use std::fmt; + use values::AuExtensionMethods; + + #[derive(Debug, Clone, Copy, PartialEq, HeapSizeOf)] + pub enum SpecifiedValue { + Auto, + Specified(specified::Length), + } + + impl ToCss for SpecifiedValue { + fn to_css(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { + match *self { + SpecifiedValue::Auto => dest.write_str("auto"), + SpecifiedValue::Specified(l) => l.to_css(dest), + } + } + } + + pub mod computed_value { + use app_units::Au; + #[derive(Debug, Clone, PartialEq, HeapSizeOf)] + pub struct T(pub Option); + } + + impl ToCss for computed_value::T { + fn to_css(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { + match self.0 { + None => dest.write_str("auto"), + Some(l) => l.to_css(dest), + } + } + } + + #[inline] + pub fn get_initial_value() -> computed_value::T { + computed_value::T(None) + } + + impl ToComputedValue for SpecifiedValue { + type ComputedValue = computed_value::T; + + #[inline] + fn to_computed_value(&self, context: &Cx) -> computed_value::T { + match *self { + SpecifiedValue::Auto => computed_value::T(None), + SpecifiedValue::Specified(l) => + computed_value::T(Some(l.to_computed_value(context))) + } + } + } + + pub fn parse(_context: &ParserContext, input: &mut Parser) -> Result { + if input.try(|input| input.expect_ident_matching("auto")).is_ok() { + Ok(SpecifiedValue::Auto) + } else { + specified::Length::parse_non_negative(input).map(SpecifiedValue::Specified) + } + } + + +<%helpers:longhand name="column-count" experimental="True"> + use cssparser::ToCss; + use std::fmt; + + #[derive(Debug, Clone, Copy, PartialEq, HeapSizeOf)] + pub enum SpecifiedValue { + Auto, + Specified(u32), + } + + impl ToCss for SpecifiedValue { + fn to_css(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { + match *self { + SpecifiedValue::Auto => dest.write_str("auto"), + SpecifiedValue::Specified(count) => write!(dest, "{}", count), + } + } + } + + pub mod computed_value { + #[derive(Debug, Clone, PartialEq, HeapSizeOf)] + pub struct T(pub Option); + } + + impl ToCss for computed_value::T { + fn to_css(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { + match self.0 { + None => dest.write_str("auto"), + Some(count) => write!(dest, "{}", count), + } + } + } + + #[inline] + pub fn get_initial_value() -> computed_value::T { + computed_value::T(None) + } + + impl ToComputedValue for SpecifiedValue { + type ComputedValue = computed_value::T; + + #[inline] + fn to_computed_value(&self, _context: &Cx) -> computed_value::T { + match *self { + SpecifiedValue::Auto => computed_value::T(None), + SpecifiedValue::Specified(count) => + computed_value::T(Some(count)) + } + } + } + + pub fn parse(_context: &ParserContext, input: &mut Parser) -> Result { + if input.try(|input| input.expect_ident_matching("auto")).is_ok() { + Ok(SpecifiedValue::Auto) + } else { + let count = try!(specified::parse_integer(input)); + // Zero is invalid + if count <= 0 { + return Err(()) + } + Ok(SpecifiedValue::Specified(count as u32)) + } + } + + +<%helpers:longhand name="column-gap" experimental="True"> + use cssparser::ToCss; + use std::fmt; + use values::AuExtensionMethods; + + #[derive(Debug, Clone, Copy, PartialEq, HeapSizeOf)] + pub enum SpecifiedValue { + Normal, + Specified(specified::Length), + } + + impl ToCss for SpecifiedValue { + fn to_css(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { + match *self { + SpecifiedValue::Normal => dest.write_str("normal"), + SpecifiedValue::Specified(l) => l.to_css(dest), + } + } + } + + pub mod computed_value { + use app_units::Au; + #[derive(Debug, Clone, PartialEq, HeapSizeOf)] + pub struct T(pub Option); + } + + impl ToCss for computed_value::T { + fn to_css(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { + match self.0 { + None => dest.write_str("normal"), + Some(l) => l.to_css(dest), + } + } + } + + #[inline] + pub fn get_initial_value() -> computed_value::T { + computed_value::T(None) + } + + impl ToComputedValue for SpecifiedValue { + type ComputedValue = computed_value::T; + + #[inline] + fn to_computed_value(&self, context: &Cx) -> computed_value::T { + match *self { + SpecifiedValue::Normal => computed_value::T(None), + SpecifiedValue::Specified(l) => + computed_value::T(Some(l.to_computed_value(context))) + } + } + } + + pub fn parse(_context: &ParserContext, input: &mut Parser) -> Result { + if input.try(|input| input.expect_ident_matching("normal")).is_ok() { + Ok(SpecifiedValue::Normal) + } else { + specified::Length::parse_non_negative(input).map(SpecifiedValue::Specified) + } + } + diff --git a/components/style/properties/longhand/counters.mako.rs b/components/style/properties/longhand/counters.mako.rs new file mode 100644 index 00000000000..9af2ca8aa9c --- /dev/null +++ b/components/style/properties/longhand/counters.mako.rs @@ -0,0 +1,248 @@ +/* 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/. */ + +<%namespace name="helpers" file="/helpers.mako.rs" /> + +<% data.new_style_struct("Counters", inherited=False, gecko_ffi_name="nsStyleContent") %> + +<%helpers:longhand name="content"> + use cssparser::Token; + use std::ascii::AsciiExt; + use values::computed::ComputedValueAsSpecified; + + use super::list_style_type; + + pub use self::computed_value::T as SpecifiedValue; + pub use self::computed_value::ContentItem; + + impl ComputedValueAsSpecified for SpecifiedValue {} + + pub mod computed_value { + use super::super::list_style_type; + + use cssparser::{self, ToCss}; + use std::fmt; + + #[derive(Debug, PartialEq, Eq, Clone, HeapSizeOf)] + pub enum ContentItem { + /// Literal string content. + String(String), + /// `counter(name, style)`. + Counter(String, list_style_type::computed_value::T), + /// `counters(name, separator, style)`. + Counters(String, String, list_style_type::computed_value::T), + /// `open-quote`. + OpenQuote, + /// `close-quote`. + CloseQuote, + /// `no-open-quote`. + NoOpenQuote, + /// `no-close-quote`. + NoCloseQuote, + } + + impl ToCss for ContentItem { + fn to_css(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { + match *self { + ContentItem::String(ref s) => { + cssparser::serialize_string(&**s, dest) + } + ContentItem::Counter(ref s, ref list_style_type) => { + try!(dest.write_str("counter(")); + try!(cssparser::serialize_identifier(&**s, dest)); + try!(dest.write_str(", ")); + try!(list_style_type.to_css(dest)); + dest.write_str(")") + } + ContentItem::Counters(ref s, ref separator, ref list_style_type) => { + try!(dest.write_str("counter(")); + try!(cssparser::serialize_identifier(&**s, dest)); + try!(dest.write_str(", ")); + try!(cssparser::serialize_string(&**separator, dest)); + try!(dest.write_str(", ")); + try!(list_style_type.to_css(dest)); + dest.write_str(")") + } + ContentItem::OpenQuote => dest.write_str("open-quote"), + ContentItem::CloseQuote => dest.write_str("close-quote"), + ContentItem::NoOpenQuote => dest.write_str("no-open-quote"), + ContentItem::NoCloseQuote => dest.write_str("no-close-quote"), + } + } + } + + #[allow(non_camel_case_types)] + #[derive(Debug, PartialEq, Eq, Clone, HeapSizeOf)] + pub enum T { + normal, + none, + Content(Vec), + } + + impl ToCss for T { + fn to_css(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { + match *self { + T::normal => dest.write_str("normal"), + T::none => dest.write_str("none"), + T::Content(ref content) => { + let mut iter = content.iter(); + try!(iter.next().unwrap().to_css(dest)); + for c in iter { + try!(dest.write_str(" ")); + try!(c.to_css(dest)); + } + Ok(()) + } + } + } + } + } + #[inline] + pub fn get_initial_value() -> computed_value::T { + computed_value::T::normal + } + + pub fn counter_name_is_illegal(name: &str) -> bool { + name.eq_ignore_ascii_case("none") || name.eq_ignore_ascii_case("inherit") || + name.eq_ignore_ascii_case("initial") + } + + // normal | none | [ | | open-quote | close-quote | no-open-quote | + // no-close-quote ]+ + // TODO: , attr() + pub fn parse(context: &ParserContext, input: &mut Parser) + -> Result { + if input.try(|input| input.expect_ident_matching("normal")).is_ok() { + return Ok(SpecifiedValue::normal) + } + if input.try(|input| input.expect_ident_matching("none")).is_ok() { + return Ok(SpecifiedValue::none) + } + let mut content = vec![]; + loop { + match input.next() { + Ok(Token::QuotedString(value)) => { + content.push(ContentItem::String(value.into_owned())) + } + Ok(Token::Function(name)) => { + content.push(try!(match_ignore_ascii_case! { name, + "counter" => input.parse_nested_block(|input| { + let name = try!(input.expect_ident()).into_owned(); + let style = input.try(|input| { + try!(input.expect_comma()); + list_style_type::parse(context, input) + }).unwrap_or(list_style_type::computed_value::T::decimal); + Ok(ContentItem::Counter(name, style)) + }), + "counters" => input.parse_nested_block(|input| { + let name = try!(input.expect_ident()).into_owned(); + try!(input.expect_comma()); + let separator = try!(input.expect_string()).into_owned(); + let style = input.try(|input| { + try!(input.expect_comma()); + list_style_type::parse(context, input) + }).unwrap_or(list_style_type::computed_value::T::decimal); + Ok(ContentItem::Counters(name, separator, style)) + }), + _ => return Err(()) + })); + } + Ok(Token::Ident(ident)) => { + match_ignore_ascii_case! { ident, + "open-quote" => content.push(ContentItem::OpenQuote), + "close-quote" => content.push(ContentItem::CloseQuote), + "no-open-quote" => content.push(ContentItem::NoOpenQuote), + "no-close-quote" => content.push(ContentItem::NoCloseQuote), + _ => return Err(()) + } + } + Err(_) => break, + _ => return Err(()) + } + } + if !content.is_empty() { + Ok(SpecifiedValue::Content(content)) + } else { + Err(()) + } + } + + +<%helpers:longhand name="counter-increment"> + use std::fmt; + use super::content; + use values::computed::ComputedValueAsSpecified; + + use cssparser::{ToCss, Token, serialize_identifier}; + use std::borrow::{Cow, ToOwned}; + + pub use self::computed_value::T as SpecifiedValue; + + pub mod computed_value { + #[derive(Debug, Clone, PartialEq, HeapSizeOf)] + pub struct T(pub Vec<(String,i32)>); + } + + #[inline] + pub fn get_initial_value() -> computed_value::T { + computed_value::T(Vec::new()) + } + + impl ComputedValueAsSpecified for SpecifiedValue {} + + impl ToCss for SpecifiedValue { + fn to_css(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { + let mut first = true; + for pair in &self.0 { + if !first { + try!(dest.write_str(" ")); + } + first = false; + try!(serialize_identifier(&pair.0, dest)); + try!(write!(dest, " {}", pair.1)); + } + Ok(()) + } + } + + pub fn parse(_: &ParserContext, input: &mut Parser) -> Result { + parse_common(1, input) + } + + pub fn parse_common(default_value: i32, input: &mut Parser) -> Result { + if input.try(|input| input.expect_ident_matching("none")).is_ok() { + return Ok(SpecifiedValue(Vec::new())) + } + + let mut counters = Vec::new(); + loop { + let counter_name = match input.next() { + Ok(Token::Ident(ident)) => (*ident).to_owned(), + Ok(_) => return Err(()), + Err(_) => break, + }; + if content::counter_name_is_illegal(&counter_name) { + return Err(()) + } + let counter_delta = + input.try(|input| specified::parse_integer(input)).unwrap_or(default_value); + counters.push((counter_name, counter_delta)) + } + + if !counters.is_empty() { + Ok(SpecifiedValue(counters)) + } else { + Err(()) + } + } + + +<%helpers:longhand name="counter-reset"> + pub use super::counter_increment::{SpecifiedValue, computed_value, get_initial_value}; + use super::counter_increment::{parse_common}; + + pub fn parse(_: &ParserContext, input: &mut Parser) -> Result { + parse_common(0, input) + } + diff --git a/components/style/properties/longhand/effects.mako.rs b/components/style/properties/longhand/effects.mako.rs new file mode 100644 index 00000000000..3424debe2b8 --- /dev/null +++ b/components/style/properties/longhand/effects.mako.rs @@ -0,0 +1,1343 @@ +/* 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/. */ + +<%namespace name="helpers" file="/helpers.mako.rs" /> + +// Box-shadow, etc. +<% data.new_style_struct("Effects", inherited=False, gecko_ffi_name="nsStyleEffects") %> + +<%helpers:longhand name="opacity"> + use cssparser::ToCss; + use std::fmt; + use values::CSSFloat; + + impl ToCss for SpecifiedValue { + fn to_css(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { + self.0.to_css(dest) + } + } + + #[derive(Debug, Clone, PartialEq, HeapSizeOf)] + pub struct SpecifiedValue(pub CSSFloat); + pub mod computed_value { + use values::CSSFloat; + pub type T = CSSFloat; + } + #[inline] + pub fn get_initial_value() -> computed_value::T { + 1.0 + } + + impl ToComputedValue for SpecifiedValue { + type ComputedValue = computed_value::T; + + #[inline] + fn to_computed_value(&self, _context: &Cx) -> computed_value::T { + if self.0 < 0.0 { + 0.0 + } else if self.0 > 1.0 { + 1.0 + } else { + self.0 + } + } + } + fn parse(_context: &ParserContext, input: &mut Parser) -> Result { + specified::parse_number(input).map(SpecifiedValue) + } + + +<%helpers:longhand name="box-shadow"> + use cssparser::{self, ToCss}; + use std::fmt; + use values::AuExtensionMethods; + + #[derive(Debug, Clone, PartialEq, HeapSizeOf)] + pub struct SpecifiedValue(Vec); + + #[derive(Debug, Clone, PartialEq, HeapSizeOf)] + pub struct SpecifiedBoxShadow { + pub offset_x: specified::Length, + pub offset_y: specified::Length, + pub blur_radius: specified::Length, + pub spread_radius: specified::Length, + pub color: Option, + pub inset: bool, + } + + impl ToCss for SpecifiedValue { + fn to_css(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { + let mut iter = self.0.iter(); + if let Some(shadow) = iter.next() { + try!(shadow.to_css(dest)); + } else { + try!(dest.write_str("none")); + return Ok(()) + } + for shadow in iter { + try!(dest.write_str(", ")); + try!(shadow.to_css(dest)); + } + Ok(()) + } + } + + impl ToCss for SpecifiedBoxShadow { + fn to_css(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { + if self.inset { + try!(dest.write_str("inset ")); + } + try!(self.blur_radius.to_css(dest)); + try!(dest.write_str(" ")); + try!(self.spread_radius.to_css(dest)); + try!(dest.write_str(" ")); + try!(self.offset_x.to_css(dest)); + try!(dest.write_str(" ")); + try!(self.offset_y.to_css(dest)); + + if let Some(ref color) = self.color { + try!(dest.write_str(" ")); + try!(color.to_css(dest)); + } + Ok(()) + } + } + + pub mod computed_value { + use app_units::Au; + use std::fmt; + use values::computed; + + #[derive(Clone, PartialEq, HeapSizeOf, Debug)] + pub struct T(pub Vec); + + #[derive(Clone, PartialEq, Copy, HeapSizeOf, Debug)] + pub struct BoxShadow { + pub offset_x: Au, + pub offset_y: Au, + pub blur_radius: Au, + pub spread_radius: Au, + pub color: computed::CSSColor, + pub inset: bool, + } + } + + impl ToCss for computed_value::T { + fn to_css(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { + let mut iter = self.0.iter(); + if let Some(shadow) = iter.next() { + try!(shadow.to_css(dest)); + } else { + try!(dest.write_str("none")); + return Ok(()) + } + for shadow in iter { + try!(dest.write_str(", ")); + try!(shadow.to_css(dest)); + } + Ok(()) + } + } + + impl ToCss for computed_value::BoxShadow { + fn to_css(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { + if self.inset { + try!(dest.write_str("inset ")); + } + try!(self.blur_radius.to_css(dest)); + try!(dest.write_str(" ")); + try!(self.spread_radius.to_css(dest)); + try!(dest.write_str(" ")); + try!(self.offset_x.to_css(dest)); + try!(dest.write_str(" ")); + try!(self.offset_y.to_css(dest)); + try!(dest.write_str(" ")); + try!(self.color.to_css(dest)); + Ok(()) + } + } + + #[inline] + pub fn get_initial_value() -> computed_value::T { + computed_value::T(Vec::new()) + } + + pub fn parse(_context: &ParserContext, input: &mut Parser) -> Result { + if input.try(|input| input.expect_ident_matching("none")).is_ok() { + Ok(SpecifiedValue(Vec::new())) + } else { + input.parse_comma_separated(parse_one_box_shadow).map(SpecifiedValue) + } + } + + impl ToComputedValue for SpecifiedValue { + type ComputedValue = computed_value::T; + + #[inline] + fn to_computed_value(&self, context: &Cx) -> computed_value::T { + computed_value::T(self.0.iter().map(|value| compute_one_box_shadow(value, context)).collect()) + } + } + + pub fn compute_one_box_shadow(value: &SpecifiedBoxShadow, context: &Cx) + -> computed_value::BoxShadow { + computed_value::BoxShadow { + offset_x: value.offset_x.to_computed_value(context), + offset_y: value.offset_y.to_computed_value(context), + blur_radius: value.blur_radius.to_computed_value(context), + spread_radius: value.spread_radius.to_computed_value(context), + color: value.color + .as_ref() + .map(|color| color.parsed) + .unwrap_or(cssparser::Color::CurrentColor), + inset: value.inset, + } + } + + pub fn parse_one_box_shadow(input: &mut Parser) -> Result { + use app_units::Au; + let mut lengths = [specified::Length::Absolute(Au(0)); 4]; + let mut lengths_parsed = false; + let mut color = None; + let mut inset = false; + + loop { + if !inset { + if input.try(|input| input.expect_ident_matching("inset")).is_ok() { + inset = true; + continue + } + } + if !lengths_parsed { + if let Ok(value) = input.try(specified::Length::parse) { + lengths[0] = value; + let mut length_parsed_count = 1; + while length_parsed_count < 4 { + if let Ok(value) = input.try(specified::Length::parse) { + lengths[length_parsed_count] = value + } else { + break + } + length_parsed_count += 1; + } + + // The first two lengths must be specified. + if length_parsed_count < 2 { + return Err(()) + } + + lengths_parsed = true; + continue + } + } + if color.is_none() { + if let Ok(value) = input.try(specified::CSSColor::parse) { + color = Some(value); + continue + } + } + break + } + + // Lengths must be specified. + if !lengths_parsed { + return Err(()) + } + + Ok(SpecifiedBoxShadow { + offset_x: lengths[0], + offset_y: lengths[1], + blur_radius: lengths[2], + spread_radius: lengths[3], + color: color, + inset: inset, + }) + } + + +<%helpers:longhand name="clip"> + use cssparser::ToCss; + use std::fmt; + use values::AuExtensionMethods; + + // NB: `top` and `left` are 0 if `auto` per CSS 2.1 11.1.2. + + pub mod computed_value { + use app_units::Au; + + #[derive(Clone, PartialEq, Eq, Copy, Debug, HeapSizeOf)] + pub struct ClipRect { + pub top: Au, + pub right: Option, + pub bottom: Option, + pub left: Au, + } + + #[derive(Debug, Clone, PartialEq, HeapSizeOf)] + pub struct T(pub Option); + } + + impl ToCss for computed_value::T { + fn to_css(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { + match self.0 { + None => dest.write_str("auto"), + Some(rect) => { + try!(dest.write_str("rect(")); + try!(rect.top.to_css(dest)); + try!(dest.write_str(", ")); + if let Some(right) = rect.right { + try!(right.to_css(dest)); + try!(dest.write_str(", ")); + } else { + try!(dest.write_str("auto, ")); + } + + if let Some(bottom) = rect.bottom { + try!(bottom.to_css(dest)); + try!(dest.write_str(", ")); + } else { + try!(dest.write_str("auto, ")); + } + + try!(rect.left.to_css(dest)); + try!(dest.write_str(")")); + Ok(()) + } + } + } + } + + #[derive(Clone, Debug, PartialEq, Copy, HeapSizeOf)] + pub struct SpecifiedClipRect { + pub top: specified::Length, + pub right: Option, + pub bottom: Option, + pub left: specified::Length, + } + + #[derive(Clone, Debug, PartialEq, Copy, HeapSizeOf)] + pub struct SpecifiedValue(Option); + + impl ToCss for SpecifiedClipRect { + fn to_css(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { + try!(dest.write_str("rect(")); + + try!(self.top.to_css(dest)); + try!(dest.write_str(", ")); + + if let Some(right) = self.right { + try!(right.to_css(dest)); + try!(dest.write_str(", ")); + } else { + try!(dest.write_str("auto, ")); + } + + if let Some(bottom) = self.bottom { + try!(bottom.to_css(dest)); + try!(dest.write_str(", ")); + } else { + try!(dest.write_str("auto, ")); + } + + try!(self.left.to_css(dest)); + + try!(dest.write_str(")")); + Ok(()) + } + } + + impl ToCss for SpecifiedValue { + fn to_css(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { + if let Some(ref rect) = self.0 { + rect.to_css(dest) + } else { + dest.write_str("auto") + } + } + } + + #[inline] + pub fn get_initial_value() -> computed_value::T { + computed_value::T(None) + } + + impl ToComputedValue for SpecifiedValue { + type ComputedValue = computed_value::T; + + #[inline] + fn to_computed_value(&self, context: &Cx) -> computed_value::T { + computed_value::T(self.0.map(|value| computed_value::ClipRect { + top: value.top.to_computed_value(context), + right: value.right.map(|right| right.to_computed_value(context)), + bottom: value.bottom.map(|bottom| bottom.to_computed_value(context)), + left: value.left.to_computed_value(context), + })) + } + } + + pub fn parse(_context: &ParserContext, input: &mut Parser) -> Result { + use app_units::Au; + use std::ascii::AsciiExt; + use values::specified::Length; + + if input.try(|input| input.expect_ident_matching("auto")).is_ok() { + return Ok(SpecifiedValue(None)) + } + if !try!(input.expect_function()).eq_ignore_ascii_case("rect") { + return Err(()) + } + let sides = try!(input.parse_nested_block(|input| { + input.parse_comma_separated(|input| { + if input.try(|input| input.expect_ident_matching("auto")).is_ok() { + Ok(None) + } else { + Length::parse(input).map(Some) + } + }) + })); + if sides.len() == 4 { + Ok(SpecifiedValue(Some(SpecifiedClipRect { + top: sides[0].unwrap_or(Length::Absolute(Au(0))), + right: sides[1], + bottom: sides[2], + left: sides[3].unwrap_or(Length::Absolute(Au(0))), + }))) + } else { + Err(()) + } + } + + +<%helpers:longhand name="filter"> + //pub use self::computed_value::T as SpecifiedValue; + use cssparser::ToCss; + use std::fmt; + use values::AuExtensionMethods; + use values::CSSFloat; + use values::specified::{Angle, Length}; + + #[derive(Debug, Clone, PartialEq, HeapSizeOf)] + pub struct SpecifiedValue(Vec); + + // TODO(pcwalton): `drop-shadow` + #[derive(Clone, PartialEq, Debug, HeapSizeOf)] + pub enum SpecifiedFilter { + Blur(Length), + Brightness(CSSFloat), + Contrast(CSSFloat), + Grayscale(CSSFloat), + HueRotate(Angle), + Invert(CSSFloat), + Opacity(CSSFloat), + Saturate(CSSFloat), + Sepia(CSSFloat), + } + + pub mod computed_value { + use app_units::Au; + use values::CSSFloat; + use values::specified::{Angle}; + + #[derive(Clone, PartialEq, Debug, HeapSizeOf, Deserialize, Serialize)] + pub enum Filter { + Blur(Au), + Brightness(CSSFloat), + Contrast(CSSFloat), + Grayscale(CSSFloat), + HueRotate(Angle), + Invert(CSSFloat), + Opacity(CSSFloat), + Saturate(CSSFloat), + Sepia(CSSFloat), + } + + #[derive(Clone, PartialEq, Debug, HeapSizeOf, Deserialize, Serialize)] + pub struct T { pub filters: Vec } + + impl T { + /// Creates a new filter pipeline. + #[inline] + pub fn new(filters: Vec) -> T { + T + { + filters: filters, + } + } + + /// Adds a new filter to the filter pipeline. + #[inline] + pub fn push(&mut self, filter: Filter) { + self.filters.push(filter) + } + + /// Returns true if this filter pipeline is empty and false otherwise. + #[inline] + pub fn is_empty(&self) -> bool { + self.filters.is_empty() + } + + /// Returns the resulting opacity of this filter pipeline. + #[inline] + pub fn opacity(&self) -> CSSFloat { + let mut opacity = 1.0; + + for filter in &self.filters { + if let Filter::Opacity(ref opacity_value) = *filter { + opacity *= *opacity_value + } + } + opacity + } + } + } + + impl ToCss for computed_value::T { + fn to_css(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { + let mut iter = self.filters.iter(); + if let Some(filter) = iter.next() { + try!(filter.to_css(dest)); + } else { + try!(dest.write_str("none")); + return Ok(()) + } + for filter in iter { + try!(dest.write_str(" ")); + try!(filter.to_css(dest)); + } + Ok(()) + } + } + + impl ToCss for SpecifiedValue { + fn to_css(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { + let mut iter = self.0.iter(); + if let Some(filter) = iter.next() { + try!(filter.to_css(dest)); + } else { + try!(dest.write_str("none")); + return Ok(()) + } + for filter in iter { + try!(dest.write_str(" ")); + try!(filter.to_css(dest)); + } + Ok(()) + } + } + + impl ToCss for computed_value::Filter { + fn to_css(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { + match *self { + computed_value::Filter::Blur(value) => { + try!(dest.write_str("blur(")); + try!(value.to_css(dest)); + try!(dest.write_str(")")); + } + computed_value::Filter::Brightness(value) => try!(write!(dest, "brightness({})", value)), + computed_value::Filter::Contrast(value) => try!(write!(dest, "contrast({})", value)), + computed_value::Filter::Grayscale(value) => try!(write!(dest, "grayscale({})", value)), + computed_value::Filter::HueRotate(value) => { + try!(dest.write_str("hue-rotate(")); + try!(value.to_css(dest)); + try!(dest.write_str(")")); + } + computed_value::Filter::Invert(value) => try!(write!(dest, "invert({})", value)), + computed_value::Filter::Opacity(value) => try!(write!(dest, "opacity({})", value)), + computed_value::Filter::Saturate(value) => try!(write!(dest, "saturate({})", value)), + computed_value::Filter::Sepia(value) => try!(write!(dest, "sepia({})", value)), + } + Ok(()) + } + } + + impl ToCss for SpecifiedFilter { + fn to_css(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { + match *self { + SpecifiedFilter::Blur(value) => { + try!(dest.write_str("blur(")); + try!(value.to_css(dest)); + try!(dest.write_str(")")); + } + SpecifiedFilter::Brightness(value) => try!(write!(dest, "brightness({})", value)), + SpecifiedFilter::Contrast(value) => try!(write!(dest, "contrast({})", value)), + SpecifiedFilter::Grayscale(value) => try!(write!(dest, "grayscale({})", value)), + SpecifiedFilter::HueRotate(value) => { + try!(dest.write_str("hue-rotate(")); + try!(value.to_css(dest)); + try!(dest.write_str(")")); + } + SpecifiedFilter::Invert(value) => try!(write!(dest, "invert({})", value)), + SpecifiedFilter::Opacity(value) => try!(write!(dest, "opacity({})", value)), + SpecifiedFilter::Saturate(value) => try!(write!(dest, "saturate({})", value)), + SpecifiedFilter::Sepia(value) => try!(write!(dest, "sepia({})", value)), + } + Ok(()) + } + } + + #[inline] + pub fn get_initial_value() -> computed_value::T { + computed_value::T::new(Vec::new()) + } + + pub fn parse(_context: &ParserContext, input: &mut Parser) -> Result { + let mut filters = Vec::new(); + if input.try(|input| input.expect_ident_matching("none")).is_ok() { + return Ok(SpecifiedValue(filters)) + } + loop { + if let Ok(function_name) = input.try(|input| input.expect_function()) { + filters.push(try!(input.parse_nested_block(|input| { + match_ignore_ascii_case! { function_name, + "blur" => specified::Length::parse_non_negative(input).map(SpecifiedFilter::Blur), + "brightness" => parse_factor(input).map(SpecifiedFilter::Brightness), + "contrast" => parse_factor(input).map(SpecifiedFilter::Contrast), + "grayscale" => parse_factor(input).map(SpecifiedFilter::Grayscale), + "hue-rotate" => Angle::parse(input).map(SpecifiedFilter::HueRotate), + "invert" => parse_factor(input).map(SpecifiedFilter::Invert), + "opacity" => parse_factor(input).map(SpecifiedFilter::Opacity), + "saturate" => parse_factor(input).map(SpecifiedFilter::Saturate), + "sepia" => parse_factor(input).map(SpecifiedFilter::Sepia), + _ => Err(()) + } + }))); + } else if filters.is_empty() { + return Err(()) + } else { + return Ok(SpecifiedValue(filters)) + } + } + } + + fn parse_factor(input: &mut Parser) -> Result<::values::CSSFloat, ()> { + use cssparser::Token; + match input.next() { + Ok(Token::Number(value)) => Ok(value.value), + Ok(Token::Percentage(value)) => Ok(value.unit_value), + _ => Err(()) + } + } + + impl ToComputedValue for SpecifiedValue { + type ComputedValue = computed_value::T; + + fn to_computed_value(&self, context: &Cx) -> computed_value::T { + computed_value::T{ filters: self.0.iter().map(|value| { + match *value { + SpecifiedFilter::Blur(factor) => + computed_value::Filter::Blur(factor.to_computed_value(context)), + SpecifiedFilter::Brightness(factor) => computed_value::Filter::Brightness(factor), + SpecifiedFilter::Contrast(factor) => computed_value::Filter::Contrast(factor), + SpecifiedFilter::Grayscale(factor) => computed_value::Filter::Grayscale(factor), + SpecifiedFilter::HueRotate(factor) => computed_value::Filter::HueRotate(factor), + SpecifiedFilter::Invert(factor) => computed_value::Filter::Invert(factor), + SpecifiedFilter::Opacity(factor) => computed_value::Filter::Opacity(factor), + SpecifiedFilter::Saturate(factor) => computed_value::Filter::Saturate(factor), + SpecifiedFilter::Sepia(factor) => computed_value::Filter::Sepia(factor), + } + }).collect() } + } + } + + +<%helpers:longhand name="transform"> + use app_units::Au; + use values::CSSFloat; + + use cssparser::ToCss; + use std::fmt; + + pub mod computed_value { + use values::CSSFloat; + use values::computed; + + #[derive(Clone, Copy, Debug, PartialEq, HeapSizeOf)] + pub struct ComputedMatrix { + pub m11: CSSFloat, pub m12: CSSFloat, pub m13: CSSFloat, pub m14: CSSFloat, + pub m21: CSSFloat, pub m22: CSSFloat, pub m23: CSSFloat, pub m24: CSSFloat, + pub m31: CSSFloat, pub m32: CSSFloat, pub m33: CSSFloat, pub m34: CSSFloat, + pub m41: CSSFloat, pub m42: CSSFloat, pub m43: CSSFloat, pub m44: CSSFloat, + } + + impl ComputedMatrix { + pub fn identity() -> ComputedMatrix { + ComputedMatrix { + m11: 1.0, m12: 0.0, m13: 0.0, m14: 0.0, + m21: 0.0, m22: 1.0, m23: 0.0, m24: 0.0, + m31: 0.0, m32: 0.0, m33: 1.0, m34: 0.0, + m41: 0.0, m42: 0.0, m43: 0.0, m44: 1.0 + } + } + } + + #[derive(Clone, Debug, PartialEq, HeapSizeOf)] + pub enum ComputedOperation { + Matrix(ComputedMatrix), + Skew(computed::Angle, computed::Angle), + Translate(computed::LengthOrPercentage, + computed::LengthOrPercentage, + computed::Length), + Scale(CSSFloat, CSSFloat, CSSFloat), + Rotate(CSSFloat, CSSFloat, CSSFloat, computed::Angle), + Perspective(computed::Length), + } + + #[derive(Clone, Debug, PartialEq, HeapSizeOf)] + pub struct T(pub Option>); + } + + pub use self::computed_value::ComputedMatrix as SpecifiedMatrix; + + fn parse_two_lengths_or_percentages(input: &mut Parser) + -> Result<(specified::LengthOrPercentage, + specified::LengthOrPercentage),()> { + let first = try!(specified::LengthOrPercentage::parse(input)); + let second = input.try(|input| { + try!(input.expect_comma()); + specified::LengthOrPercentage::parse(input) + }).unwrap_or(specified::LengthOrPercentage::zero()); + Ok((first, second)) + } + + fn parse_two_floats(input: &mut Parser) -> Result<(CSSFloat,CSSFloat),()> { + let first = try!(specified::parse_number(input)); + let second = input.try(|input| { + try!(input.expect_comma()); + specified::parse_number(input) + }).unwrap_or(first); + Ok((first, second)) + } + + fn parse_two_angles(input: &mut Parser) -> Result<(specified::Angle, specified::Angle),()> { + let first = try!(specified::Angle::parse(input)); + let second = input.try(|input| { + try!(input.expect_comma()); + specified::Angle::parse(input) + }).unwrap_or(specified::Angle(0.0)); + Ok((first, second)) + } + + #[derive(Copy, Clone, Debug, PartialEq, HeapSizeOf)] + enum TranslateKind { + Translate, + TranslateX, + TranslateY, + TranslateZ, + Translate3D, + } + + #[derive(Clone, Debug, PartialEq, HeapSizeOf)] + enum SpecifiedOperation { + Matrix(SpecifiedMatrix), + Skew(specified::Angle, specified::Angle), + Translate(TranslateKind, + specified::LengthOrPercentage, + specified::LengthOrPercentage, + specified::Length), + Scale(CSSFloat, CSSFloat, CSSFloat), + Rotate(CSSFloat, CSSFloat, CSSFloat, specified::Angle), + Perspective(specified::Length), + } + + impl ToCss for computed_value::T { + fn to_css(&self, _: &mut W) -> fmt::Result where W: fmt::Write { + // TODO(pcwalton) + Ok(()) + } + } + + impl ToCss for SpecifiedOperation { + fn to_css(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { + match *self { + // todo(gw): implement serialization for transform + // types other than translate. + SpecifiedOperation::Matrix(_m) => { + Ok(()) + } + SpecifiedOperation::Skew(_sx, _sy) => { + Ok(()) + } + SpecifiedOperation::Translate(kind, tx, ty, tz) => { + match kind { + TranslateKind::Translate => { + try!(dest.write_str("translate(")); + try!(tx.to_css(dest)); + try!(dest.write_str(", ")); + try!(ty.to_css(dest)); + dest.write_str(")") + } + TranslateKind::TranslateX => { + try!(dest.write_str("translateX(")); + try!(tx.to_css(dest)); + dest.write_str(")") + } + TranslateKind::TranslateY => { + try!(dest.write_str("translateY(")); + try!(ty.to_css(dest)); + dest.write_str(")") + } + TranslateKind::TranslateZ => { + try!(dest.write_str("translateZ(")); + try!(tz.to_css(dest)); + dest.write_str(")") + } + TranslateKind::Translate3D => { + try!(dest.write_str("translate3d(")); + try!(tx.to_css(dest)); + try!(dest.write_str(", ")); + try!(ty.to_css(dest)); + try!(dest.write_str(", ")); + try!(tz.to_css(dest)); + dest.write_str(")") + } + } + } + SpecifiedOperation::Scale(_sx, _sy, _sz) => { + Ok(()) + } + SpecifiedOperation::Rotate(_ax, _ay, _az, _angle) => { + Ok(()) + } + SpecifiedOperation::Perspective(_p) => { + Ok(()) + } + } + } + } + + #[derive(Clone, Debug, PartialEq, HeapSizeOf)] + pub struct SpecifiedValue(Vec); + + impl ToCss for SpecifiedValue { + fn to_css(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { + let mut first = true; + for operation in &self.0 { + if !first { + try!(dest.write_str(" ")); + } + first = false; + try!(operation.to_css(dest)) + } + Ok(()) + } + } + + #[inline] + pub fn get_initial_value() -> computed_value::T { + computed_value::T(None) + } + + pub fn parse(_: &ParserContext, input: &mut Parser) -> Result { + if input.try(|input| input.expect_ident_matching("none")).is_ok() { + return Ok(SpecifiedValue(Vec::new())) + } + + let mut result = Vec::new(); + loop { + let name = match input.expect_function() { + Ok(name) => name, + Err(_) => break, + }; + match_ignore_ascii_case! { + name, + "matrix" => { + try!(input.parse_nested_block(|input| { + let values = try!(input.parse_comma_separated(|input| { + specified::parse_number(input) + })); + if values.len() != 6 { + return Err(()) + } + result.push(SpecifiedOperation::Matrix( + SpecifiedMatrix { + m11: values[0], m12: values[1], m13: 0.0, m14: 0.0, + m21: values[2], m22: values[3], m23: 0.0, m24: 0.0, + m31: 0.0, m32: 0.0, m33: 1.0, m34: 0.0, + m41: values[4], m42: values[5], m43: 0.0, m44: 1.0 + })); + Ok(()) + })) + }, + "matrix3d" => { + try!(input.parse_nested_block(|input| { + let values = try!(input.parse_comma_separated(|input| { + specified::parse_number(input) + })); + if values.len() != 16 { + return Err(()) + } + result.push(SpecifiedOperation::Matrix( + SpecifiedMatrix { + m11: values[ 0], m12: values[ 1], m13: values[ 2], m14: values[ 3], + m21: values[ 4], m22: values[ 5], m23: values[ 6], m24: values[ 7], + m31: values[ 8], m32: values[ 9], m33: values[10], m34: values[11], + m41: values[12], m42: values[13], m43: values[14], m44: values[15] + })); + Ok(()) + })) + }, + "translate" => { + try!(input.parse_nested_block(|input| { + let (tx, ty) = try!(parse_two_lengths_or_percentages(input)); + result.push(SpecifiedOperation::Translate(TranslateKind::Translate, + tx, + ty, + specified::Length::Absolute(Au(0)))); + Ok(()) + })) + }, + "translatex" => { + try!(input.parse_nested_block(|input| { + let tx = try!(specified::LengthOrPercentage::parse(input)); + result.push(SpecifiedOperation::Translate( + TranslateKind::TranslateX, + tx, + specified::LengthOrPercentage::zero(), + specified::Length::Absolute(Au(0)))); + Ok(()) + })) + }, + "translatey" => { + try!(input.parse_nested_block(|input| { + let ty = try!(specified::LengthOrPercentage::parse(input)); + result.push(SpecifiedOperation::Translate( + TranslateKind::TranslateY, + specified::LengthOrPercentage::zero(), + ty, + specified::Length::Absolute(Au(0)))); + Ok(()) + })) + }, + "translatez" => { + try!(input.parse_nested_block(|input| { + let tz = try!(specified::Length::parse(input)); + result.push(SpecifiedOperation::Translate( + TranslateKind::TranslateZ, + specified::LengthOrPercentage::zero(), + specified::LengthOrPercentage::zero(), + tz)); + Ok(()) + })) + }, + "translate3d" => { + try!(input.parse_nested_block(|input| { + let tx = try!(specified::LengthOrPercentage::parse(input)); + try!(input.expect_comma()); + let ty = try!(specified::LengthOrPercentage::parse(input)); + try!(input.expect_comma()); + let tz = try!(specified::Length::parse(input)); + result.push(SpecifiedOperation::Translate( + TranslateKind::Translate3D, + tx, + ty, + tz)); + Ok(()) + })) + + }, + "scale" => { + try!(input.parse_nested_block(|input| { + let (sx, sy) = try!(parse_two_floats(input)); + result.push(SpecifiedOperation::Scale(sx, sy, 1.0)); + Ok(()) + })) + }, + "scalex" => { + try!(input.parse_nested_block(|input| { + let sx = try!(specified::parse_number(input)); + result.push(SpecifiedOperation::Scale(sx, 1.0, 1.0)); + Ok(()) + })) + }, + "scaley" => { + try!(input.parse_nested_block(|input| { + let sy = try!(specified::parse_number(input)); + result.push(SpecifiedOperation::Scale(1.0, sy, 1.0)); + Ok(()) + })) + }, + "scalez" => { + try!(input.parse_nested_block(|input| { + let sz = try!(specified::parse_number(input)); + result.push(SpecifiedOperation::Scale(1.0, 1.0, sz)); + Ok(()) + })) + }, + "scale3d" => { + try!(input.parse_nested_block(|input| { + let sx = try!(specified::parse_number(input)); + try!(input.expect_comma()); + let sy = try!(specified::parse_number(input)); + try!(input.expect_comma()); + let sz = try!(specified::parse_number(input)); + result.push(SpecifiedOperation::Scale(sx, sy, sz)); + Ok(()) + })) + }, + "rotate" => { + try!(input.parse_nested_block(|input| { + let theta = try!(specified::Angle::parse(input)); + result.push(SpecifiedOperation::Rotate(0.0, 0.0, 1.0, theta)); + Ok(()) + })) + }, + "rotatex" => { + try!(input.parse_nested_block(|input| { + let theta = try!(specified::Angle::parse(input)); + result.push(SpecifiedOperation::Rotate(1.0, 0.0, 0.0, theta)); + Ok(()) + })) + }, + "rotatey" => { + try!(input.parse_nested_block(|input| { + let theta = try!(specified::Angle::parse(input)); + result.push(SpecifiedOperation::Rotate(0.0, 1.0, 0.0, theta)); + Ok(()) + })) + }, + "rotatez" => { + try!(input.parse_nested_block(|input| { + let theta = try!(specified::Angle::parse(input)); + result.push(SpecifiedOperation::Rotate(0.0, 0.0, 1.0, theta)); + Ok(()) + })) + }, + "rotate3d" => { + try!(input.parse_nested_block(|input| { + let ax = try!(specified::parse_number(input)); + try!(input.expect_comma()); + let ay = try!(specified::parse_number(input)); + try!(input.expect_comma()); + let az = try!(specified::parse_number(input)); + try!(input.expect_comma()); + let theta = try!(specified::Angle::parse(input)); + // TODO(gw): Check the axis can be normalized!! + result.push(SpecifiedOperation::Rotate(ax, ay, az, theta)); + Ok(()) + })) + }, + "skew" => { + try!(input.parse_nested_block(|input| { + let (theta_x, theta_y) = try!(parse_two_angles(input)); + result.push(SpecifiedOperation::Skew(theta_x, theta_y)); + Ok(()) + })) + }, + "skewx" => { + try!(input.parse_nested_block(|input| { + let theta_x = try!(specified::Angle::parse(input)); + result.push(SpecifiedOperation::Skew(theta_x, specified::Angle(0.0))); + Ok(()) + })) + }, + "skewy" => { + try!(input.parse_nested_block(|input| { + let theta_y = try!(specified::Angle::parse(input)); + result.push(SpecifiedOperation::Skew(specified::Angle(0.0), theta_y)); + Ok(()) + })) + }, + "perspective" => { + try!(input.parse_nested_block(|input| { + let d = try!(specified::Length::parse(input)); + result.push(SpecifiedOperation::Perspective(d)); + Ok(()) + })) + }, + _ => return Err(()) + } + } + + if !result.is_empty() { + Ok(SpecifiedValue(result)) + } else { + Err(()) + } + } + + impl ToComputedValue for SpecifiedValue { + type ComputedValue = computed_value::T; + + #[inline] + fn to_computed_value(&self, context: &Cx) -> computed_value::T { + if self.0.is_empty() { + return computed_value::T(None) + } + + let mut result = vec!(); + for operation in &self.0 { + match *operation { + SpecifiedOperation::Matrix(ref matrix) => { + result.push(computed_value::ComputedOperation::Matrix(*matrix)); + } + SpecifiedOperation::Translate(_, ref tx, ref ty, ref tz) => { + result.push(computed_value::ComputedOperation::Translate(tx.to_computed_value(context), + ty.to_computed_value(context), + tz.to_computed_value(context))); + } + SpecifiedOperation::Scale(sx, sy, sz) => { + result.push(computed_value::ComputedOperation::Scale(sx, sy, sz)); + } + SpecifiedOperation::Rotate(ax, ay, az, theta) => { + result.push(computed_value::ComputedOperation::Rotate(ax, ay, az, theta)); + } + SpecifiedOperation::Skew(theta_x, theta_y) => { + result.push(computed_value::ComputedOperation::Skew(theta_x, theta_y)); + } + SpecifiedOperation::Perspective(d) => { + result.push(computed_value::ComputedOperation::Perspective(d.to_computed_value(context))); + } + }; + } + + computed_value::T(Some(result)) + } + } + + +pub struct OriginParseResult { + horizontal: Option, + vertical: Option, + depth: Option +} + +pub fn parse_origin(_: &ParserContext, input: &mut Parser) -> Result { + use values::specified::{LengthOrPercentage, Percentage}; + let (mut horizontal, mut vertical, mut depth) = (None, None, None); + loop { + if let Err(_) = input.try(|input| { + let token = try!(input.expect_ident()); + match_ignore_ascii_case! { + token, + "left" => { + if horizontal.is_none() { + horizontal = Some(LengthOrPercentage::Percentage(Percentage(0.0))) + } else { + return Err(()) + } + }, + "center" => { + if horizontal.is_none() { + horizontal = Some(LengthOrPercentage::Percentage(Percentage(0.5))) + } else if vertical.is_none() { + vertical = Some(LengthOrPercentage::Percentage(Percentage(0.5))) + } else { + return Err(()) + } + }, + "right" => { + if horizontal.is_none() { + horizontal = Some(LengthOrPercentage::Percentage(Percentage(1.0))) + } else { + return Err(()) + } + }, + "top" => { + if vertical.is_none() { + vertical = Some(LengthOrPercentage::Percentage(Percentage(0.0))) + } else { + return Err(()) + } + }, + "bottom" => { + if vertical.is_none() { + vertical = Some(LengthOrPercentage::Percentage(Percentage(1.0))) + } else { + return Err(()) + } + }, + _ => return Err(()) + } + Ok(()) + }) { + match LengthOrPercentage::parse(input) { + Ok(value) => { + if horizontal.is_none() { + horizontal = Some(value); + } else if vertical.is_none() { + vertical = Some(value); + } else if let LengthOrPercentage::Length(length) = value { + depth = Some(length); + } else { + break; + } + } + _ => break, + } + } + } + + if horizontal.is_some() || vertical.is_some() { + Ok(OriginParseResult { + horizontal: horizontal, + vertical: vertical, + depth: depth, + }) + } else { + Err(()) + } +} + +${helpers.single_keyword("backface-visibility", "visible hidden")} + +${helpers.single_keyword("transform-box", "border-box fill-box view-box", products="gecko")} + +${helpers.single_keyword("transform-style", "auto flat preserve-3d")} + +<%helpers:longhand name="transform-origin"> + use app_units::Au; + use values::AuExtensionMethods; + use values::specified::{Length, LengthOrPercentage, Percentage}; + + use cssparser::ToCss; + use std::fmt; + + pub mod computed_value { + use values::computed::{Length, LengthOrPercentage}; + + #[derive(Clone, Copy, Debug, PartialEq, HeapSizeOf)] + pub struct T { + pub horizontal: LengthOrPercentage, + pub vertical: LengthOrPercentage, + pub depth: Length, + } + } + + #[derive(Clone, Copy, Debug, PartialEq, HeapSizeOf)] + pub struct SpecifiedValue { + horizontal: LengthOrPercentage, + vertical: LengthOrPercentage, + depth: Length, + } + + impl ToCss for computed_value::T { + fn to_css(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { + try!(self.horizontal.to_css(dest)); + try!(dest.write_str(" ")); + try!(self.vertical.to_css(dest)); + try!(dest.write_str(" ")); + self.depth.to_css(dest) + } + } + + impl ToCss for SpecifiedValue { + fn to_css(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { + try!(self.horizontal.to_css(dest)); + try!(dest.write_str(" ")); + try!(self.vertical.to_css(dest)); + try!(dest.write_str(" ")); + self.depth.to_css(dest) + } + } + + #[inline] + pub fn get_initial_value() -> computed_value::T { + computed_value::T { + horizontal: computed::LengthOrPercentage::Percentage(0.5), + vertical: computed::LengthOrPercentage::Percentage(0.5), + depth: Au(0), + } + } + + pub fn parse(context: &ParserContext, input: &mut Parser) -> Result { + let result = try!(super::parse_origin(context, input)); + Ok(SpecifiedValue { + horizontal: result.horizontal.unwrap_or(LengthOrPercentage::Percentage(Percentage(0.5))), + vertical: result.vertical.unwrap_or(LengthOrPercentage::Percentage(Percentage(0.5))), + depth: result.depth.unwrap_or(Length::Absolute(Au(0))), + }) + } + + impl ToComputedValue for SpecifiedValue { + type ComputedValue = computed_value::T; + + #[inline] + fn to_computed_value(&self, context: &Cx) -> computed_value::T { + computed_value::T { + horizontal: self.horizontal.to_computed_value(context), + vertical: self.vertical.to_computed_value(context), + depth: self.depth.to_computed_value(context), + } + } + } + + +${helpers.predefined_type("perspective", + "LengthOrNone", + "computed::LengthOrNone::None")} + +<%helpers:longhand name="perspective-origin"> + use values::specified::{LengthOrPercentage, Percentage}; + + use cssparser::ToCss; + use std::fmt; + + pub mod computed_value { + use values::computed::LengthOrPercentage; + + #[derive(Clone, Copy, Debug, PartialEq, HeapSizeOf)] + pub struct T { + pub horizontal: LengthOrPercentage, + pub vertical: LengthOrPercentage, + } + } + + impl ToCss for computed_value::T { + fn to_css(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { + try!(self.horizontal.to_css(dest)); + try!(dest.write_str(" ")); + self.vertical.to_css(dest) + } + } + + #[derive(Clone, Copy, Debug, PartialEq, HeapSizeOf)] + pub struct SpecifiedValue { + horizontal: LengthOrPercentage, + vertical: LengthOrPercentage, + } + + impl ToCss for SpecifiedValue { + fn to_css(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { + try!(self.horizontal.to_css(dest)); + try!(dest.write_str(" ")); + self.vertical.to_css(dest) + } + } + + #[inline] + pub fn get_initial_value() -> computed_value::T { + computed_value::T { + horizontal: computed::LengthOrPercentage::Percentage(0.5), + vertical: computed::LengthOrPercentage::Percentage(0.5), + } + } + + pub fn parse(context: &ParserContext, input: &mut Parser) -> Result { + let result = try!(super::parse_origin(context, input)); + match result.depth { + Some(_) => Err(()), + None => Ok(SpecifiedValue { + horizontal: result.horizontal.unwrap_or(LengthOrPercentage::Percentage(Percentage(0.5))), + vertical: result.vertical.unwrap_or(LengthOrPercentage::Percentage(Percentage(0.5))), + }) + } + } + + impl ToComputedValue for SpecifiedValue { + type ComputedValue = computed_value::T; + + #[inline] + fn to_computed_value(&self, context: &Cx) -> computed_value::T { + computed_value::T { + horizontal: self.horizontal.to_computed_value(context), + vertical: self.vertical.to_computed_value(context), + } + } + } + + +${helpers.single_keyword("mix-blend-mode", + """normal multiply screen overlay darken lighten color-dodge + color-burn hard-light soft-light difference exclusion hue + saturation color luminosity""", gecko_constant_prefix="NS_STYLE_BLEND")} diff --git a/components/style/properties/longhand/font.mako.rs b/components/style/properties/longhand/font.mako.rs new file mode 100644 index 00000000000..b12acc6ccc7 --- /dev/null +++ b/components/style/properties/longhand/font.mako.rs @@ -0,0 +1,312 @@ +/* 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/. */ + +<%namespace name="helpers" file="/helpers.mako.rs" /> +<% from data import Method %> + +<% data.new_style_struct("Font", + inherited=True, + gecko_ffi_name="nsStyleFont", + additional_methods=[Method("compute_font_hash", is_mut=True)]) %> +<%helpers:longhand name="font-family"> + use self::computed_value::FontFamily; + use values::computed::ComputedValueAsSpecified; + pub use self::computed_value::T as SpecifiedValue; + + const SERIF: &'static str = "serif"; + const SANS_SERIF: &'static str = "sans-serif"; + const CURSIVE: &'static str = "cursive"; + const FANTASY: &'static str = "fantasy"; + const MONOSPACE: &'static str = "monospace"; + + impl ComputedValueAsSpecified for SpecifiedValue {} + pub mod computed_value { + use cssparser::ToCss; + use std::fmt; + use string_cache::Atom; + + #[derive(Debug, PartialEq, Eq, Clone, Hash, HeapSizeOf, Deserialize, Serialize)] + pub enum FontFamily { + FamilyName(Atom), + // Generic, + Serif, + SansSerif, + Cursive, + Fantasy, + Monospace, + } + impl FontFamily { + #[inline] + pub fn name(&self) -> &str { + match *self { + FontFamily::FamilyName(ref name) => &*name, + FontFamily::Serif => super::SERIF, + FontFamily::SansSerif => super::SANS_SERIF, + FontFamily::Cursive => super::CURSIVE, + FontFamily::Fantasy => super::FANTASY, + FontFamily::Monospace => super::MONOSPACE + } + } + + pub fn from_atom(input: Atom) -> FontFamily { + let option = match_ignore_ascii_case! { &input, + super::SERIF => Some(FontFamily::Serif), + super::SANS_SERIF => Some(FontFamily::SansSerif), + super::CURSIVE => Some(FontFamily::Cursive), + super::FANTASY => Some(FontFamily::Fantasy), + super::MONOSPACE => Some(FontFamily::Monospace), + _ => None + }; + + match option { + Some(family) => family, + None => FontFamily::FamilyName(input) + } + } + } + impl ToCss for FontFamily { + fn to_css(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { + dest.write_str(self.name()) + } + } + impl ToCss for T { + fn to_css(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { + let mut iter = self.0.iter(); + try!(iter.next().unwrap().to_css(dest)); + for family in iter { + try!(dest.write_str(", ")); + try!(family.to_css(dest)); + } + Ok(()) + } + } + #[derive(Debug, Clone, PartialEq, Eq, Hash, HeapSizeOf)] + pub struct T(pub Vec); + } + + #[inline] + pub fn get_initial_value() -> computed_value::T { + computed_value::T(vec![FontFamily::Serif]) + } + /// # + /// = | [ + ] + /// TODO: + pub fn parse(_context: &ParserContext, input: &mut Parser) -> Result { + input.parse_comma_separated(parse_one_family).map(SpecifiedValue) + } + pub fn parse_one_family(input: &mut Parser) -> Result { + if let Ok(value) = input.try(|input| input.expect_string()) { + return Ok(FontFamily::FamilyName(Atom::from(&*value))) + } + let first_ident = try!(input.expect_ident()); + + match_ignore_ascii_case! { first_ident, + SERIF => return Ok(FontFamily::Serif), + SANS_SERIF => return Ok(FontFamily::SansSerif), + CURSIVE => return Ok(FontFamily::Cursive), + FANTASY => return Ok(FontFamily::Fantasy), + MONOSPACE => return Ok(FontFamily::Monospace), + _ => {} + } + let mut value = first_ident.into_owned(); + while let Ok(ident) = input.try(|input| input.expect_ident()) { + value.push_str(" "); + value.push_str(&ident); + } + Ok(FontFamily::FamilyName(Atom::from(value))) + } + + + +${helpers.single_keyword("font-style", "normal italic oblique")} +${helpers.single_keyword("font-variant", "normal small-caps")} + +<%helpers:longhand name="font-weight" need_clone="True"> + use cssparser::ToCss; + use std::fmt; + + #[derive(Debug, Clone, PartialEq, Eq, Copy, HeapSizeOf)] + pub enum SpecifiedValue { + Bolder, + Lighter, + % for weight in range(100, 901, 100): + Weight${weight}, + % endfor + } + + impl ToCss for SpecifiedValue { + fn to_css(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { + match *self { + SpecifiedValue::Bolder => dest.write_str("bolder"), + SpecifiedValue::Lighter => dest.write_str("lighter"), + % for weight in range(100, 901, 100): + SpecifiedValue::Weight${weight} => dest.write_str("${weight}"), + % endfor + } + } + } + /// normal | bold | bolder | lighter | 100 | 200 | 300 | 400 | 500 | 600 | 700 | 800 | 900 + pub fn parse(_context: &ParserContext, input: &mut Parser) -> Result { + input.try(|input| { + match_ignore_ascii_case! { try!(input.expect_ident()), + "bold" => Ok(SpecifiedValue::Weight700), + "normal" => Ok(SpecifiedValue::Weight400), + "bolder" => Ok(SpecifiedValue::Bolder), + "lighter" => Ok(SpecifiedValue::Lighter), + _ => Err(()) + } + }).or_else(|()| { + match try!(input.expect_integer()) { + 100 => Ok(SpecifiedValue::Weight100), + 200 => Ok(SpecifiedValue::Weight200), + 300 => Ok(SpecifiedValue::Weight300), + 400 => Ok(SpecifiedValue::Weight400), + 500 => Ok(SpecifiedValue::Weight500), + 600 => Ok(SpecifiedValue::Weight600), + 700 => Ok(SpecifiedValue::Weight700), + 800 => Ok(SpecifiedValue::Weight800), + 900 => Ok(SpecifiedValue::Weight900), + _ => Err(()) + } + }) + } + pub mod computed_value { + use std::fmt; + #[derive(PartialEq, Eq, Copy, Clone, Hash, Deserialize, Serialize, HeapSizeOf, Debug)] + pub enum T { + % for weight in range(100, 901, 100): + Weight${weight} = ${weight}, + % endfor + } + impl T { + #[inline] + pub fn is_bold(self) -> bool { + match self { + T::Weight900 | T::Weight800 | + T::Weight700 | T::Weight600 => true, + _ => false + } + } + } + } + impl ToCss for computed_value::T { + fn to_css(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { + match *self { + % for weight in range(100, 901, 100): + computed_value::T::Weight${weight} => dest.write_str("${weight}"), + % endfor + } + } + } + #[inline] + pub fn get_initial_value() -> computed_value::T { + computed_value::T::Weight400 // normal + } + + impl ToComputedValue for SpecifiedValue { + type ComputedValue = computed_value::T; + + #[inline] + fn to_computed_value(&self, context: &Cx) -> computed_value::T { + match *self { + % for weight in range(100, 901, 100): + SpecifiedValue::Weight${weight} => computed_value::T::Weight${weight}, + % endfor + SpecifiedValue::Bolder => match context.inherited_style().get_font().clone_font_weight() { + computed_value::T::Weight100 => computed_value::T::Weight400, + computed_value::T::Weight200 => computed_value::T::Weight400, + computed_value::T::Weight300 => computed_value::T::Weight400, + computed_value::T::Weight400 => computed_value::T::Weight700, + computed_value::T::Weight500 => computed_value::T::Weight700, + computed_value::T::Weight600 => computed_value::T::Weight900, + computed_value::T::Weight700 => computed_value::T::Weight900, + computed_value::T::Weight800 => computed_value::T::Weight900, + computed_value::T::Weight900 => computed_value::T::Weight900, + }, + SpecifiedValue::Lighter => match context.inherited_style().get_font().clone_font_weight() { + computed_value::T::Weight100 => computed_value::T::Weight100, + computed_value::T::Weight200 => computed_value::T::Weight100, + computed_value::T::Weight300 => computed_value::T::Weight100, + computed_value::T::Weight400 => computed_value::T::Weight100, + computed_value::T::Weight500 => computed_value::T::Weight100, + computed_value::T::Weight600 => computed_value::T::Weight400, + computed_value::T::Weight700 => computed_value::T::Weight400, + computed_value::T::Weight800 => computed_value::T::Weight700, + computed_value::T::Weight900 => computed_value::T::Weight700, + }, + } + } + } + + +<%helpers:longhand name="font-size" need_clone="True"> + use app_units::Au; + use cssparser::ToCss; + use std::fmt; + use values::FONT_MEDIUM_PX; + use values::specified::{LengthOrPercentage, Length, Percentage}; + + impl ToCss for SpecifiedValue { + fn to_css(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { + self.0.to_css(dest) + } + } + + #[derive(Debug, Clone, PartialEq, HeapSizeOf)] + pub struct SpecifiedValue(pub specified::LengthOrPercentage); + pub mod computed_value { + use app_units::Au; + pub type T = Au; + } + #[inline] pub fn get_initial_value() -> computed_value::T { + Au::from_px(FONT_MEDIUM_PX) + } + + impl ToComputedValue for SpecifiedValue { + type ComputedValue = computed_value::T; + + #[inline] + fn to_computed_value(&self, context: &Cx) -> computed_value::T { + match self.0 { + LengthOrPercentage::Length(Length::FontRelative(value)) => { + value.to_computed_value(context.inherited_style().get_font().clone_font_size(), + context.style().root_font_size()) + } + LengthOrPercentage::Length(Length::ServoCharacterWidth(value)) => { + value.to_computed_value(context.inherited_style().get_font().clone_font_size()) + } + LengthOrPercentage::Length(l) => { + l.to_computed_value(context) + } + LengthOrPercentage::Percentage(Percentage(value)) => { + context.inherited_style().get_font().clone_font_size().scale_by(value) + } + LengthOrPercentage::Calc(calc) => { + let calc = calc.to_computed_value(context); + calc.length() + context.inherited_style().get_font().clone_font_size() + .scale_by(calc.percentage()) + } + } + } + } + /// | | | + pub fn parse(_context: &ParserContext, input: &mut Parser) -> Result { + use values::specified::{Length, LengthOrPercentage}; + + input.try(specified::LengthOrPercentage::parse_non_negative) + .or_else(|()| { + let ident = try!(input.expect_ident()); + specified::Length::from_str(&ident as &str) + .ok_or(()) + .map(specified::LengthOrPercentage::Length) + }) + .map(SpecifiedValue) + } + + +${helpers.single_keyword("font-stretch", + "normal ultra-condensed extra-condensed condensed semi-condensed semi-expanded \ + expanded extra-expanded ultra-expanded")} + +${helpers.single_keyword("font-kerning", "auto none normal", products="gecko")} diff --git a/components/style/properties/longhand/inherited_box.mako.rs b/components/style/properties/longhand/inherited_box.mako.rs new file mode 100644 index 00000000000..4c8dd202596 --- /dev/null +++ b/components/style/properties/longhand/inherited_box.mako.rs @@ -0,0 +1,90 @@ +/* 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/. */ + +<%namespace name="helpers" file="/helpers.mako.rs" /> + +<% data.new_style_struct("InheritedBox", inherited=True, gecko_ffi_name="nsStyleVisibility") %> + +${helpers.single_keyword("direction", "ltr rtl", need_clone=True)} + +// TODO: collapse. Well, do tables first. +${helpers.single_keyword("visibility", + "visible hidden", + extra_gecko_values="collapse", + gecko_ffi_name="mVisible")} + +// CSS Writing Modes Level 3 +// http://dev.w3.org/csswg/css-writing-modes/ +${helpers.single_keyword("writing-mode", + "horizontal-tb vertical-rl vertical-lr", + experimental=True, + need_clone=True)} + +// FIXME(SimonSapin): Add 'mixed' and 'upright' (needs vertical text support) +// FIXME(SimonSapin): initial (first) value should be 'mixed', when that's implemented +// FIXME(bholley): sideways-right is needed as an alias to sideways in gecko. +${helpers.single_keyword("text-orientation", + "sideways", + experimental=True, + need_clone=True, + extra_gecko_values="mixed upright", + extra_servo_values="sideways-right sideways-left")} + +// CSS Color Module Level 4 +// https://drafts.csswg.org/css-color/ +${helpers.single_keyword("color-adjust", "economy exact", products="gecko")} + +<%helpers:longhand name="image-rendering"> + pub mod computed_value { + use cssparser::ToCss; + use std::fmt; + + #[derive(Copy, Clone, Debug, PartialEq, HeapSizeOf, Deserialize, Serialize)] + pub enum T { + Auto, + CrispEdges, + Pixelated, + } + + impl ToCss for T { + fn to_css(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { + match *self { + T::Auto => dest.write_str("auto"), + T::CrispEdges => dest.write_str("crisp-edges"), + T::Pixelated => dest.write_str("pixelated"), + } + } + } + } + + pub type SpecifiedValue = computed_value::T; + + #[inline] + pub fn get_initial_value() -> computed_value::T { + computed_value::T::Auto + } + + pub fn parse(_: &ParserContext, input: &mut Parser) -> Result { + // According to to CSS-IMAGES-3, `optimizespeed` and `optimizequality` are synonyms for + // `auto`. + match_ignore_ascii_case! { + try!(input.expect_ident()), + "auto" => Ok(computed_value::T::Auto), + "optimizespeed" => Ok(computed_value::T::Auto), + "optimizequality" => Ok(computed_value::T::Auto), + "crisp-edges" => Ok(computed_value::T::CrispEdges), + "pixelated" => Ok(computed_value::T::Pixelated), + _ => Err(()) + } + } + + impl ToComputedValue for SpecifiedValue { + type ComputedValue = computed_value::T; + + #[inline] + fn to_computed_value(&self, _: &Cx) -> computed_value::T { + *self + } + } + diff --git a/components/style/properties/longhand/inherited_table.mako.rs b/components/style/properties/longhand/inherited_table.mako.rs new file mode 100644 index 00000000000..5ec6a2e1982 --- /dev/null +++ b/components/style/properties/longhand/inherited_table.mako.rs @@ -0,0 +1,100 @@ +/* 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/. */ + + <%namespace name="helpers" file="/helpers.mako.rs" /> + +<% data.new_style_struct("InheritedTable", inherited=True, gecko_ffi_name="nsStyleTableBorder") %> + +${helpers.single_keyword("border-collapse", "separate collapse", gecko_constant_prefix="NS_STYLE_BORDER")} +${helpers.single_keyword("empty-cells", "show hide", gecko_constant_prefix="NS_STYLE_TABLE_EMPTY_CELLS")} +${helpers.single_keyword("caption-side", "top bottom", extra_gecko_values="right left top-outside bottom-outside")} + +<%helpers:longhand name="border-spacing"> + use app_units::Au; + use values::AuExtensionMethods; + + use cssparser::ToCss; + use std::fmt; + + pub mod computed_value { + use app_units::Au; + + #[derive(Clone, Copy, Debug, PartialEq, RustcEncodable, HeapSizeOf)] + pub struct T { + pub horizontal: Au, + pub vertical: Au, + } + } + + #[derive(Clone, Debug, PartialEq, HeapSizeOf)] + pub struct SpecifiedValue { + pub horizontal: specified::Length, + pub vertical: specified::Length, + } + + #[inline] + pub fn get_initial_value() -> computed_value::T { + computed_value::T { + horizontal: Au(0), + vertical: Au(0), + } + } + + impl ToCss for SpecifiedValue { + fn to_css(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { + try!(self.horizontal.to_css(dest)); + try!(dest.write_str(" ")); + self.vertical.to_css(dest) + } + } + + impl ToCss for computed_value::T { + fn to_css(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { + try!(self.horizontal.to_css(dest)); + try!(dest.write_str(" ")); + self.vertical.to_css(dest) + } + } + + impl ToComputedValue for SpecifiedValue { + type ComputedValue = computed_value::T; + + #[inline] + fn to_computed_value(&self, context: &Cx) -> computed_value::T { + computed_value::T { + horizontal: self.horizontal.to_computed_value(context), + vertical: self.vertical.to_computed_value(context), + } + } + } + + pub fn parse(_: &ParserContext, input: &mut Parser) -> Result { + let mut lengths = [ None, None ]; + for i in 0..2 { + match specified::Length::parse_non_negative(input) { + Err(()) => break, + Ok(length) => lengths[i] = Some(length), + } + } + if input.next().is_ok() { + return Err(()) + } + match (lengths[0], lengths[1]) { + (None, None) => Err(()), + (Some(length), None) => { + Ok(SpecifiedValue { + horizontal: length, + vertical: length, + }) + } + (Some(horizontal), Some(vertical)) => { + Ok(SpecifiedValue { + horizontal: horizontal, + vertical: vertical, + }) + } + (None, Some(_)) => panic!("shouldn't happen"), + } + } + diff --git a/components/style/properties/longhand/inherited_text.mako.rs b/components/style/properties/longhand/inherited_text.mako.rs new file mode 100644 index 00000000000..32fef25c68a --- /dev/null +++ b/components/style/properties/longhand/inherited_text.mako.rs @@ -0,0 +1,613 @@ +/* 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/. */ + +<%namespace name="helpers" file="/helpers.mako.rs" /> + +<% data.new_style_struct("InheritedText", inherited=True, gecko_ffi_name="nsStyleText") %> + +<%helpers:longhand name="line-height"> + use cssparser::ToCss; + use std::fmt; + use values::AuExtensionMethods; + use values::CSSFloat; + + #[derive(Debug, Clone, PartialEq, Copy, HeapSizeOf)] + pub enum SpecifiedValue { + Normal, + Number(CSSFloat), + LengthOrPercentage(specified::LengthOrPercentage), + } + + impl ToCss for SpecifiedValue { + fn to_css(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { + match *self { + SpecifiedValue::Normal => dest.write_str("normal"), + SpecifiedValue::LengthOrPercentage(value) => value.to_css(dest), + SpecifiedValue::Number(number) => write!(dest, "{}", number), + } + } + } + /// normal | | | + pub fn parse(_context: &ParserContext, input: &mut Parser) -> Result { + use cssparser::Token; + use std::ascii::AsciiExt; + input.try(specified::LengthOrPercentage::parse_non_negative) + .map(SpecifiedValue::LengthOrPercentage) + .or_else(|()| { + match try!(input.next()) { + Token::Number(ref value) if value.value >= 0. => { + Ok(SpecifiedValue::Number(value.value)) + } + Token::Ident(ref value) if value.eq_ignore_ascii_case("normal") => { + Ok(SpecifiedValue::Normal) + } + _ => Err(()), + } + }) + } + pub mod computed_value { + use app_units::Au; + use std::fmt; + use values::CSSFloat; + #[derive(PartialEq, Copy, Clone, HeapSizeOf, Debug)] + pub enum T { + Normal, + Length(Au), + Number(CSSFloat), + } + } + impl ToCss for computed_value::T { + fn to_css(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { + match *self { + computed_value::T::Normal => dest.write_str("normal"), + computed_value::T::Length(length) => length.to_css(dest), + computed_value::T::Number(number) => write!(dest, "{}", number), + } + } + } + #[inline] + pub fn get_initial_value() -> computed_value::T { computed_value::T::Normal } + + impl ToComputedValue for SpecifiedValue { + type ComputedValue = computed_value::T; + + #[inline] + fn to_computed_value(&self, context: &Cx) -> computed_value::T { + match *self { + SpecifiedValue::Normal => computed_value::T::Normal, + SpecifiedValue::Number(value) => computed_value::T::Number(value), + SpecifiedValue::LengthOrPercentage(value) => { + match value { + specified::LengthOrPercentage::Length(value) => + computed_value::T::Length(value.to_computed_value(context)), + specified::LengthOrPercentage::Percentage(specified::Percentage(value)) => { + let fr = specified::Length::FontRelative(specified::FontRelativeLength::Em(value)); + computed_value::T::Length(fr.to_computed_value(context)) + }, + specified::LengthOrPercentage::Calc(calc) => { + let calc = calc.to_computed_value(context); + let fr = specified::FontRelativeLength::Em(calc.percentage()); + let fr = specified::Length::FontRelative(fr); + computed_value::T::Length(calc.length() + fr.to_computed_value(context)) + } + } + } + } + } + } + + +<%helpers:longhand name="text-align"> + pub use self::computed_value::T as SpecifiedValue; + use values::computed::ComputedValueAsSpecified; + impl ComputedValueAsSpecified for SpecifiedValue {} + pub mod computed_value { + macro_rules! define_text_align { + ( $( $name: ident ( $string: expr ) => $discriminant: expr, )+ ) => { + define_css_keyword_enum! { T: + $( + $string => $name, + )+ + } + impl T { + pub fn to_u32(self) -> u32 { + match self { + $( + T::$name => $discriminant, + )+ + } + } + pub fn from_u32(discriminant: u32) -> Option { + match discriminant { + $( + $discriminant => Some(T::$name), + )+ + _ => None + } + } + } + } + } + define_text_align! { + start("start") => 0, + end("end") => 1, + left("left") => 2, + right("right") => 3, + center("center") => 4, + justify("justify") => 5, + servo_center("-servo-center") => 6, + servo_left("-servo-left") => 7, + servo_right("-servo-right") => 8, + } + } + #[inline] pub fn get_initial_value() -> computed_value::T { + computed_value::T::start + } + pub fn parse(_context: &ParserContext, input: &mut Parser) + -> Result { + computed_value::T::parse(input) + } + + +<%helpers:longhand name="letter-spacing"> + use cssparser::ToCss; + use std::fmt; + use values::AuExtensionMethods; + + #[derive(Debug, Clone, Copy, PartialEq, HeapSizeOf)] + pub enum SpecifiedValue { + Normal, + Specified(specified::Length), + } + + impl ToCss for SpecifiedValue { + fn to_css(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { + match *self { + SpecifiedValue::Normal => dest.write_str("normal"), + SpecifiedValue::Specified(l) => l.to_css(dest), + } + } + } + + pub mod computed_value { + use app_units::Au; + #[derive(Debug, Clone, PartialEq, HeapSizeOf)] + pub struct T(pub Option); + } + + impl ToCss for computed_value::T { + fn to_css(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { + match self.0 { + None => dest.write_str("normal"), + Some(l) => l.to_css(dest), + } + } + } + + #[inline] + pub fn get_initial_value() -> computed_value::T { + computed_value::T(None) + } + + impl ToComputedValue for SpecifiedValue { + type ComputedValue = computed_value::T; + + #[inline] + fn to_computed_value(&self, context: &Cx) -> computed_value::T { + match *self { + SpecifiedValue::Normal => computed_value::T(None), + SpecifiedValue::Specified(l) => + computed_value::T(Some(l.to_computed_value(context))) + } + } + } + + pub fn parse(_context: &ParserContext, input: &mut Parser) -> Result { + if input.try(|input| input.expect_ident_matching("normal")).is_ok() { + Ok(SpecifiedValue::Normal) + } else { + specified::Length::parse_non_negative(input).map(SpecifiedValue::Specified) + } + } + + +<%helpers:longhand name="word-spacing"> + use cssparser::ToCss; + use std::fmt; + use values::AuExtensionMethods; + + #[derive(Debug, Clone, Copy, PartialEq, HeapSizeOf)] + pub enum SpecifiedValue { + Normal, + Specified(specified::Length), // FIXME(SimonSapin) support percentages + } + + impl ToCss for SpecifiedValue { + fn to_css(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { + match *self { + SpecifiedValue::Normal => dest.write_str("normal"), + SpecifiedValue::Specified(l) => l.to_css(dest), + } + } + } + + pub mod computed_value { + use app_units::Au; + #[derive(Debug, Clone, PartialEq, HeapSizeOf)] + pub struct T(pub Option); + } + + impl ToCss for computed_value::T { + fn to_css(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { + match self.0 { + None => dest.write_str("normal"), + Some(l) => l.to_css(dest), + } + } + } + + #[inline] + pub fn get_initial_value() -> computed_value::T { + computed_value::T(None) + } + + impl ToComputedValue for SpecifiedValue { + type ComputedValue = computed_value::T; + + #[inline] + fn to_computed_value(&self, context: &Cx) -> computed_value::T { + match *self { + SpecifiedValue::Normal => computed_value::T(None), + SpecifiedValue::Specified(l) => + computed_value::T(Some(l.to_computed_value(context))) + } + } + } + + pub fn parse(_context: &ParserContext, input: &mut Parser) -> Result { + if input.try(|input| input.expect_ident_matching("normal")).is_ok() { + Ok(SpecifiedValue::Normal) + } else { + specified::Length::parse_non_negative(input).map(SpecifiedValue::Specified) + } + } + + +${helpers.predefined_type("text-indent", + "LengthOrPercentage", + "computed::LengthOrPercentage::Length(Au(0))")} + +// Also known as "word-wrap" (which is more popular because of IE), but this is the preferred +// name per CSS-TEXT 6.2. +${helpers.single_keyword("overflow-wrap", + "normal break-word", + gecko_ffi_name="mWordWrap", + gecko_constant_prefix="NS_STYLE_WORDWRAP")} + +// TODO(pcwalton): Support `word-break: keep-all` once we have better CJK support. +${helpers.single_keyword("word-break", + "normal break-all", + extra_gecko_values="keep-all", + gecko_constant_prefix="NS_STYLE_WORDBREAK")} + +// TODO(pcwalton): Support `text-justify: distribute`. +${helpers.single_keyword("text-justify", + "auto none inter-word", + products="servo")} + +<%helpers:longhand name="-servo-text-decorations-in-effect" + derived_from="display text-decoration" need_clone="True" products="servo"> + use cssparser::{RGBA, ToCss}; + use std::fmt; + + use values::computed::ComputedValueAsSpecified; + use properties::style_struct_traits::{Box, Color, Text}; + + impl ComputedValueAsSpecified for SpecifiedValue {} + + #[derive(Clone, PartialEq, Copy, Debug, HeapSizeOf)] + pub struct SpecifiedValue { + pub underline: Option, + pub overline: Option, + pub line_through: Option, + } + + pub mod computed_value { + pub type T = super::SpecifiedValue; + } + + impl ToCss for SpecifiedValue { + fn to_css(&self, _: &mut W) -> fmt::Result where W: fmt::Write { + // Web compat doesn't matter here. + Ok(()) + } + } + + #[inline] + pub fn get_initial_value() -> computed_value::T { + SpecifiedValue { + underline: None, + overline: None, + line_through: None, + } + } + + fn maybe(flag: bool, context: &Cx) -> Option { + if flag { + Some(context.style().get_color().clone_color()) + } else { + None + } + } + + fn derive(context: &Cx) -> computed_value::T { + // Start with no declarations if this is an atomic inline-level box; otherwise, start with the + // declarations in effect and add in the text decorations that this block specifies. + let mut result = match context.style().get_box().clone_display() { + super::display::computed_value::T::inline_block | + super::display::computed_value::T::inline_table => SpecifiedValue { + underline: None, + overline: None, + line_through: None, + }, + _ => context.inherited_style().get_inheritedtext().clone__servo_text_decorations_in_effect() + }; + + result.underline = maybe(context.style().get_text().has_underline() + || result.underline.is_some(), context); + result.overline = maybe(context.style().get_text().has_overline() + || result.overline.is_some(), context); + result.line_through = maybe(context.style().get_text().has_line_through() + || result.line_through.is_some(), context); + + result + } + + #[inline] + pub fn derive_from_text_decoration(context: &mut Cx) { + let derived = derive(context); + context.mutate_style().mutate_inheritedtext().set__servo_text_decorations_in_effect(derived); + } + + #[inline] + pub fn derive_from_display(context: &mut Cx) { + let derived = derive(context); + context.mutate_style().mutate_inheritedtext().set__servo_text_decorations_in_effect(derived); + } + + +<%helpers:single_keyword_computed name="white-space" values="normal pre nowrap pre-wrap pre-line", + gecko_constant_prefix="NS_STYLE_WHITESPACE"> + use values::computed::ComputedValueAsSpecified; + impl ComputedValueAsSpecified for SpecifiedValue {} + + impl SpecifiedValue { + pub fn allow_wrap(&self) -> bool { + match *self { + SpecifiedValue::nowrap | + SpecifiedValue::pre => false, + SpecifiedValue::normal | + SpecifiedValue::pre_wrap | + SpecifiedValue::pre_line => true, + } + } + + pub fn preserve_newlines(&self) -> bool { + match *self { + SpecifiedValue::normal | + SpecifiedValue::nowrap => false, + SpecifiedValue::pre | + SpecifiedValue::pre_wrap | + SpecifiedValue::pre_line => true, + } + } + + pub fn preserve_spaces(&self) -> bool { + match *self { + SpecifiedValue::normal | + SpecifiedValue::nowrap | + SpecifiedValue::pre_line => false, + SpecifiedValue::pre | + SpecifiedValue::pre_wrap => true, + } + } + } + + +<%helpers:longhand name="text-shadow"> + use cssparser::{self, ToCss}; + use std::fmt; + use values::AuExtensionMethods; + + #[derive(Clone, PartialEq, Debug, HeapSizeOf)] + pub struct SpecifiedValue(Vec); + + #[derive(Clone, PartialEq, Debug, HeapSizeOf)] + pub struct SpecifiedTextShadow { + pub offset_x: specified::Length, + pub offset_y: specified::Length, + pub blur_radius: specified::Length, + pub color: Option, + } + + pub mod computed_value { + use app_units::Au; + use cssparser::Color; + + #[derive(Clone, PartialEq, Debug, HeapSizeOf)] + pub struct T(pub Vec); + + #[derive(Clone, PartialEq, Debug, HeapSizeOf)] + pub struct TextShadow { + pub offset_x: Au, + pub offset_y: Au, + pub blur_radius: Au, + pub color: Color, + } + } + + impl ToCss for computed_value::T { + fn to_css(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { + let mut iter = self.0.iter(); + if let Some(shadow) = iter.next() { + try!(shadow.to_css(dest)); + } else { + try!(dest.write_str("none")); + return Ok(()) + } + for shadow in iter { + try!(dest.write_str(", ")); + try!(shadow.to_css(dest)); + } + Ok(()) + } + } + + impl ToCss for computed_value::TextShadow { + fn to_css(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { + try!(self.offset_x.to_css(dest)); + try!(dest.write_str(" ")); + try!(self.offset_y.to_css(dest)); + try!(dest.write_str(" ")); + try!(self.blur_radius.to_css(dest)); + try!(dest.write_str(" ")); + try!(self.color.to_css(dest)); + Ok(()) + } + } + + impl ToCss for SpecifiedValue { + fn to_css(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { + let mut iter = self.0.iter(); + if let Some(shadow) = iter.next() { + try!(shadow.to_css(dest)); + } else { + try!(dest.write_str("none")); + return Ok(()) + } + for shadow in iter { + try!(dest.write_str(", ")); + try!(shadow.to_css(dest)); + } + Ok(()) + } + } + + impl ToCss for SpecifiedTextShadow { + fn to_css(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { + try!(self.offset_x.to_css(dest)); + try!(dest.write_str(" ")); + try!(self.offset_y.to_css(dest)); + try!(dest.write_str(" ")); + try!(self.blur_radius.to_css(dest)); + + if let Some(ref color) = self.color { + try!(dest.write_str(" ")); + try!(color.to_css(dest)); + } + Ok(()) + } + } + + #[inline] + pub fn get_initial_value() -> computed_value::T { + computed_value::T(Vec::new()) + } + + pub fn parse(_: &ParserContext, input: &mut Parser) -> Result { + if input.try(|input| input.expect_ident_matching("none")).is_ok() { + Ok(SpecifiedValue(Vec::new())) + } else { + input.parse_comma_separated(parse_one_text_shadow).map(SpecifiedValue) + } + } + + fn parse_one_text_shadow(input: &mut Parser) -> Result { + use app_units::Au; + let mut lengths = [specified::Length::Absolute(Au(0)); 3]; + let mut lengths_parsed = false; + let mut color = None; + + loop { + if !lengths_parsed { + if let Ok(value) = input.try(specified::Length::parse) { + lengths[0] = value; + let mut length_parsed_count = 1; + while length_parsed_count < 3 { + if let Ok(value) = input.try(specified::Length::parse) { + lengths[length_parsed_count] = value + } else { + break + } + length_parsed_count += 1; + } + + // The first two lengths must be specified. + if length_parsed_count < 2 { + return Err(()) + } + + lengths_parsed = true; + continue + } + } + if color.is_none() { + if let Ok(value) = input.try(specified::CSSColor::parse) { + color = Some(value); + continue + } + } + break + } + + // Lengths must be specified. + if !lengths_parsed { + return Err(()) + } + + Ok(SpecifiedTextShadow { + offset_x: lengths[0], + offset_y: lengths[1], + blur_radius: lengths[2], + color: color, + }) + } + + impl ToComputedValue for SpecifiedValue { + type ComputedValue = computed_value::T; + + fn to_computed_value(&self, context: &Cx) -> computed_value::T { + computed_value::T(self.0.iter().map(|value| { + computed_value::TextShadow { + offset_x: value.offset_x.to_computed_value(context), + offset_y: value.offset_y.to_computed_value(context), + blur_radius: value.blur_radius.to_computed_value(context), + color: value.color + .as_ref() + .map(|color| color.parsed) + .unwrap_or(cssparser::Color::CurrentColor), + } + }).collect()) + } + } + + + + +// TODO(pcwalton): `full-width` +${helpers.single_keyword("text-transform", + "none capitalize uppercase lowercase", + extra_gecko_values="full-width")} + +${helpers.single_keyword("text-rendering", "auto optimizespeed optimizelegibility geometricprecision")} + +// CSS Text Module Level 3 +// https://www.w3.org/TR/css-text-3/ +${helpers.single_keyword("hyphens", "none manual auto", products="gecko")} + +// CSS Ruby Layout Module Level 1 +// https://www.w3.org/TR/css-ruby-1/ +${helpers.single_keyword("ruby-align", "start center space-between space-around", products="gecko")} + +${helpers.single_keyword("ruby-position", "over under", products="gecko")} diff --git a/components/style/properties/longhand/list.mako.rs b/components/style/properties/longhand/list.mako.rs new file mode 100644 index 00000000000..764a50617a6 --- /dev/null +++ b/components/style/properties/longhand/list.mako.rs @@ -0,0 +1,153 @@ +/* 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/. */ + +<%namespace name="helpers" file="/helpers.mako.rs" /> + +<% data.new_style_struct("List", inherited=True, gecko_ffi_name="nsStyleList") %> + +${helpers.single_keyword("list-style-position", "outside inside")} + +// TODO(pcwalton): Implement the full set of counter styles per CSS-COUNTER-STYLES [1] 6.1: +// +// decimal-leading-zero, armenian, upper-armenian, lower-armenian, georgian, lower-roman, +// upper-roman +// +// [1]: http://dev.w3.org/csswg/css-counter-styles/ +${helpers.single_keyword("list-style-type", """ + disc none circle square decimal arabic-indic bengali cambodian cjk-decimal devanagari + gujarati gurmukhi kannada khmer lao malayalam mongolian myanmar oriya persian telugu thai + tibetan lower-alpha upper-alpha cjk-earthly-branch cjk-heavenly-stem lower-greek hiragana + hiragana-iroha katakana katakana-iroha disclosure-open disclosure-closed +""")} + +<%helpers:longhand name="list-style-image"> + use cssparser::{ToCss, Token}; + use std::fmt; + use url::Url; + use values::LocalToCss; + + #[derive(Debug, Clone, PartialEq, Eq, HeapSizeOf)] + pub enum SpecifiedValue { + None, + Url(Url), + } + + impl ToCss for SpecifiedValue { + fn to_css(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { + match *self { + SpecifiedValue::None => dest.write_str("none"), + SpecifiedValue::Url(ref url) => url.to_css(dest), + } + } + } + + pub mod computed_value { + use cssparser::{ToCss, Token}; + use std::fmt; + use url::Url; + use values::LocalToCss; + + #[derive(Debug, Clone, PartialEq, HeapSizeOf)] + pub struct T(pub Option); + + impl ToCss for T { + fn to_css(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { + match self.0 { + None => dest.write_str("none"), + Some(ref url) => url.to_css(dest), + } + } + } + } + + impl ToComputedValue for SpecifiedValue { + type ComputedValue = computed_value::T; + + #[inline] + fn to_computed_value(&self, _context: &Cx) -> computed_value::T { + match *self { + SpecifiedValue::None => computed_value::T(None), + SpecifiedValue::Url(ref url) => computed_value::T(Some(url.clone())), + } + } + } + + pub fn parse(context: &ParserContext, input: &mut Parser) -> Result { + if input.try(|input| input.expect_ident_matching("none")).is_ok() { + Ok(SpecifiedValue::None) + } else { + Ok(SpecifiedValue::Url(context.parse_url(&*try!(input.expect_url())))) + } + } + #[inline] + pub fn get_initial_value() -> computed_value::T { + computed_value::T(None) + } + + +<%helpers:longhand name="quotes"> + use std::borrow::Cow; + use std::fmt; + use values::computed::ComputedValueAsSpecified; + + use cssparser::{ToCss, Token}; + + pub use self::computed_value::T as SpecifiedValue; + + pub mod computed_value { + #[derive(Debug, Clone, PartialEq, HeapSizeOf)] + pub struct T(pub Vec<(String,String)>); + } + + impl ComputedValueAsSpecified for SpecifiedValue {} + + impl ToCss for SpecifiedValue { + fn to_css(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { + let mut first = true; + for pair in &self.0 { + if !first { + try!(dest.write_str(" ")); + } + first = false; + try!(Token::QuotedString(Cow::from(&*pair.0)).to_css(dest)); + try!(dest.write_str(" ")); + try!(Token::QuotedString(Cow::from(&*pair.1)).to_css(dest)); + } + Ok(()) + } + } + + #[inline] + pub fn get_initial_value() -> computed_value::T { + computed_value::T(vec![ + ("\u{201c}".to_owned(), "\u{201d}".to_owned()), + ("\u{2018}".to_owned(), "\u{2019}".to_owned()), + ]) + } + + pub fn parse(_: &ParserContext, input: &mut Parser) -> Result { + if input.try(|input| input.expect_ident_matching("none")).is_ok() { + return Ok(SpecifiedValue(Vec::new())) + } + + let mut quotes = Vec::new(); + loop { + let first = match input.next() { + Ok(Token::QuotedString(value)) => value.into_owned(), + Ok(_) => return Err(()), + Err(()) => break, + }; + let second = match input.next() { + Ok(Token::QuotedString(value)) => value.into_owned(), + _ => return Err(()), + }; + quotes.push((first, second)) + } + if !quotes.is_empty() { + Ok(SpecifiedValue(quotes)) + } else { + Err(()) + } + } + diff --git a/components/style/properties/longhand/outline.mako.rs b/components/style/properties/longhand/outline.mako.rs index 0b36e664a23..3df026263b4 100644 --- a/components/style/properties/longhand/outline.mako.rs +++ b/components/style/properties/longhand/outline.mako.rs @@ -3,7 +3,6 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ <%namespace name="helpers" file="/helpers.mako.rs" /> - <% from data import Method %> <% data.new_style_struct("Outline", diff --git a/components/style/properties/longhand/pointing.mako.rs b/components/style/properties/longhand/pointing.mako.rs new file mode 100644 index 00000000000..1d7f4a4040b --- /dev/null +++ b/components/style/properties/longhand/pointing.mako.rs @@ -0,0 +1,56 @@ +/* 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/. */ + +<%namespace name="helpers" file="/helpers.mako.rs" /> + +<% data.new_style_struct("Pointing", inherited=True, gecko_ffi_name="nsStyleUserInterface") %> + +<%helpers:longhand name="cursor"> + pub use self::computed_value::T as SpecifiedValue; + use values::computed::ComputedValueAsSpecified; + + impl ComputedValueAsSpecified for SpecifiedValue {} + + pub mod computed_value { + use cssparser::ToCss; + use std::fmt; + use style_traits::cursor::Cursor; + + #[derive(Clone, PartialEq, Eq, Copy, Debug, HeapSizeOf)] + pub enum T { + AutoCursor, + SpecifiedCursor(Cursor), + } + + impl ToCss for T { + fn to_css(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { + match *self { + T::AutoCursor => dest.write_str("auto"), + T::SpecifiedCursor(c) => c.to_css(dest), + } + } + } + } + + #[inline] + pub fn get_initial_value() -> computed_value::T { + computed_value::T::AutoCursor + } + pub fn parse(_context: &ParserContext, input: &mut Parser) -> Result { + use std::ascii::AsciiExt; + use style_traits::cursor::Cursor; + let ident = try!(input.expect_ident()); + if ident.eq_ignore_ascii_case("auto") { + Ok(SpecifiedValue::AutoCursor) + } else { + Cursor::from_css_keyword(&ident) + .map(SpecifiedValue::SpecifiedCursor) + } + } + + +// NB: `pointer-events: auto` (and use of `pointer-events` in anything that isn't SVG, in fact) +// is nonstandard, slated for CSS4-UI. +// TODO(pcwalton): SVG-only values. +${helpers.single_keyword("pointer-events", "auto none")} diff --git a/components/style/properties/longhand/position.mako.rs b/components/style/properties/longhand/position.mako.rs index 8a945fa0ec2..b3d35516b79 100644 --- a/components/style/properties/longhand/position.mako.rs +++ b/components/style/properties/longhand/position.mako.rs @@ -56,3 +56,62 @@ } } + +// CSS Flexible Box Layout Module Level 1 +// http://www.w3.org/TR/css3-flexbox/ + +// Flex container properties +${helpers.single_keyword("flex-direction", "row row-reverse column column-reverse", experimental=True)} + +// https://drafts.csswg.org/css-flexbox/#propdef-order +<%helpers:longhand name="order"> + use values::computed::ComputedValueAsSpecified; + + impl ComputedValueAsSpecified for SpecifiedValue {} + + pub type SpecifiedValue = computed_value::T; + + pub mod computed_value { + pub type T = i32; + } + + #[inline] + pub fn get_initial_value() -> computed_value::T { + 0 + } + + fn parse(_context: &ParserContext, input: &mut Parser) -> Result { + specified::parse_integer(input) + } + + +${helpers.predefined_type("flex-basis", + "LengthOrPercentageOrAutoOrContent", + "computed::LengthOrPercentageOrAutoOrContent::Auto")} + +${helpers.single_keyword("flex-wrap", "nowrap wrap wrap-reverse", products="gecko")} + +${helpers.predefined_type("min-width", + "LengthOrPercentage", + "computed::LengthOrPercentage::Length(Au(0))", + "parse_non_negative")} +${helpers.predefined_type("max-width", + "LengthOrPercentageOrNone", + "computed::LengthOrPercentageOrNone::None", + "parse_non_negative")} + +${helpers.predefined_type("min-height", + "LengthOrPercentage", + "computed::LengthOrPercentage::Length(Au(0))", + "parse_non_negative")} +${helpers.predefined_type("max-height", + "LengthOrPercentageOrNone", + "computed::LengthOrPercentageOrNone::None", + "parse_non_negative")} + +${helpers.single_keyword("box-sizing", + "content-box border-box")} + +// CSS Image Values and Replaced Content Module Level 3 +// https://drafts.csswg.org/css-images-3/ +${helpers.single_keyword("object-fit", "fill contain cover none scale-down", products="gecko")} diff --git a/components/style/properties/longhand/svg.mako.rs b/components/style/properties/longhand/svg.mako.rs new file mode 100644 index 00000000000..759ac3fe2f6 --- /dev/null +++ b/components/style/properties/longhand/svg.mako.rs @@ -0,0 +1,18 @@ +/* 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/. */ + +<%namespace name="helpers" file="/helpers.mako.rs" /> + +<% data.new_style_struct("SVG", inherited=False, gecko_ffi_name="nsStyleSVGReset") %> + +${helpers.single_keyword("dominant-baseline", + """auto use-script no-change reset-size ideographic alphabetic hanging + mathematical central middle text-after-edge text-before-edge""", + products="gecko")} + +${helpers.single_keyword("vector-effect", "none non-scaling-stroke", products="gecko")} + +// CSS Masking Module Level 1 +// https://www.w3.org/TR/css-masking-1/ +${helpers.single_keyword("mask-type", "luminance alpha", products="gecko")} diff --git a/components/style/properties/longhand/svg_inherited.mako.rs b/components/style/properties/longhand/svg_inherited.mako.rs new file mode 100644 index 00000000000..2a0c6884974 --- /dev/null +++ b/components/style/properties/longhand/svg_inherited.mako.rs @@ -0,0 +1,38 @@ +/* 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/. */ + +<%namespace name="helpers" file="/helpers.mako.rs" /> + +// SVG 1.1 (Second Edition) +// https://www.w3.org/TR/SVG/ +<% data.new_style_struct("SVGInherited", + inherited=True, + gecko_ffi_name="nsStyleSVG") %> + +// Section 10 - Text + +${helpers.single_keyword("text-anchor", "start middle end", products="gecko")} + +// Section 11 - Painting: Filling, Stroking and Marker Symbols +${helpers.single_keyword("color-interpolation", "auto sRGB linearRGB", products="gecko")} + +${helpers.single_keyword("color-interpolation-filters", + "auto sRGB linearRGB", + products="gecko", + gecko_constant_prefix="NS_STYLE_COLOR_INTERPOLATION")} + +${helpers.single_keyword("fill-rule", "nonzero evenodd", products="gecko")} + +${helpers.single_keyword("shape-rendering", + "auto optimizeSpeed crispEdges geometricPrecision", + products="gecko")} + +${helpers.single_keyword("stroke-linecap", "butt round square", products="gecko")} + +${helpers.single_keyword("stroke-linejoin", "miter round bevel", products="gecko")} + +// Section 14 - Clipping, Masking and Compositing +${helpers.single_keyword("clip-rule", "nonzero evenodd", + products="gecko", + gecko_constant_prefix="NS_STYLE_FILL_RULE")} diff --git a/components/style/properties/longhand/table.mako.rs b/components/style/properties/longhand/table.mako.rs new file mode 100644 index 00000000000..0abe7b2ce1a --- /dev/null +++ b/components/style/properties/longhand/table.mako.rs @@ -0,0 +1,9 @@ +/* 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/. */ + +<%namespace name="helpers" file="/helpers.mako.rs" /> + +<% data.new_style_struct("Table", inherited=False, gecko_ffi_name="nsStyleTable") %> + +${helpers.single_keyword("table-layout", "auto fixed", gecko_ffi_name="mLayoutStrategy")} diff --git a/components/style/properties/longhand/text.mako.rs b/components/style/properties/longhand/text.mako.rs new file mode 100644 index 00000000000..b6d30dd0131 --- /dev/null +++ b/components/style/properties/longhand/text.mako.rs @@ -0,0 +1,109 @@ +/* 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/. */ + +<%namespace name="helpers" file="/helpers.mako.rs" /> +<% from data import Method %> + +<% data.new_style_struct("Text", + inherited=False, + gecko_ffi_name="nsStyleTextReset", + additional_methods=[Method("has_underline", "bool"), + Method("has_overline", "bool"), + Method("has_line_through", "bool")]) %> + +${helpers.single_keyword("text-overflow", "clip ellipsis")} + +${helpers.single_keyword("unicode-bidi", "normal embed isolate bidi-override isolate-override plaintext")} + +<%helpers:longhand name="text-decoration" custom_cascade="${product == 'servo'}"> + use cssparser::ToCss; + use std::fmt; + use values::computed::ComputedValueAsSpecified; + + impl ComputedValueAsSpecified for SpecifiedValue {} + + #[derive(PartialEq, Eq, Copy, Clone, Debug, HeapSizeOf)] + pub struct SpecifiedValue { + pub underline: bool, + pub overline: bool, + pub line_through: bool, + // 'blink' is accepted in the parser but ignored. + // Just not blinking the text is a conforming implementation per CSS 2.1. + } + + impl ToCss for SpecifiedValue { + fn to_css(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { + let mut space = false; + if self.underline { + try!(dest.write_str("underline")); + space = true; + } + if self.overline { + if space { + try!(dest.write_str(" ")); + } + try!(dest.write_str("overline")); + space = true; + } + if self.line_through { + if space { + try!(dest.write_str(" ")); + } + try!(dest.write_str("line-through")); + } + Ok(()) + } + } + pub mod computed_value { + pub type T = super::SpecifiedValue; + #[allow(non_upper_case_globals)] + pub const none: T = super::SpecifiedValue { + underline: false, overline: false, line_through: false + }; + } + #[inline] pub fn get_initial_value() -> computed_value::T { + computed_value::none + } + /// none | [ underline || overline || line-through || blink ] + pub fn parse(_context: &ParserContext, input: &mut Parser) -> Result { + let mut result = SpecifiedValue { + underline: false, overline: false, line_through: false, + }; + if input.try(|input| input.expect_ident_matching("none")).is_ok() { + return Ok(result) + } + let mut blink = false; + let mut empty = true; + while let Ok(ident) = input.expect_ident() { + match_ignore_ascii_case! { ident, + "underline" => if result.underline { return Err(()) } + else { empty = false; result.underline = true }, + "overline" => if result.overline { return Err(()) } + else { empty = false; result.overline = true }, + "line-through" => if result.line_through { return Err(()) } + else { empty = false; result.line_through = true }, + "blink" => if blink { return Err(()) } + else { empty = false; blink = true }, + _ => break + } + } + if !empty { Ok(result) } else { Err(()) } + } + + % if product == "servo": + fn cascade_property_custom( + _declaration: &PropertyDeclaration, + _inherited_style: &C, + context: &mut computed::Context, + _seen: &mut PropertyBitField, + _cacheable: &mut bool, + _error_reporter: &mut StdBox) { + longhands::_servo_text_decorations_in_effect::derive_from_text_decoration(context); + } + % endif + + +${helpers.single_keyword("text-decoration-style", + "-moz-none solid double dotted dashed wavy", + products="gecko")} diff --git a/components/style/properties/properties.mako.rs b/components/style/properties/properties.mako.rs index 5b000c20642..ab71f3047aa 100644 --- a/components/style/properties/properties.mako.rs +++ b/components/style/properties/properties.mako.rs @@ -47,4363 +47,27 @@ pub mod longhands { use parser::ParserContext; use values::specified; + <%include file="/longhand/background.mako.rs" /> <%include file="/longhand/border.mako.rs" /> <%include file="/longhand/box.mako.rs" /> + <%include file="/longhand/color.mako.rs" /> + <%include file="/longhand/column.mako.rs" /> + <%include file="/longhand/counters.mako.rs" /> + <%include file="/longhand/effects.mako.rs" /> + <%include file="/longhand/font.mako.rs" /> + <%include file="/longhand/inherited_box.mako.rs" /> + <%include file="/longhand/inherited_table.mako.rs" /> + <%include file="/longhand/inherited_text.mako.rs" /> + <%include file="/longhand/list.mako.rs" /> <%include file="/longhand/margin.mako.rs" /> <%include file="/longhand/outline.mako.rs" /> <%include file="/longhand/padding.mako.rs" /> + <%include file="/longhand/pointing.mako.rs" /> <%include file="/longhand/position.mako.rs" /> - - <% data.new_style_struct("InheritedBox", inherited=True, gecko_ffi_name="nsStyleVisibility") %> - - ${helpers.single_keyword("direction", "ltr rtl", need_clone=True)} - - // CSS 2.1, Section 10 - Visual formatting model details - - <% data.switch_to_style_struct("Box") %> - - ${helpers.predefined_type("width", "LengthOrPercentageOrAuto", - "computed::LengthOrPercentageOrAuto::Auto", - "parse_non_negative")} - - ${helpers.predefined_type("height", "LengthOrPercentageOrAuto", - "computed::LengthOrPercentageOrAuto::Auto", - "parse_non_negative")} - - <% data.switch_to_style_struct("Position") %> - - ${helpers.predefined_type("min-width", "LengthOrPercentage", - "computed::LengthOrPercentage::Length(Au(0))", - "parse_non_negative")} - ${helpers.predefined_type("max-width", "LengthOrPercentageOrNone", - "computed::LengthOrPercentageOrNone::None", - "parse_non_negative")} - - ${helpers.predefined_type("min-height", "LengthOrPercentage", - "computed::LengthOrPercentage::Length(Au(0))", - "parse_non_negative")} - ${helpers.predefined_type("max-height", "LengthOrPercentageOrNone", - "computed::LengthOrPercentageOrNone::None", - "parse_non_negative")} - - <% data.new_style_struct("InheritedText", inherited=True, gecko_ffi_name="nsStyleText") %> - - <%helpers:longhand name="line-height"> - use cssparser::ToCss; - use std::fmt; - use values::AuExtensionMethods; - use values::CSSFloat; - - #[derive(Debug, Clone, PartialEq, Copy, HeapSizeOf)] - pub enum SpecifiedValue { - Normal, - Number(CSSFloat), - LengthOrPercentage(specified::LengthOrPercentage), - } - - impl ToCss for SpecifiedValue { - fn to_css(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { - match *self { - SpecifiedValue::Normal => dest.write_str("normal"), - SpecifiedValue::LengthOrPercentage(value) => value.to_css(dest), - SpecifiedValue::Number(number) => write!(dest, "{}", number), - } - } - } - /// normal | | | - pub fn parse(_context: &ParserContext, input: &mut Parser) -> Result { - use cssparser::Token; - use std::ascii::AsciiExt; - input.try(specified::LengthOrPercentage::parse_non_negative) - .map(SpecifiedValue::LengthOrPercentage) - .or_else(|()| { - match try!(input.next()) { - Token::Number(ref value) if value.value >= 0. => { - Ok(SpecifiedValue::Number(value.value)) - } - Token::Ident(ref value) if value.eq_ignore_ascii_case("normal") => { - Ok(SpecifiedValue::Normal) - } - _ => Err(()), - } - }) - } - pub mod computed_value { - use app_units::Au; - use std::fmt; - use values::CSSFloat; - #[derive(PartialEq, Copy, Clone, HeapSizeOf, Debug)] - pub enum T { - Normal, - Length(Au), - Number(CSSFloat), - } - } - impl ToCss for computed_value::T { - fn to_css(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { - match *self { - computed_value::T::Normal => dest.write_str("normal"), - computed_value::T::Length(length) => length.to_css(dest), - computed_value::T::Number(number) => write!(dest, "{}", number), - } - } - } - #[inline] - pub fn get_initial_value() -> computed_value::T { computed_value::T::Normal } - - impl ToComputedValue for SpecifiedValue { - type ComputedValue = computed_value::T; - - #[inline] - fn to_computed_value(&self, context: &Cx) -> computed_value::T { - match *self { - SpecifiedValue::Normal => computed_value::T::Normal, - SpecifiedValue::Number(value) => computed_value::T::Number(value), - SpecifiedValue::LengthOrPercentage(value) => { - match value { - specified::LengthOrPercentage::Length(value) => - computed_value::T::Length(value.to_computed_value(context)), - specified::LengthOrPercentage::Percentage(specified::Percentage(value)) => { - let fr = specified::Length::FontRelative(specified::FontRelativeLength::Em(value)); - computed_value::T::Length(fr.to_computed_value(context)) - }, - specified::LengthOrPercentage::Calc(calc) => { - let calc = calc.to_computed_value(context); - let fr = specified::FontRelativeLength::Em(calc.percentage()); - let fr = specified::Length::FontRelative(fr); - computed_value::T::Length(calc.length() + fr.to_computed_value(context)) - } - } - } - } - } - } - - - <% data.switch_to_style_struct("Box") %> - - <%helpers:longhand name="vertical-align"> - use cssparser::ToCss; - use std::fmt; - - <% vertical_align_keywords = ( - "baseline sub super top text-top middle bottom text-bottom".split()) %> - #[allow(non_camel_case_types)] - #[derive(Debug, Clone, PartialEq, Copy, HeapSizeOf)] - pub enum SpecifiedValue { - % for keyword in vertical_align_keywords: - ${to_rust_ident(keyword)}, - % endfor - LengthOrPercentage(specified::LengthOrPercentage), - } - - impl ToCss for SpecifiedValue { - fn to_css(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { - match *self { - % for keyword in vertical_align_keywords: - SpecifiedValue::${to_rust_ident(keyword)} => dest.write_str("${keyword}"), - % endfor - SpecifiedValue::LengthOrPercentage(value) => value.to_css(dest), - } - } - } - /// baseline | sub | super | top | text-top | middle | bottom | text-bottom - /// | | - pub fn parse(_context: &ParserContext, input: &mut Parser) -> Result { - input.try(specified::LengthOrPercentage::parse) - .map(SpecifiedValue::LengthOrPercentage) - .or_else(|()| { - match_ignore_ascii_case! { try!(input.expect_ident()), - % for keyword in vertical_align_keywords: - "${keyword}" => Ok(SpecifiedValue::${to_rust_ident(keyword)}), - % endfor - _ => Err(()) - } - }) - } - pub mod computed_value { - use app_units::Au; - use std::fmt; - use values::AuExtensionMethods; - use values::{CSSFloat, computed}; - #[allow(non_camel_case_types)] - #[derive(PartialEq, Copy, Clone, HeapSizeOf, Debug)] - pub enum T { - % for keyword in vertical_align_keywords: - ${to_rust_ident(keyword)}, - % endfor - LengthOrPercentage(computed::LengthOrPercentage), - } - impl ::cssparser::ToCss for T { - fn to_css(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { - match *self { - % for keyword in vertical_align_keywords: - T::${to_rust_ident(keyword)} => dest.write_str("${keyword}"), - % endfor - T::LengthOrPercentage(value) => value.to_css(dest), - } - } - } - } - #[inline] - pub fn get_initial_value() -> computed_value::T { computed_value::T::baseline } - - impl ToComputedValue for SpecifiedValue { - type ComputedValue = computed_value::T; - - #[inline] - fn to_computed_value(&self, context: &Cx) -> computed_value::T { - match *self { - % for keyword in vertical_align_keywords: - SpecifiedValue::${to_rust_ident(keyword)} => { - computed_value::T::${to_rust_ident(keyword)} - } - % endfor - SpecifiedValue::LengthOrPercentage(value) => - computed_value::T::LengthOrPercentage(value.to_computed_value(context)), - } - } - } - - - - // CSS 2.1, Section 11 - Visual effects - - // Non-standard, see https://developer.mozilla.org/en-US/docs/Web/CSS/overflow-clip-box#Specifications - ${helpers.single_keyword("-servo-overflow-clip-box", "padding-box content-box", products="servo", - internal=True)} - - ${helpers.single_keyword("overflow-clip-box", "padding-box content-box", products="gecko", - internal=True)} - - // FIXME(pcwalton, #2742): Implement scrolling for `scroll` and `auto`. - ${helpers.single_keyword("overflow-x", "visible hidden scroll auto", need_clone=True, - gecko_constant_prefix="NS_STYLE_OVERFLOW")} - - // FIXME(pcwalton, #2742): Implement scrolling for `scroll` and `auto`. - <%helpers:longhand name="overflow-y" need_clone="True"> - use super::overflow_x; - - use cssparser::ToCss; - use std::fmt; - - pub use self::computed_value::T as SpecifiedValue; - - impl ToCss for SpecifiedValue { - fn to_css(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { - self.0.to_css(dest) - } - } - - pub mod computed_value { - #[derive(Debug, Clone, Copy, PartialEq, HeapSizeOf)] - pub struct T(pub super::super::overflow_x::computed_value::T); - } - - impl ToComputedValue for SpecifiedValue { - type ComputedValue = computed_value::T; - - #[inline] - fn to_computed_value(&self, context: &Cx) -> computed_value::T { - computed_value::T(self.0.to_computed_value(context)) - } - } - - pub fn get_initial_value() -> computed_value::T { - computed_value::T(overflow_x::get_initial_value()) - } - - pub fn parse(context: &ParserContext, input: &mut Parser) -> Result { - overflow_x::parse(context, input).map(SpecifiedValue) - } - - - // CSSOM View Module - // https://www.w3.org/TR/cssom-view-1/ - ${helpers.single_keyword("scroll-behavior", "auto smooth", products="gecko")} - - // Non-standard: https://developer.mozilla.org/en-US/docs/Web/CSS/scroll-snap-type-x - ${helpers.single_keyword("scroll-snap-type-x", "none mandatory proximity", - products="gecko", gecko_constant_prefix="NS_STYLE_SCROLL_SNAP_TYPE")} - - // Non-standard: https://developer.mozilla.org/en-US/docs/Web/CSS/scroll-snap-type-y - ${helpers.single_keyword("scroll-snap-type-y", "none mandatory proximity", - products="gecko", gecko_constant_prefix="NS_STYLE_SCROLL_SNAP_TYPE")} - - // Compositing and Blending Level 1 - // http://www.w3.org/TR/compositing-1/ - ${helpers.single_keyword("isolation", "auto isolate", products="gecko")} - - <% data.switch_to_style_struct("InheritedBox") %> - - // TODO: collapse. Well, do tables first. - ${helpers.single_keyword("visibility", "visible hidden", extra_gecko_values="collapse", - gecko_ffi_name="mVisible")} - - // CSS 2.1, Section 12 - Generated content, automatic numbering, and lists - - <% data.new_style_struct("Counters", inherited=False, gecko_ffi_name="nsStyleContent") %> - - <%helpers:longhand name="content"> - use cssparser::Token; - use std::ascii::AsciiExt; - use values::computed::ComputedValueAsSpecified; - - use super::list_style_type; - - pub use self::computed_value::T as SpecifiedValue; - pub use self::computed_value::ContentItem; - - impl ComputedValueAsSpecified for SpecifiedValue {} - - pub mod computed_value { - use super::super::list_style_type; - - use cssparser::{self, ToCss}; - use std::fmt; - - #[derive(Debug, PartialEq, Eq, Clone, HeapSizeOf)] - pub enum ContentItem { - /// Literal string content. - String(String), - /// `counter(name, style)`. - Counter(String, list_style_type::computed_value::T), - /// `counters(name, separator, style)`. - Counters(String, String, list_style_type::computed_value::T), - /// `open-quote`. - OpenQuote, - /// `close-quote`. - CloseQuote, - /// `no-open-quote`. - NoOpenQuote, - /// `no-close-quote`. - NoCloseQuote, - } - - impl ToCss for ContentItem { - fn to_css(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { - match *self { - ContentItem::String(ref s) => { - cssparser::serialize_string(&**s, dest) - } - ContentItem::Counter(ref s, ref list_style_type) => { - try!(dest.write_str("counter(")); - try!(cssparser::serialize_identifier(&**s, dest)); - try!(dest.write_str(", ")); - try!(list_style_type.to_css(dest)); - dest.write_str(")") - } - ContentItem::Counters(ref s, ref separator, ref list_style_type) => { - try!(dest.write_str("counter(")); - try!(cssparser::serialize_identifier(&**s, dest)); - try!(dest.write_str(", ")); - try!(cssparser::serialize_string(&**separator, dest)); - try!(dest.write_str(", ")); - try!(list_style_type.to_css(dest)); - dest.write_str(")") - } - ContentItem::OpenQuote => dest.write_str("open-quote"), - ContentItem::CloseQuote => dest.write_str("close-quote"), - ContentItem::NoOpenQuote => dest.write_str("no-open-quote"), - ContentItem::NoCloseQuote => dest.write_str("no-close-quote"), - } - } - } - - #[allow(non_camel_case_types)] - #[derive(Debug, PartialEq, Eq, Clone, HeapSizeOf)] - pub enum T { - normal, - none, - Content(Vec), - } - - impl ToCss for T { - fn to_css(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { - match *self { - T::normal => dest.write_str("normal"), - T::none => dest.write_str("none"), - T::Content(ref content) => { - let mut iter = content.iter(); - try!(iter.next().unwrap().to_css(dest)); - for c in iter { - try!(dest.write_str(" ")); - try!(c.to_css(dest)); - } - Ok(()) - } - } - } - } - } - #[inline] - pub fn get_initial_value() -> computed_value::T { - computed_value::T::normal - } - - pub fn counter_name_is_illegal(name: &str) -> bool { - name.eq_ignore_ascii_case("none") || name.eq_ignore_ascii_case("inherit") || - name.eq_ignore_ascii_case("initial") - } - - // normal | none | [ | | open-quote | close-quote | no-open-quote | - // no-close-quote ]+ - // TODO: , attr() - pub fn parse(context: &ParserContext, input: &mut Parser) - -> Result { - if input.try(|input| input.expect_ident_matching("normal")).is_ok() { - return Ok(SpecifiedValue::normal) - } - if input.try(|input| input.expect_ident_matching("none")).is_ok() { - return Ok(SpecifiedValue::none) - } - let mut content = vec![]; - loop { - match input.next() { - Ok(Token::QuotedString(value)) => { - content.push(ContentItem::String(value.into_owned())) - } - Ok(Token::Function(name)) => { - content.push(try!(match_ignore_ascii_case! { name, - "counter" => input.parse_nested_block(|input| { - let name = try!(input.expect_ident()).into_owned(); - let style = input.try(|input| { - try!(input.expect_comma()); - list_style_type::parse(context, input) - }).unwrap_or(list_style_type::computed_value::T::decimal); - Ok(ContentItem::Counter(name, style)) - }), - "counters" => input.parse_nested_block(|input| { - let name = try!(input.expect_ident()).into_owned(); - try!(input.expect_comma()); - let separator = try!(input.expect_string()).into_owned(); - let style = input.try(|input| { - try!(input.expect_comma()); - list_style_type::parse(context, input) - }).unwrap_or(list_style_type::computed_value::T::decimal); - Ok(ContentItem::Counters(name, separator, style)) - }), - _ => return Err(()) - })); - } - Ok(Token::Ident(ident)) => { - match_ignore_ascii_case! { ident, - "open-quote" => content.push(ContentItem::OpenQuote), - "close-quote" => content.push(ContentItem::CloseQuote), - "no-open-quote" => content.push(ContentItem::NoOpenQuote), - "no-close-quote" => content.push(ContentItem::NoCloseQuote), - _ => return Err(()) - } - } - Err(_) => break, - _ => return Err(()) - } - } - if !content.is_empty() { - Ok(SpecifiedValue::Content(content)) - } else { - Err(()) - } - } - - - <% data.new_style_struct("List", inherited=True, gecko_ffi_name="nsStyleList") %> - - ${helpers.single_keyword("list-style-position", "outside inside")} - - // TODO(pcwalton): Implement the full set of counter styles per CSS-COUNTER-STYLES [1] 6.1: - // - // decimal-leading-zero, armenian, upper-armenian, lower-armenian, georgian, lower-roman, - // upper-roman - // - // [1]: http://dev.w3.org/csswg/css-counter-styles/ - ${helpers.single_keyword("list-style-type", """ - disc none circle square decimal arabic-indic bengali cambodian cjk-decimal devanagari - gujarati gurmukhi kannada khmer lao malayalam mongolian myanmar oriya persian telugu thai - tibetan lower-alpha upper-alpha cjk-earthly-branch cjk-heavenly-stem lower-greek hiragana - hiragana-iroha katakana katakana-iroha disclosure-open disclosure-closed - """)} - - <%helpers:longhand name="list-style-image"> - use cssparser::{ToCss, Token}; - use std::fmt; - use url::Url; - use values::LocalToCss; - - #[derive(Debug, Clone, PartialEq, Eq, HeapSizeOf)] - pub enum SpecifiedValue { - None, - Url(Url), - } - - impl ToCss for SpecifiedValue { - fn to_css(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { - match *self { - SpecifiedValue::None => dest.write_str("none"), - SpecifiedValue::Url(ref url) => url.to_css(dest), - } - } - } - - pub mod computed_value { - use cssparser::{ToCss, Token}; - use std::fmt; - use url::Url; - use values::LocalToCss; - - #[derive(Debug, Clone, PartialEq, HeapSizeOf)] - pub struct T(pub Option); - - impl ToCss for T { - fn to_css(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { - match self.0 { - None => dest.write_str("none"), - Some(ref url) => url.to_css(dest), - } - } - } - } - - impl ToComputedValue for SpecifiedValue { - type ComputedValue = computed_value::T; - - #[inline] - fn to_computed_value(&self, _context: &Cx) -> computed_value::T { - match *self { - SpecifiedValue::None => computed_value::T(None), - SpecifiedValue::Url(ref url) => computed_value::T(Some(url.clone())), - } - } - } - - pub fn parse(context: &ParserContext, input: &mut Parser) -> Result { - if input.try(|input| input.expect_ident_matching("none")).is_ok() { - Ok(SpecifiedValue::None) - } else { - Ok(SpecifiedValue::Url(context.parse_url(&*try!(input.expect_url())))) - } - } - #[inline] - pub fn get_initial_value() -> computed_value::T { - computed_value::T(None) - } - - - <%helpers:longhand name="quotes"> - use std::borrow::Cow; - use std::fmt; - use values::computed::ComputedValueAsSpecified; - - use cssparser::{ToCss, Token}; - - pub use self::computed_value::T as SpecifiedValue; - - pub mod computed_value { - #[derive(Debug, Clone, PartialEq, HeapSizeOf)] - pub struct T(pub Vec<(String,String)>); - } - - impl ComputedValueAsSpecified for SpecifiedValue {} - - impl ToCss for SpecifiedValue { - fn to_css(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { - let mut first = true; - for pair in &self.0 { - if !first { - try!(dest.write_str(" ")); - } - first = false; - try!(Token::QuotedString(Cow::from(&*pair.0)).to_css(dest)); - try!(dest.write_str(" ")); - try!(Token::QuotedString(Cow::from(&*pair.1)).to_css(dest)); - } - Ok(()) - } - } - - #[inline] - pub fn get_initial_value() -> computed_value::T { - computed_value::T(vec![ - ("\u{201c}".to_owned(), "\u{201d}".to_owned()), - ("\u{2018}".to_owned(), "\u{2019}".to_owned()), - ]) - } - - pub fn parse(_: &ParserContext, input: &mut Parser) -> Result { - if input.try(|input| input.expect_ident_matching("none")).is_ok() { - return Ok(SpecifiedValue(Vec::new())) - } - - let mut quotes = Vec::new(); - loop { - let first = match input.next() { - Ok(Token::QuotedString(value)) => value.into_owned(), - Ok(_) => return Err(()), - Err(()) => break, - }; - let second = match input.next() { - Ok(Token::QuotedString(value)) => value.into_owned(), - _ => return Err(()), - }; - quotes.push((first, second)) - } - if !quotes.is_empty() { - Ok(SpecifiedValue(quotes)) - } else { - Err(()) - } - } - - - <% data.switch_to_style_struct("Counters") %> - - <%helpers:longhand name="counter-increment"> - use std::fmt; - use super::content; - use values::computed::ComputedValueAsSpecified; - - use cssparser::{ToCss, Token, serialize_identifier}; - use std::borrow::{Cow, ToOwned}; - - pub use self::computed_value::T as SpecifiedValue; - - pub mod computed_value { - #[derive(Debug, Clone, PartialEq, HeapSizeOf)] - pub struct T(pub Vec<(String,i32)>); - } - - #[inline] - pub fn get_initial_value() -> computed_value::T { - computed_value::T(Vec::new()) - } - - impl ComputedValueAsSpecified for SpecifiedValue {} - - impl ToCss for SpecifiedValue { - fn to_css(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { - let mut first = true; - for pair in &self.0 { - if !first { - try!(dest.write_str(" ")); - } - first = false; - try!(serialize_identifier(&pair.0, dest)); - try!(write!(dest, " {}", pair.1)); - } - Ok(()) - } - } - - pub fn parse(_: &ParserContext, input: &mut Parser) -> Result { - parse_common(1, input) - } - - pub fn parse_common(default_value: i32, input: &mut Parser) -> Result { - if input.try(|input| input.expect_ident_matching("none")).is_ok() { - return Ok(SpecifiedValue(Vec::new())) - } - - let mut counters = Vec::new(); - loop { - let counter_name = match input.next() { - Ok(Token::Ident(ident)) => (*ident).to_owned(), - Ok(_) => return Err(()), - Err(_) => break, - }; - if content::counter_name_is_illegal(&counter_name) { - return Err(()) - } - let counter_delta = - input.try(|input| specified::parse_integer(input)).unwrap_or(default_value); - counters.push((counter_name, counter_delta)) - } - - if !counters.is_empty() { - Ok(SpecifiedValue(counters)) - } else { - Err(()) - } - } - - - <%helpers:longhand name="counter-reset"> - pub use super::counter_increment::{SpecifiedValue, computed_value, get_initial_value}; - use super::counter_increment::{parse_common}; - - pub fn parse(_: &ParserContext, input: &mut Parser) -> Result { - parse_common(0, input) - } - - - // CSS 2.1, Section 13 - Paged media - - <% data.switch_to_style_struct("Box") %> - - ${helpers.single_keyword("page-break-after", "auto always avoid left right", products="gecko")} - ${helpers.single_keyword("page-break-before", "auto always avoid left right", products="gecko")} - ${helpers.single_keyword("page-break-inside", "auto avoid", - products="gecko", gecko_ffi_name="mBreakInside", gecko_constant_prefix="NS_STYLE_PAGE_BREAK")} - - // CSS 2.1, Section 14 - Colors and Backgrounds - - <% data.new_style_struct("Background", inherited=False, gecko_ffi_name="nsStyleBackground") %> - ${helpers.predefined_type( - "background-color", "CSSColor", - "::cssparser::Color::RGBA(::cssparser::RGBA { red: 0., green: 0., blue: 0., alpha: 0. }) /* transparent */")} - - <%helpers:longhand name="background-image"> - use cssparser::ToCss; - use std::fmt; - use values::specified::Image; - use values::LocalToCss; - - pub mod computed_value { - use values::computed; - #[derive(Debug, Clone, PartialEq, HeapSizeOf)] - pub struct T(pub Option); - } - - impl ToCss for computed_value::T { - fn to_css(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { - match self.0 { - None => dest.write_str("none"), - Some(computed::Image::Url(ref url)) => url.to_css(dest), - Some(computed::Image::LinearGradient(ref gradient)) => - gradient.to_css(dest) - } - } - } - - #[derive(Debug, Clone, PartialEq, HeapSizeOf)] - pub struct SpecifiedValue(pub Option); - - impl ToCss for SpecifiedValue { - fn to_css(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { - match *self { - SpecifiedValue(Some(ref image)) => image.to_css(dest), - SpecifiedValue(None) => dest.write_str("none"), - } - } - } - - #[inline] - pub fn get_initial_value() -> computed_value::T { - computed_value::T(None) - } - pub fn parse(context: &ParserContext, input: &mut Parser) -> Result { - if input.try(|input| input.expect_ident_matching("none")).is_ok() { - Ok(SpecifiedValue(None)) - } else { - Ok(SpecifiedValue(Some(try!(Image::parse(context, input))))) - } - } - impl ToComputedValue for SpecifiedValue { - type ComputedValue = computed_value::T; - - #[inline] - fn to_computed_value(&self, context: &Cx) -> computed_value::T { - match *self { - SpecifiedValue(None) => computed_value::T(None), - SpecifiedValue(Some(ref image)) => - computed_value::T(Some(image.to_computed_value(context))), - } - } - } - - - <%helpers:longhand name="background-position"> - use cssparser::ToCss; - use std::fmt; - use values::AuExtensionMethods; - - pub mod computed_value { - use values::computed::LengthOrPercentage; - - #[derive(PartialEq, Copy, Clone, Debug, HeapSizeOf)] - pub struct T { - pub horizontal: LengthOrPercentage, - pub vertical: LengthOrPercentage, - } - } - - #[derive(Debug, Clone, PartialEq, Copy, HeapSizeOf)] - pub struct SpecifiedValue { - pub horizontal: specified::LengthOrPercentage, - pub vertical: specified::LengthOrPercentage, - } - - impl ToCss for SpecifiedValue { - fn to_css(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { - try!(self.horizontal.to_css(dest)); - try!(dest.write_str(" ")); - try!(self.vertical.to_css(dest)); - Ok(()) - } - } - - impl ToCss for computed_value::T { - fn to_css(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { - try!(self.horizontal.to_css(dest)); - try!(dest.write_str(" ")); - try!(self.vertical.to_css(dest)); - Ok(()) - } - } - - impl SpecifiedValue { - fn new(first: specified::PositionComponent, second: specified::PositionComponent) - -> Result { - let (horiz, vert) = match (category(first), category(second)) { - // Don't allow two vertical keywords or two horizontal keywords. - (PositionCategory::HorizontalKeyword, PositionCategory::HorizontalKeyword) | - (PositionCategory::VerticalKeyword, PositionCategory::VerticalKeyword) => return Err(()), - - // Swap if both are keywords and vertical precedes horizontal. - (PositionCategory::VerticalKeyword, PositionCategory::HorizontalKeyword) | - (PositionCategory::VerticalKeyword, PositionCategory::OtherKeyword) | - (PositionCategory::OtherKeyword, PositionCategory::HorizontalKeyword) => (second, first), - - // By default, horizontal is first. - _ => (first, second), - }; - Ok(SpecifiedValue { - horizontal: horiz.to_length_or_percentage(), - vertical: vert.to_length_or_percentage(), - }) - } - } - - // Collapse `Position` into a few categories to simplify the above `match` expression. - enum PositionCategory { - HorizontalKeyword, - VerticalKeyword, - OtherKeyword, - LengthOrPercentage, - } - fn category(p: specified::PositionComponent) -> PositionCategory { - match p { - specified::PositionComponent::Left | - specified::PositionComponent::Right => - PositionCategory::HorizontalKeyword, - specified::PositionComponent::Top | - specified::PositionComponent::Bottom => - PositionCategory::VerticalKeyword, - specified::PositionComponent::Center => - PositionCategory::OtherKeyword, - specified::PositionComponent::LengthOrPercentage(_) => - PositionCategory::LengthOrPercentage, - } - } - - impl ToComputedValue for SpecifiedValue { - type ComputedValue = computed_value::T; - - #[inline] - fn to_computed_value(&self, context: &Cx) -> computed_value::T { - computed_value::T { - horizontal: self.horizontal.to_computed_value(context), - vertical: self.vertical.to_computed_value(context), - } - } - } - - #[inline] - pub fn get_initial_value() -> computed_value::T { - computed_value::T { - horizontal: computed::LengthOrPercentage::Percentage(0.0), - vertical: computed::LengthOrPercentage::Percentage(0.0), - } - } - - pub fn parse(_context: &ParserContext, input: &mut Parser) - -> Result { - let first = try!(specified::PositionComponent::parse(input)); - let second = input.try(specified::PositionComponent::parse) - .unwrap_or(specified::PositionComponent::Center); - SpecifiedValue::new(first, second) - } - - - ${helpers.single_keyword("background-repeat", "repeat repeat-x repeat-y no-repeat")} - - ${helpers.single_keyword("background-attachment", "scroll fixed")} - - ${helpers.single_keyword("background-clip", "border-box padding-box content-box")} - - ${helpers.single_keyword("background-origin", "padding-box border-box content-box")} - - <%helpers:longhand name="background-size"> - use cssparser::{ToCss, Token}; - use std::ascii::AsciiExt; - use std::fmt; - - pub mod computed_value { - use values::computed::LengthOrPercentageOrAuto; - - #[derive(PartialEq, Clone, Debug, HeapSizeOf)] - pub struct ExplicitSize { - pub width: LengthOrPercentageOrAuto, - pub height: LengthOrPercentageOrAuto, - } - - #[derive(PartialEq, Clone, Debug, HeapSizeOf)] - pub enum T { - Explicit(ExplicitSize), - Cover, - Contain, - } - } - - impl ToCss for computed_value::T { - fn to_css(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { - match *self { - computed_value::T::Explicit(ref size) => size.to_css(dest), - computed_value::T::Cover => dest.write_str("cover"), - computed_value::T::Contain => dest.write_str("contain"), - } - } - } - - #[derive(Clone, PartialEq, Debug, HeapSizeOf)] - pub struct SpecifiedExplicitSize { - pub width: specified::LengthOrPercentageOrAuto, - pub height: specified::LengthOrPercentageOrAuto, - } - - impl ToCss for SpecifiedExplicitSize { - fn to_css(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { - try!(self.width.to_css(dest)); - try!(dest.write_str(" ")); - self.height.to_css(dest) - } - } - - impl ToCss for computed_value::ExplicitSize { - fn to_css(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { - try!(self.width.to_css(dest)); - try!(dest.write_str(" ")); - self.height.to_css(dest) - } - } - - - #[derive(Clone, PartialEq, Debug, HeapSizeOf)] - pub enum SpecifiedValue { - Explicit(SpecifiedExplicitSize), - Cover, - Contain, - } - - impl ToCss for SpecifiedValue { - fn to_css(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { - match *self { - SpecifiedValue::Explicit(ref size) => size.to_css(dest), - SpecifiedValue::Cover => dest.write_str("cover"), - SpecifiedValue::Contain => dest.write_str("contain"), - } - } - } - - impl ToComputedValue for SpecifiedValue { - type ComputedValue = computed_value::T; - - #[inline] - fn to_computed_value(&self, context: &Cx) -> computed_value::T { - match *self { - SpecifiedValue::Explicit(ref size) => { - computed_value::T::Explicit(computed_value::ExplicitSize { - width: size.width.to_computed_value(context), - height: size.height.to_computed_value(context), - }) - } - SpecifiedValue::Cover => computed_value::T::Cover, - SpecifiedValue::Contain => computed_value::T::Contain, - } - } - } - - #[inline] - pub fn get_initial_value() -> computed_value::T { - computed_value::T::Explicit(computed_value::ExplicitSize { - width: computed::LengthOrPercentageOrAuto::Auto, - height: computed::LengthOrPercentageOrAuto::Auto, - }) - } - - pub fn parse(_: &ParserContext, input: &mut Parser) -> Result { - let width; - if let Ok(value) = input.try(|input| { - match input.next() { - Err(_) => Err(()), - Ok(Token::Ident(ref ident)) if ident.eq_ignore_ascii_case("cover") => { - Ok(SpecifiedValue::Cover) - } - Ok(Token::Ident(ref ident)) if ident.eq_ignore_ascii_case("contain") => { - Ok(SpecifiedValue::Contain) - } - Ok(_) => Err(()), - } - }) { - return Ok(value) - } else { - width = try!(specified::LengthOrPercentageOrAuto::parse(input)) - } - - let height; - if let Ok(value) = input.try(|input| { - match input.next() { - Err(_) => Ok(specified::LengthOrPercentageOrAuto::Auto), - Ok(_) => Err(()), - } - }) { - height = value - } else { - height = try!(specified::LengthOrPercentageOrAuto::parse(input)); - } - - Ok(SpecifiedValue::Explicit(SpecifiedExplicitSize { - width: width, - height: height, - })) - } - - - <% data.new_style_struct("Color", inherited=True, gecko_ffi_name="nsStyleColor") %> - - <%helpers:raw_longhand name="color" need_clone="True"> - use cssparser::Color as CSSParserColor; - use cssparser::RGBA; - use values::specified::{CSSColor, CSSRGBA}; - - impl ToComputedValue for SpecifiedValue { - type ComputedValue = computed_value::T; - - #[inline] - fn to_computed_value(&self, _context: &Cx) -> computed_value::T { - self.parsed - } - } - - pub type SpecifiedValue = CSSRGBA; - pub mod computed_value { - use cssparser; - pub type T = cssparser::RGBA; - } - #[inline] pub fn get_initial_value() -> computed_value::T { - RGBA { red: 0., green: 0., blue: 0., alpha: 1. } /* black */ - } - pub fn parse_specified(_context: &ParserContext, input: &mut Parser) - -> Result, ()> { - let value = try!(CSSColor::parse(input)); - let rgba = match value.parsed { - CSSParserColor::RGBA(rgba) => rgba, - CSSParserColor::CurrentColor => return Ok(DeclaredValue::Inherit) - }; - Ok(DeclaredValue::Value(CSSRGBA { - parsed: rgba, - authored: value.authored, - })) - } - - - // CSS 2.1, Section 15 - Fonts - - <% data.new_style_struct("Font", inherited=True, gecko_ffi_name="nsStyleFont", - additional_methods=[Method("compute_font_hash", is_mut=True)]) %> - <%helpers:longhand name="font-family"> - use self::computed_value::FontFamily; - use values::computed::ComputedValueAsSpecified; - pub use self::computed_value::T as SpecifiedValue; - - const SERIF: &'static str = "serif"; - const SANS_SERIF: &'static str = "sans-serif"; - const CURSIVE: &'static str = "cursive"; - const FANTASY: &'static str = "fantasy"; - const MONOSPACE: &'static str = "monospace"; - - impl ComputedValueAsSpecified for SpecifiedValue {} - pub mod computed_value { - use cssparser::ToCss; - use std::fmt; - use string_cache::Atom; - - #[derive(Debug, PartialEq, Eq, Clone, Hash, HeapSizeOf, Deserialize, Serialize)] - pub enum FontFamily { - FamilyName(Atom), - // Generic, - Serif, - SansSerif, - Cursive, - Fantasy, - Monospace, - } - impl FontFamily { - #[inline] - pub fn name(&self) -> &str { - match *self { - FontFamily::FamilyName(ref name) => &*name, - FontFamily::Serif => super::SERIF, - FontFamily::SansSerif => super::SANS_SERIF, - FontFamily::Cursive => super::CURSIVE, - FontFamily::Fantasy => super::FANTASY, - FontFamily::Monospace => super::MONOSPACE - } - } - - pub fn from_atom(input: Atom) -> FontFamily { - let option = match_ignore_ascii_case! { &input, - super::SERIF => Some(FontFamily::Serif), - super::SANS_SERIF => Some(FontFamily::SansSerif), - super::CURSIVE => Some(FontFamily::Cursive), - super::FANTASY => Some(FontFamily::Fantasy), - super::MONOSPACE => Some(FontFamily::Monospace), - _ => None - }; - - match option { - Some(family) => family, - None => FontFamily::FamilyName(input) - } - } - } - impl ToCss for FontFamily { - fn to_css(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { - dest.write_str(self.name()) - } - } - impl ToCss for T { - fn to_css(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { - let mut iter = self.0.iter(); - try!(iter.next().unwrap().to_css(dest)); - for family in iter { - try!(dest.write_str(", ")); - try!(family.to_css(dest)); - } - Ok(()) - } - } - #[derive(Debug, Clone, PartialEq, Eq, Hash, HeapSizeOf)] - pub struct T(pub Vec); - } - - #[inline] - pub fn get_initial_value() -> computed_value::T { - computed_value::T(vec![FontFamily::Serif]) - } - /// # - /// = | [ + ] - /// TODO: - pub fn parse(_context: &ParserContext, input: &mut Parser) -> Result { - input.parse_comma_separated(parse_one_family).map(SpecifiedValue) - } - pub fn parse_one_family(input: &mut Parser) -> Result { - if let Ok(value) = input.try(|input| input.expect_string()) { - return Ok(FontFamily::FamilyName(Atom::from(&*value))) - } - let first_ident = try!(input.expect_ident()); - - match_ignore_ascii_case! { first_ident, - SERIF => return Ok(FontFamily::Serif), - SANS_SERIF => return Ok(FontFamily::SansSerif), - CURSIVE => return Ok(FontFamily::Cursive), - FANTASY => return Ok(FontFamily::Fantasy), - MONOSPACE => return Ok(FontFamily::Monospace), - _ => {} - } - let mut value = first_ident.into_owned(); - while let Ok(ident) = input.try(|input| input.expect_ident()) { - value.push_str(" "); - value.push_str(&ident); - } - Ok(FontFamily::FamilyName(Atom::from(value))) - } - - - - ${helpers.single_keyword("font-style", "normal italic oblique")} - ${helpers.single_keyword("font-variant", "normal small-caps")} - - <%helpers:longhand name="font-weight" need_clone="True"> - use cssparser::ToCss; - use std::fmt; - - #[derive(Debug, Clone, PartialEq, Eq, Copy, HeapSizeOf)] - pub enum SpecifiedValue { - Bolder, - Lighter, - % for weight in range(100, 901, 100): - Weight${weight}, - % endfor - } - - impl ToCss for SpecifiedValue { - fn to_css(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { - match *self { - SpecifiedValue::Bolder => dest.write_str("bolder"), - SpecifiedValue::Lighter => dest.write_str("lighter"), - % for weight in range(100, 901, 100): - SpecifiedValue::Weight${weight} => dest.write_str("${weight}"), - % endfor - } - } - } - /// normal | bold | bolder | lighter | 100 | 200 | 300 | 400 | 500 | 600 | 700 | 800 | 900 - pub fn parse(_context: &ParserContext, input: &mut Parser) -> Result { - input.try(|input| { - match_ignore_ascii_case! { try!(input.expect_ident()), - "bold" => Ok(SpecifiedValue::Weight700), - "normal" => Ok(SpecifiedValue::Weight400), - "bolder" => Ok(SpecifiedValue::Bolder), - "lighter" => Ok(SpecifiedValue::Lighter), - _ => Err(()) - } - }).or_else(|()| { - match try!(input.expect_integer()) { - 100 => Ok(SpecifiedValue::Weight100), - 200 => Ok(SpecifiedValue::Weight200), - 300 => Ok(SpecifiedValue::Weight300), - 400 => Ok(SpecifiedValue::Weight400), - 500 => Ok(SpecifiedValue::Weight500), - 600 => Ok(SpecifiedValue::Weight600), - 700 => Ok(SpecifiedValue::Weight700), - 800 => Ok(SpecifiedValue::Weight800), - 900 => Ok(SpecifiedValue::Weight900), - _ => Err(()) - } - }) - } - pub mod computed_value { - use std::fmt; - #[derive(PartialEq, Eq, Copy, Clone, Hash, Deserialize, Serialize, HeapSizeOf, Debug)] - pub enum T { - % for weight in range(100, 901, 100): - Weight${weight} = ${weight}, - % endfor - } - impl T { - #[inline] - pub fn is_bold(self) -> bool { - match self { - T::Weight900 | T::Weight800 | - T::Weight700 | T::Weight600 => true, - _ => false - } - } - } - } - impl ToCss for computed_value::T { - fn to_css(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { - match *self { - % for weight in range(100, 901, 100): - computed_value::T::Weight${weight} => dest.write_str("${weight}"), - % endfor - } - } - } - #[inline] - pub fn get_initial_value() -> computed_value::T { - computed_value::T::Weight400 // normal - } - - impl ToComputedValue for SpecifiedValue { - type ComputedValue = computed_value::T; - - #[inline] - fn to_computed_value(&self, context: &Cx) -> computed_value::T { - match *self { - % for weight in range(100, 901, 100): - SpecifiedValue::Weight${weight} => computed_value::T::Weight${weight}, - % endfor - SpecifiedValue::Bolder => match context.inherited_style().get_font().clone_font_weight() { - computed_value::T::Weight100 => computed_value::T::Weight400, - computed_value::T::Weight200 => computed_value::T::Weight400, - computed_value::T::Weight300 => computed_value::T::Weight400, - computed_value::T::Weight400 => computed_value::T::Weight700, - computed_value::T::Weight500 => computed_value::T::Weight700, - computed_value::T::Weight600 => computed_value::T::Weight900, - computed_value::T::Weight700 => computed_value::T::Weight900, - computed_value::T::Weight800 => computed_value::T::Weight900, - computed_value::T::Weight900 => computed_value::T::Weight900, - }, - SpecifiedValue::Lighter => match context.inherited_style().get_font().clone_font_weight() { - computed_value::T::Weight100 => computed_value::T::Weight100, - computed_value::T::Weight200 => computed_value::T::Weight100, - computed_value::T::Weight300 => computed_value::T::Weight100, - computed_value::T::Weight400 => computed_value::T::Weight100, - computed_value::T::Weight500 => computed_value::T::Weight100, - computed_value::T::Weight600 => computed_value::T::Weight400, - computed_value::T::Weight700 => computed_value::T::Weight400, - computed_value::T::Weight800 => computed_value::T::Weight700, - computed_value::T::Weight900 => computed_value::T::Weight700, - }, - } - } - } - - - <%helpers:longhand name="font-size" need_clone="True"> - use app_units::Au; - use cssparser::ToCss; - use std::fmt; - use values::FONT_MEDIUM_PX; - use values::specified::{LengthOrPercentage, Length, Percentage}; - - impl ToCss for SpecifiedValue { - fn to_css(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { - self.0.to_css(dest) - } - } - - #[derive(Debug, Clone, PartialEq, HeapSizeOf)] - pub struct SpecifiedValue(pub specified::LengthOrPercentage); - pub mod computed_value { - use app_units::Au; - pub type T = Au; - } - #[inline] pub fn get_initial_value() -> computed_value::T { - Au::from_px(FONT_MEDIUM_PX) - } - - impl ToComputedValue for SpecifiedValue { - type ComputedValue = computed_value::T; - - #[inline] - fn to_computed_value(&self, context: &Cx) -> computed_value::T { - match self.0 { - LengthOrPercentage::Length(Length::FontRelative(value)) => { - value.to_computed_value(context.inherited_style().get_font().clone_font_size(), - context.style().root_font_size()) - } - LengthOrPercentage::Length(Length::ServoCharacterWidth(value)) => { - value.to_computed_value(context.inherited_style().get_font().clone_font_size()) - } - LengthOrPercentage::Length(l) => { - l.to_computed_value(context) - } - LengthOrPercentage::Percentage(Percentage(value)) => { - context.inherited_style().get_font().clone_font_size().scale_by(value) - } - LengthOrPercentage::Calc(calc) => { - let calc = calc.to_computed_value(context); - calc.length() + context.inherited_style().get_font().clone_font_size() - .scale_by(calc.percentage()) - } - } - } - } - /// | | | - pub fn parse(_context: &ParserContext, input: &mut Parser) -> Result { - use values::specified::{Length, LengthOrPercentage}; - - input.try(specified::LengthOrPercentage::parse_non_negative) - .or_else(|()| { - let ident = try!(input.expect_ident()); - specified::Length::from_str(&ident as &str) - .ok_or(()) - .map(specified::LengthOrPercentage::Length) - }) - .map(SpecifiedValue) - } - - - ${helpers.single_keyword("font-stretch", - "normal ultra-condensed extra-condensed condensed semi-condensed semi-expanded \ - expanded extra-expanded ultra-expanded")} - - ${helpers.single_keyword("font-kerning", "auto none normal", products="gecko")} - - // CSS 2.1, Section 16 - Text - - <% data.switch_to_style_struct("InheritedText") %> - - <%helpers:longhand name="text-align"> - pub use self::computed_value::T as SpecifiedValue; - use values::computed::ComputedValueAsSpecified; - impl ComputedValueAsSpecified for SpecifiedValue {} - pub mod computed_value { - macro_rules! define_text_align { - ( $( $name: ident ( $string: expr ) => $discriminant: expr, )+ ) => { - define_css_keyword_enum! { T: - $( - $string => $name, - )+ - } - impl T { - pub fn to_u32(self) -> u32 { - match self { - $( - T::$name => $discriminant, - )+ - } - } - pub fn from_u32(discriminant: u32) -> Option { - match discriminant { - $( - $discriminant => Some(T::$name), - )+ - _ => None - } - } - } - } - } - define_text_align! { - start("start") => 0, - end("end") => 1, - left("left") => 2, - right("right") => 3, - center("center") => 4, - justify("justify") => 5, - servo_center("-servo-center") => 6, - servo_left("-servo-left") => 7, - servo_right("-servo-right") => 8, - } - } - #[inline] pub fn get_initial_value() -> computed_value::T { - computed_value::T::start - } - pub fn parse(_context: &ParserContext, input: &mut Parser) - -> Result { - computed_value::T::parse(input) - } - - - <%helpers:longhand name="letter-spacing"> - use cssparser::ToCss; - use std::fmt; - use values::AuExtensionMethods; - - #[derive(Debug, Clone, Copy, PartialEq, HeapSizeOf)] - pub enum SpecifiedValue { - Normal, - Specified(specified::Length), - } - - impl ToCss for SpecifiedValue { - fn to_css(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { - match *self { - SpecifiedValue::Normal => dest.write_str("normal"), - SpecifiedValue::Specified(l) => l.to_css(dest), - } - } - } - - pub mod computed_value { - use app_units::Au; - #[derive(Debug, Clone, PartialEq, HeapSizeOf)] - pub struct T(pub Option); - } - - impl ToCss for computed_value::T { - fn to_css(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { - match self.0 { - None => dest.write_str("normal"), - Some(l) => l.to_css(dest), - } - } - } - - #[inline] - pub fn get_initial_value() -> computed_value::T { - computed_value::T(None) - } - - impl ToComputedValue for SpecifiedValue { - type ComputedValue = computed_value::T; - - #[inline] - fn to_computed_value(&self, context: &Cx) -> computed_value::T { - match *self { - SpecifiedValue::Normal => computed_value::T(None), - SpecifiedValue::Specified(l) => - computed_value::T(Some(l.to_computed_value(context))) - } - } - } - - pub fn parse(_context: &ParserContext, input: &mut Parser) -> Result { - if input.try(|input| input.expect_ident_matching("normal")).is_ok() { - Ok(SpecifiedValue::Normal) - } else { - specified::Length::parse_non_negative(input).map(SpecifiedValue::Specified) - } - } - - - <%helpers:longhand name="word-spacing"> - use cssparser::ToCss; - use std::fmt; - use values::AuExtensionMethods; - - #[derive(Debug, Clone, Copy, PartialEq, HeapSizeOf)] - pub enum SpecifiedValue { - Normal, - Specified(specified::Length), // FIXME(SimonSapin) support percentages - } - - impl ToCss for SpecifiedValue { - fn to_css(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { - match *self { - SpecifiedValue::Normal => dest.write_str("normal"), - SpecifiedValue::Specified(l) => l.to_css(dest), - } - } - } - - pub mod computed_value { - use app_units::Au; - #[derive(Debug, Clone, PartialEq, HeapSizeOf)] - pub struct T(pub Option); - } - - impl ToCss for computed_value::T { - fn to_css(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { - match self.0 { - None => dest.write_str("normal"), - Some(l) => l.to_css(dest), - } - } - } - - #[inline] - pub fn get_initial_value() -> computed_value::T { - computed_value::T(None) - } - - impl ToComputedValue for SpecifiedValue { - type ComputedValue = computed_value::T; - - #[inline] - fn to_computed_value(&self, context: &Cx) -> computed_value::T { - match *self { - SpecifiedValue::Normal => computed_value::T(None), - SpecifiedValue::Specified(l) => - computed_value::T(Some(l.to_computed_value(context))) - } - } - } - - pub fn parse(_context: &ParserContext, input: &mut Parser) -> Result { - if input.try(|input| input.expect_ident_matching("normal")).is_ok() { - Ok(SpecifiedValue::Normal) - } else { - specified::Length::parse_non_negative(input).map(SpecifiedValue::Specified) - } - } - - - ${helpers.predefined_type("text-indent", "LengthOrPercentage", "computed::LengthOrPercentage::Length(Au(0))")} - - // Also known as "word-wrap" (which is more popular because of IE), but this is the preferred - // name per CSS-TEXT 6.2. - ${helpers.single_keyword("overflow-wrap", "normal break-word", gecko_ffi_name="mWordWrap", - gecko_constant_prefix="NS_STYLE_WORDWRAP")} - - // TODO(pcwalton): Support `word-break: keep-all` once we have better CJK support. - ${helpers.single_keyword("word-break", "normal break-all", extra_gecko_values="keep-all", - gecko_constant_prefix="NS_STYLE_WORDBREAK")} - - // TODO(pcwalton): Support `text-justify: distribute`. - ${helpers.single_keyword("text-justify", "auto none inter-word", products="servo")} - - <% data.new_style_struct("Text", inherited=False, gecko_ffi_name="nsStyleTextReset", - additional_methods=[Method("has_underline", "bool"), - Method("has_overline", "bool"), - Method("has_line_through", "bool")]) %> - - ${helpers.single_keyword("text-overflow", "clip ellipsis")} - - ${helpers.single_keyword("unicode-bidi", "normal embed isolate bidi-override isolate-override plaintext")} - - <%helpers:longhand name="text-decoration" custom_cascade="${product == 'servo'}"> - use cssparser::ToCss; - use std::fmt; - use values::computed::ComputedValueAsSpecified; - - impl ComputedValueAsSpecified for SpecifiedValue {} - - #[derive(PartialEq, Eq, Copy, Clone, Debug, HeapSizeOf)] - pub struct SpecifiedValue { - pub underline: bool, - pub overline: bool, - pub line_through: bool, - // 'blink' is accepted in the parser but ignored. - // Just not blinking the text is a conforming implementation per CSS 2.1. - } - - impl ToCss for SpecifiedValue { - fn to_css(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { - let mut space = false; - if self.underline { - try!(dest.write_str("underline")); - space = true; - } - if self.overline { - if space { - try!(dest.write_str(" ")); - } - try!(dest.write_str("overline")); - space = true; - } - if self.line_through { - if space { - try!(dest.write_str(" ")); - } - try!(dest.write_str("line-through")); - } - Ok(()) - } - } - pub mod computed_value { - pub type T = super::SpecifiedValue; - #[allow(non_upper_case_globals)] - pub const none: T = super::SpecifiedValue { - underline: false, overline: false, line_through: false - }; - } - #[inline] pub fn get_initial_value() -> computed_value::T { - computed_value::none - } - /// none | [ underline || overline || line-through || blink ] - pub fn parse(_context: &ParserContext, input: &mut Parser) -> Result { - let mut result = SpecifiedValue { - underline: false, overline: false, line_through: false, - }; - if input.try(|input| input.expect_ident_matching("none")).is_ok() { - return Ok(result) - } - let mut blink = false; - let mut empty = true; - while let Ok(ident) = input.expect_ident() { - match_ignore_ascii_case! { ident, - "underline" => if result.underline { return Err(()) } - else { empty = false; result.underline = true }, - "overline" => if result.overline { return Err(()) } - else { empty = false; result.overline = true }, - "line-through" => if result.line_through { return Err(()) } - else { empty = false; result.line_through = true }, - "blink" => if blink { return Err(()) } - else { empty = false; blink = true }, - _ => break - } - } - if !empty { Ok(result) } else { Err(()) } - } - - % if product == "servo": - fn cascade_property_custom( - _declaration: &PropertyDeclaration, - _inherited_style: &C, - context: &mut computed::Context, - _seen: &mut PropertyBitField, - _cacheable: &mut bool, - _error_reporter: &mut StdBox) { - longhands::_servo_text_decorations_in_effect::derive_from_text_decoration(context); - } - % endif - - - ${helpers.single_keyword("text-decoration-style", "-moz-none solid double dotted dashed wavy", - products="gecko")} - - <% data.switch_to_style_struct("InheritedText") %> - - <%helpers:longhand name="-servo-text-decorations-in-effect" - derived_from="display text-decoration" need_clone="True" products="servo"> - use cssparser::{RGBA, ToCss}; - use std::fmt; - - use values::computed::ComputedValueAsSpecified; - use properties::style_struct_traits::{Box, Color, Text}; - - impl ComputedValueAsSpecified for SpecifiedValue {} - - #[derive(Clone, PartialEq, Copy, Debug, HeapSizeOf)] - pub struct SpecifiedValue { - pub underline: Option, - pub overline: Option, - pub line_through: Option, - } - - pub mod computed_value { - pub type T = super::SpecifiedValue; - } - - impl ToCss for SpecifiedValue { - fn to_css(&self, _: &mut W) -> fmt::Result where W: fmt::Write { - // Web compat doesn't matter here. - Ok(()) - } - } - - #[inline] - pub fn get_initial_value() -> computed_value::T { - SpecifiedValue { - underline: None, - overline: None, - line_through: None, - } - } - - fn maybe(flag: bool, context: &Cx) -> Option { - if flag { - Some(context.style().get_color().clone_color()) - } else { - None - } - } - - fn derive(context: &Cx) -> computed_value::T { - // Start with no declarations if this is an atomic inline-level box; otherwise, start with the - // declarations in effect and add in the text decorations that this block specifies. - let mut result = match context.style().get_box().clone_display() { - super::display::computed_value::T::inline_block | - super::display::computed_value::T::inline_table => SpecifiedValue { - underline: None, - overline: None, - line_through: None, - }, - _ => context.inherited_style().get_inheritedtext().clone__servo_text_decorations_in_effect() - }; - - result.underline = maybe(context.style().get_text().has_underline() - || result.underline.is_some(), context); - result.overline = maybe(context.style().get_text().has_overline() - || result.overline.is_some(), context); - result.line_through = maybe(context.style().get_text().has_line_through() - || result.line_through.is_some(), context); - - result - } - - #[inline] - pub fn derive_from_text_decoration(context: &mut Cx) { - let derived = derive(context); - context.mutate_style().mutate_inheritedtext().set__servo_text_decorations_in_effect(derived); - } - - #[inline] - pub fn derive_from_display(context: &mut Cx) { - let derived = derive(context); - context.mutate_style().mutate_inheritedtext().set__servo_text_decorations_in_effect(derived); - } - - - <%helpers:single_keyword_computed name="white-space" values="normal pre nowrap pre-wrap pre-line", - gecko_constant_prefix="NS_STYLE_WHITESPACE"> - use values::computed::ComputedValueAsSpecified; - impl ComputedValueAsSpecified for SpecifiedValue {} - - impl SpecifiedValue { - pub fn allow_wrap(&self) -> bool { - match *self { - SpecifiedValue::nowrap | - SpecifiedValue::pre => false, - SpecifiedValue::normal | - SpecifiedValue::pre_wrap | - SpecifiedValue::pre_line => true, - } - } - - pub fn preserve_newlines(&self) -> bool { - match *self { - SpecifiedValue::normal | - SpecifiedValue::nowrap => false, - SpecifiedValue::pre | - SpecifiedValue::pre_wrap | - SpecifiedValue::pre_line => true, - } - } - - pub fn preserve_spaces(&self) -> bool { - match *self { - SpecifiedValue::normal | - SpecifiedValue::nowrap | - SpecifiedValue::pre_line => false, - SpecifiedValue::pre | - SpecifiedValue::pre_wrap => true, - } - } - } - - - // TODO(pcwalton): `full-width` - ${helpers.single_keyword("text-transform", "none capitalize uppercase lowercase", - extra_gecko_values="full-width")} - - ${helpers.single_keyword("text-rendering", "auto optimizespeed optimizelegibility geometricprecision")} - - // CSS Text Module Level 3 - // https://www.w3.org/TR/css-text-3/ - ${helpers.single_keyword("hyphens", "none manual auto", products="gecko")} - - // CSS Ruby Layout Module Level 1 - // https://www.w3.org/TR/css-ruby-1/ - ${helpers.single_keyword("ruby-align", "start center space-between space-around", products="gecko")} - - ${helpers.single_keyword("ruby-position", "over under", products="gecko")} - - // CSS 2.1, Section 17 - Tables - <% data.new_style_struct("Table", inherited=False, gecko_ffi_name="nsStyleTable") %> - - ${helpers.single_keyword("table-layout", "auto fixed", gecko_ffi_name="mLayoutStrategy")} - - <% data.new_style_struct("InheritedTable", inherited=True, gecko_ffi_name="nsStyleTableBorder") %> - - ${helpers.single_keyword("border-collapse", "separate collapse", gecko_constant_prefix="NS_STYLE_BORDER")} - - ${helpers.single_keyword("empty-cells", "show hide", gecko_constant_prefix="NS_STYLE_TABLE_EMPTY_CELLS")} - - ${helpers.single_keyword("caption-side", "top bottom", extra_gecko_values="right left top-outside bottom-outside")} - - <%helpers:longhand name="border-spacing"> - use app_units::Au; - use values::AuExtensionMethods; - - use cssparser::ToCss; - use std::fmt; - - pub mod computed_value { - use app_units::Au; - - #[derive(Clone, Copy, Debug, PartialEq, RustcEncodable, HeapSizeOf)] - pub struct T { - pub horizontal: Au, - pub vertical: Au, - } - } - - #[derive(Clone, Debug, PartialEq, HeapSizeOf)] - pub struct SpecifiedValue { - pub horizontal: specified::Length, - pub vertical: specified::Length, - } - - #[inline] - pub fn get_initial_value() -> computed_value::T { - computed_value::T { - horizontal: Au(0), - vertical: Au(0), - } - } - - impl ToCss for SpecifiedValue { - fn to_css(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { - try!(self.horizontal.to_css(dest)); - try!(dest.write_str(" ")); - self.vertical.to_css(dest) - } - } - - impl ToCss for computed_value::T { - fn to_css(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { - try!(self.horizontal.to_css(dest)); - try!(dest.write_str(" ")); - self.vertical.to_css(dest) - } - } - - impl ToComputedValue for SpecifiedValue { - type ComputedValue = computed_value::T; - - #[inline] - fn to_computed_value(&self, context: &Cx) -> computed_value::T { - computed_value::T { - horizontal: self.horizontal.to_computed_value(context), - vertical: self.vertical.to_computed_value(context), - } - } - } - - pub fn parse(_: &ParserContext, input: &mut Parser) -> Result { - let mut lengths = [ None, None ]; - for i in 0..2 { - match specified::Length::parse_non_negative(input) { - Err(()) => break, - Ok(length) => lengths[i] = Some(length), - } - } - if input.next().is_ok() { - return Err(()) - } - match (lengths[0], lengths[1]) { - (None, None) => Err(()), - (Some(length), None) => { - Ok(SpecifiedValue { - horizontal: length, - vertical: length, - }) - } - (Some(horizontal), Some(vertical)) => { - Ok(SpecifiedValue { - horizontal: horizontal, - vertical: vertical, - }) - } - (None, Some(_)) => panic!("shouldn't happen"), - } - } - - - // CSS Fragmentation Module Level 3 - // https://www.w3.org/TR/css-break-3/ - <% data.switch_to_style_struct("Border") %> - - ${helpers.single_keyword("box-decoration-break", "slice clone", products="gecko")} - - // CSS Writing Modes Level 3 - // http://dev.w3.org/csswg/css-writing-modes/ - <% data.switch_to_style_struct("InheritedBox") %> - - ${helpers.single_keyword("writing-mode", "horizontal-tb vertical-rl vertical-lr", - experimental=True, need_clone=True)} - - // FIXME(SimonSapin): Add 'mixed' and 'upright' (needs vertical text support) - // FIXME(SimonSapin): initial (first) value should be 'mixed', when that's implemented - // FIXME(bholley): sideways-right is needed as an alias to sideways in gecko. - ${helpers.single_keyword("text-orientation", "sideways", - experimental=True, need_clone=True, - extra_gecko_values="mixed upright", - extra_servo_values="sideways-right sideways-left")} - - // CSS Color Module Level 4 - // https://drafts.csswg.org/css-color/ - ${helpers.single_keyword("color-adjust", "economy exact", products="gecko")} - - // CSS Basic User Interface Module Level 3 - // http://dev.w3.org/csswg/css-ui/ - <% data.switch_to_style_struct("Box") %> - - ${helpers.single_keyword("resize", "none both horizontal vertical", products="gecko")} - - <% data.switch_to_style_struct("Position") %> - - ${helpers.single_keyword("box-sizing", "content-box border-box")} - - <% data.new_style_struct("Pointing", inherited=True, gecko_ffi_name="nsStyleUserInterface") %> - - <%helpers:longhand name="cursor"> - pub use self::computed_value::T as SpecifiedValue; - use values::computed::ComputedValueAsSpecified; - - impl ComputedValueAsSpecified for SpecifiedValue {} - - pub mod computed_value { - use cssparser::ToCss; - use std::fmt; - use style_traits::cursor::Cursor; - - #[derive(Clone, PartialEq, Eq, Copy, Debug, HeapSizeOf)] - pub enum T { - AutoCursor, - SpecifiedCursor(Cursor), - } - - impl ToCss for T { - fn to_css(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { - match *self { - T::AutoCursor => dest.write_str("auto"), - T::SpecifiedCursor(c) => c.to_css(dest), - } - } - } - } - - #[inline] - pub fn get_initial_value() -> computed_value::T { - computed_value::T::AutoCursor - } - pub fn parse(_context: &ParserContext, input: &mut Parser) -> Result { - use std::ascii::AsciiExt; - use style_traits::cursor::Cursor; - let ident = try!(input.expect_ident()); - if ident.eq_ignore_ascii_case("auto") { - Ok(SpecifiedValue::AutoCursor) - } else { - Cursor::from_css_keyword(&ident) - .map(SpecifiedValue::SpecifiedCursor) - } - } - - - // NB: `pointer-events: auto` (and use of `pointer-events` in anything that isn't SVG, in fact) - // is nonstandard, slated for CSS4-UI. - // TODO(pcwalton): SVG-only values. - ${helpers.single_keyword("pointer-events", "auto none")} - - - <% data.new_style_struct("Column", inherited=False, gecko_ffi_name="nsStyleColumn") %> - - <%helpers:longhand name="column-width" experimental="True"> - use cssparser::ToCss; - use std::fmt; - use values::AuExtensionMethods; - - #[derive(Debug, Clone, Copy, PartialEq, HeapSizeOf)] - pub enum SpecifiedValue { - Auto, - Specified(specified::Length), - } - - impl ToCss for SpecifiedValue { - fn to_css(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { - match *self { - SpecifiedValue::Auto => dest.write_str("auto"), - SpecifiedValue::Specified(l) => l.to_css(dest), - } - } - } - - pub mod computed_value { - use app_units::Au; - #[derive(Debug, Clone, PartialEq, HeapSizeOf)] - pub struct T(pub Option); - } - - impl ToCss for computed_value::T { - fn to_css(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { - match self.0 { - None => dest.write_str("auto"), - Some(l) => l.to_css(dest), - } - } - } - - #[inline] - pub fn get_initial_value() -> computed_value::T { - computed_value::T(None) - } - - impl ToComputedValue for SpecifiedValue { - type ComputedValue = computed_value::T; - - #[inline] - fn to_computed_value(&self, context: &Cx) -> computed_value::T { - match *self { - SpecifiedValue::Auto => computed_value::T(None), - SpecifiedValue::Specified(l) => - computed_value::T(Some(l.to_computed_value(context))) - } - } - } - - pub fn parse(_context: &ParserContext, input: &mut Parser) -> Result { - if input.try(|input| input.expect_ident_matching("auto")).is_ok() { - Ok(SpecifiedValue::Auto) - } else { - specified::Length::parse_non_negative(input).map(SpecifiedValue::Specified) - } - } - - - <%helpers:longhand name="column-count" experimental="True"> - use cssparser::ToCss; - use std::fmt; - - #[derive(Debug, Clone, Copy, PartialEq, HeapSizeOf)] - pub enum SpecifiedValue { - Auto, - Specified(u32), - } - - impl ToCss for SpecifiedValue { - fn to_css(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { - match *self { - SpecifiedValue::Auto => dest.write_str("auto"), - SpecifiedValue::Specified(count) => write!(dest, "{}", count), - } - } - } - - pub mod computed_value { - #[derive(Debug, Clone, PartialEq, HeapSizeOf)] - pub struct T(pub Option); - } - - impl ToCss for computed_value::T { - fn to_css(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { - match self.0 { - None => dest.write_str("auto"), - Some(count) => write!(dest, "{}", count), - } - } - } - - #[inline] - pub fn get_initial_value() -> computed_value::T { - computed_value::T(None) - } - - impl ToComputedValue for SpecifiedValue { - type ComputedValue = computed_value::T; - - #[inline] - fn to_computed_value(&self, _context: &Cx) -> computed_value::T { - match *self { - SpecifiedValue::Auto => computed_value::T(None), - SpecifiedValue::Specified(count) => - computed_value::T(Some(count)) - } - } - } - - pub fn parse(_context: &ParserContext, input: &mut Parser) -> Result { - if input.try(|input| input.expect_ident_matching("auto")).is_ok() { - Ok(SpecifiedValue::Auto) - } else { - let count = try!(specified::parse_integer(input)); - // Zero is invalid - if count <= 0 { - return Err(()) - } - Ok(SpecifiedValue::Specified(count as u32)) - } - } - - - <%helpers:longhand name="column-gap" experimental="True"> - use cssparser::ToCss; - use std::fmt; - use values::AuExtensionMethods; - - #[derive(Debug, Clone, Copy, PartialEq, HeapSizeOf)] - pub enum SpecifiedValue { - Normal, - Specified(specified::Length), - } - - impl ToCss for SpecifiedValue { - fn to_css(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { - match *self { - SpecifiedValue::Normal => dest.write_str("normal"), - SpecifiedValue::Specified(l) => l.to_css(dest), - } - } - } - - pub mod computed_value { - use app_units::Au; - #[derive(Debug, Clone, PartialEq, HeapSizeOf)] - pub struct T(pub Option); - } - - impl ToCss for computed_value::T { - fn to_css(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { - match self.0 { - None => dest.write_str("normal"), - Some(l) => l.to_css(dest), - } - } - } - - #[inline] - pub fn get_initial_value() -> computed_value::T { - computed_value::T(None) - } - - impl ToComputedValue for SpecifiedValue { - type ComputedValue = computed_value::T; - - #[inline] - fn to_computed_value(&self, context: &Cx) -> computed_value::T { - match *self { - SpecifiedValue::Normal => computed_value::T(None), - SpecifiedValue::Specified(l) => - computed_value::T(Some(l.to_computed_value(context))) - } - } - } - - pub fn parse(_context: &ParserContext, input: &mut Parser) -> Result { - if input.try(|input| input.expect_ident_matching("normal")).is_ok() { - Ok(SpecifiedValue::Normal) - } else { - specified::Length::parse_non_negative(input).map(SpecifiedValue::Specified) - } - } - - - // Box-shadow, etc. - <% data.new_style_struct("Effects", inherited=False, gecko_ffi_name="nsStyleEffects") %> - - <%helpers:longhand name="opacity"> - use cssparser::ToCss; - use std::fmt; - use values::CSSFloat; - - impl ToCss for SpecifiedValue { - fn to_css(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { - self.0.to_css(dest) - } - } - - #[derive(Debug, Clone, PartialEq, HeapSizeOf)] - pub struct SpecifiedValue(pub CSSFloat); - pub mod computed_value { - use values::CSSFloat; - pub type T = CSSFloat; - } - #[inline] - pub fn get_initial_value() -> computed_value::T { - 1.0 - } - - impl ToComputedValue for SpecifiedValue { - type ComputedValue = computed_value::T; - - #[inline] - fn to_computed_value(&self, _context: &Cx) -> computed_value::T { - if self.0 < 0.0 { - 0.0 - } else if self.0 > 1.0 { - 1.0 - } else { - self.0 - } - } - } - fn parse(_context: &ParserContext, input: &mut Parser) -> Result { - specified::parse_number(input).map(SpecifiedValue) - } - - - <%helpers:longhand name="box-shadow"> - use cssparser::{self, ToCss}; - use std::fmt; - use values::AuExtensionMethods; - - #[derive(Debug, Clone, PartialEq, HeapSizeOf)] - pub struct SpecifiedValue(Vec); - - #[derive(Debug, Clone, PartialEq, HeapSizeOf)] - pub struct SpecifiedBoxShadow { - pub offset_x: specified::Length, - pub offset_y: specified::Length, - pub blur_radius: specified::Length, - pub spread_radius: specified::Length, - pub color: Option, - pub inset: bool, - } - - impl ToCss for SpecifiedValue { - fn to_css(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { - let mut iter = self.0.iter(); - if let Some(shadow) = iter.next() { - try!(shadow.to_css(dest)); - } else { - try!(dest.write_str("none")); - return Ok(()) - } - for shadow in iter { - try!(dest.write_str(", ")); - try!(shadow.to_css(dest)); - } - Ok(()) - } - } - - impl ToCss for SpecifiedBoxShadow { - fn to_css(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { - if self.inset { - try!(dest.write_str("inset ")); - } - try!(self.blur_radius.to_css(dest)); - try!(dest.write_str(" ")); - try!(self.spread_radius.to_css(dest)); - try!(dest.write_str(" ")); - try!(self.offset_x.to_css(dest)); - try!(dest.write_str(" ")); - try!(self.offset_y.to_css(dest)); - - if let Some(ref color) = self.color { - try!(dest.write_str(" ")); - try!(color.to_css(dest)); - } - Ok(()) - } - } - - pub mod computed_value { - use app_units::Au; - use std::fmt; - use values::computed; - - #[derive(Clone, PartialEq, HeapSizeOf, Debug)] - pub struct T(pub Vec); - - #[derive(Clone, PartialEq, Copy, HeapSizeOf, Debug)] - pub struct BoxShadow { - pub offset_x: Au, - pub offset_y: Au, - pub blur_radius: Au, - pub spread_radius: Au, - pub color: computed::CSSColor, - pub inset: bool, - } - } - - impl ToCss for computed_value::T { - fn to_css(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { - let mut iter = self.0.iter(); - if let Some(shadow) = iter.next() { - try!(shadow.to_css(dest)); - } else { - try!(dest.write_str("none")); - return Ok(()) - } - for shadow in iter { - try!(dest.write_str(", ")); - try!(shadow.to_css(dest)); - } - Ok(()) - } - } - - impl ToCss for computed_value::BoxShadow { - fn to_css(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { - if self.inset { - try!(dest.write_str("inset ")); - } - try!(self.blur_radius.to_css(dest)); - try!(dest.write_str(" ")); - try!(self.spread_radius.to_css(dest)); - try!(dest.write_str(" ")); - try!(self.offset_x.to_css(dest)); - try!(dest.write_str(" ")); - try!(self.offset_y.to_css(dest)); - try!(dest.write_str(" ")); - try!(self.color.to_css(dest)); - Ok(()) - } - } - - #[inline] - pub fn get_initial_value() -> computed_value::T { - computed_value::T(Vec::new()) - } - - pub fn parse(_context: &ParserContext, input: &mut Parser) -> Result { - if input.try(|input| input.expect_ident_matching("none")).is_ok() { - Ok(SpecifiedValue(Vec::new())) - } else { - input.parse_comma_separated(parse_one_box_shadow).map(SpecifiedValue) - } - } - - impl ToComputedValue for SpecifiedValue { - type ComputedValue = computed_value::T; - - #[inline] - fn to_computed_value(&self, context: &Cx) -> computed_value::T { - computed_value::T(self.0.iter().map(|value| compute_one_box_shadow(value, context)).collect()) - } - } - - pub fn compute_one_box_shadow(value: &SpecifiedBoxShadow, context: &Cx) - -> computed_value::BoxShadow { - computed_value::BoxShadow { - offset_x: value.offset_x.to_computed_value(context), - offset_y: value.offset_y.to_computed_value(context), - blur_radius: value.blur_radius.to_computed_value(context), - spread_radius: value.spread_radius.to_computed_value(context), - color: value.color - .as_ref() - .map(|color| color.parsed) - .unwrap_or(cssparser::Color::CurrentColor), - inset: value.inset, - } - } - - pub fn parse_one_box_shadow(input: &mut Parser) -> Result { - use app_units::Au; - let mut lengths = [specified::Length::Absolute(Au(0)); 4]; - let mut lengths_parsed = false; - let mut color = None; - let mut inset = false; - - loop { - if !inset { - if input.try(|input| input.expect_ident_matching("inset")).is_ok() { - inset = true; - continue - } - } - if !lengths_parsed { - if let Ok(value) = input.try(specified::Length::parse) { - lengths[0] = value; - let mut length_parsed_count = 1; - while length_parsed_count < 4 { - if let Ok(value) = input.try(specified::Length::parse) { - lengths[length_parsed_count] = value - } else { - break - } - length_parsed_count += 1; - } - - // The first two lengths must be specified. - if length_parsed_count < 2 { - return Err(()) - } - - lengths_parsed = true; - continue - } - } - if color.is_none() { - if let Ok(value) = input.try(specified::CSSColor::parse) { - color = Some(value); - continue - } - } - break - } - - // Lengths must be specified. - if !lengths_parsed { - return Err(()) - } - - Ok(SpecifiedBoxShadow { - offset_x: lengths[0], - offset_y: lengths[1], - blur_radius: lengths[2], - spread_radius: lengths[3], - color: color, - inset: inset, - }) - } - - - <%helpers:longhand name="clip"> - use cssparser::ToCss; - use std::fmt; - use values::AuExtensionMethods; - - // NB: `top` and `left` are 0 if `auto` per CSS 2.1 11.1.2. - - pub mod computed_value { - use app_units::Au; - - #[derive(Clone, PartialEq, Eq, Copy, Debug, HeapSizeOf)] - pub struct ClipRect { - pub top: Au, - pub right: Option, - pub bottom: Option, - pub left: Au, - } - - #[derive(Debug, Clone, PartialEq, HeapSizeOf)] - pub struct T(pub Option); - } - - impl ToCss for computed_value::T { - fn to_css(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { - match self.0 { - None => dest.write_str("auto"), - Some(rect) => { - try!(dest.write_str("rect(")); - try!(rect.top.to_css(dest)); - try!(dest.write_str(", ")); - if let Some(right) = rect.right { - try!(right.to_css(dest)); - try!(dest.write_str(", ")); - } else { - try!(dest.write_str("auto, ")); - } - - if let Some(bottom) = rect.bottom { - try!(bottom.to_css(dest)); - try!(dest.write_str(", ")); - } else { - try!(dest.write_str("auto, ")); - } - - try!(rect.left.to_css(dest)); - try!(dest.write_str(")")); - Ok(()) - } - } - } - } - - #[derive(Clone, Debug, PartialEq, Copy, HeapSizeOf)] - pub struct SpecifiedClipRect { - pub top: specified::Length, - pub right: Option, - pub bottom: Option, - pub left: specified::Length, - } - - #[derive(Clone, Debug, PartialEq, Copy, HeapSizeOf)] - pub struct SpecifiedValue(Option); - - impl ToCss for SpecifiedClipRect { - fn to_css(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { - try!(dest.write_str("rect(")); - - try!(self.top.to_css(dest)); - try!(dest.write_str(", ")); - - if let Some(right) = self.right { - try!(right.to_css(dest)); - try!(dest.write_str(", ")); - } else { - try!(dest.write_str("auto, ")); - } - - if let Some(bottom) = self.bottom { - try!(bottom.to_css(dest)); - try!(dest.write_str(", ")); - } else { - try!(dest.write_str("auto, ")); - } - - try!(self.left.to_css(dest)); - - try!(dest.write_str(")")); - Ok(()) - } - } - - impl ToCss for SpecifiedValue { - fn to_css(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { - if let Some(ref rect) = self.0 { - rect.to_css(dest) - } else { - dest.write_str("auto") - } - } - } - - #[inline] - pub fn get_initial_value() -> computed_value::T { - computed_value::T(None) - } - - impl ToComputedValue for SpecifiedValue { - type ComputedValue = computed_value::T; - - #[inline] - fn to_computed_value(&self, context: &Cx) -> computed_value::T { - computed_value::T(self.0.map(|value| computed_value::ClipRect { - top: value.top.to_computed_value(context), - right: value.right.map(|right| right.to_computed_value(context)), - bottom: value.bottom.map(|bottom| bottom.to_computed_value(context)), - left: value.left.to_computed_value(context), - })) - } - } - - pub fn parse(_context: &ParserContext, input: &mut Parser) -> Result { - use app_units::Au; - use std::ascii::AsciiExt; - use values::specified::Length; - - if input.try(|input| input.expect_ident_matching("auto")).is_ok() { - return Ok(SpecifiedValue(None)) - } - if !try!(input.expect_function()).eq_ignore_ascii_case("rect") { - return Err(()) - } - let sides = try!(input.parse_nested_block(|input| { - input.parse_comma_separated(|input| { - if input.try(|input| input.expect_ident_matching("auto")).is_ok() { - Ok(None) - } else { - Length::parse(input).map(Some) - } - }) - })); - if sides.len() == 4 { - Ok(SpecifiedValue(Some(SpecifiedClipRect { - top: sides[0].unwrap_or(Length::Absolute(Au(0))), - right: sides[1], - bottom: sides[2], - left: sides[3].unwrap_or(Length::Absolute(Au(0))), - }))) - } else { - Err(()) - } - } - - - <% data.switch_to_style_struct("InheritedText") %> - - <%helpers:longhand name="text-shadow"> - use cssparser::{self, ToCss}; - use std::fmt; - use values::AuExtensionMethods; - - #[derive(Clone, PartialEq, Debug, HeapSizeOf)] - pub struct SpecifiedValue(Vec); - - #[derive(Clone, PartialEq, Debug, HeapSizeOf)] - pub struct SpecifiedTextShadow { - pub offset_x: specified::Length, - pub offset_y: specified::Length, - pub blur_radius: specified::Length, - pub color: Option, - } - - pub mod computed_value { - use app_units::Au; - use cssparser::Color; - - #[derive(Clone, PartialEq, Debug, HeapSizeOf)] - pub struct T(pub Vec); - - #[derive(Clone, PartialEq, Debug, HeapSizeOf)] - pub struct TextShadow { - pub offset_x: Au, - pub offset_y: Au, - pub blur_radius: Au, - pub color: Color, - } - } - - impl ToCss for computed_value::T { - fn to_css(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { - let mut iter = self.0.iter(); - if let Some(shadow) = iter.next() { - try!(shadow.to_css(dest)); - } else { - try!(dest.write_str("none")); - return Ok(()) - } - for shadow in iter { - try!(dest.write_str(", ")); - try!(shadow.to_css(dest)); - } - Ok(()) - } - } - - impl ToCss for computed_value::TextShadow { - fn to_css(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { - try!(self.offset_x.to_css(dest)); - try!(dest.write_str(" ")); - try!(self.offset_y.to_css(dest)); - try!(dest.write_str(" ")); - try!(self.blur_radius.to_css(dest)); - try!(dest.write_str(" ")); - try!(self.color.to_css(dest)); - Ok(()) - } - } - - impl ToCss for SpecifiedValue { - fn to_css(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { - let mut iter = self.0.iter(); - if let Some(shadow) = iter.next() { - try!(shadow.to_css(dest)); - } else { - try!(dest.write_str("none")); - return Ok(()) - } - for shadow in iter { - try!(dest.write_str(", ")); - try!(shadow.to_css(dest)); - } - Ok(()) - } - } - - impl ToCss for SpecifiedTextShadow { - fn to_css(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { - try!(self.offset_x.to_css(dest)); - try!(dest.write_str(" ")); - try!(self.offset_y.to_css(dest)); - try!(dest.write_str(" ")); - try!(self.blur_radius.to_css(dest)); - - if let Some(ref color) = self.color { - try!(dest.write_str(" ")); - try!(color.to_css(dest)); - } - Ok(()) - } - } - - #[inline] - pub fn get_initial_value() -> computed_value::T { - computed_value::T(Vec::new()) - } - - pub fn parse(_: &ParserContext, input: &mut Parser) -> Result { - if input.try(|input| input.expect_ident_matching("none")).is_ok() { - Ok(SpecifiedValue(Vec::new())) - } else { - input.parse_comma_separated(parse_one_text_shadow).map(SpecifiedValue) - } - } - - fn parse_one_text_shadow(input: &mut Parser) -> Result { - use app_units::Au; - let mut lengths = [specified::Length::Absolute(Au(0)); 3]; - let mut lengths_parsed = false; - let mut color = None; - - loop { - if !lengths_parsed { - if let Ok(value) = input.try(specified::Length::parse) { - lengths[0] = value; - let mut length_parsed_count = 1; - while length_parsed_count < 3 { - if let Ok(value) = input.try(specified::Length::parse) { - lengths[length_parsed_count] = value - } else { - break - } - length_parsed_count += 1; - } - - // The first two lengths must be specified. - if length_parsed_count < 2 { - return Err(()) - } - - lengths_parsed = true; - continue - } - } - if color.is_none() { - if let Ok(value) = input.try(specified::CSSColor::parse) { - color = Some(value); - continue - } - } - break - } - - // Lengths must be specified. - if !lengths_parsed { - return Err(()) - } - - Ok(SpecifiedTextShadow { - offset_x: lengths[0], - offset_y: lengths[1], - blur_radius: lengths[2], - color: color, - }) - } - - impl ToComputedValue for SpecifiedValue { - type ComputedValue = computed_value::T; - - fn to_computed_value(&self, context: &Cx) -> computed_value::T { - computed_value::T(self.0.iter().map(|value| { - computed_value::TextShadow { - offset_x: value.offset_x.to_computed_value(context), - offset_y: value.offset_y.to_computed_value(context), - blur_radius: value.blur_radius.to_computed_value(context), - color: value.color - .as_ref() - .map(|color| color.parsed) - .unwrap_or(cssparser::Color::CurrentColor), - } - }).collect()) - } - } - - - <% data.switch_to_style_struct("Effects") %> - - <%helpers:longhand name="filter"> - //pub use self::computed_value::T as SpecifiedValue; - use cssparser::ToCss; - use std::fmt; - use values::AuExtensionMethods; - use values::CSSFloat; - use values::specified::{Angle, Length}; - - #[derive(Debug, Clone, PartialEq, HeapSizeOf)] - pub struct SpecifiedValue(Vec); - - // TODO(pcwalton): `drop-shadow` - #[derive(Clone, PartialEq, Debug, HeapSizeOf)] - pub enum SpecifiedFilter { - Blur(Length), - Brightness(CSSFloat), - Contrast(CSSFloat), - Grayscale(CSSFloat), - HueRotate(Angle), - Invert(CSSFloat), - Opacity(CSSFloat), - Saturate(CSSFloat), - Sepia(CSSFloat), - } - - pub mod computed_value { - use app_units::Au; - use values::CSSFloat; - use values::specified::{Angle}; - - #[derive(Clone, PartialEq, Debug, HeapSizeOf, Deserialize, Serialize)] - pub enum Filter { - Blur(Au), - Brightness(CSSFloat), - Contrast(CSSFloat), - Grayscale(CSSFloat), - HueRotate(Angle), - Invert(CSSFloat), - Opacity(CSSFloat), - Saturate(CSSFloat), - Sepia(CSSFloat), - } - - #[derive(Clone, PartialEq, Debug, HeapSizeOf, Deserialize, Serialize)] - pub struct T { pub filters: Vec } - - impl T { - /// Creates a new filter pipeline. - #[inline] - pub fn new(filters: Vec) -> T { - T - { - filters: filters, - } - } - - /// Adds a new filter to the filter pipeline. - #[inline] - pub fn push(&mut self, filter: Filter) { - self.filters.push(filter) - } - - /// Returns true if this filter pipeline is empty and false otherwise. - #[inline] - pub fn is_empty(&self) -> bool { - self.filters.is_empty() - } - - /// Returns the resulting opacity of this filter pipeline. - #[inline] - pub fn opacity(&self) -> CSSFloat { - let mut opacity = 1.0; - - for filter in &self.filters { - if let Filter::Opacity(ref opacity_value) = *filter { - opacity *= *opacity_value - } - } - opacity - } - } - } - - impl ToCss for computed_value::T { - fn to_css(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { - let mut iter = self.filters.iter(); - if let Some(filter) = iter.next() { - try!(filter.to_css(dest)); - } else { - try!(dest.write_str("none")); - return Ok(()) - } - for filter in iter { - try!(dest.write_str(" ")); - try!(filter.to_css(dest)); - } - Ok(()) - } - } - - impl ToCss for SpecifiedValue { - fn to_css(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { - let mut iter = self.0.iter(); - if let Some(filter) = iter.next() { - try!(filter.to_css(dest)); - } else { - try!(dest.write_str("none")); - return Ok(()) - } - for filter in iter { - try!(dest.write_str(" ")); - try!(filter.to_css(dest)); - } - Ok(()) - } - } - - impl ToCss for computed_value::Filter { - fn to_css(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { - match *self { - computed_value::Filter::Blur(value) => { - try!(dest.write_str("blur(")); - try!(value.to_css(dest)); - try!(dest.write_str(")")); - } - computed_value::Filter::Brightness(value) => try!(write!(dest, "brightness({})", value)), - computed_value::Filter::Contrast(value) => try!(write!(dest, "contrast({})", value)), - computed_value::Filter::Grayscale(value) => try!(write!(dest, "grayscale({})", value)), - computed_value::Filter::HueRotate(value) => { - try!(dest.write_str("hue-rotate(")); - try!(value.to_css(dest)); - try!(dest.write_str(")")); - } - computed_value::Filter::Invert(value) => try!(write!(dest, "invert({})", value)), - computed_value::Filter::Opacity(value) => try!(write!(dest, "opacity({})", value)), - computed_value::Filter::Saturate(value) => try!(write!(dest, "saturate({})", value)), - computed_value::Filter::Sepia(value) => try!(write!(dest, "sepia({})", value)), - } - Ok(()) - } - } - - impl ToCss for SpecifiedFilter { - fn to_css(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { - match *self { - SpecifiedFilter::Blur(value) => { - try!(dest.write_str("blur(")); - try!(value.to_css(dest)); - try!(dest.write_str(")")); - } - SpecifiedFilter::Brightness(value) => try!(write!(dest, "brightness({})", value)), - SpecifiedFilter::Contrast(value) => try!(write!(dest, "contrast({})", value)), - SpecifiedFilter::Grayscale(value) => try!(write!(dest, "grayscale({})", value)), - SpecifiedFilter::HueRotate(value) => { - try!(dest.write_str("hue-rotate(")); - try!(value.to_css(dest)); - try!(dest.write_str(")")); - } - SpecifiedFilter::Invert(value) => try!(write!(dest, "invert({})", value)), - SpecifiedFilter::Opacity(value) => try!(write!(dest, "opacity({})", value)), - SpecifiedFilter::Saturate(value) => try!(write!(dest, "saturate({})", value)), - SpecifiedFilter::Sepia(value) => try!(write!(dest, "sepia({})", value)), - } - Ok(()) - } - } - - #[inline] - pub fn get_initial_value() -> computed_value::T { - computed_value::T::new(Vec::new()) - } - - pub fn parse(_context: &ParserContext, input: &mut Parser) -> Result { - let mut filters = Vec::new(); - if input.try(|input| input.expect_ident_matching("none")).is_ok() { - return Ok(SpecifiedValue(filters)) - } - loop { - if let Ok(function_name) = input.try(|input| input.expect_function()) { - filters.push(try!(input.parse_nested_block(|input| { - match_ignore_ascii_case! { function_name, - "blur" => specified::Length::parse_non_negative(input).map(SpecifiedFilter::Blur), - "brightness" => parse_factor(input).map(SpecifiedFilter::Brightness), - "contrast" => parse_factor(input).map(SpecifiedFilter::Contrast), - "grayscale" => parse_factor(input).map(SpecifiedFilter::Grayscale), - "hue-rotate" => Angle::parse(input).map(SpecifiedFilter::HueRotate), - "invert" => parse_factor(input).map(SpecifiedFilter::Invert), - "opacity" => parse_factor(input).map(SpecifiedFilter::Opacity), - "saturate" => parse_factor(input).map(SpecifiedFilter::Saturate), - "sepia" => parse_factor(input).map(SpecifiedFilter::Sepia), - _ => Err(()) - } - }))); - } else if filters.is_empty() { - return Err(()) - } else { - return Ok(SpecifiedValue(filters)) - } - } - } - - fn parse_factor(input: &mut Parser) -> Result<::values::CSSFloat, ()> { - use cssparser::Token; - match input.next() { - Ok(Token::Number(value)) => Ok(value.value), - Ok(Token::Percentage(value)) => Ok(value.unit_value), - _ => Err(()) - } - } - - impl ToComputedValue for SpecifiedValue { - type ComputedValue = computed_value::T; - - fn to_computed_value(&self, context: &Cx) -> computed_value::T { - computed_value::T{ filters: self.0.iter().map(|value| { - match *value { - SpecifiedFilter::Blur(factor) => - computed_value::Filter::Blur(factor.to_computed_value(context)), - SpecifiedFilter::Brightness(factor) => computed_value::Filter::Brightness(factor), - SpecifiedFilter::Contrast(factor) => computed_value::Filter::Contrast(factor), - SpecifiedFilter::Grayscale(factor) => computed_value::Filter::Grayscale(factor), - SpecifiedFilter::HueRotate(factor) => computed_value::Filter::HueRotate(factor), - SpecifiedFilter::Invert(factor) => computed_value::Filter::Invert(factor), - SpecifiedFilter::Opacity(factor) => computed_value::Filter::Opacity(factor), - SpecifiedFilter::Saturate(factor) => computed_value::Filter::Saturate(factor), - SpecifiedFilter::Sepia(factor) => computed_value::Filter::Sepia(factor), - } - }).collect() } - } - } - - - <%helpers:longhand name="transform"> - use app_units::Au; - use values::CSSFloat; - - use cssparser::ToCss; - use std::fmt; - - pub mod computed_value { - use values::CSSFloat; - use values::computed; - - #[derive(Clone, Copy, Debug, PartialEq, HeapSizeOf)] - pub struct ComputedMatrix { - pub m11: CSSFloat, pub m12: CSSFloat, pub m13: CSSFloat, pub m14: CSSFloat, - pub m21: CSSFloat, pub m22: CSSFloat, pub m23: CSSFloat, pub m24: CSSFloat, - pub m31: CSSFloat, pub m32: CSSFloat, pub m33: CSSFloat, pub m34: CSSFloat, - pub m41: CSSFloat, pub m42: CSSFloat, pub m43: CSSFloat, pub m44: CSSFloat, - } - - impl ComputedMatrix { - pub fn identity() -> ComputedMatrix { - ComputedMatrix { - m11: 1.0, m12: 0.0, m13: 0.0, m14: 0.0, - m21: 0.0, m22: 1.0, m23: 0.0, m24: 0.0, - m31: 0.0, m32: 0.0, m33: 1.0, m34: 0.0, - m41: 0.0, m42: 0.0, m43: 0.0, m44: 1.0 - } - } - } - - #[derive(Clone, Debug, PartialEq, HeapSizeOf)] - pub enum ComputedOperation { - Matrix(ComputedMatrix), - Skew(computed::Angle, computed::Angle), - Translate(computed::LengthOrPercentage, - computed::LengthOrPercentage, - computed::Length), - Scale(CSSFloat, CSSFloat, CSSFloat), - Rotate(CSSFloat, CSSFloat, CSSFloat, computed::Angle), - Perspective(computed::Length), - } - - #[derive(Clone, Debug, PartialEq, HeapSizeOf)] - pub struct T(pub Option>); - } - - pub use self::computed_value::ComputedMatrix as SpecifiedMatrix; - - fn parse_two_lengths_or_percentages(input: &mut Parser) - -> Result<(specified::LengthOrPercentage, - specified::LengthOrPercentage),()> { - let first = try!(specified::LengthOrPercentage::parse(input)); - let second = input.try(|input| { - try!(input.expect_comma()); - specified::LengthOrPercentage::parse(input) - }).unwrap_or(specified::LengthOrPercentage::zero()); - Ok((first, second)) - } - - fn parse_two_floats(input: &mut Parser) -> Result<(CSSFloat,CSSFloat),()> { - let first = try!(specified::parse_number(input)); - let second = input.try(|input| { - try!(input.expect_comma()); - specified::parse_number(input) - }).unwrap_or(first); - Ok((first, second)) - } - - fn parse_two_angles(input: &mut Parser) -> Result<(specified::Angle, specified::Angle),()> { - let first = try!(specified::Angle::parse(input)); - let second = input.try(|input| { - try!(input.expect_comma()); - specified::Angle::parse(input) - }).unwrap_or(specified::Angle(0.0)); - Ok((first, second)) - } - - #[derive(Copy, Clone, Debug, PartialEq, HeapSizeOf)] - enum TranslateKind { - Translate, - TranslateX, - TranslateY, - TranslateZ, - Translate3D, - } - - #[derive(Clone, Debug, PartialEq, HeapSizeOf)] - enum SpecifiedOperation { - Matrix(SpecifiedMatrix), - Skew(specified::Angle, specified::Angle), - Translate(TranslateKind, - specified::LengthOrPercentage, - specified::LengthOrPercentage, - specified::Length), - Scale(CSSFloat, CSSFloat, CSSFloat), - Rotate(CSSFloat, CSSFloat, CSSFloat, specified::Angle), - Perspective(specified::Length), - } - - impl ToCss for computed_value::T { - fn to_css(&self, _: &mut W) -> fmt::Result where W: fmt::Write { - // TODO(pcwalton) - Ok(()) - } - } - - impl ToCss for SpecifiedOperation { - fn to_css(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { - match *self { - // todo(gw): implement serialization for transform - // types other than translate. - SpecifiedOperation::Matrix(_m) => { - Ok(()) - } - SpecifiedOperation::Skew(_sx, _sy) => { - Ok(()) - } - SpecifiedOperation::Translate(kind, tx, ty, tz) => { - match kind { - TranslateKind::Translate => { - try!(dest.write_str("translate(")); - try!(tx.to_css(dest)); - try!(dest.write_str(", ")); - try!(ty.to_css(dest)); - dest.write_str(")") - } - TranslateKind::TranslateX => { - try!(dest.write_str("translateX(")); - try!(tx.to_css(dest)); - dest.write_str(")") - } - TranslateKind::TranslateY => { - try!(dest.write_str("translateY(")); - try!(ty.to_css(dest)); - dest.write_str(")") - } - TranslateKind::TranslateZ => { - try!(dest.write_str("translateZ(")); - try!(tz.to_css(dest)); - dest.write_str(")") - } - TranslateKind::Translate3D => { - try!(dest.write_str("translate3d(")); - try!(tx.to_css(dest)); - try!(dest.write_str(", ")); - try!(ty.to_css(dest)); - try!(dest.write_str(", ")); - try!(tz.to_css(dest)); - dest.write_str(")") - } - } - } - SpecifiedOperation::Scale(_sx, _sy, _sz) => { - Ok(()) - } - SpecifiedOperation::Rotate(_ax, _ay, _az, _angle) => { - Ok(()) - } - SpecifiedOperation::Perspective(_p) => { - Ok(()) - } - } - } - } - - #[derive(Clone, Debug, PartialEq, HeapSizeOf)] - pub struct SpecifiedValue(Vec); - - impl ToCss for SpecifiedValue { - fn to_css(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { - let mut first = true; - for operation in &self.0 { - if !first { - try!(dest.write_str(" ")); - } - first = false; - try!(operation.to_css(dest)) - } - Ok(()) - } - } - - #[inline] - pub fn get_initial_value() -> computed_value::T { - computed_value::T(None) - } - - pub fn parse(_: &ParserContext, input: &mut Parser) -> Result { - if input.try(|input| input.expect_ident_matching("none")).is_ok() { - return Ok(SpecifiedValue(Vec::new())) - } - - let mut result = Vec::new(); - loop { - let name = match input.expect_function() { - Ok(name) => name, - Err(_) => break, - }; - match_ignore_ascii_case! { - name, - "matrix" => { - try!(input.parse_nested_block(|input| { - let values = try!(input.parse_comma_separated(|input| { - specified::parse_number(input) - })); - if values.len() != 6 { - return Err(()) - } - result.push(SpecifiedOperation::Matrix( - SpecifiedMatrix { - m11: values[0], m12: values[1], m13: 0.0, m14: 0.0, - m21: values[2], m22: values[3], m23: 0.0, m24: 0.0, - m31: 0.0, m32: 0.0, m33: 1.0, m34: 0.0, - m41: values[4], m42: values[5], m43: 0.0, m44: 1.0 - })); - Ok(()) - })) - }, - "matrix3d" => { - try!(input.parse_nested_block(|input| { - let values = try!(input.parse_comma_separated(|input| { - specified::parse_number(input) - })); - if values.len() != 16 { - return Err(()) - } - result.push(SpecifiedOperation::Matrix( - SpecifiedMatrix { - m11: values[ 0], m12: values[ 1], m13: values[ 2], m14: values[ 3], - m21: values[ 4], m22: values[ 5], m23: values[ 6], m24: values[ 7], - m31: values[ 8], m32: values[ 9], m33: values[10], m34: values[11], - m41: values[12], m42: values[13], m43: values[14], m44: values[15] - })); - Ok(()) - })) - }, - "translate" => { - try!(input.parse_nested_block(|input| { - let (tx, ty) = try!(parse_two_lengths_or_percentages(input)); - result.push(SpecifiedOperation::Translate(TranslateKind::Translate, - tx, - ty, - specified::Length::Absolute(Au(0)))); - Ok(()) - })) - }, - "translatex" => { - try!(input.parse_nested_block(|input| { - let tx = try!(specified::LengthOrPercentage::parse(input)); - result.push(SpecifiedOperation::Translate( - TranslateKind::TranslateX, - tx, - specified::LengthOrPercentage::zero(), - specified::Length::Absolute(Au(0)))); - Ok(()) - })) - }, - "translatey" => { - try!(input.parse_nested_block(|input| { - let ty = try!(specified::LengthOrPercentage::parse(input)); - result.push(SpecifiedOperation::Translate( - TranslateKind::TranslateY, - specified::LengthOrPercentage::zero(), - ty, - specified::Length::Absolute(Au(0)))); - Ok(()) - })) - }, - "translatez" => { - try!(input.parse_nested_block(|input| { - let tz = try!(specified::Length::parse(input)); - result.push(SpecifiedOperation::Translate( - TranslateKind::TranslateZ, - specified::LengthOrPercentage::zero(), - specified::LengthOrPercentage::zero(), - tz)); - Ok(()) - })) - }, - "translate3d" => { - try!(input.parse_nested_block(|input| { - let tx = try!(specified::LengthOrPercentage::parse(input)); - try!(input.expect_comma()); - let ty = try!(specified::LengthOrPercentage::parse(input)); - try!(input.expect_comma()); - let tz = try!(specified::Length::parse(input)); - result.push(SpecifiedOperation::Translate( - TranslateKind::Translate3D, - tx, - ty, - tz)); - Ok(()) - })) - - }, - "scale" => { - try!(input.parse_nested_block(|input| { - let (sx, sy) = try!(parse_two_floats(input)); - result.push(SpecifiedOperation::Scale(sx, sy, 1.0)); - Ok(()) - })) - }, - "scalex" => { - try!(input.parse_nested_block(|input| { - let sx = try!(specified::parse_number(input)); - result.push(SpecifiedOperation::Scale(sx, 1.0, 1.0)); - Ok(()) - })) - }, - "scaley" => { - try!(input.parse_nested_block(|input| { - let sy = try!(specified::parse_number(input)); - result.push(SpecifiedOperation::Scale(1.0, sy, 1.0)); - Ok(()) - })) - }, - "scalez" => { - try!(input.parse_nested_block(|input| { - let sz = try!(specified::parse_number(input)); - result.push(SpecifiedOperation::Scale(1.0, 1.0, sz)); - Ok(()) - })) - }, - "scale3d" => { - try!(input.parse_nested_block(|input| { - let sx = try!(specified::parse_number(input)); - try!(input.expect_comma()); - let sy = try!(specified::parse_number(input)); - try!(input.expect_comma()); - let sz = try!(specified::parse_number(input)); - result.push(SpecifiedOperation::Scale(sx, sy, sz)); - Ok(()) - })) - }, - "rotate" => { - try!(input.parse_nested_block(|input| { - let theta = try!(specified::Angle::parse(input)); - result.push(SpecifiedOperation::Rotate(0.0, 0.0, 1.0, theta)); - Ok(()) - })) - }, - "rotatex" => { - try!(input.parse_nested_block(|input| { - let theta = try!(specified::Angle::parse(input)); - result.push(SpecifiedOperation::Rotate(1.0, 0.0, 0.0, theta)); - Ok(()) - })) - }, - "rotatey" => { - try!(input.parse_nested_block(|input| { - let theta = try!(specified::Angle::parse(input)); - result.push(SpecifiedOperation::Rotate(0.0, 1.0, 0.0, theta)); - Ok(()) - })) - }, - "rotatez" => { - try!(input.parse_nested_block(|input| { - let theta = try!(specified::Angle::parse(input)); - result.push(SpecifiedOperation::Rotate(0.0, 0.0, 1.0, theta)); - Ok(()) - })) - }, - "rotate3d" => { - try!(input.parse_nested_block(|input| { - let ax = try!(specified::parse_number(input)); - try!(input.expect_comma()); - let ay = try!(specified::parse_number(input)); - try!(input.expect_comma()); - let az = try!(specified::parse_number(input)); - try!(input.expect_comma()); - let theta = try!(specified::Angle::parse(input)); - // TODO(gw): Check the axis can be normalized!! - result.push(SpecifiedOperation::Rotate(ax, ay, az, theta)); - Ok(()) - })) - }, - "skew" => { - try!(input.parse_nested_block(|input| { - let (theta_x, theta_y) = try!(parse_two_angles(input)); - result.push(SpecifiedOperation::Skew(theta_x, theta_y)); - Ok(()) - })) - }, - "skewx" => { - try!(input.parse_nested_block(|input| { - let theta_x = try!(specified::Angle::parse(input)); - result.push(SpecifiedOperation::Skew(theta_x, specified::Angle(0.0))); - Ok(()) - })) - }, - "skewy" => { - try!(input.parse_nested_block(|input| { - let theta_y = try!(specified::Angle::parse(input)); - result.push(SpecifiedOperation::Skew(specified::Angle(0.0), theta_y)); - Ok(()) - })) - }, - "perspective" => { - try!(input.parse_nested_block(|input| { - let d = try!(specified::Length::parse(input)); - result.push(SpecifiedOperation::Perspective(d)); - Ok(()) - })) - }, - _ => return Err(()) - } - } - - if !result.is_empty() { - Ok(SpecifiedValue(result)) - } else { - Err(()) - } - } - - impl ToComputedValue for SpecifiedValue { - type ComputedValue = computed_value::T; - - #[inline] - fn to_computed_value(&self, context: &Cx) -> computed_value::T { - if self.0.is_empty() { - return computed_value::T(None) - } - - let mut result = vec!(); - for operation in &self.0 { - match *operation { - SpecifiedOperation::Matrix(ref matrix) => { - result.push(computed_value::ComputedOperation::Matrix(*matrix)); - } - SpecifiedOperation::Translate(_, ref tx, ref ty, ref tz) => { - result.push(computed_value::ComputedOperation::Translate(tx.to_computed_value(context), - ty.to_computed_value(context), - tz.to_computed_value(context))); - } - SpecifiedOperation::Scale(sx, sy, sz) => { - result.push(computed_value::ComputedOperation::Scale(sx, sy, sz)); - } - SpecifiedOperation::Rotate(ax, ay, az, theta) => { - result.push(computed_value::ComputedOperation::Rotate(ax, ay, az, theta)); - } - SpecifiedOperation::Skew(theta_x, theta_y) => { - result.push(computed_value::ComputedOperation::Skew(theta_x, theta_y)); - } - SpecifiedOperation::Perspective(d) => { - result.push(computed_value::ComputedOperation::Perspective(d.to_computed_value(context))); - } - }; - } - - computed_value::T(Some(result)) - } - } - - - pub struct OriginParseResult { - horizontal: Option, - vertical: Option, - depth: Option - } - - pub fn parse_origin(_: &ParserContext, input: &mut Parser) -> Result { - use values::specified::{LengthOrPercentage, Percentage}; - let (mut horizontal, mut vertical, mut depth) = (None, None, None); - loop { - if let Err(_) = input.try(|input| { - let token = try!(input.expect_ident()); - match_ignore_ascii_case! { - token, - "left" => { - if horizontal.is_none() { - horizontal = Some(LengthOrPercentage::Percentage(Percentage(0.0))) - } else { - return Err(()) - } - }, - "center" => { - if horizontal.is_none() { - horizontal = Some(LengthOrPercentage::Percentage(Percentage(0.5))) - } else if vertical.is_none() { - vertical = Some(LengthOrPercentage::Percentage(Percentage(0.5))) - } else { - return Err(()) - } - }, - "right" => { - if horizontal.is_none() { - horizontal = Some(LengthOrPercentage::Percentage(Percentage(1.0))) - } else { - return Err(()) - } - }, - "top" => { - if vertical.is_none() { - vertical = Some(LengthOrPercentage::Percentage(Percentage(0.0))) - } else { - return Err(()) - } - }, - "bottom" => { - if vertical.is_none() { - vertical = Some(LengthOrPercentage::Percentage(Percentage(1.0))) - } else { - return Err(()) - } - }, - _ => return Err(()) - } - Ok(()) - }) { - match LengthOrPercentage::parse(input) { - Ok(value) => { - if horizontal.is_none() { - horizontal = Some(value); - } else if vertical.is_none() { - vertical = Some(value); - } else if let LengthOrPercentage::Length(length) = value { - depth = Some(length); - } else { - break; - } - } - _ => break, - } - } - } - - if horizontal.is_some() || vertical.is_some() { - Ok(OriginParseResult { - horizontal: horizontal, - vertical: vertical, - depth: depth, - }) - } else { - Err(()) - } - } - - ${helpers.single_keyword("backface-visibility", "visible hidden")} - - ${helpers.single_keyword("transform-box", "border-box fill-box view-box", products="gecko")} - - ${helpers.single_keyword("transform-style", "auto flat preserve-3d")} - - <%helpers:longhand name="transform-origin"> - use app_units::Au; - use values::AuExtensionMethods; - use values::specified::{Length, LengthOrPercentage, Percentage}; - - use cssparser::ToCss; - use std::fmt; - - pub mod computed_value { - use values::computed::{Length, LengthOrPercentage}; - - #[derive(Clone, Copy, Debug, PartialEq, HeapSizeOf)] - pub struct T { - pub horizontal: LengthOrPercentage, - pub vertical: LengthOrPercentage, - pub depth: Length, - } - } - - #[derive(Clone, Copy, Debug, PartialEq, HeapSizeOf)] - pub struct SpecifiedValue { - horizontal: LengthOrPercentage, - vertical: LengthOrPercentage, - depth: Length, - } - - impl ToCss for computed_value::T { - fn to_css(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { - try!(self.horizontal.to_css(dest)); - try!(dest.write_str(" ")); - try!(self.vertical.to_css(dest)); - try!(dest.write_str(" ")); - self.depth.to_css(dest) - } - } - - impl ToCss for SpecifiedValue { - fn to_css(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { - try!(self.horizontal.to_css(dest)); - try!(dest.write_str(" ")); - try!(self.vertical.to_css(dest)); - try!(dest.write_str(" ")); - self.depth.to_css(dest) - } - } - - #[inline] - pub fn get_initial_value() -> computed_value::T { - computed_value::T { - horizontal: computed::LengthOrPercentage::Percentage(0.5), - vertical: computed::LengthOrPercentage::Percentage(0.5), - depth: Au(0), - } - } - - pub fn parse(context: &ParserContext, input: &mut Parser) -> Result { - let result = try!(super::parse_origin(context, input)); - Ok(SpecifiedValue { - horizontal: result.horizontal.unwrap_or(LengthOrPercentage::Percentage(Percentage(0.5))), - vertical: result.vertical.unwrap_or(LengthOrPercentage::Percentage(Percentage(0.5))), - depth: result.depth.unwrap_or(Length::Absolute(Au(0))), - }) - } - - impl ToComputedValue for SpecifiedValue { - type ComputedValue = computed_value::T; - - #[inline] - fn to_computed_value(&self, context: &Cx) -> computed_value::T { - computed_value::T { - horizontal: self.horizontal.to_computed_value(context), - vertical: self.vertical.to_computed_value(context), - depth: self.depth.to_computed_value(context), - } - } - } - - - ${helpers.predefined_type("perspective", - "LengthOrNone", - "computed::LengthOrNone::None")} - - <%helpers:longhand name="perspective-origin"> - use values::specified::{LengthOrPercentage, Percentage}; - - use cssparser::ToCss; - use std::fmt; - - pub mod computed_value { - use values::computed::LengthOrPercentage; - - #[derive(Clone, Copy, Debug, PartialEq, HeapSizeOf)] - pub struct T { - pub horizontal: LengthOrPercentage, - pub vertical: LengthOrPercentage, - } - } - - impl ToCss for computed_value::T { - fn to_css(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { - try!(self.horizontal.to_css(dest)); - try!(dest.write_str(" ")); - self.vertical.to_css(dest) - } - } - - #[derive(Clone, Copy, Debug, PartialEq, HeapSizeOf)] - pub struct SpecifiedValue { - horizontal: LengthOrPercentage, - vertical: LengthOrPercentage, - } - - impl ToCss for SpecifiedValue { - fn to_css(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { - try!(self.horizontal.to_css(dest)); - try!(dest.write_str(" ")); - self.vertical.to_css(dest) - } - } - - #[inline] - pub fn get_initial_value() -> computed_value::T { - computed_value::T { - horizontal: computed::LengthOrPercentage::Percentage(0.5), - vertical: computed::LengthOrPercentage::Percentage(0.5), - } - } - - pub fn parse(context: &ParserContext, input: &mut Parser) -> Result { - let result = try!(super::parse_origin(context, input)); - match result.depth { - Some(_) => Err(()), - None => Ok(SpecifiedValue { - horizontal: result.horizontal.unwrap_or(LengthOrPercentage::Percentage(Percentage(0.5))), - vertical: result.vertical.unwrap_or(LengthOrPercentage::Percentage(Percentage(0.5))), - }) - } - } - - impl ToComputedValue for SpecifiedValue { - type ComputedValue = computed_value::T; - - #[inline] - fn to_computed_value(&self, context: &Cx) -> computed_value::T { - computed_value::T { - horizontal: self.horizontal.to_computed_value(context), - vertical: self.vertical.to_computed_value(context), - } - } - } - - - ${helpers.single_keyword("mix-blend-mode", - """normal multiply screen overlay darken lighten color-dodge - color-burn hard-light soft-light difference exclusion hue - saturation color luminosity""", gecko_constant_prefix="NS_STYLE_BLEND")} - - // CSS Image Values and Replaced Content Module Level 3 - // https://drafts.csswg.org/css-images-3/ - - <% data.switch_to_style_struct("Position") %> - - ${helpers.single_keyword("object-fit", "fill contain cover none scale-down", products="gecko")} - - <% data.switch_to_style_struct("InheritedBox") %> - - <%helpers:longhand name="image-rendering"> - - pub mod computed_value { - use cssparser::ToCss; - use std::fmt; - - #[derive(Copy, Clone, Debug, PartialEq, HeapSizeOf, Deserialize, Serialize)] - pub enum T { - Auto, - CrispEdges, - Pixelated, - } - - impl ToCss for T { - fn to_css(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { - match *self { - T::Auto => dest.write_str("auto"), - T::CrispEdges => dest.write_str("crisp-edges"), - T::Pixelated => dest.write_str("pixelated"), - } - } - } - } - - pub type SpecifiedValue = computed_value::T; - - #[inline] - pub fn get_initial_value() -> computed_value::T { - computed_value::T::Auto - } - - pub fn parse(_: &ParserContext, input: &mut Parser) -> Result { - // According to to CSS-IMAGES-3, `optimizespeed` and `optimizequality` are synonyms for - // `auto`. - match_ignore_ascii_case! { - try!(input.expect_ident()), - "auto" => Ok(computed_value::T::Auto), - "optimizespeed" => Ok(computed_value::T::Auto), - "optimizequality" => Ok(computed_value::T::Auto), - "crisp-edges" => Ok(computed_value::T::CrispEdges), - "pixelated" => Ok(computed_value::T::Pixelated), - _ => Err(()) - } - } - - impl ToComputedValue for SpecifiedValue { - type ComputedValue = computed_value::T; - - #[inline] - fn to_computed_value(&self, _: &Cx) -> computed_value::T { - *self - } - } - - - <% data.switch_to_style_struct("Box") %> - - // TODO(pcwalton): Multiple transitions. - <%helpers:longhand name="transition-duration"> - use values::specified::Time; - - pub use self::computed_value::T as SpecifiedValue; - pub use values::specified::Time as SingleSpecifiedValue; - - pub mod computed_value { - use cssparser::ToCss; - use std::fmt; - use values::computed::{TContext, ToComputedValue}; - - pub use values::computed::Time as SingleComputedValue; - - #[derive(Debug, Clone, PartialEq, HeapSizeOf)] - pub struct T(pub Vec); - - impl ToComputedValue for T { - type ComputedValue = T; - - #[inline] - fn to_computed_value(&self, _: &Cx) -> T { - (*self).clone() - } - } - - impl ToCss for T { - fn to_css(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { - if self.0.is_empty() { - return dest.write_str("none") - } - for (i, value) in self.0.iter().enumerate() { - if i != 0 { - try!(dest.write_str(", ")) - } - try!(value.to_css(dest)) - } - Ok(()) - } - } - } - - #[inline] - pub fn parse_one(input: &mut Parser) -> Result { - Time::parse(input) - } - - #[inline] - pub fn get_initial_value() -> computed_value::T { - computed_value::T(vec![get_initial_single_value()]) - } - - #[inline] - pub fn get_initial_single_value() -> Time { - Time(0.0) - } - - pub fn parse(_: &ParserContext, input: &mut Parser) -> Result { - Ok(SpecifiedValue(try!(input.parse_comma_separated(parse_one)))) - } - - - // TODO(pcwalton): Lots more timing functions. - // TODO(pcwalton): Multiple transitions. - <%helpers:longhand name="transition-timing-function"> - use self::computed_value::{StartEnd, TransitionTimingFunction}; - - use euclid::point::Point2D; - - pub use self::computed_value::SingleComputedValue as SingleSpecifiedValue; - pub use self::computed_value::T as SpecifiedValue; - - static EASE: TransitionTimingFunction = TransitionTimingFunction::CubicBezier(Point2D { - x: 0.25, - y: 0.1, - }, Point2D { - x: 0.25, - y: 1.0, - }); - static LINEAR: TransitionTimingFunction = TransitionTimingFunction::CubicBezier(Point2D { - x: 0.0, - y: 0.0, - }, Point2D { - x: 1.0, - y: 1.0, - }); - static EASE_IN: TransitionTimingFunction = TransitionTimingFunction::CubicBezier(Point2D { - x: 0.42, - y: 0.0, - }, Point2D { - x: 1.0, - y: 1.0, - }); - static EASE_OUT: TransitionTimingFunction = TransitionTimingFunction::CubicBezier(Point2D { - x: 0.0, - y: 0.0, - }, Point2D { - x: 0.58, - y: 1.0, - }); - static EASE_IN_OUT: TransitionTimingFunction = - TransitionTimingFunction::CubicBezier(Point2D { - x: 0.42, - y: 0.0, - }, Point2D { - x: 0.58, - y: 1.0, - }); - static STEP_START: TransitionTimingFunction = - TransitionTimingFunction::Steps(1, StartEnd::Start); - static STEP_END: TransitionTimingFunction = - TransitionTimingFunction::Steps(1, StartEnd::End); - - pub mod computed_value { - use cssparser::ToCss; - use euclid::point::Point2D; - use std::fmt; - - pub use self::TransitionTimingFunction as SingleComputedValue; - - #[derive(Copy, Clone, Debug, PartialEq, HeapSizeOf)] - pub enum TransitionTimingFunction { - CubicBezier(Point2D, Point2D), - Steps(u32, StartEnd), - } - - impl ToCss for TransitionTimingFunction { - fn to_css(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { - match *self { - TransitionTimingFunction::CubicBezier(p1, p2) => { - try!(dest.write_str("cubic-bezier(")); - try!(p1.x.to_css(dest)); - try!(dest.write_str(", ")); - try!(p1.y.to_css(dest)); - try!(dest.write_str(", ")); - try!(p2.x.to_css(dest)); - try!(dest.write_str(", ")); - try!(p2.y.to_css(dest)); - dest.write_str(")") - } - TransitionTimingFunction::Steps(steps, start_end) => { - try!(dest.write_str("steps(")); - try!(steps.to_css(dest)); - try!(dest.write_str(", ")); - try!(start_end.to_css(dest)); - dest.write_str(")") - } - } - } - } - - #[derive(Copy, Clone, Debug, PartialEq, HeapSizeOf)] - pub enum StartEnd { - Start, - End, - } - - impl ToCss for StartEnd { - fn to_css(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { - match *self { - StartEnd::Start => dest.write_str("start"), - StartEnd::End => dest.write_str("end"), - } - } - } - - #[derive(Clone, Debug, PartialEq, HeapSizeOf)] - pub struct T(pub Vec); - - impl ToCss for T { - fn to_css(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { - if self.0.is_empty() { - return dest.write_str("none") - } - for (i, value) in self.0.iter().enumerate() { - if i != 0 { - try!(dest.write_str(", ")) - } - try!(value.to_css(dest)) - } - Ok(()) - } - } - } - - impl ToComputedValue for SpecifiedValue { - type ComputedValue = computed_value::T; - - #[inline] - fn to_computed_value(&self, _: &Cx) -> computed_value::T { - (*self).clone() - } - } - - #[inline] - pub fn get_initial_value() -> computed_value::T { - computed_value::T(vec![get_initial_single_value()]) - } - - #[inline] - pub fn get_initial_single_value() -> TransitionTimingFunction { - EASE - } - - pub fn parse_one(input: &mut Parser) -> Result { - if let Ok(function_name) = input.try(|input| input.expect_function()) { - return match_ignore_ascii_case! { - function_name, - "cubic-bezier" => { - let (mut p1x, mut p1y, mut p2x, mut p2y) = (0.0, 0.0, 0.0, 0.0); - try!(input.parse_nested_block(|input| { - p1x = try!(specified::parse_number(input)); - try!(input.expect_comma()); - p1y = try!(specified::parse_number(input)); - try!(input.expect_comma()); - p2x = try!(specified::parse_number(input)); - try!(input.expect_comma()); - p2y = try!(specified::parse_number(input)); - Ok(()) - })); - let (p1, p2) = (Point2D::new(p1x, p1y), Point2D::new(p2x, p2y)); - Ok(TransitionTimingFunction::CubicBezier(p1, p2)) - }, - "steps" => { - let (mut step_count, mut start_end) = (0, computed_value::StartEnd::Start); - try!(input.parse_nested_block(|input| { - step_count = try!(specified::parse_integer(input)); - try!(input.expect_comma()); - start_end = try!(match_ignore_ascii_case! { - try!(input.expect_ident()), - "start" => Ok(computed_value::StartEnd::Start), - "end" => Ok(computed_value::StartEnd::End), - _ => Err(()) - }); - Ok(()) - })); - Ok(TransitionTimingFunction::Steps(step_count as u32, start_end)) - }, - _ => Err(()) - } - } - match_ignore_ascii_case! { - try!(input.expect_ident()), - "ease" => Ok(EASE), - "linear" => Ok(LINEAR), - "ease-in" => Ok(EASE_IN), - "ease-out" => Ok(EASE_OUT), - "ease-in-out" => Ok(EASE_IN_OUT), - "step-start" => Ok(STEP_START), - "step-end" => Ok(STEP_END), - _ => Err(()) - } - } - - pub fn parse(_: &ParserContext, input: &mut Parser) -> Result { - Ok(SpecifiedValue(try!(input.parse_comma_separated(parse_one)))) - } - - - // TODO(pcwalton): Lots more properties. - <%helpers:longhand name="transition-property"> - use self::computed_value::TransitionProperty; - - pub use self::computed_value::SingleComputedValue as SingleSpecifiedValue; - pub use self::computed_value::T as SpecifiedValue; - - pub mod computed_value { - use cssparser::ToCss; - use std::fmt; - - pub use self::TransitionProperty as SingleComputedValue; - - #[derive(Copy, Clone, Debug, PartialEq, HeapSizeOf)] - pub enum TransitionProperty { - All, - BackgroundColor, - BackgroundPosition, - BorderBottomColor, - BorderBottomWidth, - BorderLeftColor, - BorderLeftWidth, - BorderRightColor, - BorderRightWidth, - BorderSpacing, - BorderTopColor, - BorderTopWidth, - Bottom, - Color, - Clip, - FontSize, - FontWeight, - Height, - Left, - LetterSpacing, - LineHeight, - MarginBottom, - MarginLeft, - MarginRight, - MarginTop, - MaxHeight, - MaxWidth, - MinHeight, - MinWidth, - Opacity, - OutlineColor, - OutlineWidth, - PaddingBottom, - PaddingLeft, - PaddingRight, - PaddingTop, - Right, - TextIndent, - TextShadow, - Top, - Transform, - VerticalAlign, - Visibility, - Width, - WordSpacing, - ZIndex, - } - - pub static ALL_TRANSITION_PROPERTIES: [TransitionProperty; 45] = [ - TransitionProperty::BackgroundColor, - TransitionProperty::BackgroundPosition, - TransitionProperty::BorderBottomColor, - TransitionProperty::BorderBottomWidth, - TransitionProperty::BorderLeftColor, - TransitionProperty::BorderLeftWidth, - TransitionProperty::BorderRightColor, - TransitionProperty::BorderRightWidth, - TransitionProperty::BorderSpacing, - TransitionProperty::BorderTopColor, - TransitionProperty::BorderTopWidth, - TransitionProperty::Bottom, - TransitionProperty::Color, - TransitionProperty::Clip, - TransitionProperty::FontSize, - TransitionProperty::FontWeight, - TransitionProperty::Height, - TransitionProperty::Left, - TransitionProperty::LetterSpacing, - TransitionProperty::LineHeight, - TransitionProperty::MarginBottom, - TransitionProperty::MarginLeft, - TransitionProperty::MarginRight, - TransitionProperty::MarginTop, - TransitionProperty::MaxHeight, - TransitionProperty::MaxWidth, - TransitionProperty::MinHeight, - TransitionProperty::MinWidth, - TransitionProperty::Opacity, - TransitionProperty::OutlineColor, - TransitionProperty::OutlineWidth, - TransitionProperty::PaddingBottom, - TransitionProperty::PaddingLeft, - TransitionProperty::PaddingRight, - TransitionProperty::PaddingTop, - TransitionProperty::Right, - TransitionProperty::TextIndent, - TransitionProperty::TextShadow, - TransitionProperty::Top, - TransitionProperty::Transform, - TransitionProperty::VerticalAlign, - TransitionProperty::Visibility, - TransitionProperty::Width, - TransitionProperty::WordSpacing, - TransitionProperty::ZIndex, - ]; - - impl ToCss for TransitionProperty { - fn to_css(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { - match *self { - TransitionProperty::All => dest.write_str("all"), - TransitionProperty::BackgroundColor => dest.write_str("background-color"), - TransitionProperty::BackgroundPosition => dest.write_str("background-position"), - TransitionProperty::BorderBottomColor => dest.write_str("border-bottom-color"), - TransitionProperty::BorderBottomWidth => dest.write_str("border-bottom-width"), - TransitionProperty::BorderLeftColor => dest.write_str("border-left-color"), - TransitionProperty::BorderLeftWidth => dest.write_str("border-left-width"), - TransitionProperty::BorderRightColor => dest.write_str("border-right-color"), - TransitionProperty::BorderRightWidth => dest.write_str("border-right-width"), - TransitionProperty::BorderSpacing => dest.write_str("border-spacing"), - TransitionProperty::BorderTopColor => dest.write_str("border-top-color"), - TransitionProperty::BorderTopWidth => dest.write_str("border-top-width"), - TransitionProperty::Bottom => dest.write_str("bottom"), - TransitionProperty::Color => dest.write_str("color"), - TransitionProperty::Clip => dest.write_str("clip"), - TransitionProperty::FontSize => dest.write_str("font-size"), - TransitionProperty::FontWeight => dest.write_str("font-weight"), - TransitionProperty::Height => dest.write_str("height"), - TransitionProperty::Left => dest.write_str("left"), - TransitionProperty::LetterSpacing => dest.write_str("letter-spacing"), - TransitionProperty::LineHeight => dest.write_str("line-height"), - TransitionProperty::MarginBottom => dest.write_str("margin-bottom"), - TransitionProperty::MarginLeft => dest.write_str("margin-left"), - TransitionProperty::MarginRight => dest.write_str("margin-right"), - TransitionProperty::MarginTop => dest.write_str("margin-top"), - TransitionProperty::MaxHeight => dest.write_str("max-height"), - TransitionProperty::MaxWidth => dest.write_str("max-width"), - TransitionProperty::MinHeight => dest.write_str("min-height"), - TransitionProperty::MinWidth => dest.write_str("min-width"), - TransitionProperty::Opacity => dest.write_str("opacity"), - TransitionProperty::OutlineColor => dest.write_str("outline-color"), - TransitionProperty::OutlineWidth => dest.write_str("outline-width"), - TransitionProperty::PaddingBottom => dest.write_str("padding-bottom"), - TransitionProperty::PaddingLeft => dest.write_str("padding-left"), - TransitionProperty::PaddingRight => dest.write_str("padding-right"), - TransitionProperty::PaddingTop => dest.write_str("padding-top"), - TransitionProperty::Right => dest.write_str("right"), - TransitionProperty::TextIndent => dest.write_str("text-indent"), - TransitionProperty::TextShadow => dest.write_str("text-shadow"), - TransitionProperty::Top => dest.write_str("top"), - TransitionProperty::Transform => dest.write_str("transform"), - TransitionProperty::VerticalAlign => dest.write_str("vertical-align"), - TransitionProperty::Visibility => dest.write_str("visibility"), - TransitionProperty::Width => dest.write_str("width"), - TransitionProperty::WordSpacing => dest.write_str("word-spacing"), - TransitionProperty::ZIndex => dest.write_str("z-index"), - } - } - } - - #[derive(Clone, Debug, PartialEq, HeapSizeOf)] - pub struct T(pub Vec); - - impl ToCss for T { - fn to_css(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { - if self.0.is_empty() { - return dest.write_str("none") - } - for (i, value) in self.0.iter().enumerate() { - if i != 0 { - try!(dest.write_str(", ")) - } - try!(value.to_css(dest)) - } - Ok(()) - } - } - } - - #[inline] - pub fn get_initial_value() -> computed_value::T { - computed_value::T(Vec::new()) - } - - pub fn parse_one(input: &mut Parser) -> Result { - match_ignore_ascii_case! { - try!(input.expect_ident()), - "all" => Ok(TransitionProperty::All), - "background-color" => Ok(TransitionProperty::BackgroundColor), - "background-position" => Ok(TransitionProperty::BackgroundPosition), - "border-bottom-color" => Ok(TransitionProperty::BorderBottomColor), - "border-bottom-width" => Ok(TransitionProperty::BorderBottomWidth), - "border-left-color" => Ok(TransitionProperty::BorderLeftColor), - "border-left-width" => Ok(TransitionProperty::BorderLeftWidth), - "border-right-color" => Ok(TransitionProperty::BorderRightColor), - "border-right-width" => Ok(TransitionProperty::BorderRightWidth), - "border-spacing" => Ok(TransitionProperty::BorderSpacing), - "border-top-color" => Ok(TransitionProperty::BorderTopColor), - "border-top-width" => Ok(TransitionProperty::BorderTopWidth), - "bottom" => Ok(TransitionProperty::Bottom), - "color" => Ok(TransitionProperty::Color), - "clip" => Ok(TransitionProperty::Clip), - "font-size" => Ok(TransitionProperty::FontSize), - "font-weight" => Ok(TransitionProperty::FontWeight), - "height" => Ok(TransitionProperty::Height), - "left" => Ok(TransitionProperty::Left), - "letter-spacing" => Ok(TransitionProperty::LetterSpacing), - "line-height" => Ok(TransitionProperty::LineHeight), - "margin-bottom" => Ok(TransitionProperty::MarginBottom), - "margin-left" => Ok(TransitionProperty::MarginLeft), - "margin-right" => Ok(TransitionProperty::MarginRight), - "margin-top" => Ok(TransitionProperty::MarginTop), - "max-height" => Ok(TransitionProperty::MaxHeight), - "max-width" => Ok(TransitionProperty::MaxWidth), - "min-height" => Ok(TransitionProperty::MinHeight), - "min-width" => Ok(TransitionProperty::MinWidth), - "opacity" => Ok(TransitionProperty::Opacity), - "outline-color" => Ok(TransitionProperty::OutlineColor), - "outline-width" => Ok(TransitionProperty::OutlineWidth), - "padding-bottom" => Ok(TransitionProperty::PaddingBottom), - "padding-left" => Ok(TransitionProperty::PaddingLeft), - "padding-right" => Ok(TransitionProperty::PaddingRight), - "padding-top" => Ok(TransitionProperty::PaddingTop), - "right" => Ok(TransitionProperty::Right), - "text-indent" => Ok(TransitionProperty::TextIndent), - "text-shadow" => Ok(TransitionProperty::TextShadow), - "top" => Ok(TransitionProperty::Top), - "transform" => Ok(TransitionProperty::Transform), - "vertical-align" => Ok(TransitionProperty::VerticalAlign), - "visibility" => Ok(TransitionProperty::Visibility), - "width" => Ok(TransitionProperty::Width), - "word-spacing" => Ok(TransitionProperty::WordSpacing), - "z-index" => Ok(TransitionProperty::ZIndex), - _ => Err(()) - } - } - - pub fn parse(_: &ParserContext, input: &mut Parser) -> Result { - Ok(SpecifiedValue(try!(input.parse_comma_separated(parse_one)))) - } - - impl ToComputedValue for SpecifiedValue { - type ComputedValue = computed_value::T; - - #[inline] - fn to_computed_value(&self, _: &Cx) -> computed_value::T { - (*self).clone() - } - } - - - <%helpers:longhand name="transition-delay"> - pub use properties::longhands::transition_duration::{SingleSpecifiedValue, SpecifiedValue}; - pub use properties::longhands::transition_duration::{computed_value}; - pub use properties::longhands::transition_duration::{get_initial_single_value}; - pub use properties::longhands::transition_duration::{get_initial_value, parse, parse_one}; - - - // CSS Flexible Box Layout Module Level 1 - // http://www.w3.org/TR/css3-flexbox/ - - <% data.switch_to_style_struct("Position") %> - - // Flex container properties - ${helpers.single_keyword("flex-direction", "row row-reverse column column-reverse", experimental=True)} - - // https://drafts.csswg.org/css-flexbox/#propdef-order - <%helpers:longhand name="order"> - use values::computed::ComputedValueAsSpecified; - - impl ComputedValueAsSpecified for SpecifiedValue {} - - pub type SpecifiedValue = computed_value::T; - - pub mod computed_value { - pub type T = i32; - } - - #[inline] - pub fn get_initial_value() -> computed_value::T { - 0 - } - - fn parse(_context: &ParserContext, input: &mut Parser) -> Result { - specified::parse_integer(input) - } - - - ${helpers.predefined_type("flex-basis", "LengthOrPercentageOrAutoOrContent", - "computed::LengthOrPercentageOrAutoOrContent::Auto")} - - ${helpers.single_keyword("flex-wrap", "nowrap wrap wrap-reverse", products="gecko")} - - // SVG 1.1 (Second Edition) - // https://www.w3.org/TR/SVG/ - <% data.new_style_struct("SVGInherited", inherited=True, gecko_ffi_name="nsStyleSVG") %> - - // Section 10 - Text - - ${helpers.single_keyword("text-anchor", "start middle end", products="gecko")} - - // Section 11 - Painting: Filling, Stroking and Marker Symbols - ${helpers.single_keyword("color-interpolation", "auto sRGB linearRGB", products="gecko")} - - ${helpers.single_keyword("color-interpolation-filters", "auto sRGB linearRGB", - products="gecko", gecko_constant_prefix="NS_STYLE_COLOR_INTERPOLATION")} - - ${helpers.single_keyword("fill-rule", "nonzero evenodd", products="gecko")} - - ${helpers.single_keyword("shape-rendering", "auto optimizeSpeed crispEdges geometricPrecision", - products="gecko")} - - ${helpers.single_keyword("stroke-linecap", "butt round square", products="gecko")} - - ${helpers.single_keyword("stroke-linejoin", "miter round bevel", products="gecko")} - - // Section 14 - Clipping, Masking and Compositing - ${helpers.single_keyword("clip-rule", "nonzero evenodd", - products="gecko", gecko_constant_prefix="NS_STYLE_FILL_RULE")} - - <% data.new_style_struct("SVG", inherited=False, gecko_ffi_name="nsStyleSVGReset") %> - - ${helpers.single_keyword("dominant-baseline", - """auto use-script no-change reset-size ideographic alphabetic hanging - mathematical central middle text-after-edge text-before-edge""", - products="gecko")} - - ${helpers.single_keyword("vector-effect", "none non-scaling-stroke", products="gecko")} - - // CSS Masking Module Level 1 - // https://www.w3.org/TR/css-masking-1/ - ${helpers.single_keyword("mask-type", "luminance alpha", products="gecko")} + <%include file="/longhand/table.mako.rs" /> + <%include file="/longhand/text.mako.rs" /> + <%include file="/longhand/svg_inherited.mako.rs" /> + <%include file="/longhand/svg.mako.rs" /> }