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::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)),
|
||||
|
|
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_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),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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,
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue