mirror of
https://github.com/servo/servo.git
synced 2025-07-23 15:23:42 +01:00
Add initial style system support for @counter-style rules
This commit is contained in:
parent
5a8e3308c1
commit
797f40b0a3
5 changed files with 194 additions and 8 deletions
|
@ -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)),
|
||||||
|
|
150
components/style/counter_style.rs
Normal file
150
components/style/counter_style.rs
Normal 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 we’d 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")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -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),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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,
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue