mirror of
https://github.com/servo/servo.git
synced 2025-06-24 17:14:33 +01:00
Make stylo use counter-style for list-style-type and counter functions.
This commit is contained in:
parent
3e00a91e20
commit
ff1ac8346f
5 changed files with 200 additions and 69 deletions
|
@ -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 {
|
||||
|
|
|
@ -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":
|
||||
|
|
|
@ -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'}"
|
||||
|
|
|
@ -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) => {
|
||||
|
|
|
@ -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),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue