diff options
-rw-r--r-- | components/style/properties/gecko.mako.rs | 43 | ||||
-rw-r--r-- | components/style/properties/longhand/counters.mako.rs | 48 | ||||
-rw-r--r-- | components/style/properties/longhand/list.mako.rs | 94 | ||||
-rw-r--r-- | components/style/properties/shorthand/list.mako.rs | 34 | ||||
-rw-r--r-- | components/style/values/generics/mod.rs | 50 |
5 files changed, 200 insertions, 69 deletions
diff --git a/components/style/properties/gecko.mako.rs b/components/style/properties/gecko.mako.rs index 49cf7695833..146c8827b9d 100644 --- a/components/style/properties/gecko.mako.rs +++ b/components/style/properties/gecko.mako.rs @@ -2987,29 +2987,12 @@ fn static_assert() { } pub fn set_list_style_type(&mut self, v: longhands::list_style_type::computed_value::T) { - use properties::longhands::list_style_type::computed_value::T as Keyword; - <% - keyword = data.longhands_by_name["list-style-type"].keyword - # The first four are @counter-styles - # The rest have special fallback behavior - special = """upper-roman lower-roman upper-alpha lower-alpha - japanese-informal japanese-formal korean-hangul-formal korean-hanja-informal - korean-hanja-formal simp-chinese-informal simp-chinese-formal - trad-chinese-informal trad-chinese-formal""".split() - %> - let result = match v { - % for value in keyword.values_for('gecko'): - % if value in special: - // Special keywords are implemented as @counter-styles - // and need to be manually set as strings - Keyword::${to_rust_ident(value)} => structs::${keyword.gecko_constant("none")}, - % else: - Keyword::${to_rust_ident(value)} => - structs::${keyword.gecko_constant(value)}, - % endif - % endfor + use values::generics::CounterStyleOrNone; + let name = match v.0 { + CounterStyleOrNone::None_ => atom!("none"), + CounterStyleOrNone::Name(name) => name.0, }; - unsafe { Gecko_SetListStyleType(&mut self.gecko, result as u32); } + unsafe { Gecko_SetListStyleType(&mut self.gecko, name.as_ptr()); } } @@ -4072,7 +4055,8 @@ clip-path pub fn set_content(&mut self, v: longhands::content::computed_value::T) { use properties::longhands::content::computed_value::T; use properties::longhands::content::computed_value::ContentItem; - use style_traits::ToCss; + use values::generics::CounterStyleOrNone; + use gecko_bindings::structs::nsCSSValue; use gecko_bindings::structs::nsStyleContentType::*; use gecko_bindings::bindings::Gecko_ClearAndResizeStyleContents; @@ -4086,6 +4070,13 @@ clip-path ptr } + fn set_counter_style(style: CounterStyleOrNone, dest: &mut nsCSSValue) { + dest.set_atom_ident(match style { + CounterStyleOrNone::None_ => atom!("none"), + CounterStyleOrNone::Name(name) => name.0, + }); + } + match v { T::none | T::normal => { @@ -4147,8 +4138,7 @@ clip-path } let mut array = unsafe { &mut **self.gecko.mContents[i].mContent.mCounters.as_mut() }; array[0].set_string(&name); - // When we support <custom-ident> values for list-style-type this will need to be updated - array[1].set_atom_ident(style.to_css_string().into()); + set_counter_style(style, &mut array[1]); } ContentItem::Counters(name, sep, style) => { unsafe { @@ -4158,8 +4148,7 @@ clip-path let mut array = unsafe { &mut **self.gecko.mContents[i].mContent.mCounters.as_mut() }; array[0].set_string(&name); array[1].set_string(&sep); - // When we support <custom-ident> values for list-style-type this will need to be updated - array[2].set_atom_ident(style.to_css_string().into()); + set_counter_style(style, &mut array[2]); } ContentItem::Url(ref url) => { unsafe { diff --git a/components/style/properties/longhand/counters.mako.rs b/components/style/properties/longhand/counters.mako.rs index 054746bdc7a..4c4ac955d5b 100644 --- a/components/style/properties/longhand/counters.mako.rs +++ b/components/style/properties/longhand/counters.mako.rs @@ -11,9 +11,12 @@ use cssparser::Token; use std::ascii::AsciiExt; use values::computed::ComputedValueAsSpecified; + #[cfg(feature = "gecko")] + use values::generics::CounterStyleOrNone; use values::specified::url::SpecifiedUrl; use values::HasViewportPercentage; + #[cfg(feature = "servo")] use super::list_style_type; pub use self::computed_value::T as SpecifiedValue; @@ -23,22 +26,25 @@ no_viewport_percentage!(SpecifiedValue); pub mod computed_value { - use super::super::list_style_type; - use cssparser; use std::fmt; use style_traits::ToCss; use values::specified::url::SpecifiedUrl; + #[cfg(feature = "servo")] + type CounterStyleType = super::super::list_style_type::computed_value::T; + #[cfg(feature = "gecko")] + type CounterStyleType = ::values::generics::CounterStyleOrNone; + #[derive(Debug, PartialEq, Eq, Clone)] #[cfg_attr(feature = "servo", derive(HeapSizeOf))] pub enum ContentItem { /// Literal string content. String(String), /// `counter(name, style)`. - Counter(String, list_style_type::computed_value::T), + Counter(String, CounterStyleType), /// `counters(name, separator, style)`. - Counters(String, String, list_style_type::computed_value::T), + Counters(String, String, CounterStyleType), /// `open-quote`. OpenQuote, /// `close-quote`. @@ -64,20 +70,20 @@ ContentItem::String(ref s) => { cssparser::serialize_string(&**s, dest) } - ContentItem::Counter(ref s, ref list_style_type) => { + ContentItem::Counter(ref s, ref counter_style) => { try!(dest.write_str("counter(")); try!(cssparser::serialize_identifier(&**s, dest)); try!(dest.write_str(", ")); - try!(list_style_type.to_css(dest)); + try!(counter_style.to_css(dest)); dest.write_str(")") } - ContentItem::Counters(ref s, ref separator, ref list_style_type) => { + ContentItem::Counters(ref s, ref separator, ref counter_style) => { try!(dest.write_str("counters(")); 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)); + try!(counter_style.to_css(dest)); dest.write_str(")") } ContentItem::OpenQuote => dest.write_str("open-quote"), @@ -134,6 +140,22 @@ computed_value::T::normal } + #[cfg(feature = "servo")] + fn parse_counter_style(context: &ParserContext, input: &mut Parser) -> list_style_type::computed_value::T { + input.try(|input| { + input.expect_comma()?; + list_style_type::parse(context, input) + }).unwrap_or(list_style_type::computed_value::T::decimal) + } + + #[cfg(feature = "gecko")] + fn parse_counter_style(context: &ParserContext, input: &mut Parser) -> CounterStyleOrNone { + input.try(|input| { + input.expect_comma()?; + CounterStyleOrNone::parse(context, input) + }).unwrap_or(CounterStyleOrNone::decimal()) + } + // normal | none | [ <string> | <counter> | open-quote | close-quote | no-open-quote | // no-close-quote ]+ // TODO: <uri>, attr(<identifier>) @@ -162,20 +184,14 @@ 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); + let style = parse_counter_style(context, input); 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); + let style = parse_counter_style(context, input); Ok(ContentItem::Counters(name, separator, style)) }), % if product == "gecko": diff --git a/components/style/properties/longhand/list.mako.rs b/components/style/properties/longhand/list.mako.rs index ece28aaf4ec..14084f894d2 100644 --- a/components/style/properties/longhand/list.mako.rs +++ b/components/style/properties/longhand/list.mako.rs @@ -21,21 +21,85 @@ ${helpers.single_keyword("list-style-position", "outside inside", animation_valu // we may need to look into this and handle these differently. // // [1]: http://dev.w3.org/csswg/css-counter-styles/ -${helpers.single_keyword("list-style-type", """ - disc none circle square decimal disclosure-open disclosure-closed lower-alpha upper-alpha -""", extra_servo_values="""arabic-indic bengali cambodian cjk-decimal devanagari - gujarati gurmukhi kannada khmer lao malayalam mongolian - myanmar oriya persian telugu thai tibetan cjk-earthly-branch - cjk-heavenly-stem lower-greek hiragana hiragana-iroha katakana - katakana-iroha""", - extra_gecko_values="""japanese-informal japanese-formal korean-hangul-formal - korean-hanja-formal korean-hanja-informal simp-chinese-informal simp-chinese-formal - trad-chinese-informal trad-chinese-formal ethiopic-numeric upper-roman lower-roman - """, - gecko_constant_prefix="NS_STYLE_LIST_STYLE", - needs_conversion="True", - animation_value_type="none", - spec="https://drafts.csswg.org/css-lists/#propdef-list-style-type")} +% if product == "servo": + ${helpers.single_keyword("list-style-type", """ + disc none circle square decimal disclosure-open disclosure-closed lower-alpha upper-alpha + arabic-indic bengali cambodian cjk-decimal devanagari gujarati gurmukhi kannada khmer lao + malayalam mongolian myanmar oriya persian telugu thai tibetan cjk-earthly-branch + cjk-heavenly-stem lower-greek hiragana hiragana-iroha katakana katakana-iroha""", + needs_conversion="True", + animation_value_type="none", + spec="https://drafts.csswg.org/css-lists/#propdef-list-style-type")} +% else: + <%helpers:longhand name="list-style-type" animation_value_type="none" + spec="https://drafts.csswg.org/css-lists/#propdef-list-style-type"> + use std::fmt; + use style_traits::ToCss; + use values::CustomIdent; + use values::HasViewportPercentage; + use values::computed::ComputedValueAsSpecified; + use values::generics::CounterStyleOrNone; + + pub use self::computed_value::T as SpecifiedValue; + + pub mod computed_value { + use values::generics::CounterStyleOrNone; + + /// <counter-style> | none + #[derive(Debug, Clone, PartialEq, Eq)] + pub struct T(pub CounterStyleOrNone); + } + + impl ComputedValueAsSpecified for SpecifiedValue {} + no_viewport_percentage!(SpecifiedValue); + + impl ToCss for SpecifiedValue { + fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { + self.0.to_css(dest) + } + } + + #[cfg(feature = "gecko")] + impl SpecifiedValue { + /// Convert from gecko keyword to list-style-type. + /// + /// This should only be used for mapping type attribute to + /// list-style-type, and thus only values possible in that + /// attribute is considered here. + pub fn from_gecko_keyword(value: u32) -> Self { + use gecko_bindings::structs; + SpecifiedValue(if value == structs::NS_STYLE_LIST_STYLE_NONE { + CounterStyleOrNone::None_ + } else { + <% + values = """disc circle square decimal lower-roman + upper-roman lower-alpha upper-alpha""".split() + %> + CounterStyleOrNone::Name(CustomIdent(match value { + % for style in values: + structs::NS_STYLE_LIST_STYLE_${style.replace('-', '_').upper()} => atom!("${style}"), + % endfor + _ => unreachable!("Unknown counter style keyword value"), + })) + }) + } + } + + #[inline] + pub fn get_initial_value() -> computed_value::T { + computed_value::T(CounterStyleOrNone::disc()) + } + + #[inline] + pub fn get_initial_specified_value() -> SpecifiedValue { + SpecifiedValue(CounterStyleOrNone::disc()) + } + + pub fn parse(context: &ParserContext, input: &mut Parser) -> Result<SpecifiedValue, ()> { + CounterStyleOrNone::parse(context, input).map(SpecifiedValue) + } + </%helpers:longhand> +% endif <%helpers:longhand name="list-style-image" animation_value_type="none" boxed="${product == 'gecko'}" diff --git a/components/style/properties/shorthand/list.mako.rs b/components/style/properties/shorthand/list.mako.rs index 55a3448cf3f..11a9e170bd1 100644 --- a/components/style/properties/shorthand/list.mako.rs +++ b/components/style/properties/shorthand/list.mako.rs @@ -25,14 +25,6 @@ continue } - if list_style_type.is_none() { - if let Ok(value) = input.try(|input| list_style_type::parse(context, input)) { - list_style_type = Some(value); - any = true; - continue - } - } - if image.is_none() { if let Ok(value) = input.try(|input| list_style_image::parse(context, input)) { image = Some(value); @@ -48,11 +40,31 @@ continue } } + + // list-style-type must be checked the last, because it accepts + // arbitrary identifier for custom counter style, and thus may + // affect values of list-style-position. + if list_style_type.is_none() { + if let Ok(value) = input.try(|input| list_style_type::parse(context, input)) { + list_style_type = Some(value); + any = true; + continue + } + } break } let position = unwrap_or_initial!(list_style_position, position); + fn list_style_type_none() -> list_style_type::SpecifiedValue { + % if product == "servo": + list_style_type::SpecifiedValue::none + % else: + use values::generics::CounterStyleOrNone; + list_style_type::SpecifiedValue(CounterStyleOrNone::None_) + % endif + } + // If there are two `none`s, then we can't have a type or image; if there is one `none`, // then we can't have both a type *and* an image; if there is no `none` then we're fine as // long as we parsed something. @@ -61,14 +73,14 @@ Ok(Longhands { list_style_position: position, list_style_image: list_style_image::SpecifiedValue(Either::Second(None_)), - list_style_type: list_style_type::SpecifiedValue::none, + list_style_type: list_style_type_none(), }) } (true, 1, None, Some(image)) => { Ok(Longhands { list_style_position: position, list_style_image: image, - list_style_type: list_style_type::SpecifiedValue::none, + list_style_type: list_style_type_none(), }) } (true, 1, Some(list_style_type), None) => { @@ -82,7 +94,7 @@ Ok(Longhands { list_style_position: position, list_style_image: list_style_image::SpecifiedValue(Either::Second(None_)), - list_style_type: list_style_type::SpecifiedValue::none, + list_style_type: list_style_type_none(), }) } (true, 0, list_style_type, image) => { diff --git a/components/style/values/generics/mod.rs b/components/style/values/generics/mod.rs index 604d6e21238..9ad4668f4da 100644 --- a/components/style/values/generics/mod.rs +++ b/components/style/values/generics/mod.rs @@ -5,9 +5,13 @@ //! Generic types that share their serialization implementations //! for both specified and computed values. +use counter_style::parse_counter_style_name; +use cssparser::Parser; use euclid::size::Size2D; +use parser::{Parse, ParserContext}; use std::fmt; use style_traits::ToCss; +use super::CustomIdent; use super::HasViewportPercentage; use super::computed::{Context, ToComputedValue}; @@ -75,3 +79,49 @@ impl<L: ToComputedValue> ToComputedValue for BorderRadiusSize<L> { BorderRadiusSize(Size2D::new(w, h)) } } + +/// https://drafts.csswg.org/css-counter-styles/#typedef-counter-style +/// +/// Since wherever <counter-style> is used, 'none' is a valid value as +/// well, we combine them into one type to make code simpler. +#[derive(Clone, PartialEq, Eq, Debug)] +pub enum CounterStyleOrNone { + /// none + None_, + /// <counter-style-name> + Name(CustomIdent), +} + +impl CounterStyleOrNone { + /// disc value + pub fn disc() -> Self { + CounterStyleOrNone::Name(CustomIdent(atom!("disc"))) + } + + /// decimal value + pub fn decimal() -> Self { + CounterStyleOrNone::Name(CustomIdent(atom!("decimal"))) + } +} + +no_viewport_percentage!(CounterStyleOrNone); + +impl Parse for CounterStyleOrNone { + fn parse(_: &ParserContext, input: &mut Parser) -> Result<Self, ()> { + input.try(|input| { + parse_counter_style_name(input).map(CounterStyleOrNone::Name) + }).or_else(|_| { + input.expect_ident_matching("none").map(|_| CounterStyleOrNone::None_) + }) + } +} + +impl ToCss for CounterStyleOrNone { + #[inline] + fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { + match self { + &CounterStyleOrNone::None_ => dest.write_str("none"), + &CounterStyleOrNone::Name(ref name) => name.to_css(dest), + } + } +} |