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::Style(s) => Root::upcast(CSSStyleRule::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::Media(s) => Root::upcast(CSSMediaRule::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_family::FamilyName;
use counter_style::System;
use cssparser::UnicodeRange;
use font_face::{FontFaceRuleData, Source};
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::refptr::{RefPtr, UniqueRefPtr};
use shared_lock::{ToCssWithGuard, SharedRwLockReadGuard};
@ -133,3 +134,15 @@ impl ToCssWithGuard for FontFaceRule {
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 cascade_info;
pub mod context;
pub mod counter_style;
pub mod custom_properties;
pub mod data;
pub mod dom;

View file

@ -7,6 +7,7 @@
#![deny(missing_docs)]
use {Atom, Prefix, Namespace};
use counter_style::{CounterStyleRule, parse_counter_style_body};
use cssparser::{AtRuleParser, Parser, QualifiedRuleParser};
use cssparser::{AtRuleType, RuleListParser, Token, parse_one_rule};
use cssparser::ToCss as ParserToCss;
@ -290,6 +291,7 @@ pub enum CssRule {
Style(Arc<Locked<StyleRule>>),
Media(Arc<Locked<MediaRule>>),
FontFace(Arc<Locked<FontFaceRule>>),
CounterStyle(Arc<Locked<CounterStyleRule>>),
Viewport(Arc<Locked<ViewportRule>>),
Keyframes(Arc<Locked<KeyframesRule>>),
Supports(Arc<Locked<SupportsRule>>),
@ -336,6 +338,7 @@ impl CssRule {
CssRule::Import(_) => CssRuleType::Import,
CssRule::Media(_) => CssRuleType::Media,
CssRule::FontFace(_) => CssRuleType::FontFace,
CssRule::CounterStyle(_) => CssRuleType::CounterStyle,
CssRule::Keyframes(_) => CssRuleType::Keyframes,
CssRule::Namespace(_) => CssRuleType::Namespace,
CssRule::Viewport(_) => CssRuleType::Viewport,
@ -373,6 +376,7 @@ impl CssRule {
CssRule::Namespace(_) |
CssRule::Style(_) |
CssRule::FontFace(_) |
CssRule::CounterStyle(_) |
CssRule::Viewport(_) |
CssRule::Keyframes(_) |
CssRule::Page(_) => {
@ -446,6 +450,7 @@ impl ToCssWithGuard for CssRule {
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::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::Keyframes(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_media_rules(Media => MediaRule),
effective_font_face_rules(FontFace => FontFaceRule),
effective_counter_style_rules(CounterStyle => CounterStyleRule),
effective_viewport_rules(Viewport => ViewportRule),
effective_keyframes_rules(Keyframes => KeyframesRule),
effective_supports_rules(Supports => SupportsRule),
@ -916,6 +922,8 @@ pub enum VendorPrefix {
enum AtRulePrelude {
/// A @font-face rule prelude.
FontFace,
/// A @counter-style rule prelude, with its counter style name.
CounterStyle(CustomIdent),
/// A @media rule prelude, with its media queries.
Media(Arc<Locked<MediaList>>),
/// An @supports rule, with its conditional
@ -1103,6 +1111,14 @@ impl<'a, 'b> AtRuleParser for NestedRuleParser<'a, 'b> {
"font-face" => {
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" => {
if is_viewport_enabled() {
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(
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) => {
Ok(CssRule::Media(Arc::new(self.shared_lock.wrap(MediaRule {
media_queries: media_queries,