Add initial style system support for @counter-style rules

This commit is contained in:
Simon Sapin 2017-04-14 07:38:54 +02:00
parent 5a8e3308c1
commit 797f40b0a3
5 changed files with 194 additions and 8 deletions

View file

@ -78,6 +78,7 @@ impl CSSRule {
StyleCssRule::Import(s) => Root::upcast(CSSImportRule::new(window, parent_stylesheet, s)), StyleCssRule::Import(s) => Root::upcast(CSSImportRule::new(window, parent_stylesheet, s)),
StyleCssRule::Style(s) => Root::upcast(CSSStyleRule::new(window, parent_stylesheet, s)), StyleCssRule::Style(s) => Root::upcast(CSSStyleRule::new(window, parent_stylesheet, s)),
StyleCssRule::FontFace(s) => Root::upcast(CSSFontFaceRule::new(window, parent_stylesheet, s)), StyleCssRule::FontFace(s) => Root::upcast(CSSFontFaceRule::new(window, parent_stylesheet, s)),
StyleCssRule::CounterStyle(_) => unimplemented!(),
StyleCssRule::Keyframes(s) => Root::upcast(CSSKeyframesRule::new(window, parent_stylesheet, s)), StyleCssRule::Keyframes(s) => Root::upcast(CSSKeyframesRule::new(window, parent_stylesheet, s)),
StyleCssRule::Media(s) => Root::upcast(CSSMediaRule::new(window, parent_stylesheet, s)), StyleCssRule::Media(s) => Root::upcast(CSSMediaRule::new(window, parent_stylesheet, s)),
StyleCssRule::Namespace(s) => Root::upcast(CSSNamespaceRule::new(window, parent_stylesheet, s)), StyleCssRule::Namespace(s) => Root::upcast(CSSNamespaceRule::new(window, parent_stylesheet, s)),

View file

@ -0,0 +1,150 @@
/* 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/. */
//! The [`@counter-style`][counter-style] at-rule.
//!
//! [counter-style]: https://drafts.csswg.org/css-counter-styles/
use cssparser::{AtRuleParser, DeclarationListParser, DeclarationParser, Parser};
#[cfg(feature = "gecko")] use gecko::rules::CounterStyleDescriptors;
#[cfg(feature = "gecko")] use gecko_bindings::structs::nsCSSCounterDesc;
use parser::{ParserContext, log_css_error, Parse};
use shared_lock::{SharedRwLockReadGuard, ToCssWithGuard};
use std::fmt;
use style_traits::ToCss;
use values::CustomIdent;
/// Parse the body (inside `{}`) of an @counter-style rule
pub fn parse_counter_style_body(name: CustomIdent, context: &ParserContext, input: &mut Parser)
-> Result<CounterStyleRule, ()> {
let mut rule = CounterStyleRule::initial(name);
{
let parser = CounterStyleRuleParser {
context: context,
rule: &mut rule,
};
let mut iter = DeclarationListParser::new(input, parser);
while let Some(declaration) = iter.next() {
if let Err(range) = declaration {
let pos = range.start;
let message = format!("Unsupported @counter-style descriptor declaration: '{}'",
iter.input.slice(range));
log_css_error(iter.input, pos, &*message, context);
}
}
}
Ok(rule)
}
struct CounterStyleRuleParser<'a, 'b: 'a> {
context: &'a ParserContext<'b>,
rule: &'a mut CounterStyleRule,
}
/// Default methods reject all at rules.
impl<'a, 'b> AtRuleParser for CounterStyleRuleParser<'a, 'b> {
type Prelude = ();
type AtRule = ();
}
macro_rules! counter_style_descriptors {
(
$( #[$doc: meta] $name: tt $ident: ident / $gecko_ident: ident: $ty: ty = $initial: expr, )+
) => {
/// An @counter-style rule
#[derive(Debug)]
pub struct CounterStyleRule {
name: CustomIdent,
$(
#[$doc]
$ident: $ty,
)+
}
impl CounterStyleRule {
fn initial(name: CustomIdent) -> Self {
CounterStyleRule {
name: name,
$(
$ident: $initial,
)+
}
}
/// Convert to Gecko types
#[cfg(feature = "gecko")]
pub fn set_descriptors(&self, descriptors: &mut CounterStyleDescriptors) {
$(
descriptors[nsCSSCounterDesc::$gecko_ident as usize].set_from(&self.$ident)
)*
}
}
impl<'a, 'b> DeclarationParser for CounterStyleRuleParser<'a, 'b> {
type Declaration = ();
fn parse_value(&mut self, name: &str, input: &mut Parser) -> Result<(), ()> {
match_ignore_ascii_case! { name,
$(
$name => {
// DeclarationParser also calls parse_entirely
// so wed normally not need to,
// but in this case we do because we set the value as a side effect
// rather than returning it.
let value = input.parse_entirely(|i| Parse::parse(self.context, i))?;
self.rule.$ident = value
}
)*
_ => return Err(())
}
Ok(())
}
}
impl ToCssWithGuard for CounterStyleRule {
fn to_css<W>(&self, _guard: &SharedRwLockReadGuard, dest: &mut W) -> fmt::Result
where W: fmt::Write {
dest.write_str("@counter-style ")?;
self.name.to_css(dest)?;
dest.write_str(" {\n")?;
$(
dest.write_str(concat!(" ", $name, ": "))?;
ToCss::to_css(&self.$ident, dest)?;
dest.write_str(";\n")?;
)+
dest.write_str("}")
}
}
}
}
counter_style_descriptors! {
/// The algorithm for constructing a string representation of a counter value
"system" system / eCSSCounterDesc_System: System = System::Symbolic,
}
/// Value of the 'system' descriptor
#[derive(Debug)]
pub enum System {
/// Cycles through provided symbols, doubling, tripling, etc.
Symbolic,
}
impl Parse for System {
fn parse(_context: &ParserContext, input: &mut Parser) -> Result<Self, ()> {
match_ignore_ascii_case! { &input.expect_ident()?,
"symbolic" => Ok(System::Symbolic),
_ => Err(())
}
}
}
impl ToCss for System {
fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
match *self {
System::Symbolic => dest.write_str("symbolic")
}
}
}

View file

@ -6,10 +6,11 @@
use computed_values::{font_style, font_weight, font_stretch}; use computed_values::{font_style, font_weight, font_stretch};
use computed_values::font_family::FamilyName; use computed_values::font_family::FamilyName;
use counter_style::System;
use cssparser::UnicodeRange; use cssparser::UnicodeRange;
use font_face::{FontFaceRuleData, Source}; use font_face::{FontFaceRuleData, Source};
use gecko_bindings::bindings; use gecko_bindings::bindings;
use gecko_bindings::structs::{self, nsCSSFontFaceRule, nsCSSValue}; use gecko_bindings::structs::{self, nsCSSFontFaceRule, nsCSSValue, nsCSSCounterDesc};
use gecko_bindings::sugar::ns_css_value::ToNsCssValue; use gecko_bindings::sugar::ns_css_value::ToNsCssValue;
use gecko_bindings::sugar::refptr::{RefPtr, UniqueRefPtr}; use gecko_bindings::sugar::refptr::{RefPtr, UniqueRefPtr};
use shared_lock::{ToCssWithGuard, SharedRwLockReadGuard}; use shared_lock::{ToCssWithGuard, SharedRwLockReadGuard};
@ -133,3 +134,15 @@ impl ToCssWithGuard for FontFaceRule {
write!(dest, "{}", css_text) write!(dest, "{}", css_text)
} }
} }
/// The type of nsCSSCounterStyleRule::mValues
pub type CounterStyleDescriptors = [nsCSSValue; nsCSSCounterDesc::eCSSCounterDesc_COUNT as usize];
impl ToNsCssValue for System {
fn convert(&self, v: &mut nsCSSValue) {
match *self {
System::Symbolic => v.set_enum(structs::NS_STYLE_COUNTER_SYSTEM_SYMBOLIC as i32),
}
}
}

View file

@ -89,6 +89,7 @@ pub mod bloom;
pub mod cache; pub mod cache;
pub mod cascade_info; pub mod cascade_info;
pub mod context; pub mod context;
pub mod counter_style;
pub mod custom_properties; pub mod custom_properties;
pub mod data; pub mod data;
pub mod dom; pub mod dom;

View file

@ -7,6 +7,7 @@
#![deny(missing_docs)] #![deny(missing_docs)]
use {Atom, Prefix, Namespace}; use {Atom, Prefix, Namespace};
use counter_style::{CounterStyleRule, parse_counter_style_body};
use cssparser::{AtRuleParser, Parser, QualifiedRuleParser}; use cssparser::{AtRuleParser, Parser, QualifiedRuleParser};
use cssparser::{AtRuleType, RuleListParser, Token, parse_one_rule}; use cssparser::{AtRuleType, RuleListParser, Token, parse_one_rule};
use cssparser::ToCss as ParserToCss; use cssparser::ToCss as ParserToCss;
@ -290,6 +291,7 @@ pub enum CssRule {
Style(Arc<Locked<StyleRule>>), Style(Arc<Locked<StyleRule>>),
Media(Arc<Locked<MediaRule>>), Media(Arc<Locked<MediaRule>>),
FontFace(Arc<Locked<FontFaceRule>>), FontFace(Arc<Locked<FontFaceRule>>),
CounterStyle(Arc<Locked<CounterStyleRule>>),
Viewport(Arc<Locked<ViewportRule>>), Viewport(Arc<Locked<ViewportRule>>),
Keyframes(Arc<Locked<KeyframesRule>>), Keyframes(Arc<Locked<KeyframesRule>>),
Supports(Arc<Locked<SupportsRule>>), Supports(Arc<Locked<SupportsRule>>),
@ -332,15 +334,16 @@ impl CssRule {
#[allow(missing_docs)] #[allow(missing_docs)]
pub fn rule_type(&self) -> CssRuleType { pub fn rule_type(&self) -> CssRuleType {
match *self { match *self {
CssRule::Style(_) => CssRuleType::Style, CssRule::Style(_) => CssRuleType::Style,
CssRule::Import(_) => CssRuleType::Import, CssRule::Import(_) => CssRuleType::Import,
CssRule::Media(_) => CssRuleType::Media, CssRule::Media(_) => CssRuleType::Media,
CssRule::FontFace(_) => CssRuleType::FontFace, CssRule::FontFace(_) => CssRuleType::FontFace,
CssRule::CounterStyle(_) => CssRuleType::CounterStyle,
CssRule::Keyframes(_) => CssRuleType::Keyframes, CssRule::Keyframes(_) => CssRuleType::Keyframes,
CssRule::Namespace(_) => CssRuleType::Namespace, CssRule::Namespace(_) => CssRuleType::Namespace,
CssRule::Viewport(_) => CssRuleType::Viewport, CssRule::Viewport(_) => CssRuleType::Viewport,
CssRule::Supports(_) => CssRuleType::Supports, CssRule::Supports(_) => CssRuleType::Supports,
CssRule::Page(_) => CssRuleType::Page, CssRule::Page(_) => CssRuleType::Page,
} }
} }
@ -373,6 +376,7 @@ impl CssRule {
CssRule::Namespace(_) | CssRule::Namespace(_) |
CssRule::Style(_) | CssRule::Style(_) |
CssRule::FontFace(_) | CssRule::FontFace(_) |
CssRule::CounterStyle(_) |
CssRule::Viewport(_) | CssRule::Viewport(_) |
CssRule::Keyframes(_) | CssRule::Keyframes(_) |
CssRule::Page(_) => { CssRule::Page(_) => {
@ -446,6 +450,7 @@ impl ToCssWithGuard for CssRule {
CssRule::Import(ref lock) => lock.read_with(guard).to_css(guard, dest), CssRule::Import(ref lock) => lock.read_with(guard).to_css(guard, dest),
CssRule::Style(ref lock) => lock.read_with(guard).to_css(guard, dest), CssRule::Style(ref lock) => lock.read_with(guard).to_css(guard, dest),
CssRule::FontFace(ref lock) => lock.read_with(guard).to_css(guard, dest), CssRule::FontFace(ref lock) => lock.read_with(guard).to_css(guard, dest),
CssRule::CounterStyle(ref lock) => lock.read_with(guard).to_css(guard, dest),
CssRule::Viewport(ref lock) => lock.read_with(guard).to_css(guard, dest), CssRule::Viewport(ref lock) => lock.read_with(guard).to_css(guard, dest),
CssRule::Keyframes(ref lock) => lock.read_with(guard).to_css(guard, dest), CssRule::Keyframes(ref lock) => lock.read_with(guard).to_css(guard, dest),
CssRule::Media(ref lock) => lock.read_with(guard).to_css(guard, dest), CssRule::Media(ref lock) => lock.read_with(guard).to_css(guard, dest),
@ -835,6 +840,7 @@ rule_filter! {
effective_style_rules(Style => StyleRule), effective_style_rules(Style => StyleRule),
effective_media_rules(Media => MediaRule), effective_media_rules(Media => MediaRule),
effective_font_face_rules(FontFace => FontFaceRule), effective_font_face_rules(FontFace => FontFaceRule),
effective_counter_style_rules(CounterStyle => CounterStyleRule),
effective_viewport_rules(Viewport => ViewportRule), effective_viewport_rules(Viewport => ViewportRule),
effective_keyframes_rules(Keyframes => KeyframesRule), effective_keyframes_rules(Keyframes => KeyframesRule),
effective_supports_rules(Supports => SupportsRule), effective_supports_rules(Supports => SupportsRule),
@ -916,6 +922,8 @@ pub enum VendorPrefix {
enum AtRulePrelude { enum AtRulePrelude {
/// A @font-face rule prelude. /// A @font-face rule prelude.
FontFace, FontFace,
/// A @counter-style rule prelude, with its counter style name.
CounterStyle(CustomIdent),
/// A @media rule prelude, with its media queries. /// A @media rule prelude, with its media queries.
Media(Arc<Locked<MediaList>>), Media(Arc<Locked<MediaList>>),
/// An @supports rule, with its conditional /// An @supports rule, with its conditional
@ -1103,6 +1111,14 @@ impl<'a, 'b> AtRuleParser for NestedRuleParser<'a, 'b> {
"font-face" => { "font-face" => {
Ok(AtRuleType::WithBlock(AtRulePrelude::FontFace)) Ok(AtRuleType::WithBlock(AtRulePrelude::FontFace))
}, },
"counter-style" => {
if !cfg!(feature = "gecko") {
// Support for this rule is not fully implemented in Servo yet.
return Err(())
}
let name = CustomIdent::from_ident(input.expect_ident()?, &["decimal", "none"])?;
Ok(AtRuleType::WithBlock(AtRulePrelude::CounterStyle(name)))
},
"viewport" => { "viewport" => {
if is_viewport_enabled() { if is_viewport_enabled() {
Ok(AtRuleType::WithBlock(AtRulePrelude::Viewport)) Ok(AtRuleType::WithBlock(AtRulePrelude::Viewport))
@ -1149,6 +1165,11 @@ impl<'a, 'b> AtRuleParser for NestedRuleParser<'a, 'b> {
Ok(CssRule::FontFace(Arc::new(self.shared_lock.wrap( Ok(CssRule::FontFace(Arc::new(self.shared_lock.wrap(
parse_font_face_block(&context, input).into())))) parse_font_face_block(&context, input).into()))))
} }
AtRulePrelude::CounterStyle(name) => {
let context = ParserContext::new_with_rule_type(self.context, Some(CssRuleType::CounterStyle));
Ok(CssRule::CounterStyle(Arc::new(self.shared_lock.wrap(
parse_counter_style_body(name, &context, input)?))))
}
AtRulePrelude::Media(media_queries) => { AtRulePrelude::Media(media_queries) => {
Ok(CssRule::Media(Arc::new(self.shared_lock.wrap(MediaRule { Ok(CssRule::Media(Arc::new(self.shared_lock.wrap(MediaRule {
media_queries: media_queries, media_queries: media_queries,