aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--components/style/properties/gecko.mako.rs43
-rw-r--r--components/style/properties/longhand/counters.mako.rs48
-rw-r--r--components/style/properties/longhand/list.mako.rs94
-rw-r--r--components/style/properties/shorthand/list.mako.rs34
-rw-r--r--components/style/values/generics/mod.rs50
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),
+ }
+ }
+}