Auto merge of #20708 - emilio:gecko-sync, r=emilio

style: sync changes from mozilla-central.

<!-- Reviewable:start -->
This change is [<img src="https://reviewable.io/review_button.svg" height="34" align="absmiddle" alt="Reviewable"/>](https://reviewable.io/reviews/servo/servo/20708)
<!-- Reviewable:end -->
This commit is contained in:
bors-servo 2018-04-29 01:03:40 -04:00 committed by GitHub
commit 02c75ea2d9
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
95 changed files with 1940 additions and 1068 deletions

2
Cargo.lock generated
View file

@ -997,7 +997,6 @@ dependencies = [
"atomic_refcell 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "atomic_refcell 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"cssparser 0.23.2 (registry+https://github.com/rust-lang/crates.io-index)", "cssparser 0.23.2 (registry+https://github.com/rust-lang/crates.io-index)",
"cstr 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", "cstr 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
"env_logger 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.39 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.39 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
"malloc_size_of 0.0.1", "malloc_size_of 0.0.1",
@ -3123,6 +3122,7 @@ dependencies = [
"serde 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)",
"servo_arc 0.1.1", "servo_arc 0.1.1",
"servo_atoms 0.0.1", "servo_atoms 0.0.1",
"servo_url 0.0.1",
"webrender_api 0.57.2 (git+https://github.com/servo/webrender)", "webrender_api 0.57.2 (git+https://github.com/servo/webrender)",
] ]

View file

@ -66,9 +66,9 @@ use style::servo::restyle_damage::ServoRestyleDamage;
use style::values::{Either, RGBA}; use style::values::{Either, RGBA};
use style::values::computed::Gradient; use style::values::computed::Gradient;
use style::values::computed::effects::SimpleShadow; use style::values::computed::effects::SimpleShadow;
use style::values::computed::pointing::Cursor;
use style::values::generics::background::BackgroundSize; use style::values::generics::background::BackgroundSize;
use style::values::generics::image::{GradientKind, Image, PaintWorklet}; use style::values::generics::image::{GradientKind, Image, PaintWorklet};
use style::values::generics::pointing::Cursor;
use style_traits::CSSPixel; use style_traits::CSSPixel;
use style_traits::ToCss; use style_traits::ToCss;
use style_traits::cursor::CursorKind; use style_traits::cursor::CursorKind;
@ -2952,11 +2952,11 @@ impl ComputedValuesCursorUtility for ComputedValues {
fn get_cursor(&self, default_cursor: CursorKind) -> Option<CursorKind> { fn get_cursor(&self, default_cursor: CursorKind) -> Option<CursorKind> {
match ( match (
self.get_pointing().pointer_events, self.get_pointing().pointer_events,
self.get_pointing().cursor, &self.get_pointing().cursor,
) { ) {
(PointerEvents::None, _) => None, (PointerEvents::None, _) => None,
(PointerEvents::Auto, Cursor(CursorKind::Auto)) => Some(default_cursor), (PointerEvents::Auto, &Cursor { keyword: CursorKind::Auto, .. }) => Some(default_cursor),
(PointerEvents::Auto, Cursor(cursor)) => Some(cursor), (PointerEvents::Auto, &Cursor { keyword, .. }) => Some(keyword),
} }
} }
} }

View file

@ -39,6 +39,7 @@ use std::convert::From;
use std::fmt; use std::fmt;
use std::hash::{Hash, Hasher}; use std::hash::{Hash, Hasher};
use std::iter::{ExactSizeIterator, Iterator}; use std::iter::{ExactSizeIterator, Iterator};
use std::marker::PhantomData;
use std::mem; use std::mem;
use std::ops::{Deref, DerefMut}; use std::ops::{Deref, DerefMut};
use std::os::raw::c_void; use std::os::raw::c_void;
@ -924,7 +925,7 @@ impl<T: 'static> Arc<T> {
/// ///
/// ArcBorrow lets us deal with borrows of known-refcounted objects /// ArcBorrow lets us deal with borrows of known-refcounted objects
/// without needing to worry about how they're actually stored. /// without needing to worry about how they're actually stored.
#[derive(Eq, PartialEq)] #[derive(Debug, Eq, PartialEq)]
pub struct ArcBorrow<'a, T: 'a>(&'a T); pub struct ArcBorrow<'a, T: 'a>(&'a T);
impl<'a, T> Copy for ArcBorrow<'a, T> {} impl<'a, T> Copy for ArcBorrow<'a, T> {}
@ -951,6 +952,10 @@ impl<'a, T> ArcBorrow<'a, T> {
ArcBorrow(r) ArcBorrow(r)
} }
pub fn ptr_eq(this: &Self, other: &Self) -> bool {
this.0 as *const T == other.0 as *const T
}
#[inline] #[inline]
pub fn with_arc<F, U>(&self, f: F) -> U pub fn with_arc<F, U>(&self, f: F) -> U
where where
@ -971,6 +976,13 @@ impl<'a, T> ArcBorrow<'a, T> {
// Forward the result. // Forward the result.
result result
} }
/// Similar to deref, but uses the lifetime |a| rather than the lifetime of
/// self, which is incompatible with the signature of the Deref trait.
#[inline]
pub fn get(&self) -> &'a T {
self.0
}
} }
impl<'a, T> Deref for ArcBorrow<'a, T> { impl<'a, T> Deref for ArcBorrow<'a, T> {
@ -978,7 +990,127 @@ impl<'a, T> Deref for ArcBorrow<'a, T> {
#[inline] #[inline]
fn deref(&self) -> &T { fn deref(&self) -> &T {
&*self.0 self.0
}
}
/// A tagged union that can represent Arc<A> or Arc<B> while only consuming a
/// single word. The type is also NonZero, and thus can be stored in an Option
/// without increasing size.
///
/// This could probably be extended to support four types if necessary.
pub struct ArcUnion<A: 'static, B: 'static> {
p: NonZeroPtrMut<()>,
phantom_a: PhantomData<&'static A>,
phantom_b: PhantomData<&'static B>,
}
impl<A: PartialEq + 'static, B: PartialEq + 'static> PartialEq for ArcUnion<A, B> {
fn eq(&self, other: &Self) -> bool {
use ArcUnionBorrow::*;
match (self.borrow(), other.borrow()) {
(First(x), First(y)) => x == y,
(Second(x), Second(y)) => x == y,
(_, _) => false,
}
}
}
#[derive(Debug)]
pub enum ArcUnionBorrow<'a, A: 'static, B: 'static> {
First(ArcBorrow<'a, A>),
Second(ArcBorrow<'a, B>),
}
impl<A: 'static, B: 'static> ArcUnion<A, B> {
fn new(ptr: *mut ()) -> Self {
ArcUnion {
p: NonZeroPtrMut::new(ptr),
phantom_a: PhantomData,
phantom_b: PhantomData,
}
}
/// Returns true if the two values are pointer-equal.
pub fn ptr_eq(this: &Self, other: &Self) -> bool {
this.p == other.p
}
/// Returns an enum representing a borrow of either A or B.
pub fn borrow(&self) -> ArcUnionBorrow<A, B> {
if self.is_first() {
let ptr = self.p.ptr() as *const A;
let borrow = unsafe { ArcBorrow::from_ref(&*ptr) };
ArcUnionBorrow::First(borrow)
} else {
let ptr = ((self.p.ptr() as usize) & !0x1) as *const B;
let borrow = unsafe { ArcBorrow::from_ref(&*ptr) };
ArcUnionBorrow::Second(borrow)
}
}
/// Creates an ArcUnion from an instance of the first type.
pub fn from_first(other: Arc<A>) -> Self {
Self::new(Arc::into_raw(other) as *mut _)
}
/// Creates an ArcUnion from an instance of the second type.
pub fn from_second(other: Arc<B>) -> Self {
Self::new(((Arc::into_raw(other) as usize) | 0x1) as *mut _)
}
/// Returns true if this ArcUnion contains the first type.
pub fn is_first(&self) -> bool {
self.p.ptr() as usize & 0x1 == 0
}
/// Returns true if this ArcUnion contains the second type.
pub fn is_second(&self) -> bool {
!self.is_first()
}
/// Returns a borrow of the first type if applicable, otherwise None.
pub fn as_first(&self) -> Option<ArcBorrow<A>> {
match self.borrow() {
ArcUnionBorrow::First(x) => Some(x),
ArcUnionBorrow::Second(_) => None,
}
}
/// Returns a borrow of the second type if applicable, otherwise None.
pub fn as_second(&self) -> Option<ArcBorrow<B>> {
match self.borrow() {
ArcUnionBorrow::First(_) => None,
ArcUnionBorrow::Second(x) => Some(x),
}
}
}
impl<A: 'static, B: 'static> Clone for ArcUnion<A, B> {
fn clone(&self) -> Self {
match self.borrow() {
ArcUnionBorrow::First(x) => ArcUnion::from_first(x.clone_arc()),
ArcUnionBorrow::Second(x) => ArcUnion::from_second(x.clone_arc()),
}
}
}
impl<A: 'static, B: 'static> Drop for ArcUnion<A, B> {
fn drop(&mut self) {
match self.borrow() {
ArcUnionBorrow::First(x) => unsafe {
let _ = Arc::from_raw(&*x);
},
ArcUnionBorrow::Second(x) => unsafe {
let _ = Arc::from_raw(&*x);
},
}
}
}
impl<A: fmt::Debug, B: fmt::Debug> fmt::Debug for ArcUnion<A, B> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
fmt::Debug::fmt(&self.borrow(), f)
} }
} }

View file

@ -116,7 +116,7 @@ impl ApplicableDeclarationBlock {
level: CascadeLevel, level: CascadeLevel,
) -> Self { ) -> Self {
ApplicableDeclarationBlock { ApplicableDeclarationBlock {
source: StyleSource::Declarations(declarations), source: StyleSource::from_declarations(declarations),
bits: ApplicableDeclarationBits::new(0, level, 0), bits: ApplicableDeclarationBits::new(0, level, 0),
specificity: 0, specificity: 0,
} }

View file

@ -94,15 +94,15 @@ impl StylesheetInDocument for GeckoStyleSheet {
} }
fn media<'a>(&'a self, guard: &'a SharedRwLockReadGuard) -> Option<&'a MediaList> { fn media<'a>(&'a self, guard: &'a SharedRwLockReadGuard) -> Option<&'a MediaList> {
use gecko_bindings::structs::ServoMediaList; use gecko_bindings::structs::mozilla::dom::MediaList as DomMediaList;
use std::mem; use std::mem;
unsafe { unsafe {
let servo_media_list = self.raw()._base.mMedia.mRawPtr as *const ServoMediaList; let dom_media_list = self.raw()._base.mMedia.mRawPtr as *const DomMediaList;
if servo_media_list.is_null() { if dom_media_list.is_null() {
return None; return None;
} }
let raw_list = &*(*servo_media_list).mRawList.mRawPtr; let raw_list = &*(*dom_media_list).mRawList.mRawPtr;
let list = Locked::<MediaList>::as_arc(mem::transmute(&raw_list)); let list = Locked::<MediaList>::as_arc(mem::transmute(&raw_list));
Some(list.read_with(guard)) Some(list.read_with(guard))
} }

View file

@ -19,7 +19,7 @@ use style_traits::ParseError;
/// A CSS url() value for gecko. /// A CSS url() value for gecko.
#[css(function = "url")] #[css(function = "url")]
#[derive(Clone, Debug, PartialEq, ToCss)] #[derive(Clone, Debug, PartialEq, SpecifiedValueInfo, ToCss)]
pub struct CssUrl { pub struct CssUrl {
/// The URL in unresolved string form. /// The URL in unresolved string form.
/// ///
@ -121,7 +121,7 @@ impl MallocSizeOf for CssUrl {
} }
/// A specified url() value for general usage. /// A specified url() value for general usage.
#[derive(Clone, Debug, ToComputedValue, ToCss)] #[derive(Clone, Debug, SpecifiedValueInfo, ToComputedValue, ToCss)]
pub struct SpecifiedUrl { pub struct SpecifiedUrl {
/// The specified url value. /// The specified url value.
pub url: CssUrl, pub url: CssUrl,
@ -179,7 +179,7 @@ impl MallocSizeOf for SpecifiedUrl {
/// A specified url() value for image. /// A specified url() value for image.
/// ///
/// This exists so that we can construct `ImageValue` and reuse it. /// This exists so that we can construct `ImageValue` and reuse it.
#[derive(Clone, Debug, ToComputedValue, ToCss)] #[derive(Clone, Debug, SpecifiedValueInfo, ToComputedValue, ToCss)]
pub struct SpecifiedImageUrl { pub struct SpecifiedImageUrl {
/// The specified url value. /// The specified url value.
pub url: CssUrl, pub url: CssUrl,

View file

@ -20,6 +20,7 @@ use std::fmt::{self, Write};
use std::hash::{Hash, Hasher}; use std::hash::{Hash, Hasher};
use std::iter::Cloned; use std::iter::Cloned;
use std::ops::Deref; use std::ops::Deref;
use style_traits::SpecifiedValueInfo;
#[macro_use] #[macro_use]
#[allow(improper_ctypes, non_camel_case_types, missing_docs)] #[allow(improper_ctypes, non_camel_case_types, missing_docs)]
@ -415,3 +416,5 @@ impl From<String> for Atom {
} }
malloc_size_of_is_0!(Atom); malloc_size_of_is_0!(Atom);
impl SpecifiedValueInfo for Atom {}

View file

@ -68,8 +68,9 @@ macro_rules! try_match_ident_ignore_ascii_case {
macro_rules! define_keyword_type { macro_rules! define_keyword_type {
($name:ident, $css:expr) => { ($name:ident, $css:expr) => {
#[allow(missing_docs)] #[allow(missing_docs)]
#[derive(Animate, Clone, ComputeSquaredDistance, Copy, MallocSizeOf, PartialEq, #[derive(Animate, Clone, ComputeSquaredDistance, Copy, MallocSizeOf,
ToAnimatedValue, ToAnimatedZero, ToComputedValue, ToCss)] PartialEq, SpecifiedValueInfo, ToAnimatedValue, ToAnimatedZero,
ToComputedValue, ToCss)]
pub struct $name; pub struct $name;
impl fmt::Debug for $name { impl fmt::Debug for $name {

View file

@ -164,7 +164,7 @@
% if separator == "Comma": % if separator == "Comma":
#[css(comma)] #[css(comma)]
% endif % endif
#[derive(Clone, Debug, MallocSizeOf, PartialEq, ToCss)] #[derive(Clone, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo, ToCss)]
pub struct SpecifiedValue( pub struct SpecifiedValue(
% if not allow_empty: % if not allow_empty:
#[css(iterable)] #[css(iterable)]
@ -396,8 +396,8 @@
pub mod computed_value { pub mod computed_value {
#[cfg_attr(feature = "servo", derive(Deserialize, Serialize))] #[cfg_attr(feature = "servo", derive(Deserialize, Serialize))]
#[derive(Clone, Copy, Debug, Eq, Hash, MallocSizeOf, Parse)] #[derive(Clone, Copy, Debug, Eq, Hash, MallocSizeOf, Parse,
#[derive(PartialEq, ToCss)] PartialEq, SpecifiedValueInfo, ToCss)]
pub enum T { pub enum T {
% for value in keyword.values_for(product): % for value in keyword.values_for(product):
${to_camel_case(value)}, ${to_camel_case(value)},
@ -408,9 +408,10 @@
} }
#[cfg_attr(feature = "gecko", derive(MallocSizeOf))] #[cfg_attr(feature = "gecko", derive(MallocSizeOf))]
#[derive(Clone, Copy, Debug, Eq, PartialEq, ToCss)] #[derive(Clone, Copy, Debug, Eq, PartialEq, SpecifiedValueInfo, ToCss)]
pub enum SpecifiedValue { pub enum SpecifiedValue {
Keyword(computed_value::T), Keyword(computed_value::T),
#[css(skip)]
System(SystemFont), System(SystemFont),
} }
@ -558,7 +559,8 @@
</%def> </%def>
% if extra_specified: % if extra_specified:
#[cfg_attr(feature = "servo", derive(Deserialize, Serialize))] #[cfg_attr(feature = "servo", derive(Deserialize, Serialize))]
#[derive(Clone, Copy, Debug, Eq, MallocSizeOf, Parse, PartialEq, ToCss)] #[derive(Clone, Copy, Debug, Eq, MallocSizeOf, Parse, PartialEq,
SpecifiedValueInfo, ToCss)]
pub enum SpecifiedValue { pub enum SpecifiedValue {
${variants(keyword.values_for(product) + extra_specified.split(), bool(extra_specified))} ${variants(keyword.values_for(product) + extra_specified.split(), bool(extra_specified))}
} }
@ -569,7 +571,7 @@
#[cfg_attr(feature = "servo", derive(Deserialize, Serialize))] #[cfg_attr(feature = "servo", derive(Deserialize, Serialize))]
#[derive(Clone, Copy, Debug, Eq, MallocSizeOf, PartialEq, ToCss)] #[derive(Clone, Copy, Debug, Eq, MallocSizeOf, PartialEq, ToCss)]
% if not extra_specified: % if not extra_specified:
#[derive(Parse, ToComputedValue)] #[derive(Parse, SpecifiedValueInfo, ToComputedValue)]
% endif % endif
pub enum T { pub enum T {
${variants(data.longhands_by_name[name].keyword.values_for(product), not extra_specified)} ${variants(data.longhands_by_name[name].keyword.values_for(product), not extra_specified)}
@ -617,9 +619,14 @@
% endif % endif
</%def> </%def>
<%def name="shorthand(name, sub_properties, derive_serialize=False, **kwargs)"> <%def name="shorthand(name, sub_properties, derive_serialize=False,
derive_value_info=True, **kwargs)">
<% <%
shorthand = data.declare_shorthand(name, sub_properties.split(), **kwargs) shorthand = data.declare_shorthand(name, sub_properties.split(), **kwargs)
# mako doesn't accept non-string value in parameters with <% %> form, so
# we have to workaround it this way.
if not isinstance(derive_value_info, bool):
derive_value_info = eval(derive_value_info)
%> %>
% if shorthand: % if shorthand:
/// ${shorthand.spec} /// ${shorthand.spec}
@ -634,8 +641,11 @@
#[allow(unused_imports)] #[allow(unused_imports)]
use style_traits::{ParseError, StyleParseErrorKind}; use style_traits::{ParseError, StyleParseErrorKind};
#[allow(unused_imports)] #[allow(unused_imports)]
use style_traits::{CssWriter, ToCss}; use style_traits::{CssWriter, KeywordsCollectFn, SpecifiedValueInfo, ToCss};
% if derive_value_info:
#[derive(SpecifiedValueInfo)]
% endif
pub struct Longhands { pub struct Longhands {
% for sub_property in shorthand.sub_properties: % for sub_property in shorthand.sub_properties:
pub ${sub_property.ident}: pub ${sub_property.ident}:

View file

@ -27,7 +27,7 @@ use smallvec::SmallVec;
use std::{cmp, ptr}; use std::{cmp, ptr};
use std::mem::{self, ManuallyDrop}; use std::mem::{self, ManuallyDrop};
#[cfg(feature = "gecko")] use hash::FnvHashMap; #[cfg(feature = "gecko")] use hash::FnvHashMap;
use style_traits::ParseError; use style_traits::{KeywordsCollectFn, ParseError, SpecifiedValueInfo};
use super::ComputedValues; use super::ComputedValues;
use values::{CSSFloat, CustomIdent, Either}; use values::{CSSFloat, CustomIdent, Either};
use values::animated::{Animate, Procedure, ToAnimatedValue, ToAnimatedZero}; use values::animated::{Animate, Procedure, ToAnimatedValue, ToAnimatedZero};
@ -172,6 +172,15 @@ impl From<nsCSSPropertyID> for TransitionProperty {
} }
} }
impl SpecifiedValueInfo for TransitionProperty {
fn collect_completion_keywords(f: KeywordsCollectFn) {
// `transition-property` can actually accept all properties and
// arbitrary identifiers, but `all` is a special one we'd like
// to list.
f(&["all"]);
}
}
/// Returns true if this nsCSSPropertyID is one of the transitionable properties. /// Returns true if this nsCSSPropertyID is one of the transitionable properties.
#[cfg(feature = "gecko")] #[cfg(feature = "gecko")]
pub fn nscsspropertyid_is_transitionable(property: nsCSSPropertyID) -> bool { pub fn nscsspropertyid_is_transitionable(property: nsCSSPropertyID) -> bool {

View file

@ -660,9 +660,21 @@ ${helpers.predefined_type(
products="gecko", products="gecko",
gecko_pref="layout.css.shape-outside.enabled", gecko_pref="layout.css.shape-outside.enabled",
animation_value_type="ComputedValue", animation_value_type="ComputedValue",
flags="APPLIES_TO_FIRST_LETTER",
spec="https://drafts.csswg.org/css-shapes/#shape-image-threshold-property", spec="https://drafts.csswg.org/css-shapes/#shape-image-threshold-property",
)} )}
${helpers.predefined_type(
"shape-margin",
"NonNegativeLengthOrPercentage",
"computed::NonNegativeLengthOrPercentage::zero()",
products="gecko",
gecko_pref="layout.css.shape-outside.enabled",
animation_value_type="NonNegativeLengthOrPercentage",
flags="APPLIES_TO_FIRST_LETTER",
spec="https://drafts.csswg.org/css-shapes/#shape-margin-property",
)}
${helpers.predefined_type( ${helpers.predefined_type(
"shape-outside", "shape-outside",
"basic_shape::FloatAreaShape", "basic_shape::FloatAreaShape",

View file

@ -274,6 +274,11 @@ ${helpers.predefined_type("-x-text-zoom",
//! detects that a value has a system font, it will resolve it, and //! detects that a value has a system font, it will resolve it, and
//! cache it on the ComputedValues. After this, it can be just fetched //! cache it on the ComputedValues. After this, it can be just fetched
//! whenever a font longhand on the same element needs the system font. //! whenever a font longhand on the same element needs the system font.
//!
//! When a longhand property is holding a SystemFont, it's serialized
//! to an empty string as if its value comes from a shorthand with
//! variable reference. We may want to improve this behavior at some
//! point. See also https://github.com/w3c/csswg-drafts/issues/1586.
use app_units::Au; use app_units::Au;
use cssparser::{Parser, ToCss}; use cssparser::{Parser, ToCss};
@ -296,7 +301,8 @@ ${helpers.predefined_type("-x-text-zoom",
kw_cast = """font_variant_caps font_kerning font_variant_position kw_cast = """font_variant_caps font_kerning font_variant_position
font_optical_sizing""".split() font_optical_sizing""".split()
%> %>
#[derive(Clone, Copy, Debug, Eq, Hash, MallocSizeOf, PartialEq, ToCss)] #[derive(Clone, Copy, Debug, Eq, Hash, MallocSizeOf, PartialEq,
SpecifiedValueInfo, ToCss)]
pub enum SystemFont { pub enum SystemFont {
% for font in system_fonts: % for font in system_fonts:
${to_camel_case(font)}, ${to_camel_case(font)},
@ -444,7 +450,7 @@ ${helpers.predefined_type("-x-text-zoom",
// a lot of code with `if product == gecko` conditionals, we have a // a lot of code with `if product == gecko` conditionals, we have a
// dummy system font module that does nothing // dummy system font module that does nothing
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq, ToCss)] #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq, SpecifiedValueInfo, ToCss)]
#[cfg_attr(feature = "servo", derive(MallocSizeOf))] #[cfg_attr(feature = "servo", derive(MallocSizeOf))]
/// void enum for system font, can never exist /// void enum for system font, can never exist
pub enum SystemFont {} pub enum SystemFont {}

View file

@ -292,7 +292,6 @@ ${helpers.single_keyword("ruby-position", "over under",
${helpers.single_keyword("text-combine-upright", "none all", ${helpers.single_keyword("text-combine-upright", "none all",
products="gecko", animation_value_type="discrete", products="gecko", animation_value_type="discrete",
gecko_pref="layout.css.text-combine-upright.enabled",
spec="https://drafts.csswg.org/css-writing-modes-3/#text-combine-upright")} spec="https://drafts.csswg.org/css-writing-modes-3/#text-combine-upright")}
// SVG 1.1: Section 11 - Painting: Filling, Stroking and Marker Symbols // SVG 1.1: Section 11 - Painting: Filling, Stroking and Marker Symbols

View file

@ -42,7 +42,8 @@ use selector_parser::PseudoElement;
use selectors::parser::SelectorParseErrorKind; use selectors::parser::SelectorParseErrorKind;
#[cfg(feature = "servo")] use servo_config::prefs::PREFS; #[cfg(feature = "servo")] use servo_config::prefs::PREFS;
use shared_lock::StylesheetGuards; use shared_lock::StylesheetGuards;
use style_traits::{CssWriter, ParseError, ParsingMode, StyleParseErrorKind, ToCss}; use style_traits::{CssWriter, KeywordsCollectFn, ParseError, ParsingMode};
use style_traits::{SpecifiedValueInfo, StyleParseErrorKind, ToCss};
use stylesheets::{CssRuleType, Origin, UrlExtraData}; use stylesheets::{CssRuleType, Origin, UrlExtraData};
#[cfg(feature = "servo")] use values::Either; #[cfg(feature = "servo")] use values::Either;
use values::generics::text::LineHeight; use values::generics::text::LineHeight;
@ -541,6 +542,43 @@ impl NonCustomPropertyId {
false false
} }
/// The supported types of this property. The return value should be
/// style_traits::CssType when it can become a bitflags type.
fn supported_types(&self) -> u8 {
const SUPPORTED_TYPES: [u8; ${len(data.longhands) + len(data.shorthands)}] = [
% for prop in data.longhands:
<${prop.specified_type()} as SpecifiedValueInfo>::SUPPORTED_TYPES,
% endfor
% for prop in data.shorthands:
% if prop.name == "all":
0, // 'all' accepts no value other than CSS-wide keywords
% else:
<shorthands::${prop.ident}::Longhands as SpecifiedValueInfo>::SUPPORTED_TYPES,
% endif
% endfor
];
SUPPORTED_TYPES[self.0]
}
/// See PropertyId::collect_property_completion_keywords.
fn collect_property_completion_keywords(&self, f: KeywordsCollectFn) {
const COLLECT_FUNCTIONS: [&Fn(KeywordsCollectFn);
${len(data.longhands) + len(data.shorthands)}] = [
% for prop in data.longhands:
&<${prop.specified_type()} as SpecifiedValueInfo>::collect_completion_keywords,
% endfor
% for prop in data.shorthands:
% if prop.name == "all":
&|_f| {}, // 'all' accepts no value other than CSS-wide keywords
% else:
&<shorthands::${prop.ident}::Longhands as SpecifiedValueInfo>::
collect_completion_keywords,
% endif
% endfor
];
COLLECT_FUNCTIONS[self.0](f);
}
} }
impl From<LonghandId> for NonCustomPropertyId { impl From<LonghandId> for NonCustomPropertyId {
@ -724,7 +762,8 @@ impl LonghandIdSet {
} }
/// An enum to represent a CSS Wide keyword. /// An enum to represent a CSS Wide keyword.
#[derive(Clone, Copy, Debug, Eq, MallocSizeOf, PartialEq, ToCss)] #[derive(Clone, Copy, Debug, Eq, MallocSizeOf, PartialEq, SpecifiedValueInfo,
ToCss)]
pub enum CSSWideKeyword { pub enum CSSWideKeyword {
/// The `initial` keyword. /// The `initial` keyword.
Initial, Initial,
@ -1692,6 +1731,18 @@ impl PropertyId {
}) })
} }
/// Returns non-alias NonCustomPropertyId corresponding to this
/// property id.
fn non_custom_non_alias_id(&self) -> Option<NonCustomPropertyId> {
Some(match *self {
PropertyId::Custom(_) => return None,
PropertyId::Shorthand(id) => id.into(),
PropertyId::Longhand(id) => id.into(),
PropertyId::ShorthandAlias(id, _) => id.into(),
PropertyId::LonghandAlias(id, _) => id.into(),
})
}
/// Whether the property is enabled for all content regardless of the /// Whether the property is enabled for all content regardless of the
/// stylesheet it was declared on (that is, in practice only checks prefs). /// stylesheet it was declared on (that is, in practice only checks prefs).
#[inline] #[inline]
@ -1713,6 +1764,24 @@ impl PropertyId {
}; };
id.allowed_in(context) id.allowed_in(context)
} }
/// Whether the property supports the given CSS type.
/// `ty` should a bitflags of constants in style_traits::CssType.
pub fn supports_type(&self, ty: u8) -> bool {
let id = self.non_custom_non_alias_id();
id.map_or(0, |id| id.supported_types()) & ty != 0
}
/// Collect supported starting word of values of this property.
///
/// See style_traits::SpecifiedValueInfo::collect_completion_keywords for more
/// details.
pub fn collect_property_completion_keywords(&self, f: KeywordsCollectFn) {
if let Some(id) = self.non_custom_non_alias_id() {
id.collect_property_completion_keywords(f);
}
CSSWideKeyword::collect_completion_keywords(f);
}
} }
/// A declaration using a CSS-wide keyword. /// A declaration using a CSS-wide keyword.
@ -3424,7 +3493,7 @@ where
let source = node.style_source(); let source = node.style_source();
let declarations = if source.is_some() { let declarations = if source.is_some() {
source.read(cascade_level.guard(guards)).declaration_importance_iter() source.as_ref().unwrap().read(cascade_level.guard(guards)).declaration_importance_iter()
} else { } else {
// The root node has no style source. // The root node has no style source.
DeclarationImportanceIterator::new(&[], &empty) DeclarationImportanceIterator::new(&[], &empty)

View file

@ -140,6 +140,7 @@ pub fn parse_border<'i, 't>(
for prop in ['color', 'style', 'width'])} for prop in ['color', 'style', 'width'])}
${' '.join('border-image-%s' % name ${' '.join('border-image-%s' % name
for name in ['outset', 'repeat', 'slice', 'source', 'width'])}" for name in ['outset', 'repeat', 'slice', 'source', 'width'])}"
derive_value_info="False"
spec="https://drafts.csswg.org/css-backgrounds/#border"> spec="https://drafts.csswg.org/css-backgrounds/#border">
pub fn parse_value<'i, 't>( pub fn parse_value<'i, 't>(
@ -202,6 +203,17 @@ pub fn parse_border<'i, 't>(
} }
} }
// Just use the same as border-left. The border shorthand can't accept
// any value that the sub-shorthand couldn't.
<%
border_left = "<::properties::shorthands::border_left::Longhands as SpecifiedValueInfo>"
%>
impl SpecifiedValueInfo for Longhands {
const SUPPORTED_TYPES: u8 = ${border_left}::SUPPORTED_TYPES;
fn collect_completion_keywords(f: KeywordsCollectFn) {
${border_left}::collect_completion_keywords(f);
}
}
</%helpers:shorthand> </%helpers:shorthand>
<%helpers:shorthand name="border-radius" sub_properties="${' '.join( <%helpers:shorthand name="border-radius" sub_properties="${' '.join(

View file

@ -19,6 +19,7 @@
${'font-language-override' if product == 'gecko' else ''} ${'font-language-override' if product == 'gecko' else ''}
${'font-feature-settings' if product == 'gecko' else ''} ${'font-feature-settings' if product == 'gecko' else ''}
${'font-variation-settings' if product == 'gecko' else ''}" ${'font-variation-settings' if product == 'gecko' else ''}"
derive_value_info="False"
spec="https://drafts.csswg.org/css-fonts-3/#propdef-font"> spec="https://drafts.csswg.org/css-fonts-3/#propdef-font">
use parser::Parse; use parser::Parse;
use properties::longhands::{font_family, font_style, font_weight, font_stretch}; use properties::longhands::{font_family, font_style, font_weight, font_stretch};
@ -258,6 +259,29 @@
} }
% endif % endif
} }
<%
subprops_for_value_info = ["font_style", "font_weight", "font_stretch",
"font_variant_caps", "font_size", "font_family"]
subprops_for_value_info = [
"<longhands::{}::SpecifiedValue as SpecifiedValueInfo>".format(p)
for p in subprops_for_value_info
]
%>
impl SpecifiedValueInfo for Longhands {
const SUPPORTED_TYPES: u8 = 0
% for p in subprops_for_value_info:
| ${p}::SUPPORTED_TYPES
% endfor
;
fn collect_completion_keywords(f: KeywordsCollectFn) {
% for p in subprops_for_value_info:
${p}::collect_completion_keywords(f);
% endfor
<longhands::system_font::SystemFont as SpecifiedValueInfo>::collect_completion_keywords(f);
}
}
</%helpers:shorthand> </%helpers:shorthand>
<%helpers:shorthand name="font-variant" <%helpers:shorthand name="font-variant"

View file

@ -5,7 +5,7 @@
<%namespace name="helpers" file="/helpers.mako.rs" /> <%namespace name="helpers" file="/helpers.mako.rs" />
<%helpers:shorthand name="outline" <%helpers:shorthand name="outline"
sub_properties="outline-width outline-style outline-color" sub_properties="outline-color outline-style outline-width"
derive_serialize="True" derive_serialize="True"
spec="https://drafts.csswg.org/css-ui/#propdef-outline"> spec="https://drafts.csswg.org/css-ui/#propdef-outline">
use properties::longhands::{outline_color, outline_width, outline_style}; use properties::longhands::{outline_color, outline_width, outline_style};

View file

@ -8,7 +8,7 @@
use fnv::FnvHashMap; use fnv::FnvHashMap;
use logical_geometry::WritingMode; use logical_geometry::WritingMode;
use properties::{ComputedValues, StyleBuilder}; use properties::{ComputedValues, StyleBuilder};
use rule_tree::{StrongRuleNode, StyleSource}; use rule_tree::StrongRuleNode;
use selector_parser::PseudoElement; use selector_parser::PseudoElement;
use servo_arc::Arc; use servo_arc::Arc;
use shared_lock::StylesheetGuards; use shared_lock::StylesheetGuards;
@ -97,16 +97,18 @@ impl RuleCache {
mut rule_node: Option<&'r StrongRuleNode>, mut rule_node: Option<&'r StrongRuleNode>,
) -> Option<&'r StrongRuleNode> { ) -> Option<&'r StrongRuleNode> {
while let Some(node) = rule_node { while let Some(node) = rule_node {
match *node.style_source() { match node.style_source() {
StyleSource::Declarations(ref decls) => { Some(s) => match s.as_declarations() {
let cascade_level = node.cascade_level(); Some(decls) => {
let decls = decls.read_with(cascade_level.guard(guards)); let cascade_level = node.cascade_level();
if decls.contains_any_reset() { let decls = decls.read_with(cascade_level.guard(guards));
break; if decls.contains_any_reset() {
} break;
}
},
None => break,
}, },
StyleSource::None => {}, None => {},
StyleSource::Style(_) => break,
} }
rule_node = node.parent(); rule_node = node.parent();
} }

View file

@ -12,7 +12,7 @@ use gecko::selector_parser::PseudoElement;
#[cfg(feature = "gecko")] #[cfg(feature = "gecko")]
use malloc_size_of::{MallocSizeOf, MallocSizeOfOps}; use malloc_size_of::{MallocSizeOf, MallocSizeOfOps};
use properties::{Importance, LonghandIdSet, PropertyDeclarationBlock}; use properties::{Importance, LonghandIdSet, PropertyDeclarationBlock};
use servo_arc::{Arc, ArcBorrow, NonZeroPtrMut}; use servo_arc::{Arc, ArcBorrow, ArcUnion, ArcUnionBorrow, NonZeroPtrMut};
use shared_lock::{Locked, SharedRwLockReadGuard, StylesheetGuards}; use shared_lock::{Locked, SharedRwLockReadGuard, StylesheetGuards};
use smallvec::SmallVec; use smallvec::SmallVec;
use std::io::{self, Write}; use std::io::{self, Write};
@ -89,40 +89,27 @@ impl MallocSizeOf for RuleTree {
/// more debuggability, and also the ability of show those selectors to /// more debuggability, and also the ability of show those selectors to
/// devtools. /// devtools.
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub enum StyleSource { pub struct StyleSource(ArcUnion<Locked<StyleRule>, Locked<PropertyDeclarationBlock>>);
/// A style rule stable pointer.
Style(Arc<Locked<StyleRule>>),
/// A declaration block stable pointer.
Declarations(Arc<Locked<PropertyDeclarationBlock>>),
/// Indicates no style source. Used to save an Option wrapper around the stylesource in
/// RuleNode
None,
}
impl PartialEq for StyleSource { impl PartialEq for StyleSource {
fn eq(&self, other: &Self) -> bool { fn eq(&self, other: &Self) -> bool {
self.ptr_equals(other) ArcUnion::ptr_eq(&self.0, &other.0)
} }
} }
impl StyleSource { impl StyleSource {
#[inline] /// Creates a StyleSource from a StyleRule.
fn ptr_equals(&self, other: &Self) -> bool { pub fn from_rule(rule: Arc<Locked<StyleRule>>) -> Self {
use self::StyleSource::*; StyleSource(ArcUnion::from_first(rule))
match (self, other) { }
(&Style(ref one), &Style(ref other)) => Arc::ptr_eq(one, other),
(&Declarations(ref one), &Declarations(ref other)) => Arc::ptr_eq(one, other), /// Creates a StyleSource from a PropertyDeclarationBlock.
(&None, _) | (_, &None) => { pub fn from_declarations(decls: Arc<Locked<PropertyDeclarationBlock>>) -> Self {
panic!("Should not check for equality between null StyleSource objects") StyleSource(ArcUnion::from_second(decls))
},
_ => false,
}
} }
fn dump<W: Write>(&self, guard: &SharedRwLockReadGuard, writer: &mut W) { fn dump<W: Write>(&self, guard: &SharedRwLockReadGuard, writer: &mut W) {
use self::StyleSource::*; if let Some(ref rule) = self.0.as_first() {
if let Style(ref rule) = *self {
let rule = rule.read_with(guard); let rule = rule.read_with(guard);
let _ = write!(writer, "{:?}", rule.selectors); let _ = write!(writer, "{:?}", rule.selectors);
} }
@ -134,20 +121,31 @@ impl StyleSource {
/// underlying property declaration block. /// underlying property declaration block.
#[inline] #[inline]
pub fn read<'a>(&'a self, guard: &'a SharedRwLockReadGuard) -> &'a PropertyDeclarationBlock { pub fn read<'a>(&'a self, guard: &'a SharedRwLockReadGuard) -> &'a PropertyDeclarationBlock {
let block = match *self { let block: &Locked<PropertyDeclarationBlock> = match self.0.borrow() {
StyleSource::Style(ref rule) => &rule.read_with(guard).block, ArcUnionBorrow::First(ref rule) => &rule.get().read_with(guard).block,
StyleSource::Declarations(ref block) => block, ArcUnionBorrow::Second(ref block) => block.get(),
StyleSource::None => panic!("Cannot call read on StyleSource::None"),
}; };
block.read_with(guard) block.read_with(guard)
} }
/// Indicates if this StyleSource has a value /// Indicates if this StyleSource is a style rule.
pub fn is_some(&self) -> bool { pub fn is_rule(&self) -> bool {
match *self { self.0.is_first()
StyleSource::None => false, }
_ => true,
} /// Indicates if this StyleSource is a PropertyDeclarationBlock.
pub fn is_declarations(&self) -> bool {
self.0.is_second()
}
/// Returns the style rule if applicable, otherwise None.
pub fn as_rule(&self) -> Option<ArcBorrow<Locked<StyleRule>>> {
self.0.as_first()
}
/// Returns the declaration block if applicable, otherwise None.
pub fn as_declarations(&self) -> Option<ArcBorrow<Locked<PropertyDeclarationBlock>>> {
self.0.as_second()
} }
} }
@ -248,11 +246,12 @@ impl RuleTree {
last_cascade_order = shadow_cascade_order; last_cascade_order = shadow_cascade_order;
important_inner_shadow.push(SmallVec::new()); important_inner_shadow.push(SmallVec::new());
} }
important_inner_shadow.last_mut().unwrap().push(source.clone()) important_inner_shadow
} .last_mut()
SameTreeAuthorNormal => { .unwrap()
important_same_tree.push(source.clone()) .push(source.clone())
}, },
SameTreeAuthorNormal => important_same_tree.push(source.clone()),
UANormal => important_ua.push(source.clone()), UANormal => important_ua.push(source.clone()),
UserNormal => important_user.push(source.clone()), UserNormal => important_user.push(source.clone()),
StyleAttributeNormal => { StyleAttributeNormal => {
@ -391,7 +390,10 @@ impl RuleTree {
// First walk up until the first less-or-equally specific rule. // First walk up until the first less-or-equally specific rule.
let mut children = SmallVec::<[_; 10]>::new(); let mut children = SmallVec::<[_; 10]>::new();
while current.get().level > level { while current.get().level > level {
children.push((current.get().source.clone(), current.get().level)); children.push((
current.get().source.as_ref().unwrap().clone(),
current.get().level,
));
current = current.parent().unwrap().clone(); current = current.parent().unwrap().clone();
} }
@ -418,13 +420,14 @@ impl RuleTree {
// also equally valid. This is less likely, and would require an // also equally valid. This is less likely, and would require an
// in-place mutation of the source, which is, at best, fiddly, // in-place mutation of the source, which is, at best, fiddly,
// so let's skip it for now. // so let's skip it for now.
let is_here_already = match current.get().source { let current_decls = current
StyleSource::Declarations(ref already_here) => { .get()
pdb.with_arc(|arc| Arc::ptr_eq(arc, already_here)) .source
}, .as_ref()
_ => unreachable!("Replacing non-declarations style?"), .unwrap()
}; .as_declarations()
.expect("Replacing non-declarations style?");
let is_here_already = ArcBorrow::ptr_eq(&pdb, &current_decls);
if is_here_already { if is_here_already {
debug!("Picking the fast path in rule replacement"); debug!("Picking the fast path in rule replacement");
return None; return None;
@ -447,7 +450,7 @@ impl RuleTree {
if pdb.read_with(level.guard(guards)).any_important() { if pdb.read_with(level.guard(guards)).any_important() {
current = current.ensure_child( current = current.ensure_child(
self.root.downgrade(), self.root.downgrade(),
StyleSource::Declarations(pdb.clone_arc()), StyleSource::from_declarations(pdb.clone_arc()),
level, level,
); );
} }
@ -455,7 +458,7 @@ impl RuleTree {
if pdb.read_with(level.guard(guards)).any_normal() { if pdb.read_with(level.guard(guards)).any_normal() {
current = current.ensure_child( current = current.ensure_child(
self.root.downgrade(), self.root.downgrade(),
StyleSource::Declarations(pdb.clone_arc()), StyleSource::from_declarations(pdb.clone_arc()),
level, level,
); );
} }
@ -491,7 +494,10 @@ impl RuleTree {
let mut children = SmallVec::<[_; 10]>::new(); let mut children = SmallVec::<[_; 10]>::new();
for node in iter { for node in iter {
if !node.cascade_level().is_animation() { if !node.cascade_level().is_animation() {
children.push((node.get().source.clone(), node.cascade_level())); children.push((
node.get().source.as_ref().unwrap().clone(),
node.cascade_level(),
));
} }
last = node; last = node;
} }
@ -689,7 +695,9 @@ pub struct RuleNode {
/// The actual style source, either coming from a selector in a StyleRule, /// The actual style source, either coming from a selector in a StyleRule,
/// or a raw property declaration block (like the style attribute). /// or a raw property declaration block (like the style attribute).
source: StyleSource, ///
/// None for the root node.
source: Option<StyleSource>,
/// The cascade level this rule is positioned at. /// The cascade level this rule is positioned at.
level: CascadeLevel, level: CascadeLevel,
@ -775,7 +783,7 @@ impl RuleNode {
RuleNode { RuleNode {
root: Some(root), root: Some(root),
parent: Some(parent), parent: Some(parent),
source: source, source: Some(source),
level: level, level: level,
refcount: AtomicUsize::new(1), refcount: AtomicUsize::new(1),
first_child: AtomicPtr::new(ptr::null_mut()), first_child: AtomicPtr::new(ptr::null_mut()),
@ -789,7 +797,7 @@ impl RuleNode {
RuleNode { RuleNode {
root: None, root: None,
parent: None, parent: None,
source: StyleSource::None, source: None,
level: CascadeLevel::UANormal, level: CascadeLevel::UANormal,
refcount: AtomicUsize::new(1), refcount: AtomicUsize::new(1),
first_child: AtomicPtr::new(ptr::null_mut()), first_child: AtomicPtr::new(ptr::null_mut()),
@ -884,7 +892,10 @@ impl RuleNode {
} }
if self.source.is_some() { if self.source.is_some() {
self.source.dump(self.level.guard(guards), writer); self.source
.as_ref()
.unwrap()
.dump(self.level.guard(guards), writer);
} else { } else {
if indent != 0 { if indent != 0 {
warn!("How has this happened?"); warn!("How has this happened?");
@ -986,7 +997,7 @@ impl StrongRuleNode {
// WeakRuleNode, and implementing this on WeakRuleNode itself... // WeakRuleNode, and implementing this on WeakRuleNode itself...
for child in self.get().iter_children() { for child in self.get().iter_children() {
let child_node = unsafe { &*child.ptr() }; let child_node = unsafe { &*child.ptr() };
if child_node.level == level && child_node.source.ptr_equals(&source) { if child_node.level == level && child_node.source.as_ref().unwrap() == &source {
return child.upgrade(); return child.upgrade();
} }
last = Some(child); last = Some(child);
@ -1026,7 +1037,7 @@ impl StrongRuleNode {
// we accessed `last`. // we accessed `last`.
next = WeakRuleNode::from_ptr(existing); next = WeakRuleNode::from_ptr(existing);
if unsafe { &*next.ptr() }.source.ptr_equals(&source) { if unsafe { &*next.ptr() }.source.as_ref().unwrap() == &source {
// That node happens to be for the same style source, use // That node happens to be for the same style source, use
// that, and let node fall out of scope. // that, and let node fall out of scope.
return next.upgrade(); return next.upgrade();
@ -1054,8 +1065,8 @@ impl StrongRuleNode {
/// Get the style source corresponding to this rule node. May return `None` /// Get the style source corresponding to this rule node. May return `None`
/// if it's the root node, which means that the node hasn't matched any /// if it's the root node, which means that the node hasn't matched any
/// rules. /// rules.
pub fn style_source(&self) -> &StyleSource { pub fn style_source(&self) -> Option<&StyleSource> {
&self.get().source self.get().source.as_ref()
} }
/// The cascade level for this node /// The cascade level for this node
@ -1317,6 +1328,8 @@ impl StrongRuleNode {
let source = node.style_source(); let source = node.style_source();
let declarations = if source.is_some() { let declarations = if source.is_some() {
source source
.as_ref()
.unwrap()
.read(node.cascade_level().guard(guards)) .read(node.cascade_level().guard(guards))
.declaration_importance_iter() .declaration_importance_iter()
} else { } else {
@ -1444,7 +1457,7 @@ impl StrongRuleNode {
.take_while(|node| node.cascade_level() > CascadeLevel::Animations); .take_while(|node| node.cascade_level() > CascadeLevel::Animations);
let mut result = (LonghandIdSet::new(), false); let mut result = (LonghandIdSet::new(), false);
for node in iter { for node in iter {
let style = node.style_source(); let style = node.style_source().unwrap();
for (decl, important) in style for (decl, important) in style
.read(node.cascade_level().guard(guards)) .read(node.cascade_level().guard(guards))
.declaration_importance_iter() .declaration_importance_iter()
@ -1464,33 +1477,6 @@ impl StrongRuleNode {
} }
result result
} }
/// Returns PropertyDeclarationBlock for this node.
/// This function must be called only for animation level node.
fn get_animation_style(&self) -> &Arc<Locked<PropertyDeclarationBlock>> {
debug_assert!(
self.cascade_level().is_animation(),
"The cascade level should be an animation level"
);
match *self.style_source() {
StyleSource::Declarations(ref block) => block,
StyleSource::Style(_) => unreachable!("animating style should not be a style rule"),
StyleSource::None => unreachable!("animating style should not be none"),
}
}
/// Returns SMIL override declaration block if exists.
pub fn get_smil_animation_rule(&self) -> Option<&Arc<Locked<PropertyDeclarationBlock>>> {
if cfg!(feature = "servo") {
// Servo has no knowledge of a SMIL rule, so just avoid looking for it.
return None;
}
self.self_and_ancestors()
.take_while(|node| node.cascade_level() >= CascadeLevel::SMILOverride)
.find(|node| node.cascade_level() == CascadeLevel::SMILOverride)
.map(|node| node.get_animation_style())
}
} }
/// An iterator over a rule node and its ancestors. /// An iterator over a rule node and its ancestors.

View file

@ -23,7 +23,7 @@ use values::computed::{Context, ToComputedValue};
/// ///
/// However, this approach is still not necessarily optimal: See /// However, this approach is still not necessarily optimal: See
/// <https://bugzilla.mozilla.org/show_bug.cgi?id=1347435#c6> /// <https://bugzilla.mozilla.org/show_bug.cgi?id=1347435#c6>
#[derive(Clone, Debug, Deserialize, MallocSizeOf, Serialize)] #[derive(Clone, Debug, Deserialize, MallocSizeOf, Serialize, SpecifiedValueInfo)]
pub struct CssUrl { pub struct CssUrl {
/// The original URI. This might be optional since we may insert computed /// The original URI. This might be optional since we may insert computed
/// values of images into the cascade directly, and we don't bother to /// values of images into the cascade directly, and we don't bother to

View file

@ -1523,7 +1523,7 @@ impl Stylist {
// just avoid allocating it and calling `apply_declarations` directly, // just avoid allocating it and calling `apply_declarations` directly,
// maybe... // maybe...
let rule_node = self.rule_tree.insert_ordered_rules(iter::once(( let rule_node = self.rule_tree.insert_ordered_rules(iter::once((
StyleSource::Declarations(declarations), StyleSource::from_declarations(declarations),
CascadeLevel::StyleAttributeNormal, CascadeLevel::StyleAttributeNormal,
))); )));
@ -2177,7 +2177,7 @@ impl CascadeData {
.expect("Expected precomputed declarations for the UA level") .expect("Expected precomputed declarations for the UA level")
.get_or_insert_with(&pseudo.canonical(), Vec::new) .get_or_insert_with(&pseudo.canonical(), Vec::new)
.push(ApplicableDeclarationBlock::new( .push(ApplicableDeclarationBlock::new(
StyleSource::Style(locked.clone()), StyleSource::from_rule(locked.clone()),
self.rules_source_order, self.rules_source_order,
CascadeLevel::UANormal, CascadeLevel::UANormal,
selector.specificity(), selector.specificity(),
@ -2480,7 +2480,7 @@ impl Rule {
level: CascadeLevel, level: CascadeLevel,
shadow_cascade_order: ShadowCascadeOrder, shadow_cascade_order: ShadowCascadeOrder,
) -> ApplicableDeclarationBlock { ) -> ApplicableDeclarationBlock {
let source = StyleSource::Style(self.style_rule.clone()); let source = StyleSource::from_rule(self.style_rule.clone());
ApplicableDeclarationBlock::new(source, self.source_order, level, self.specificity(), shadow_cascade_order) ApplicableDeclarationBlock::new(source, self.source_order, level, self.specificity(), shadow_cascade_order)
} }

View file

@ -916,7 +916,8 @@ pub type NonNegativeLengthOrPercentageOrNormal = Either<NonNegativeLengthOrPerce
/// block-size, and inline-size. /// block-size, and inline-size.
#[allow(missing_docs)] #[allow(missing_docs)]
#[cfg_attr(feature = "servo", derive(Deserialize, Serialize))] #[cfg_attr(feature = "servo", derive(Deserialize, Serialize))]
#[derive(Clone, Copy, Debug, Eq, MallocSizeOf, Parse, PartialEq, ToCss)] #[derive(Clone, Copy, Debug, Eq, MallocSizeOf, Parse, PartialEq,
SpecifiedValueInfo, ToCss)]
pub enum ExtremumLength { pub enum ExtremumLength {
MozMaxContent, MozMaxContent,
MozMinContent, MozMinContent,

View file

@ -12,8 +12,9 @@ use values::generics::NonNegative;
/// A computed percentage. /// A computed percentage.
#[cfg_attr(feature = "servo", derive(Deserialize, Serialize))] #[cfg_attr(feature = "servo", derive(Deserialize, Serialize))]
#[derive(Animate, Clone, ComputeSquaredDistance, Copy, Debug, Default, MallocSizeOf, PartialEq, #[derive(Animate, Clone, ComputeSquaredDistance, Copy, Debug, Default,
PartialOrd, ToAnimatedZero, ToComputedValue)] MallocSizeOf, PartialEq, PartialOrd, SpecifiedValueInfo,
ToAnimatedZero, ToComputedValue)]
pub struct Percentage(pub CSSFloat); pub struct Percentage(pub CSSFloat);
impl Percentage { impl Percentage {

View file

@ -6,137 +6,16 @@
//! //!
//! https://drafts.csswg.org/css-ui/#pointing-keyboard //! https://drafts.csswg.org/css-ui/#pointing-keyboard
use cssparser::Parser; use values::computed::Number;
use parser::{Parse, ParserContext};
use selectors::parser::SelectorParseErrorKind;
#[cfg(feature = "gecko")]
use std::fmt::{self, Write};
#[cfg(feature = "gecko")]
use style_traits::{CssWriter, ToCss};
use style_traits::ParseError;
use style_traits::cursor::CursorKind;
use values::computed::color::Color; use values::computed::color::Color;
use values::generics::pointing::CaretColor as GenericCaretColor; use values::computed::url::ComputedImageUrl;
#[cfg(feature = "gecko")] use values::generics::pointing as generics;
use values::specified::url::SpecifiedImageUrl;
/// The computed value for the `cursor` property.
///
/// https://drafts.csswg.org/css-ui/#cursor
pub use values::specified::pointing::Cursor;
#[cfg(feature = "gecko")]
pub use values::specified::pointing::CursorImage;
impl Cursor {
/// Set `cursor` to `auto`
#[cfg(feature = "servo")]
#[inline]
pub fn auto() -> Self {
Cursor(CursorKind::Auto)
}
/// Set `cursor` to `auto`
#[cfg(feature = "gecko")]
#[inline]
pub fn auto() -> Self {
Self {
images: vec![].into_boxed_slice(),
keyword: CursorKind::Auto,
}
}
}
impl Parse for Cursor {
/// cursor: [auto | default | ...]
#[cfg(feature = "servo")]
fn parse<'i, 't>(
context: &ParserContext,
input: &mut Parser<'i, 't>,
) -> Result<Self, ParseError<'i>> {
Ok(Cursor(CursorKind::parse(context, input)?))
}
/// cursor: [<url> [<number> <number>]?]# [auto | default | ...]
#[cfg(feature = "gecko")]
fn parse<'i, 't>(
context: &ParserContext,
input: &mut Parser<'i, 't>,
) -> Result<Self, ParseError<'i>> {
let mut images = vec![];
loop {
match input.try(|input| CursorImage::parse_image(context, input)) {
Ok(image) => images.push(image),
Err(_) => break,
}
input.expect_comma()?;
}
Ok(Self {
images: images.into_boxed_slice(),
keyword: CursorKind::parse(context, input)?,
})
}
}
#[cfg(feature = "gecko")]
impl ToCss for Cursor {
fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
where
W: Write,
{
for url in &*self.images {
url.to_css(dest)?;
dest.write_str(", ")?;
}
self.keyword.to_css(dest)
}
}
impl Parse for CursorKind {
fn parse<'i, 't>(
_context: &ParserContext,
input: &mut Parser<'i, 't>,
) -> Result<Self, ParseError<'i>> {
let location = input.current_source_location();
let ident = input.expect_ident()?;
CursorKind::from_css_keyword(&ident).map_err(|_| {
location.new_custom_error(SelectorParseErrorKind::UnexpectedIdent(ident.clone()))
})
}
}
#[cfg(feature = "gecko")]
impl CursorImage {
fn parse_image<'i, 't>(
context: &ParserContext,
input: &mut Parser<'i, 't>,
) -> Result<Self, ParseError<'i>> {
Ok(Self {
url: SpecifiedImageUrl::parse(context, input)?,
// FIXME(emilio): Should use Number::parse to handle calc() correctly.
hotspot: match input.try(|input| input.expect_number()) {
Ok(number) => Some((number, input.expect_number()?)),
Err(_) => None,
},
})
}
}
#[cfg(feature = "gecko")]
impl ToCss for CursorImage {
fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
where
W: Write,
{
self.url.to_css(dest)?;
if let Some((x, y)) = self.hotspot {
dest.write_str(" ")?;
x.to_css(dest)?;
dest.write_str(" ")?;
y.to_css(dest)?;
}
Ok(())
}
}
/// A computed value for the `caret-color` property. /// A computed value for the `caret-color` property.
pub type CaretColor = GenericCaretColor<Color>; pub type CaretColor = generics::CaretColor<Color>;
/// A computed value for the `cursor` property.
pub type Cursor = generics::Cursor<CursorImage>;
/// A computed value for item of `image cursors`.
pub type CursorImage = generics::CursorImage<ComputedImageUrl, Number>;

View file

@ -15,8 +15,7 @@ use values::generics::text::InitialLetter as GenericInitialLetter;
use values::generics::text::LineHeight as GenericLineHeight; use values::generics::text::LineHeight as GenericLineHeight;
use values::generics::text::MozTabSize as GenericMozTabSize; use values::generics::text::MozTabSize as GenericMozTabSize;
use values::generics::text::Spacing; use values::generics::text::Spacing;
use values::specified::text::{TextDecorationLine, TextEmphasisFillMode}; use values::specified::text::{TextEmphasisFillMode, TextEmphasisShapeKeyword, TextOverflowSide};
use values::specified::text::{TextEmphasisShapeKeyword, TextOverflowSide};
pub use values::specified::TextAlignKeyword as TextAlign; pub use values::specified::TextAlignKeyword as TextAlign;
pub use values::specified::TextEmphasisPosition; pub use values::specified::TextEmphasisPosition;
@ -79,36 +78,6 @@ impl ToCss for TextOverflow {
} }
} }
impl ToCss for TextDecorationLine {
fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
where
W: Write,
{
let mut has_any = false;
macro_rules! write_value {
($line:path => $css:expr) => {
if self.contains($line) {
if has_any {
dest.write_str(" ")?;
}
dest.write_str($css)?;
has_any = true;
}
};
}
write_value!(TextDecorationLine::UNDERLINE => "underline");
write_value!(TextDecorationLine::OVERLINE => "overline");
write_value!(TextDecorationLine::LINE_THROUGH => "line-through");
write_value!(TextDecorationLine::BLINK => "blink");
if !has_any {
dest.write_str("none")?;
}
Ok(())
}
}
/// A struct that represents the _used_ value of the text-decoration property. /// A struct that represents the _used_ value of the text-decoration property.
/// ///
/// FIXME(emilio): This is done at style resolution time, though probably should /// FIXME(emilio): This is done at style resolution time, though probably should

View file

@ -5,8 +5,8 @@
//! Generic types for CSS values related to backgrounds. //! Generic types for CSS values related to backgrounds.
/// A generic value for the `background-size` property. /// A generic value for the `background-size` property.
#[derive(Animate, Clone, ComputeSquaredDistance, Copy, Debug, MallocSizeOf, PartialEq, #[derive(Animate, Clone, ComputeSquaredDistance, Copy, Debug, MallocSizeOf,
ToComputedValue, ToCss)] PartialEq, SpecifiedValueInfo, ToComputedValue, ToCss)]
pub enum BackgroundSize<LengthOrPercentageOrAuto> { pub enum BackgroundSize<LengthOrPercentageOrAuto> {
/// `<width> <height>` /// `<width> <height>`
Explicit { Explicit {

View file

@ -18,7 +18,8 @@ pub type ClippingShape<BasicShape, Url> = ShapeSource<BasicShape, GeometryBox, U
/// <https://drafts.fxtf.org/css-masking-1/#typedef-geometry-box> /// <https://drafts.fxtf.org/css-masking-1/#typedef-geometry-box>
#[allow(missing_docs)] #[allow(missing_docs)]
#[derive(Animate, Clone, Copy, Debug, MallocSizeOf, PartialEq, ToComputedValue, ToCss)] #[derive(Animate, Clone, Copy, Debug, MallocSizeOf, PartialEq,
SpecifiedValueInfo, ToComputedValue, ToCss)]
pub enum GeometryBox { pub enum GeometryBox {
FillBox, FillBox,
StrokeBox, StrokeBox,
@ -32,7 +33,8 @@ pub type FloatAreaShape<BasicShape, Image> = ShapeSource<BasicShape, ShapeBox, I
/// https://drafts.csswg.org/css-shapes-1/#typedef-shape-box /// https://drafts.csswg.org/css-shapes-1/#typedef-shape-box
#[allow(missing_docs)] #[allow(missing_docs)]
#[cfg_attr(feature = "servo", derive(Deserialize, Serialize))] #[cfg_attr(feature = "servo", derive(Deserialize, Serialize))]
#[derive(Animate, Clone, Copy, Debug, Eq, MallocSizeOf, Parse, PartialEq, ToComputedValue, ToCss)] #[derive(Animate, Clone, Copy, Debug, Eq, MallocSizeOf, Parse, PartialEq,
SpecifiedValueInfo, ToComputedValue, ToCss)]
pub enum ShapeBox { pub enum ShapeBox {
MarginBox, MarginBox,
BorderBox, BorderBox,
@ -43,7 +45,8 @@ pub enum ShapeBox {
/// A shape source, for some reference box. /// A shape source, for some reference box.
#[allow(missing_docs)] #[allow(missing_docs)]
#[animation(no_bound(ImageOrUrl))] #[animation(no_bound(ImageOrUrl))]
#[derive(Animate, Clone, Debug, MallocSizeOf, PartialEq, ToComputedValue, ToCss)] #[derive(Animate, Clone, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo,
ToComputedValue, ToCss)]
pub enum ShapeSource<BasicShape, ReferenceBox, ImageOrUrl> { pub enum ShapeSource<BasicShape, ReferenceBox, ImageOrUrl> {
#[animation(error)] #[animation(error)]
ImageOrUrl(ImageOrUrl), ImageOrUrl(ImageOrUrl),
@ -55,8 +58,8 @@ pub enum ShapeSource<BasicShape, ReferenceBox, ImageOrUrl> {
} }
#[allow(missing_docs)] #[allow(missing_docs)]
#[derive(Animate, Clone, ComputeSquaredDistance, Debug, MallocSizeOf, PartialEq, ToComputedValue, #[derive(Animate, Clone, ComputeSquaredDistance, Debug, MallocSizeOf, PartialEq,
ToCss)] SpecifiedValueInfo, ToComputedValue, ToCss)]
pub enum BasicShape<H, V, LengthOrPercentage> { pub enum BasicShape<H, V, LengthOrPercentage> {
Inset(#[css(field_bound)] InsetRect<LengthOrPercentage>), Inset(#[css(field_bound)] InsetRect<LengthOrPercentage>),
Circle(#[css(field_bound)] Circle<H, V, LengthOrPercentage>), Circle(#[css(field_bound)] Circle<H, V, LengthOrPercentage>),
@ -66,7 +69,9 @@ pub enum BasicShape<H, V, LengthOrPercentage> {
/// <https://drafts.csswg.org/css-shapes/#funcdef-inset> /// <https://drafts.csswg.org/css-shapes/#funcdef-inset>
#[allow(missing_docs)] #[allow(missing_docs)]
#[derive(Animate, Clone, ComputeSquaredDistance, Debug, MallocSizeOf, PartialEq, ToComputedValue)] #[css(function = "inset")]
#[derive(Animate, Clone, ComputeSquaredDistance, Debug, MallocSizeOf, PartialEq,
SpecifiedValueInfo, ToComputedValue)]
pub struct InsetRect<LengthOrPercentage> { pub struct InsetRect<LengthOrPercentage> {
pub rect: Rect<LengthOrPercentage>, pub rect: Rect<LengthOrPercentage>,
pub round: Option<BorderRadius<LengthOrPercentage>>, pub round: Option<BorderRadius<LengthOrPercentage>>,
@ -74,8 +79,9 @@ pub struct InsetRect<LengthOrPercentage> {
/// <https://drafts.csswg.org/css-shapes/#funcdef-circle> /// <https://drafts.csswg.org/css-shapes/#funcdef-circle>
#[allow(missing_docs)] #[allow(missing_docs)]
#[derive(Animate, Clone, ComputeSquaredDistance, Copy, Debug, MallocSizeOf, PartialEq, #[css(function)]
ToComputedValue)] #[derive(Animate, Clone, ComputeSquaredDistance, Copy, Debug, MallocSizeOf,
PartialEq, SpecifiedValueInfo, ToComputedValue)]
pub struct Circle<H, V, LengthOrPercentage> { pub struct Circle<H, V, LengthOrPercentage> {
pub position: Position<H, V>, pub position: Position<H, V>,
pub radius: ShapeRadius<LengthOrPercentage>, pub radius: ShapeRadius<LengthOrPercentage>,
@ -83,8 +89,9 @@ pub struct Circle<H, V, LengthOrPercentage> {
/// <https://drafts.csswg.org/css-shapes/#funcdef-ellipse> /// <https://drafts.csswg.org/css-shapes/#funcdef-ellipse>
#[allow(missing_docs)] #[allow(missing_docs)]
#[derive(Animate, Clone, ComputeSquaredDistance, Copy, Debug, MallocSizeOf, PartialEq, #[css(function)]
ToComputedValue)] #[derive(Animate, Clone, ComputeSquaredDistance, Copy, Debug, MallocSizeOf,
PartialEq, SpecifiedValueInfo, ToComputedValue)]
pub struct Ellipse<H, V, LengthOrPercentage> { pub struct Ellipse<H, V, LengthOrPercentage> {
pub position: Position<H, V>, pub position: Position<H, V>,
pub semiaxis_x: ShapeRadius<LengthOrPercentage>, pub semiaxis_x: ShapeRadius<LengthOrPercentage>,
@ -93,8 +100,8 @@ pub struct Ellipse<H, V, LengthOrPercentage> {
/// <https://drafts.csswg.org/css-shapes/#typedef-shape-radius> /// <https://drafts.csswg.org/css-shapes/#typedef-shape-radius>
#[allow(missing_docs)] #[allow(missing_docs)]
#[derive(Animate, Clone, ComputeSquaredDistance, Copy, Debug, MallocSizeOf, PartialEq, #[derive(Animate, Clone, ComputeSquaredDistance, Copy, Debug, MallocSizeOf,
ToComputedValue, ToCss)] PartialEq, SpecifiedValueInfo, ToComputedValue, ToCss)]
pub enum ShapeRadius<LengthOrPercentage> { pub enum ShapeRadius<LengthOrPercentage> {
Length(LengthOrPercentage), Length(LengthOrPercentage),
#[animation(error)] #[animation(error)]
@ -106,7 +113,9 @@ pub enum ShapeRadius<LengthOrPercentage> {
/// A generic type for representing the `polygon()` function /// A generic type for representing the `polygon()` function
/// ///
/// <https://drafts.csswg.org/css-shapes/#funcdef-polygon> /// <https://drafts.csswg.org/css-shapes/#funcdef-polygon>
#[derive(Clone, Debug, MallocSizeOf, PartialEq, ToComputedValue)] #[css(function)]
#[derive(Clone, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo,
ToComputedValue)]
pub struct Polygon<LengthOrPercentage> { pub struct Polygon<LengthOrPercentage> {
/// The filling rule for a polygon. /// The filling rule for a polygon.
pub fill: FillRule, pub fill: FillRule,
@ -120,7 +129,8 @@ pub struct Polygon<LengthOrPercentage> {
// says that it can also be `inherit` // says that it can also be `inherit`
#[allow(missing_docs)] #[allow(missing_docs)]
#[cfg_attr(feature = "servo", derive(Deserialize, Serialize))] #[cfg_attr(feature = "servo", derive(Deserialize, Serialize))]
#[derive(Clone, Copy, Debug, Eq, MallocSizeOf, Parse, PartialEq, ToComputedValue, ToCss)] #[derive(Clone, Copy, Debug, Eq, MallocSizeOf, Parse, PartialEq,
SpecifiedValueInfo, ToComputedValue, ToCss)]
pub enum FillRule { pub enum FillRule {
Nonzero, Nonzero,
Evenodd, Evenodd,

View file

@ -10,7 +10,8 @@ use values::generics::rect::Rect;
use values::generics::size::Size; use values::generics::size::Size;
/// A generic value for a single side of a `border-image-width` property. /// A generic value for a single side of a `border-image-width` property.
#[derive(Clone, Copy, Debug, MallocSizeOf, PartialEq, ToComputedValue, ToCss)] #[derive(Clone, Copy, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo,
ToComputedValue, ToCss)]
pub enum BorderImageSideWidth<LengthOrPercentage, Number> { pub enum BorderImageSideWidth<LengthOrPercentage, Number> {
/// `<length-or-percentage>` /// `<length-or-percentage>`
Length(LengthOrPercentage), Length(LengthOrPercentage),
@ -21,17 +22,19 @@ pub enum BorderImageSideWidth<LengthOrPercentage, Number> {
} }
/// A generic value for the `border-image-slice` property. /// A generic value for the `border-image-slice` property.
#[derive(Clone, Copy, Debug, MallocSizeOf, PartialEq, ToComputedValue)] #[derive(Clone, Copy, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo,
ToComputedValue)]
pub struct BorderImageSlice<NumberOrPercentage> { pub struct BorderImageSlice<NumberOrPercentage> {
/// The offsets. /// The offsets.
pub offsets: Rect<NumberOrPercentage>, pub offsets: Rect<NumberOrPercentage>,
/// Whether to fill the middle part. /// Whether to fill the middle part.
#[value_info(represents_keyword)]
pub fill: bool, pub fill: bool,
} }
/// A generic value for the `border-*-radius` longhand properties. /// A generic value for the `border-*-radius` longhand properties.
#[derive(Animate, Clone, ComputeSquaredDistance, Copy, Debug, MallocSizeOf, PartialEq, #[derive(Animate, Clone, ComputeSquaredDistance, Copy, Debug, MallocSizeOf,
ToComputedValue, ToCss)] PartialEq, SpecifiedValueInfo, ToComputedValue, ToCss)]
pub struct BorderCornerRadius<L>(#[css(field_bound)] pub Size<L>); pub struct BorderCornerRadius<L>(#[css(field_bound)] pub Size<L>);
impl<L> BorderCornerRadius<L> { impl<L> BorderCornerRadius<L> {
@ -42,8 +45,9 @@ impl<L> BorderCornerRadius<L> {
} }
/// A generic value for the `border-spacing` property. /// A generic value for the `border-spacing` property.
#[derive(Animate, Clone, ComputeSquaredDistance, Copy, Debug, MallocSizeOf, PartialEq, #[derive(Animate, Clone, ComputeSquaredDistance, Copy, Debug, MallocSizeOf,
ToAnimatedValue, ToAnimatedZero, ToComputedValue, ToCss)] PartialEq, SpecifiedValueInfo, ToAnimatedValue, ToAnimatedZero,
ToComputedValue, ToCss)]
pub struct BorderSpacing<L>(#[css(field_bound)] pub Size<L>); pub struct BorderSpacing<L>(#[css(field_bound)] pub Size<L>);
impl<L> BorderSpacing<L> { impl<L> BorderSpacing<L> {
@ -56,8 +60,8 @@ impl<L> BorderSpacing<L> {
/// A generic value for `border-radius`, `outline-radius` and `inset()`. /// A generic value for `border-radius`, `outline-radius` and `inset()`.
/// ///
/// <https://drafts.csswg.org/css-backgrounds-3/#border-radius> /// <https://drafts.csswg.org/css-backgrounds-3/#border-radius>
#[derive(Animate, Clone, ComputeSquaredDistance, Copy, Debug, MallocSizeOf, PartialEq, #[derive(Animate, Clone, ComputeSquaredDistance, Copy, Debug, MallocSizeOf,
ToComputedValue)] PartialEq, SpecifiedValueInfo, ToComputedValue)]
pub struct BorderRadius<LengthOrPercentage> { pub struct BorderRadius<LengthOrPercentage> {
/// The top left radius. /// The top left radius.
pub top_left: BorderCornerRadius<LengthOrPercentage>, pub top_left: BorderCornerRadius<LengthOrPercentage>,

View file

@ -7,8 +7,8 @@
use values::animated::ToAnimatedZero; use values::animated::ToAnimatedZero;
/// A generic value for the `vertical-align` property. /// A generic value for the `vertical-align` property.
#[derive(Animate, Clone, ComputeSquaredDistance, Copy, Debug, MallocSizeOf, PartialEq, #[derive(Animate, Clone, ComputeSquaredDistance, Copy, Debug, MallocSizeOf,
ToComputedValue, ToCss)] PartialEq, SpecifiedValueInfo, ToComputedValue, ToCss)]
pub enum VerticalAlign<LengthOrPercentage> { pub enum VerticalAlign<LengthOrPercentage> {
/// `baseline` /// `baseline`
Baseline, Baseline,
@ -48,7 +48,8 @@ impl<L> ToAnimatedZero for VerticalAlign<L> {
} }
/// https://drafts.csswg.org/css-animations/#animation-iteration-count /// https://drafts.csswg.org/css-animations/#animation-iteration-count
#[derive(Clone, Debug, MallocSizeOf, PartialEq, ToComputedValue, ToCss)] #[derive(Clone, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo,
ToComputedValue, ToCss)]
pub enum AnimationIterationCount<Number> { pub enum AnimationIterationCount<Number> {
/// A `<number>` value. /// A `<number>` value.
Number(Number), Number(Number),
@ -57,8 +58,9 @@ pub enum AnimationIterationCount<Number> {
} }
/// A generic value for the `perspective` property. /// A generic value for the `perspective` property.
#[derive(Animate, Clone, ComputeSquaredDistance, Copy, Debug, MallocSizeOf, PartialEq, #[derive(Animate, Clone, ComputeSquaredDistance, Copy, Debug, MallocSizeOf,
ToAnimatedValue, ToAnimatedZero, ToComputedValue, ToCss)] PartialEq, SpecifiedValueInfo, ToAnimatedValue, ToAnimatedZero,
ToComputedValue, ToCss)]
pub enum Perspective<NonNegativeLength> { pub enum Perspective<NonNegativeLength> {
/// A non-negative length. /// A non-negative length.
Length(NonNegativeLength), Length(NonNegativeLength),

View file

@ -5,8 +5,9 @@
//! Generic types for the column properties. //! Generic types for the column properties.
/// A generic type for `column-count` values. /// A generic type for `column-count` values.
#[derive(Animate, Clone, ComputeSquaredDistance, Copy, Debug, MallocSizeOf, PartialEq, #[derive(Animate, Clone, ComputeSquaredDistance, Copy, Debug, MallocSizeOf,
ToAnimatedValue, ToAnimatedZero, ToComputedValue, ToCss)] PartialEq, SpecifiedValueInfo, ToAnimatedValue, ToAnimatedZero,
ToComputedValue, ToCss)]
pub enum ColumnCount<PositiveInteger> { pub enum ColumnCount<PositiveInteger> {
/// A positive integer. /// A positive integer.
Integer(PositiveInteger), Integer(PositiveInteger),

View file

@ -11,7 +11,8 @@ use style_traits::{CssWriter, ToCss};
use values::CustomIdent; use values::CustomIdent;
/// A generic value for the `counter-increment` property. /// A generic value for the `counter-increment` property.
#[derive(Clone, Debug, Default, MallocSizeOf, PartialEq, ToComputedValue, ToCss)] #[derive(Clone, Debug, Default, MallocSizeOf, PartialEq, SpecifiedValueInfo,
ToComputedValue, ToCss)]
pub struct CounterIncrement<I>(Counters<I>); pub struct CounterIncrement<I>(Counters<I>);
impl<I> CounterIncrement<I> { impl<I> CounterIncrement<I> {
@ -32,7 +33,8 @@ impl<I> Deref for CounterIncrement<I> {
} }
/// A generic value for the `counter-reset` property. /// A generic value for the `counter-reset` property.
#[derive(Clone, Debug, Default, MallocSizeOf, PartialEq, ToComputedValue, ToCss)] #[derive(Clone, Debug, Default, MallocSizeOf, PartialEq, SpecifiedValueInfo,
ToComputedValue, ToCss)]
pub struct CounterReset<I>(Counters<I>); pub struct CounterReset<I>(Counters<I>);
impl<I> CounterReset<I> { impl<I> CounterReset<I> {
@ -55,8 +57,9 @@ impl<I> Deref for CounterReset<I> {
/// A generic value for lists of counters. /// A generic value for lists of counters.
/// ///
/// Keyword `none` is represented by an empty vector. /// Keyword `none` is represented by an empty vector.
#[derive(Clone, Debug, MallocSizeOf, PartialEq, ToComputedValue)] #[derive(Clone, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo,
pub struct Counters<I>(Box<[(CustomIdent, I)]>); ToComputedValue)]
pub struct Counters<I>(#[css(if_empty = "none")] Box<[(CustomIdent, I)]>);
impl<I> Default for Counters<I> { impl<I> Default for Counters<I> {
#[inline] #[inline]

View file

@ -10,7 +10,8 @@ use style_traits::values::{CssWriter, SequenceWriter, ToCss};
use values::specified::url::SpecifiedUrl; use values::specified::url::SpecifiedUrl;
/// A generic value for a single `box-shadow`. /// A generic value for a single `box-shadow`.
#[derive(Animate, Clone, Debug, MallocSizeOf, PartialEq, ToAnimatedValue, ToAnimatedZero)] #[derive(Animate, Clone, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo,
ToAnimatedValue, ToAnimatedZero)]
pub struct BoxShadow<Color, SizeLength, BlurShapeLength, ShapeLength> { pub struct BoxShadow<Color, SizeLength, BlurShapeLength, ShapeLength> {
/// The base shadow. /// The base shadow.
pub base: SimpleShadow<Color, SizeLength, BlurShapeLength>, pub base: SimpleShadow<Color, SizeLength, BlurShapeLength>,
@ -18,13 +19,14 @@ pub struct BoxShadow<Color, SizeLength, BlurShapeLength, ShapeLength> {
pub spread: ShapeLength, pub spread: ShapeLength,
/// Whether this is an inset box shadow. /// Whether this is an inset box shadow.
#[animation(constant)] #[animation(constant)]
#[value_info(represents_keyword)]
pub inset: bool, pub inset: bool,
} }
/// A generic value for a single `filter`. /// A generic value for a single `filter`.
#[cfg_attr(feature = "servo", derive(Deserialize, Serialize))] #[cfg_attr(feature = "servo", derive(Deserialize, Serialize))]
#[derive(Clone, ComputeSquaredDistance, Debug, MallocSizeOf, PartialEq, ToAnimatedValue, #[derive(Clone, ComputeSquaredDistance, Debug, MallocSizeOf, PartialEq,
ToComputedValue, ToCss)] SpecifiedValueInfo, ToAnimatedValue, ToComputedValue, ToCss)]
pub enum Filter<Angle, Factor, Length, DropShadow> { pub enum Filter<Angle, Factor, Length, DropShadow> {
/// `blur(<length>)` /// `blur(<length>)`
#[css(function)] #[css(function)]
@ -66,8 +68,8 @@ pub enum Filter<Angle, Factor, Length, DropShadow> {
/// ///
/// Contrary to the canonical order from the spec, the color is serialised /// Contrary to the canonical order from the spec, the color is serialised
/// first, like in Gecko and Webkit. /// first, like in Gecko and Webkit.
#[derive(Animate, Clone, ComputeSquaredDistance, Debug, MallocSizeOf, PartialEq, ToAnimatedValue, #[derive(Animate, Clone, ComputeSquaredDistance, Debug, MallocSizeOf, PartialEq,
ToAnimatedZero, ToCss)] SpecifiedValueInfo, ToAnimatedValue, ToAnimatedZero, ToCss)]
pub struct SimpleShadow<Color, SizeLength, ShapeLength> { pub struct SimpleShadow<Color, SizeLength, ShapeLength> {
/// Color. /// Color.
pub color: Color, pub color: Color,

View file

@ -6,8 +6,9 @@
/// A generic value for the `flex-basis` property. /// A generic value for the `flex-basis` property.
#[cfg_attr(feature = "servo", derive(MallocSizeOf))] #[cfg_attr(feature = "servo", derive(MallocSizeOf))]
#[derive(Animate, Clone, ComputeSquaredDistance, Copy, Debug, PartialEq, ToAnimatedValue, #[derive(Animate, Clone, ComputeSquaredDistance, Copy, Debug, PartialEq,
ToAnimatedZero, ToComputedValue, ToCss)] SpecifiedValueInfo, ToAnimatedValue, ToAnimatedZero, ToComputedValue,
ToCss)]
pub enum FlexBasis<Width> { pub enum FlexBasis<Width> {
/// `content` /// `content`
Content, Content,

View file

@ -11,11 +11,13 @@ use num_traits::One;
use parser::{Parse, ParserContext}; use parser::{Parse, ParserContext};
use std::fmt::{self, Write}; use std::fmt::{self, Write};
use std::io::Cursor; use std::io::Cursor;
use style_traits::{CssWriter, ParseError, StyleParseErrorKind, ToCss}; use style_traits::{CssWriter, KeywordsCollectFn, ParseError};
use style_traits::{SpecifiedValueInfo, StyleParseErrorKind, ToCss};
use values::distance::{ComputeSquaredDistance, SquaredDistance}; use values::distance::{ComputeSquaredDistance, SquaredDistance};
/// https://drafts.csswg.org/css-fonts-4/#feature-tag-value /// https://drafts.csswg.org/css-fonts-4/#feature-tag-value
#[derive(Clone, Debug, Eq, MallocSizeOf, PartialEq, ToComputedValue)] #[derive(Clone, Debug, Eq, MallocSizeOf, PartialEq, SpecifiedValueInfo,
ToComputedValue)]
pub struct FeatureTagValue<Integer> { pub struct FeatureTagValue<Integer> {
/// A four-character tag, packed into a u32 (one byte per character). /// A four-character tag, packed into a u32 (one byte per character).
pub tag: FontTag, pub tag: FontTag,
@ -45,7 +47,8 @@ where
/// Variation setting for a single feature, see: /// Variation setting for a single feature, see:
/// ///
/// https://drafts.csswg.org/css-fonts-4/#font-variation-settings-def /// https://drafts.csswg.org/css-fonts-4/#font-variation-settings-def
#[derive(Animate, Clone, Debug, Eq, MallocSizeOf, PartialEq, ToComputedValue, ToCss)] #[derive(Animate, Clone, Debug, Eq, MallocSizeOf, PartialEq, SpecifiedValueInfo,
ToComputedValue, ToCss)]
pub struct VariationValue<Number> { pub struct VariationValue<Number> {
/// A four-character tag, packed into a u32 (one byte per character). /// A four-character tag, packed into a u32 (one byte per character).
#[animation(constant)] #[animation(constant)]
@ -69,7 +72,8 @@ where
/// A value both for font-variation-settings and font-feature-settings. /// A value both for font-variation-settings and font-feature-settings.
#[css(comma)] #[css(comma)]
#[derive(Clone, Debug, Eq, MallocSizeOf, PartialEq, ToComputedValue, ToCss)] #[derive(Clone, Debug, Eq, MallocSizeOf, PartialEq, SpecifiedValueInfo,
ToComputedValue, ToCss)]
pub struct FontSettings<T>(#[css(if_empty = "normal", iterable)] pub Box<[T]>); pub struct FontSettings<T>(#[css(if_empty = "normal", iterable)] pub Box<[T]>);
impl<T> FontSettings<T> { impl<T> FontSettings<T> {
@ -105,7 +109,8 @@ impl<T: Parse> Parse for FontSettings<T> {
/// https://drafts.csswg.org/css-fonts-4/#font-variation-settings-def /// https://drafts.csswg.org/css-fonts-4/#font-variation-settings-def
/// https://drafts.csswg.org/css-fonts-4/#descdef-font-face-font-feature-settings /// https://drafts.csswg.org/css-fonts-4/#descdef-font-face-font-feature-settings
/// ///
#[derive(Clone, Copy, Debug, Eq, MallocSizeOf, PartialEq, ToComputedValue)] #[derive(Clone, Copy, Debug, Eq, MallocSizeOf, PartialEq, SpecifiedValueInfo,
ToComputedValue)]
pub struct FontTag(pub u32); pub struct FontTag(pub u32);
impl ToCss for FontTag { impl ToCss for FontTag {
@ -177,20 +182,30 @@ where
} }
} }
impl<L> SpecifiedValueInfo for KeywordInfo<L> {
fn collect_completion_keywords(f: KeywordsCollectFn) {
<KeywordSize as SpecifiedValueInfo>::collect_completion_keywords(f);
}
}
/// CSS font keywords /// CSS font keywords
#[derive(Animate, Clone, ComputeSquaredDistance, Copy, Debug, MallocSizeOf, PartialEq, #[derive(Animate, Clone, ComputeSquaredDistance, Copy, Debug, MallocSizeOf,
ToAnimatedValue, ToAnimatedZero)] Parse, PartialEq, SpecifiedValueInfo, ToAnimatedValue, ToAnimatedZero,
ToCss)]
#[allow(missing_docs)] #[allow(missing_docs)]
pub enum KeywordSize { pub enum KeywordSize {
#[css(keyword = "xx-small")]
XXSmall, XXSmall,
XSmall, XSmall,
Small, Small,
Medium, Medium,
Large, Large,
XLarge, XLarge,
#[css(keyword = "xx-large")]
XXLarge, XXLarge,
// This is not a real font keyword and will not parse // This is not a real font keyword and will not parse
// HTML font-size 7 corresponds to this value // HTML font-size 7 corresponds to this value
#[css(skip)]
XXXLarge, XXXLarge,
} }
@ -208,41 +223,18 @@ impl Default for KeywordSize {
} }
} }
impl ToCss for KeywordSize {
fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
where
W: Write,
{
dest.write_str(match *self {
KeywordSize::XXSmall => "xx-small",
KeywordSize::XSmall => "x-small",
KeywordSize::Small => "small",
KeywordSize::Medium => "medium",
KeywordSize::Large => "large",
KeywordSize::XLarge => "x-large",
KeywordSize::XXLarge => "xx-large",
KeywordSize::XXXLarge => {
debug_assert!(
false,
"We should never serialize specified values set via HTML presentation attributes"
);
"-servo-xxx-large"
},
})
}
}
/// A generic value for the `font-style` property. /// A generic value for the `font-style` property.
/// ///
/// https://drafts.csswg.org/css-fonts-4/#font-style-prop /// https://drafts.csswg.org/css-fonts-4/#font-style-prop
#[allow(missing_docs)] #[allow(missing_docs)]
#[derive(Animate, Clone, ComputeSquaredDistance, Copy, Debug, MallocSizeOf,
PartialEq, ToAnimatedValue, ToAnimatedZero)]
#[cfg_attr(feature = "servo", derive(Deserialize, Serialize))] #[cfg_attr(feature = "servo", derive(Deserialize, Serialize))]
#[derive(Animate, Clone, ComputeSquaredDistance, Copy, Debug, MallocSizeOf,
PartialEq, SpecifiedValueInfo, ToAnimatedValue, ToAnimatedZero)]
pub enum FontStyle<Angle> { pub enum FontStyle<Angle> {
#[animation(error)] #[animation(error)]
Normal, Normal,
#[animation(error)] #[animation(error)]
Italic, Italic,
#[value_info(starts_with_keyword)]
Oblique(Angle), Oblique(Angle),
} }

View file

@ -7,7 +7,8 @@
/// A generic value for scroll snap points. /// A generic value for scroll snap points.
#[cfg_attr(feature = "gecko", derive(MallocSizeOf))] #[cfg_attr(feature = "gecko", derive(MallocSizeOf))]
#[derive(Clone, Copy, Debug, PartialEq, ToComputedValue, ToCss)] #[derive(Clone, Copy, Debug, PartialEq, SpecifiedValueInfo, ToComputedValue,
ToCss)]
pub enum ScrollSnapPoint<LengthOrPercentage> { pub enum ScrollSnapPoint<LengthOrPercentage> {
/// `none` /// `none`
None, None,

View file

@ -18,7 +18,8 @@ use values::specified::grid::parse_line_names;
/// A `<grid-line>` type. /// A `<grid-line>` type.
/// ///
/// <https://drafts.csswg.org/css-grid/#typedef-grid-row-start-grid-line> /// <https://drafts.csswg.org/css-grid/#typedef-grid-row-start-grid-line>
#[derive(Clone, Debug, Default, MallocSizeOf, PartialEq, ToComputedValue)] #[derive(Clone, Debug, Default, MallocSizeOf, PartialEq, SpecifiedValueInfo,
ToComputedValue)]
pub struct GridLine<Integer> { pub struct GridLine<Integer> {
/// Flag to check whether it's a `span` keyword. /// Flag to check whether it's a `span` keyword.
pub is_span: bool, pub is_span: bool,
@ -148,7 +149,8 @@ impl Parse for GridLine<specified::Integer> {
#[allow(missing_docs)] #[allow(missing_docs)]
#[cfg_attr(feature = "servo", derive(Deserialize, Serialize))] #[cfg_attr(feature = "servo", derive(Deserialize, Serialize))]
#[derive(Clone, Copy, Debug, Eq, MallocSizeOf, Parse, PartialEq, ToComputedValue, ToCss)] #[derive(Clone, Copy, Debug, Eq, MallocSizeOf, Parse, PartialEq,
SpecifiedValueInfo, ToComputedValue, ToCss)]
pub enum TrackKeyword { pub enum TrackKeyword {
Auto, Auto,
MaxContent, MaxContent,
@ -159,7 +161,8 @@ pub enum TrackKeyword {
/// avoid re-implementing it for the computed type. /// avoid re-implementing it for the computed type.
/// ///
/// <https://drafts.csswg.org/css-grid/#typedef-track-breadth> /// <https://drafts.csswg.org/css-grid/#typedef-track-breadth>
#[derive(Clone, Debug, MallocSizeOf, PartialEq, ToComputedValue, ToCss)] #[derive(Clone, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo,
ToComputedValue, ToCss)]
pub enum TrackBreadth<L> { pub enum TrackBreadth<L> {
/// The generic type is almost always a non-negative `<length-percentage>` /// The generic type is almost always a non-negative `<length-percentage>`
Breadth(L), Breadth(L),
@ -187,7 +190,7 @@ impl<L> TrackBreadth<L> {
/// generic only to avoid code bloat. It only takes `<length-percentage>` /// generic only to avoid code bloat. It only takes `<length-percentage>`
/// ///
/// <https://drafts.csswg.org/css-grid/#typedef-track-size> /// <https://drafts.csswg.org/css-grid/#typedef-track-size>
#[derive(Clone, Debug, MallocSizeOf, PartialEq)] #[derive(Clone, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo)]
pub enum TrackSize<L> { pub enum TrackSize<L> {
/// A flexible `<track-breadth>` /// A flexible `<track-breadth>`
Breadth(TrackBreadth<L>), Breadth(TrackBreadth<L>),
@ -195,10 +198,12 @@ pub enum TrackSize<L> {
/// and a flexible `<track-breadth>` /// and a flexible `<track-breadth>`
/// ///
/// <https://drafts.csswg.org/css-grid/#valdef-grid-template-columns-minmax> /// <https://drafts.csswg.org/css-grid/#valdef-grid-template-columns-minmax>
#[css(function)]
Minmax(TrackBreadth<L>, TrackBreadth<L>), Minmax(TrackBreadth<L>, TrackBreadth<L>),
/// A `fit-content` function. /// A `fit-content` function.
/// ///
/// <https://drafts.csswg.org/css-grid/#valdef-grid-template-columns-fit-content> /// <https://drafts.csswg.org/css-grid/#valdef-grid-template-columns-fit-content>
#[css(function)]
FitContent(L), FitContent(L),
} }
@ -378,7 +383,9 @@ impl Parse for RepeatCount<specified::Integer> {
/// ///
/// It can also hold `repeat()` function parameters, which expands into the respective /// It can also hold `repeat()` function parameters, which expands into the respective
/// values in its computed form. /// values in its computed form.
#[derive(Clone, Debug, MallocSizeOf, PartialEq, ToComputedValue)] #[derive(Clone, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo,
ToComputedValue)]
#[css(function = "repeat")]
pub struct TrackRepeat<L, I> { pub struct TrackRepeat<L, I> {
/// The number of times for the value to be repeated (could also be `auto-fit` or `auto-fill`) /// The number of times for the value to be repeated (could also be `auto-fit` or `auto-fill`)
pub count: RepeatCount<I>, pub count: RepeatCount<I>,
@ -464,7 +471,8 @@ impl<L: Clone> TrackRepeat<L, specified::Integer> {
} }
/// Track list values. Can be <track-size> or <track-repeat> /// Track list values. Can be <track-size> or <track-repeat>
#[derive(Clone, Debug, MallocSizeOf, PartialEq, ToComputedValue, ToCss)] #[derive(Clone, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo,
ToComputedValue, ToCss)]
pub enum TrackListValue<LengthOrPercentage, Integer> { pub enum TrackListValue<LengthOrPercentage, Integer> {
/// A <track-size> value. /// A <track-size> value.
TrackSize(TrackSize<LengthOrPercentage>), TrackSize(TrackSize<LengthOrPercentage>),
@ -497,12 +505,13 @@ pub enum TrackListType {
/// A grid `<track-list>` type. /// A grid `<track-list>` type.
/// ///
/// <https://drafts.csswg.org/css-grid/#typedef-track-list> /// <https://drafts.csswg.org/css-grid/#typedef-track-list>
#[derive(Clone, Debug, MallocSizeOf, PartialEq)] #[derive(Clone, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo)]
pub struct TrackList<LengthOrPercentage, Integer> { pub struct TrackList<LengthOrPercentage, Integer> {
/// The type of this `<track-list>` (auto, explicit or general). /// The type of this `<track-list>` (auto, explicit or general).
/// ///
/// In order to avoid parsing the same value multiple times, this does a single traversal /// In order to avoid parsing the same value multiple times, this does a single traversal
/// and arrives at the type of value it has parsed (or bails out gracefully with an error). /// and arrives at the type of value it has parsed (or bails out gracefully with an error).
#[css(skip)]
pub list_type: TrackListType, pub list_type: TrackListType,
/// A vector of `<track-size> | <track-repeat>` values. /// A vector of `<track-size> | <track-repeat>` values.
pub values: Vec<TrackListValue<LengthOrPercentage, Integer>>, pub values: Vec<TrackListValue<LengthOrPercentage, Integer>>,
@ -569,7 +578,8 @@ impl<L: ToCss, I: ToCss> ToCss for TrackList<L, I> {
/// ///
/// `subgrid [ <line-names> | repeat(<positive-integer> | auto-fill, <line-names>+) ]+` /// `subgrid [ <line-names> | repeat(<positive-integer> | auto-fill, <line-names>+) ]+`
/// Old spec: https://www.w3.org/TR/2015/WD-css-grid-1-20150917/#typedef-line-name-list /// Old spec: https://www.w3.org/TR/2015/WD-css-grid-1-20150917/#typedef-line-name-list
#[derive(Clone, Debug, Default, MallocSizeOf, PartialEq, ToComputedValue)] #[derive(Clone, Debug, Default, MallocSizeOf, PartialEq, SpecifiedValueInfo,
ToComputedValue)]
pub struct LineNameList { pub struct LineNameList {
/// The optional `<line-name-list>` /// The optional `<line-name-list>`
pub names: Box<[Box<[CustomIdent]>]>, pub names: Box<[Box<[CustomIdent]>]>,
@ -672,7 +682,8 @@ impl ToCss for LineNameList {
/// Variants for `<grid-template-rows> | <grid-template-columns>` /// Variants for `<grid-template-rows> | <grid-template-columns>`
/// Subgrid deferred to Level 2 spec due to lack of implementation. /// Subgrid deferred to Level 2 spec due to lack of implementation.
/// But it's implemented in gecko, so we have to as well. /// But it's implemented in gecko, so we have to as well.
#[derive(Clone, Debug, MallocSizeOf, PartialEq, ToComputedValue, ToCss)] #[derive(Clone, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo,
ToComputedValue, ToCss)]
pub enum GridTemplateComponent<L, I> { pub enum GridTemplateComponent<L, I> {
/// `none` value. /// `none` value.
None, None,

View file

@ -16,7 +16,7 @@ use values::serialize_atom_identifier;
/// An [image]. /// An [image].
/// ///
/// [image]: https://drafts.csswg.org/css-images/#image-values /// [image]: https://drafts.csswg.org/css-images/#image-values
#[derive(Clone, MallocSizeOf, PartialEq, ToComputedValue)] #[derive(Clone, MallocSizeOf, PartialEq, SpecifiedValueInfo, ToComputedValue)]
pub enum Image<Gradient, MozImageRect, ImageUrl> { pub enum Image<Gradient, MozImageRect, ImageUrl> {
/// A `<url()>` image. /// A `<url()>` image.
Url(ImageUrl), Url(ImageUrl),
@ -26,6 +26,7 @@ pub enum Image<Gradient, MozImageRect, ImageUrl> {
/// A `-moz-image-rect` image. Also fairly large and rare. /// A `-moz-image-rect` image. Also fairly large and rare.
Rect(Box<MozImageRect>), Rect(Box<MozImageRect>),
/// A `-moz-element(# <element-id>)` /// A `-moz-element(# <element-id>)`
#[css(function = "-moz-element")]
Element(Atom), Element(Atom),
/// A paint worklet image. /// A paint worklet image.
/// <https://drafts.css-houdini.org/css-paint-api/> /// <https://drafts.css-houdini.org/css-paint-api/>
@ -144,6 +145,8 @@ pub struct PaintWorklet {
pub arguments: Vec<Arc<custom_properties::SpecifiedValue>>, pub arguments: Vec<Arc<custom_properties::SpecifiedValue>>,
} }
impl ::style_traits::SpecifiedValueInfo for PaintWorklet { }
impl ToCss for PaintWorklet { impl ToCss for PaintWorklet {
fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
where where
@ -164,7 +167,8 @@ impl ToCss for PaintWorklet {
/// `-moz-image-rect(<uri>, top, right, bottom, left);` /// `-moz-image-rect(<uri>, top, right, bottom, left);`
#[allow(missing_docs)] #[allow(missing_docs)]
#[css(comma, function)] #[css(comma, function)]
#[derive(Clone, Debug, MallocSizeOf, PartialEq, ToComputedValue, ToCss)] #[derive(Clone, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo,
ToComputedValue, ToCss)]
pub struct MozImageRect<NumberOrPercentage, MozImageRectUrl> { pub struct MozImageRect<NumberOrPercentage, MozImageRectUrl> {
pub url: MozImageRectUrl, pub url: MozImageRectUrl,
pub top: NumberOrPercentage, pub top: NumberOrPercentage,

View file

@ -8,7 +8,8 @@
use counter_style::{parse_counter_style_name, Symbols}; use counter_style::{parse_counter_style_name, Symbols};
use cssparser::Parser; use cssparser::Parser;
use parser::{Parse, ParserContext}; use parser::{Parse, ParserContext};
use style_traits::{ParseError, StyleParseErrorKind}; use style_traits::{KeywordsCollectFn, ParseError};
use style_traits::{SpecifiedValueInfo, StyleParseErrorKind};
use super::CustomIdent; use super::CustomIdent;
pub mod background; pub mod background;
@ -137,14 +138,32 @@ impl Parse for CounterStyleOrNone {
} }
} }
impl SpecifiedValueInfo for CounterStyleOrNone {
fn collect_completion_keywords(f: KeywordsCollectFn) {
// XXX The best approach for implementing this is probably
// having a CounterStyleName type wrapping CustomIdent, and
// put the predefined list for that type in counter_style mod.
// But that's a non-trivial change itself, so we use a simpler
// approach here.
macro_rules! predefined {
($($name:expr,)+) => {
f(&["none", "symbols", $($name,)+]);
}
}
include!("../../counter_style/predefined.rs");
}
}
/// A wrapper of Non-negative values. /// A wrapper of Non-negative values.
#[cfg_attr(feature = "servo", derive(Deserialize, Serialize))] #[cfg_attr(feature = "servo", derive(Deserialize, Serialize))]
#[derive(Animate, Clone, ComputeSquaredDistance, Copy, Debug, MallocSizeOf, PartialEq, #[derive(Animate, Clone, ComputeSquaredDistance, Copy, Debug, MallocSizeOf,
PartialOrd, ToAnimatedZero, ToComputedValue, ToCss)] PartialEq, PartialOrd, SpecifiedValueInfo, ToAnimatedZero,
ToComputedValue, ToCss)]
pub struct NonNegative<T>(pub T); pub struct NonNegative<T>(pub T);
/// A wrapper of greater-than-or-equal-to-one values. /// A wrapper of greater-than-or-equal-to-one values.
#[cfg_attr(feature = "servo", derive(Deserialize, Serialize))] #[cfg_attr(feature = "servo", derive(Deserialize, Serialize))]
#[derive(Animate, Clone, ComputeSquaredDistance, Copy, Debug, MallocSizeOf, PartialEq, #[derive(Animate, Clone, ComputeSquaredDistance, Copy, Debug, MallocSizeOf,
PartialOrd, ToAnimatedZero, ToComputedValue, ToCss)] PartialEq, PartialOrd, SpecifiedValueInfo, ToAnimatedZero,
ToComputedValue, ToCss)]
pub struct GreaterThanOrEqualToOne<T>(pub T); pub struct GreaterThanOrEqualToOne<T>(pub T);

View file

@ -4,12 +4,79 @@
//! Generic values for pointing properties. //! Generic values for pointing properties.
use std::fmt::{self, Write};
use style_traits::{CssWriter, ToCss};
use style_traits::cursor::CursorKind;
/// A generic value for the `caret-color` property. /// A generic value for the `caret-color` property.
#[derive(Animate, Clone, ComputeSquaredDistance, Copy, Debug, MallocSizeOf, PartialEq, #[derive(Animate, Clone, ComputeSquaredDistance, Copy, Debug, MallocSizeOf,
ToAnimatedValue, ToAnimatedZero, ToComputedValue, ToCss)] PartialEq, SpecifiedValueInfo, ToAnimatedValue, ToAnimatedZero,
ToComputedValue, ToCss)]
pub enum CaretColor<Color> { pub enum CaretColor<Color> {
/// An explicit color. /// An explicit color.
Color(Color), Color(Color),
/// The keyword `auto`. /// The keyword `auto`.
Auto, Auto,
} }
/// A generic value for the `cursor` property.
///
/// https://drafts.csswg.org/css-ui/#cursor
#[derive(Clone, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo,
ToComputedValue)]
pub struct Cursor<Image> {
/// The parsed images for the cursor.
pub images: Box<[Image]>,
/// The kind of the cursor [default | help | ...].
pub keyword: CursorKind,
}
impl<Image> Cursor<Image> {
/// Set `cursor` to `auto`
#[inline]
pub fn auto() -> Self {
Self {
images: vec![].into_boxed_slice(),
keyword: CursorKind::Auto,
}
}
}
impl<Image: ToCss> ToCss for Cursor<Image> {
fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
where
W: Write,
{
for image in &*self.images {
image.to_css(dest)?;
dest.write_str(", ")?;
}
self.keyword.to_css(dest)
}
}
/// A generic value for item of `image cursors`.
#[derive(Clone, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo,
ToComputedValue)]
pub struct CursorImage<ImageUrl, Number> {
/// The url to parse images from.
pub url: ImageUrl,
/// The <x> and <y> coordinates.
pub hotspot: Option<(Number, Number)>,
}
impl<ImageUrl: ToCss, Number: ToCss> ToCss for CursorImage<ImageUrl, Number> {
fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
where
W: Write,
{
self.url.to_css(dest)?;
if let Some((ref x, ref y)) = self.hotspot {
dest.write_str(" ")?;
x.to_css(dest)?;
dest.write_str(" ")?;
y.to_css(dest)?;
}
Ok(())
}
}

View file

@ -6,8 +6,8 @@
//! [`position`](https://drafts.csswg.org/css-backgrounds-3/#position) //! [`position`](https://drafts.csswg.org/css-backgrounds-3/#position)
/// A generic type for representing a CSS [position](https://drafts.csswg.org/css-values/#position). /// A generic type for representing a CSS [position](https://drafts.csswg.org/css-values/#position).
#[derive(Animate, Clone, ComputeSquaredDistance, Copy, Debug, MallocSizeOf, PartialEq, #[derive(Animate, Clone, ComputeSquaredDistance, Copy, Debug, MallocSizeOf,
ToAnimatedZero, ToComputedValue)] PartialEq, SpecifiedValueInfo, ToAnimatedZero, ToComputedValue)]
pub struct Position<H, V> { pub struct Position<H, V> {
/// The horizontal component of position. /// The horizontal component of position.
pub horizontal: H, pub horizontal: H,
@ -26,8 +26,8 @@ impl<H, V> Position<H, V> {
} }
/// A generic value for the `z-index` property. /// A generic value for the `z-index` property.
#[derive(Animate, Clone, ComputeSquaredDistance, Copy, Debug, MallocSizeOf, PartialEq, #[derive(Animate, Clone, ComputeSquaredDistance, Copy, Debug, MallocSizeOf,
ToAnimatedZero, ToComputedValue, ToCss)] PartialEq, SpecifiedValueInfo, ToAnimatedZero, ToComputedValue, ToCss)]
pub enum ZIndex<Integer> { pub enum ZIndex<Integer> {
/// An integer value. /// An integer value.
Integer(Integer), Integer(Integer),

View file

@ -11,8 +11,8 @@ use style_traits::{CssWriter, ParseError, ToCss};
/// A CSS value made of four components, where its `ToCss` impl will try to /// A CSS value made of four components, where its `ToCss` impl will try to
/// serialize as few components as possible, like for example in `border-width`. /// serialize as few components as possible, like for example in `border-width`.
#[derive(Animate, Clone, ComputeSquaredDistance, Copy, Debug, MallocSizeOf, PartialEq, #[derive(Animate, Clone, ComputeSquaredDistance, Copy, Debug, MallocSizeOf,
ToComputedValue)] PartialEq, SpecifiedValueInfo, ToComputedValue)]
pub struct Rect<T>(pub T, pub T, pub T, pub T); pub struct Rect<T>(pub T, pub T, pub T, pub T);
impl<T> Rect<T> { impl<T> Rect<T> {

View file

@ -8,7 +8,7 @@ use cssparser::Parser;
use euclid::Size2D; use euclid::Size2D;
use parser::ParserContext; use parser::ParserContext;
use std::fmt::{self, Write}; use std::fmt::{self, Write};
use style_traits::{CssWriter, ParseError, ToCss}; use style_traits::{CssWriter, ParseError, SpecifiedValueInfo, ToCss};
use values::animated::ToAnimatedValue; use values::animated::ToAnimatedValue;
/// A generic size, for `border-*-radius` longhand properties, or /// A generic size, for `border-*-radius` longhand properties, or
@ -93,3 +93,7 @@ where
)) ))
} }
} }
impl<L: SpecifiedValueInfo> SpecifiedValueInfo for Size<L> {
const SUPPORTED_TYPES: u8 = L::SUPPORTED_TYPES;
}

View file

@ -16,8 +16,8 @@ use values::distance::{ComputeSquaredDistance, SquaredDistance};
/// ///
/// <https://www.w3.org/TR/SVG2/painting.html#SpecifyingPaint> /// <https://www.w3.org/TR/SVG2/painting.html#SpecifyingPaint>
#[animation(no_bound(UrlPaintServer))] #[animation(no_bound(UrlPaintServer))]
#[derive(Animate, Clone, ComputeSquaredDistance, Debug, MallocSizeOf, PartialEq, ToAnimatedValue, #[derive(Animate, Clone, ComputeSquaredDistance, Debug, MallocSizeOf, PartialEq,
ToComputedValue, ToCss)] SpecifiedValueInfo, ToAnimatedValue, ToComputedValue, ToCss)]
pub struct SVGPaint<ColorType, UrlPaintServer> { pub struct SVGPaint<ColorType, UrlPaintServer> {
/// The paint source /// The paint source
pub kind: SVGPaintKind<ColorType, UrlPaintServer>, pub kind: SVGPaintKind<ColorType, UrlPaintServer>,
@ -31,8 +31,9 @@ pub struct SVGPaint<ColorType, UrlPaintServer> {
/// to have a fallback, Gecko lets the context /// to have a fallback, Gecko lets the context
/// properties have a fallback as well. /// properties have a fallback as well.
#[animation(no_bound(UrlPaintServer))] #[animation(no_bound(UrlPaintServer))]
#[derive(Animate, Clone, ComputeSquaredDistance, Debug, MallocSizeOf, PartialEq, ToAnimatedValue, #[derive(Animate, Clone, ComputeSquaredDistance, Debug, MallocSizeOf, PartialEq,
ToAnimatedZero, ToComputedValue, ToCss)] SpecifiedValueInfo, ToAnimatedValue, ToAnimatedZero, ToComputedValue,
ToCss)]
pub enum SVGPaintKind<ColorType, UrlPaintServer> { pub enum SVGPaintKind<ColorType, UrlPaintServer> {
/// `none` /// `none`
#[animation(error)] #[animation(error)]
@ -112,8 +113,8 @@ impl<ColorType: Parse, UrlPaintServer: Parse> Parse for SVGPaint<ColorType, UrlP
/// A value of <length> | <percentage> | <number> for svg which allow unitless length. /// A value of <length> | <percentage> | <number> for svg which allow unitless length.
/// <https://www.w3.org/TR/SVG11/painting.html#StrokeProperties> /// <https://www.w3.org/TR/SVG11/painting.html#StrokeProperties>
#[derive(Clone, Copy, Debug, MallocSizeOf, PartialEq, ToAnimatedValue, ToAnimatedZero, #[derive(Clone, Copy, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo,
ToComputedValue, ToCss)] ToAnimatedValue, ToAnimatedZero, ToComputedValue, ToCss)]
pub enum SvgLengthOrPercentageOrNumber<LengthOrPercentage, Number> { pub enum SvgLengthOrPercentageOrNumber<LengthOrPercentage, Number> {
/// <length> | <percentage> /// <length> | <percentage>
LengthOrPercentage(LengthOrPercentage), LengthOrPercentage(LengthOrPercentage),
@ -190,8 +191,9 @@ impl<LengthOrPercentageType: Parse, NumberType: Parse> Parse
} }
/// An SVG length value supports `context-value` in addition to length. /// An SVG length value supports `context-value` in addition to length.
#[derive(Clone, ComputeSquaredDistance, Copy, Debug, MallocSizeOf, PartialEq, ToAnimatedValue, #[derive(Clone, ComputeSquaredDistance, Copy, Debug, MallocSizeOf, PartialEq,
ToAnimatedZero, ToComputedValue, ToCss)] SpecifiedValueInfo, ToAnimatedValue, ToAnimatedZero, ToComputedValue,
ToCss)]
pub enum SVGLength<LengthType> { pub enum SVGLength<LengthType> {
/// `<length> | <percentage> | <number>` /// `<length> | <percentage> | <number>`
Length(LengthType), Length(LengthType),
@ -200,8 +202,8 @@ pub enum SVGLength<LengthType> {
} }
/// Generic value for stroke-dasharray. /// Generic value for stroke-dasharray.
#[derive(Clone, ComputeSquaredDistance, Debug, MallocSizeOf, PartialEq, ToAnimatedValue, #[derive(Clone, ComputeSquaredDistance, Debug, MallocSizeOf, PartialEq,
ToComputedValue, ToCss)] SpecifiedValueInfo, ToAnimatedValue, ToComputedValue, ToCss)]
pub enum SVGStrokeDashArray<LengthType> { pub enum SVGStrokeDashArray<LengthType> {
/// `[ <length> | <percentage> | <number> ]#` /// `[ <length> | <percentage> | <number> ]#`
#[css(comma)] #[css(comma)]
@ -216,8 +218,8 @@ pub enum SVGStrokeDashArray<LengthType> {
/// An SVG opacity value accepts `context-{fill,stroke}-opacity` in /// An SVG opacity value accepts `context-{fill,stroke}-opacity` in
/// addition to opacity value. /// addition to opacity value.
#[derive(Clone, ComputeSquaredDistance, Copy, Debug, MallocSizeOf, PartialEq, ToAnimatedZero, #[derive(Clone, ComputeSquaredDistance, Copy, Debug, MallocSizeOf, PartialEq,
ToComputedValue, ToCss)] SpecifiedValueInfo, ToAnimatedZero, ToComputedValue, ToCss)]
pub enum SVGOpacity<OpacityType> { pub enum SVGOpacity<OpacityType> {
/// `<opacity-value>` /// `<opacity-value>`
Opacity(OpacityType), Opacity(OpacityType),

View file

@ -12,7 +12,8 @@ use values::animated::{Animate, Procedure, ToAnimatedZero};
use values::distance::{ComputeSquaredDistance, SquaredDistance}; use values::distance::{ComputeSquaredDistance, SquaredDistance};
/// A generic value for the `initial-letter` property. /// A generic value for the `initial-letter` property.
#[derive(Clone, Copy, Debug, MallocSizeOf, PartialEq, ToComputedValue, ToCss)] #[derive(Clone, Copy, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo,
ToComputedValue, ToCss)]
pub enum InitialLetter<Number, Integer> { pub enum InitialLetter<Number, Integer> {
/// `normal` /// `normal`
Normal, Normal,
@ -29,7 +30,8 @@ impl<N, I> InitialLetter<N, I> {
} }
/// A generic spacing value for the `letter-spacing` and `word-spacing` properties. /// A generic spacing value for the `letter-spacing` and `word-spacing` properties.
#[derive(Clone, Copy, Debug, MallocSizeOf, PartialEq, ToComputedValue, ToCss)] #[derive(Clone, Copy, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo,
ToComputedValue, ToCss)]
pub enum Spacing<Value> { pub enum Spacing<Value> {
/// `normal` /// `normal`
Normal, Normal,
@ -110,8 +112,8 @@ where
} }
/// A generic value for the `line-height` property. /// A generic value for the `line-height` property.
#[derive(Animate, Clone, ComputeSquaredDistance, Copy, Debug, MallocSizeOf, PartialEq, #[derive(Animate, Clone, ComputeSquaredDistance, Copy, Debug, MallocSizeOf,
ToAnimatedValue, ToCss)] PartialEq, SpecifiedValueInfo, ToAnimatedValue, ToCss)]
pub enum LineHeight<Number, LengthOrPercentage> { pub enum LineHeight<Number, LengthOrPercentage> {
/// `normal` /// `normal`
Normal, Normal,
@ -140,8 +142,9 @@ impl<N, L> LineHeight<N, L> {
} }
/// A generic value for the `-moz-tab-size` property. /// A generic value for the `-moz-tab-size` property.
#[derive(Animate, Clone, ComputeSquaredDistance, Copy, Debug, MallocSizeOf, PartialEq, #[derive(Animate, Clone, ComputeSquaredDistance, Copy, Debug, MallocSizeOf,
ToAnimatedValue, ToAnimatedZero, ToComputedValue, ToCss)] PartialEq, SpecifiedValueInfo, ToAnimatedValue, ToAnimatedZero,
ToComputedValue, ToCss)]
pub enum MozTabSize<Number, Length> { pub enum MozTabSize<Number, Length> {
/// A number. /// A number.
Number(Number), Number(Number),

View file

@ -15,7 +15,8 @@ use values::specified::length::LengthOrPercentage as SpecifiedLengthOrPercentage
/// A generic 2D transformation matrix. /// A generic 2D transformation matrix.
#[allow(missing_docs)] #[allow(missing_docs)]
#[derive(Clone, Copy, Debug, MallocSizeOf, PartialEq, ToComputedValue, ToCss)] #[derive(Clone, Copy, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo,
ToComputedValue, ToCss)]
#[css(comma, function)] #[css(comma, function)]
pub struct Matrix<T> { pub struct Matrix<T> {
pub a: T, pub a: T,
@ -29,7 +30,8 @@ pub struct Matrix<T> {
#[allow(missing_docs)] #[allow(missing_docs)]
#[cfg_attr(rustfmt, rustfmt_skip)] #[cfg_attr(rustfmt, rustfmt_skip)]
#[css(comma, function = "matrix3d")] #[css(comma, function = "matrix3d")]
#[derive(Clone, Copy, Debug, MallocSizeOf, PartialEq, ToComputedValue, ToCss)] #[derive(Clone, Copy, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo,
ToComputedValue, ToCss)]
pub struct Matrix3D<T> { pub struct Matrix3D<T> {
pub m11: T, pub m12: T, pub m13: T, pub m14: T, pub m11: T, pub m12: T, pub m13: T, pub m14: T,
pub m21: T, pub m22: T, pub m23: T, pub m24: T, pub m21: T, pub m22: T, pub m23: T, pub m24: T,
@ -64,8 +66,8 @@ impl<T: Into<f64>> From<Matrix3D<T>> for Transform3D<f64> {
} }
/// A generic transform origin. /// A generic transform origin.
#[derive(Animate, Clone, ComputeSquaredDistance, Copy, Debug, MallocSizeOf, PartialEq, #[derive(Animate, Clone, ComputeSquaredDistance, Copy, Debug, MallocSizeOf,
ToAnimatedZero, ToComputedValue, ToCss)] PartialEq, SpecifiedValueInfo, ToAnimatedZero, ToComputedValue, ToCss)]
pub struct TransformOrigin<H, V, Depth> { pub struct TransformOrigin<H, V, Depth> {
/// The horizontal origin. /// The horizontal origin.
pub horizontal: H, pub horizontal: H,
@ -78,7 +80,9 @@ pub struct TransformOrigin<H, V, Depth> {
/// A generic timing function. /// A generic timing function.
/// ///
/// <https://drafts.csswg.org/css-timing-1/#single-timing-function-production> /// <https://drafts.csswg.org/css-timing-1/#single-timing-function-production>
#[derive(Clone, Copy, Debug, MallocSizeOf, PartialEq, ToCss)] #[derive(Clone, Copy, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo,
ToCss)]
#[value_info(ty = "TIMING_FUNCTION")]
pub enum TimingFunction<Integer, Number> { pub enum TimingFunction<Integer, Number> {
/// `linear | ease | ease-in | ease-out | ease-in-out` /// `linear | ease | ease-in | ease-out | ease-in-out`
Keyword(TimingKeyword), Keyword(TimingKeyword),
@ -93,6 +97,7 @@ pub enum TimingFunction<Integer, Number> {
}, },
/// `step-start | step-end | steps(<integer>, [ start | end ]?)` /// `step-start | step-end | steps(<integer>, [ start | end ]?)`
#[css(comma, function)] #[css(comma, function)]
#[value_info(other_values = "step-start,step-end")]
Steps(Integer, #[css(skip_if = "is_end")] StepPosition), Steps(Integer, #[css(skip_if = "is_end")] StepPosition),
/// `frames(<integer>)` /// `frames(<integer>)`
#[css(comma, function)] #[css(comma, function)]
@ -101,7 +106,8 @@ pub enum TimingFunction<Integer, Number> {
#[allow(missing_docs)] #[allow(missing_docs)]
#[cfg_attr(feature = "servo", derive(Deserialize, Serialize))] #[cfg_attr(feature = "servo", derive(Deserialize, Serialize))]
#[derive(Clone, Copy, Debug, Eq, MallocSizeOf, Parse, PartialEq, ToComputedValue, ToCss)] #[derive(Clone, Copy, Debug, Eq, MallocSizeOf, Parse, PartialEq,
SpecifiedValueInfo, ToComputedValue, ToCss)]
pub enum TimingKeyword { pub enum TimingKeyword {
Linear, Linear,
Ease, Ease,
@ -157,7 +163,8 @@ impl TimingKeyword {
} }
} }
#[derive(Clone, Debug, MallocSizeOf, PartialEq, ToComputedValue, ToCss)] #[derive(Clone, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo,
ToComputedValue, ToCss)]
/// A single operation in the list of a `transform` value /// A single operation in the list of a `transform` value
pub enum TransformOperation<Angle, Number, Length, Integer, LengthOrPercentage> { pub enum TransformOperation<Angle, Number, Length, Integer, LengthOrPercentage> {
/// Represents a 2D 2x3 matrix. /// Represents a 2D 2x3 matrix.
@ -261,7 +268,8 @@ pub enum TransformOperation<Angle, Number, Length, Integer, LengthOrPercentage>
}, },
} }
#[derive(Clone, Debug, MallocSizeOf, PartialEq, ToComputedValue, ToCss)] #[derive(Clone, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo,
ToComputedValue, ToCss)]
/// A value of the `transform` property /// A value of the `transform` property
pub struct Transform<T>(#[css(if_empty = "none", iterable)] pub Vec<T>); pub struct Transform<T>(#[css(if_empty = "none", iterable)] pub Vec<T>);
@ -554,8 +562,8 @@ pub fn get_normalized_vector_and_angle<T: Zero>(
} }
} }
#[derive(Clone, ComputeSquaredDistance, Copy, Debug, MallocSizeOf, PartialEq, ToAnimatedZero, #[derive(Clone, ComputeSquaredDistance, Copy, Debug, MallocSizeOf, PartialEq,
ToComputedValue, ToCss)] SpecifiedValueInfo, ToAnimatedZero, ToComputedValue, ToCss)]
/// A value of the `Rotate` property /// A value of the `Rotate` property
/// ///
/// <https://drafts.csswg.org/css-transforms-2/#individual-transforms> /// <https://drafts.csswg.org/css-transforms-2/#individual-transforms>
@ -568,8 +576,8 @@ pub enum Rotate<Number, Angle> {
Rotate3D(Number, Number, Number, Angle), Rotate3D(Number, Number, Number, Angle),
} }
#[derive(Clone, ComputeSquaredDistance, Copy, Debug, MallocSizeOf, PartialEq, ToAnimatedZero, #[derive(Clone, ComputeSquaredDistance, Copy, Debug, MallocSizeOf, PartialEq,
ToComputedValue, ToCss)] SpecifiedValueInfo, ToAnimatedZero, ToComputedValue, ToCss)]
/// A value of the `Scale` property /// A value of the `Scale` property
/// ///
/// <https://drafts.csswg.org/css-transforms-2/#individual-transforms> /// <https://drafts.csswg.org/css-transforms-2/#individual-transforms>
@ -584,8 +592,8 @@ pub enum Scale<Number> {
Scale3D(Number, Number, Number), Scale3D(Number, Number, Number),
} }
#[derive(Clone, ComputeSquaredDistance, Debug, MallocSizeOf, PartialEq, ToAnimatedZero, #[derive(Clone, ComputeSquaredDistance, Debug, MallocSizeOf, PartialEq,
ToComputedValue, ToCss)] SpecifiedValueInfo, ToAnimatedZero, ToComputedValue, ToCss)]
/// A value of the `Translate` property /// A value of the `Translate` property
/// ///
/// <https://drafts.csswg.org/css-transforms-2/#individual-transforms> /// <https://drafts.csswg.org/css-transforms-2/#individual-transforms>
@ -601,7 +609,8 @@ pub enum Translate<LengthOrPercentage, Length> {
} }
#[allow(missing_docs)] #[allow(missing_docs)]
#[derive(Clone, Copy, Debug, MallocSizeOf, Parse, PartialEq, ToComputedValue, ToCss)] #[derive(Clone, Copy, Debug, MallocSizeOf, Parse, PartialEq, SpecifiedValueInfo,
ToComputedValue, ToCss)]
pub enum TransformStyle { pub enum TransformStyle {
#[cfg(feature = "servo")] #[cfg(feature = "servo")]
Auto, Auto,

View file

@ -9,8 +9,9 @@ use parser::{Parse, ParserContext};
use style_traits::ParseError; use style_traits::ParseError;
/// An image url or none, used for example in list-style-image /// An image url or none, used for example in list-style-image
#[derive(Animate, Clone, ComputeSquaredDistance, Debug, MallocSizeOf, PartialEq, ToAnimatedValue, #[derive(Animate, Clone, ComputeSquaredDistance, Debug, MallocSizeOf, PartialEq,
ToAnimatedZero, ToComputedValue, ToCss)] SpecifiedValueInfo, ToAnimatedValue, ToAnimatedZero, ToComputedValue,
ToCss)]
pub enum UrlOrNone<Url> { pub enum UrlOrNone<Url> {
/// `none` /// `none`
None, None,

View file

@ -71,7 +71,7 @@ where
/// Convenience void type to disable some properties and values through types. /// Convenience void type to disable some properties and values through types.
#[cfg_attr(feature = "servo", derive(Deserialize, MallocSizeOf, Serialize))] #[cfg_attr(feature = "servo", derive(Deserialize, MallocSizeOf, Serialize))]
#[derive(Clone, Copy, Debug, PartialEq, ToAnimatedValue, ToComputedValue, ToCss)] #[derive(Clone, Copy, Debug, PartialEq, SpecifiedValueInfo, ToAnimatedValue, ToComputedValue, ToCss)]
pub enum Impossible {} pub enum Impossible {}
// FIXME(nox): This should be derived but the derive code cannot cope // FIXME(nox): This should be derived but the derive code cannot cope
@ -93,8 +93,9 @@ impl Parse for Impossible {
} }
/// A struct representing one of two kinds of values. /// A struct representing one of two kinds of values.
#[derive(Animate, Clone, ComputeSquaredDistance, Copy, MallocSizeOf, PartialEq, ToAnimatedValue, #[derive(Animate, Clone, ComputeSquaredDistance, Copy, MallocSizeOf, PartialEq,
ToAnimatedZero, ToComputedValue, ToCss)] SpecifiedValueInfo, ToAnimatedValue, ToAnimatedZero, ToComputedValue,
ToCss)]
pub enum Either<A, B> { pub enum Either<A, B> {
/// The first value. /// The first value.
First(A), First(A),
@ -125,7 +126,8 @@ impl<A: Parse, B: Parse> Parse for Either<A, B> {
} }
/// <https://drafts.csswg.org/css-values-4/#custom-idents> /// <https://drafts.csswg.org/css-values-4/#custom-idents>
#[derive(Clone, Debug, Eq, Hash, MallocSizeOf, PartialEq, ToComputedValue)] #[derive(Clone, Debug, Eq, Hash, MallocSizeOf, PartialEq, SpecifiedValueInfo,
ToComputedValue)]
pub struct CustomIdent(pub Atom); pub struct CustomIdent(pub Atom);
impl CustomIdent { impl CustomIdent {
@ -160,7 +162,7 @@ impl ToCss for CustomIdent {
} }
/// <https://drafts.csswg.org/css-animations/#typedef-keyframes-name> /// <https://drafts.csswg.org/css-animations/#typedef-keyframes-name>
#[derive(Clone, Debug, MallocSizeOf, ToComputedValue)] #[derive(Clone, Debug, MallocSizeOf, SpecifiedValueInfo, ToComputedValue)]
pub enum KeyframesName { pub enum KeyframesName {
/// <custom-ident> /// <custom-ident>
Ident(CustomIdent), Ident(CustomIdent),

View file

@ -10,7 +10,7 @@ use cssparser::Parser;
use gecko_bindings::structs; use gecko_bindings::structs;
use parser::{Parse, ParserContext}; use parser::{Parse, ParserContext};
use std::fmt::{self, Write}; use std::fmt::{self, Write};
use style_traits::{CssWriter, ParseError, ToCss}; use style_traits::{CssWriter, KeywordsCollectFn, ParseError, SpecifiedValueInfo, ToCss};
bitflags! { bitflags! {
/// Constants shared by multiple CSS Box Alignment properties /// Constants shared by multiple CSS Box Alignment properties
@ -191,6 +191,9 @@ impl ContentDistribution {
input: &mut Parser<'i, 't>, input: &mut Parser<'i, 't>,
axis: AxisDirection, axis: AxisDirection,
) -> Result<Self, ParseError<'i>> { ) -> Result<Self, ParseError<'i>> {
// NOTE Please also update the `list_keywords` function below
// when this function is updated.
// Try to parse normal first // Try to parse normal first
if input.try(|i| i.expect_ident_matching("normal")).is_ok() { if input.try(|i| i.expect_ident_matching("normal")).is_ok() {
return Ok(ContentDistribution::normal()); return Ok(ContentDistribution::normal());
@ -227,6 +230,19 @@ impl ContentDistribution {
content_position | overflow_position, content_position | overflow_position,
)) ))
} }
fn list_keywords(f: KeywordsCollectFn, axis: AxisDirection) {
f(&["normal"]);
if axis == AxisDirection::Block {
list_baseline_keywords(f);
}
list_content_distribution_keywords(f);
list_overflow_position_keywords(f);
f(&["start", "end", "flex-start", "flex-end", "center"]);
if axis == AxisDirection::Inline {
f(&["left", "right"]);
}
}
} }
/// Value for the `align-content` property. /// Value for the `align-content` property.
@ -240,6 +256,8 @@ impl Parse for AlignContent {
_: &ParserContext, _: &ParserContext,
input: &mut Parser<'i, 't>, input: &mut Parser<'i, 't>,
) -> Result<Self, ParseError<'i>> { ) -> Result<Self, ParseError<'i>> {
// NOTE Please also update `impl SpecifiedValueInfo` below when
// this function is updated.
Ok(AlignContent(ContentDistribution::parse( Ok(AlignContent(ContentDistribution::parse(
input, input,
AxisDirection::Block, AxisDirection::Block,
@ -247,6 +265,12 @@ impl Parse for AlignContent {
} }
} }
impl SpecifiedValueInfo for AlignContent {
fn collect_completion_keywords(f: KeywordsCollectFn) {
ContentDistribution::list_keywords(f, AxisDirection::Block);
}
}
#[cfg(feature = "gecko")] #[cfg(feature = "gecko")]
impl From<u16> for AlignContent { impl From<u16> for AlignContent {
fn from(bits: u16) -> Self { fn from(bits: u16) -> Self {
@ -272,6 +296,8 @@ impl Parse for JustifyContent {
_: &ParserContext, _: &ParserContext,
input: &mut Parser<'i, 't>, input: &mut Parser<'i, 't>,
) -> Result<Self, ParseError<'i>> { ) -> Result<Self, ParseError<'i>> {
// NOTE Please also update `impl SpecifiedValueInfo` below when
// this function is updated.
Ok(JustifyContent(ContentDistribution::parse( Ok(JustifyContent(ContentDistribution::parse(
input, input,
AxisDirection::Inline, AxisDirection::Inline,
@ -279,6 +305,12 @@ impl Parse for JustifyContent {
} }
} }
impl SpecifiedValueInfo for JustifyContent {
fn collect_completion_keywords(f: KeywordsCollectFn) {
ContentDistribution::list_keywords(f, AxisDirection::Inline);
}
}
#[cfg(feature = "gecko")] #[cfg(feature = "gecko")]
impl From<u16> for JustifyContent { impl From<u16> for JustifyContent {
fn from(bits: u16) -> Self { fn from(bits: u16) -> Self {
@ -319,6 +351,9 @@ impl SelfAlignment {
input: &mut Parser<'i, 't>, input: &mut Parser<'i, 't>,
axis: AxisDirection, axis: AxisDirection,
) -> Result<Self, ParseError<'i>> { ) -> Result<Self, ParseError<'i>> {
// NOTE Please also update the `list_keywords` function below
// when this function is updated.
// <baseline-position> // <baseline-position>
// //
// It's weird that this accepts <baseline-position>, but not // It's weird that this accepts <baseline-position>, but not
@ -339,6 +374,13 @@ impl SelfAlignment {
let self_position = parse_self_position(input, axis)?; let self_position = parse_self_position(input, axis)?;
Ok(SelfAlignment(overflow_position | self_position)) Ok(SelfAlignment(overflow_position | self_position))
} }
fn list_keywords(f: KeywordsCollectFn, axis: AxisDirection) {
list_baseline_keywords(f);
list_auto_normal_stretch(f);
list_overflow_position_keywords(f);
list_self_position_keywords(f, axis);
}
} }
/// The specified value of the align-self property. /// The specified value of the align-self property.
@ -352,6 +394,8 @@ impl Parse for AlignSelf {
_: &ParserContext, _: &ParserContext,
input: &mut Parser<'i, 't>, input: &mut Parser<'i, 't>,
) -> Result<Self, ParseError<'i>> { ) -> Result<Self, ParseError<'i>> {
// NOTE Please also update `impl SpecifiedValueInfo` below when
// this function is updated.
Ok(AlignSelf(SelfAlignment::parse( Ok(AlignSelf(SelfAlignment::parse(
input, input,
AxisDirection::Block, AxisDirection::Block,
@ -359,6 +403,12 @@ impl Parse for AlignSelf {
} }
} }
impl SpecifiedValueInfo for AlignSelf {
fn collect_completion_keywords(f: KeywordsCollectFn) {
SelfAlignment::list_keywords(f, AxisDirection::Block);
}
}
impl From<u8> for AlignSelf { impl From<u8> for AlignSelf {
fn from(bits: u8) -> Self { fn from(bits: u8) -> Self {
AlignSelf(SelfAlignment(AlignFlags::from_bits_truncate(bits))) AlignSelf(SelfAlignment(AlignFlags::from_bits_truncate(bits)))
@ -382,6 +432,8 @@ impl Parse for JustifySelf {
_: &ParserContext, _: &ParserContext,
input: &mut Parser<'i, 't>, input: &mut Parser<'i, 't>,
) -> Result<Self, ParseError<'i>> { ) -> Result<Self, ParseError<'i>> {
// NOTE Please also update `impl SpecifiedValueInfo` below when
// this function is updated.
Ok(JustifySelf(SelfAlignment::parse( Ok(JustifySelf(SelfAlignment::parse(
input, input,
AxisDirection::Inline, AxisDirection::Inline,
@ -389,6 +441,12 @@ impl Parse for JustifySelf {
} }
} }
impl SpecifiedValueInfo for JustifySelf {
fn collect_completion_keywords(f: KeywordsCollectFn) {
SelfAlignment::list_keywords(f, AxisDirection::Inline);
}
}
impl From<u8> for JustifySelf { impl From<u8> for JustifySelf {
fn from(bits: u8) -> Self { fn from(bits: u8) -> Self {
JustifySelf(SelfAlignment(AlignFlags::from_bits_truncate(bits))) JustifySelf(SelfAlignment(AlignFlags::from_bits_truncate(bits)))
@ -422,6 +480,9 @@ impl Parse for AlignItems {
_: &ParserContext, _: &ParserContext,
input: &mut Parser<'i, 't>, input: &mut Parser<'i, 't>,
) -> Result<Self, ParseError<'i>> { ) -> Result<Self, ParseError<'i>> {
// NOTE Please also update `impl SpecifiedValueInfo` below when
// this function is updated.
// <baseline-position> // <baseline-position>
if let Ok(baseline) = input.try(parse_baseline) { if let Ok(baseline) = input.try(parse_baseline) {
return Ok(AlignItems(baseline)); return Ok(AlignItems(baseline));
@ -440,6 +501,15 @@ impl Parse for AlignItems {
} }
} }
impl SpecifiedValueInfo for AlignItems {
fn collect_completion_keywords(f: KeywordsCollectFn) {
list_baseline_keywords(f);
list_normal_stretch(f);
list_overflow_position_keywords(f);
list_self_position_keywords(f, AxisDirection::Block);
}
}
/// Value of the `justify-items` property /// Value of the `justify-items` property
/// ///
/// <https://drafts.csswg.org/css-align/#justify-items-property> /// <https://drafts.csswg.org/css-align/#justify-items-property>
@ -465,6 +535,9 @@ impl Parse for JustifyItems {
_: &ParserContext, _: &ParserContext,
input: &mut Parser<'i, 't>, input: &mut Parser<'i, 't>,
) -> Result<Self, ParseError<'i>> { ) -> Result<Self, ParseError<'i>> {
// NOTE Please also update `impl SpecifiedValueInfo` below when
// this function is updated.
// <baseline-position> // <baseline-position>
// //
// It's weird that this accepts <baseline-position>, but not // It's weird that this accepts <baseline-position>, but not
@ -492,10 +565,22 @@ impl Parse for JustifyItems {
} }
} }
impl SpecifiedValueInfo for JustifyItems {
fn collect_completion_keywords(f: KeywordsCollectFn) {
list_baseline_keywords(f);
list_normal_stretch(f);
list_legacy_keywords(f);
list_overflow_position_keywords(f);
list_self_position_keywords(f, AxisDirection::Inline);
}
}
// auto | normal | stretch // auto | normal | stretch
fn parse_auto_normal_stretch<'i, 't>( fn parse_auto_normal_stretch<'i, 't>(
input: &mut Parser<'i, 't>, input: &mut Parser<'i, 't>,
) -> Result<AlignFlags, ParseError<'i>> { ) -> Result<AlignFlags, ParseError<'i>> {
// NOTE Please also update the `list_auto_normal_stretch` function
// below when this function is updated.
try_match_ident_ignore_ascii_case! { input, try_match_ident_ignore_ascii_case! { input,
"auto" => Ok(AlignFlags::AUTO), "auto" => Ok(AlignFlags::AUTO),
"normal" => Ok(AlignFlags::NORMAL), "normal" => Ok(AlignFlags::NORMAL),
@ -503,16 +588,28 @@ fn parse_auto_normal_stretch<'i, 't>(
} }
} }
fn list_auto_normal_stretch(f: KeywordsCollectFn) {
f(&["auto", "normal", "stretch"]);
}
// normal | stretch // normal | stretch
fn parse_normal_stretch<'i, 't>(input: &mut Parser<'i, 't>) -> Result<AlignFlags, ParseError<'i>> { fn parse_normal_stretch<'i, 't>(input: &mut Parser<'i, 't>) -> Result<AlignFlags, ParseError<'i>> {
// NOTE Please also update the `list_normal_stretch` function below
// when this function is updated.
try_match_ident_ignore_ascii_case! { input, try_match_ident_ignore_ascii_case! { input,
"normal" => Ok(AlignFlags::NORMAL), "normal" => Ok(AlignFlags::NORMAL),
"stretch" => Ok(AlignFlags::STRETCH), "stretch" => Ok(AlignFlags::STRETCH),
} }
} }
fn list_normal_stretch(f: KeywordsCollectFn) {
f(&["normal", "stretch"]);
}
// <baseline-position> // <baseline-position>
fn parse_baseline<'i, 't>(input: &mut Parser<'i, 't>) -> Result<AlignFlags, ParseError<'i>> { fn parse_baseline<'i, 't>(input: &mut Parser<'i, 't>) -> Result<AlignFlags, ParseError<'i>> {
// NOTE Please also update the `list_baseline_keywords` function
// below when this function is updated.
try_match_ident_ignore_ascii_case! { input, try_match_ident_ignore_ascii_case! { input,
"baseline" => Ok(AlignFlags::BASELINE), "baseline" => Ok(AlignFlags::BASELINE),
"first" => { "first" => {
@ -526,10 +623,16 @@ fn parse_baseline<'i, 't>(input: &mut Parser<'i, 't>) -> Result<AlignFlags, Pars
} }
} }
fn list_baseline_keywords(f: KeywordsCollectFn) {
f(&["baseline", "first baseline", "last baseline"]);
}
// <content-distribution> // <content-distribution>
fn parse_content_distribution<'i, 't>( fn parse_content_distribution<'i, 't>(
input: &mut Parser<'i, 't>, input: &mut Parser<'i, 't>,
) -> Result<AlignFlags, ParseError<'i>> { ) -> Result<AlignFlags, ParseError<'i>> {
// NOTE Please also update the `list_content_distribution_keywords`
// function below when this function is updated.
try_match_ident_ignore_ascii_case! { input, try_match_ident_ignore_ascii_case! { input,
"stretch" => Ok(AlignFlags::STRETCH), "stretch" => Ok(AlignFlags::STRETCH),
"space-between" => Ok(AlignFlags::SPACE_BETWEEN), "space-between" => Ok(AlignFlags::SPACE_BETWEEN),
@ -538,21 +641,33 @@ fn parse_content_distribution<'i, 't>(
} }
} }
fn list_content_distribution_keywords(f: KeywordsCollectFn) {
f(&["stretch", "space-between", "space-around", "space-evenly"]);
}
// <overflow-position> // <overflow-position>
fn parse_overflow_position<'i, 't>( fn parse_overflow_position<'i, 't>(
input: &mut Parser<'i, 't>, input: &mut Parser<'i, 't>,
) -> Result<AlignFlags, ParseError<'i>> { ) -> Result<AlignFlags, ParseError<'i>> {
// NOTE Please also update the `list_overflow_position_keywords`
// function below when this function is updated.
try_match_ident_ignore_ascii_case! { input, try_match_ident_ignore_ascii_case! { input,
"safe" => Ok(AlignFlags::SAFE), "safe" => Ok(AlignFlags::SAFE),
"unsafe" => Ok(AlignFlags::UNSAFE), "unsafe" => Ok(AlignFlags::UNSAFE),
} }
} }
fn list_overflow_position_keywords(f: KeywordsCollectFn) {
f(&["safe", "unsafe"]);
}
// <self-position> | left | right in the inline axis. // <self-position> | left | right in the inline axis.
fn parse_self_position<'i, 't>( fn parse_self_position<'i, 't>(
input: &mut Parser<'i, 't>, input: &mut Parser<'i, 't>,
axis: AxisDirection, axis: AxisDirection,
) -> Result<AlignFlags, ParseError<'i>> { ) -> Result<AlignFlags, ParseError<'i>> {
// NOTE Please also update the `list_self_position_keywords`
// function below when this function is updated.
Ok(try_match_ident_ignore_ascii_case! { input, Ok(try_match_ident_ignore_ascii_case! { input,
"start" => AlignFlags::START, "start" => AlignFlags::START,
"end" => AlignFlags::END, "end" => AlignFlags::END,
@ -566,9 +681,21 @@ fn parse_self_position<'i, 't>(
}) })
} }
fn list_self_position_keywords(f: KeywordsCollectFn, axis: AxisDirection) {
f(&[
"start", "end", "flex-start", "flex-end",
"center", "self-start", "self-end",
]);
if axis == AxisDirection::Inline {
f(&["left", "right"]);
}
}
fn parse_left_right_center<'i, 't>( fn parse_left_right_center<'i, 't>(
input: &mut Parser<'i, 't>, input: &mut Parser<'i, 't>,
) -> Result<AlignFlags, ParseError<'i>> { ) -> Result<AlignFlags, ParseError<'i>> {
// NOTE Please also update the `list_legacy_keywords` function below
// when this function is updated.
Ok(try_match_ident_ignore_ascii_case! { input, Ok(try_match_ident_ignore_ascii_case! { input,
"left" => AlignFlags::LEFT, "left" => AlignFlags::LEFT,
"right" => AlignFlags::RIGHT, "right" => AlignFlags::RIGHT,
@ -578,6 +705,8 @@ fn parse_left_right_center<'i, 't>(
// legacy | [ legacy && [ left | right | center ] ] // legacy | [ legacy && [ left | right | center ] ]
fn parse_legacy<'i, 't>(input: &mut Parser<'i, 't>) -> Result<AlignFlags, ParseError<'i>> { fn parse_legacy<'i, 't>(input: &mut Parser<'i, 't>) -> Result<AlignFlags, ParseError<'i>> {
// NOTE Please also update the `list_legacy_keywords` function below
// when this function is updated.
let flags = try_match_ident_ignore_ascii_case! { input, let flags = try_match_ident_ignore_ascii_case! { input,
"legacy" => { "legacy" => {
let flags = input.try(parse_left_right_center) let flags = input.try(parse_left_right_center)
@ -593,3 +722,7 @@ fn parse_legacy<'i, 't>(input: &mut Parser<'i, 't>) -> Result<AlignFlags, ParseE
input.expect_ident_matching("legacy")?; input.expect_ident_matching("legacy")?;
Ok(AlignFlags::LEGACY | flags) Ok(AlignFlags::LEGACY | flags)
} }
fn list_legacy_keywords(f: KeywordsCollectFn) {
f(&["legacy", "left", "right", "center"]);
}

View file

@ -7,7 +7,7 @@
use cssparser::{Parser, Token}; use cssparser::{Parser, Token};
use parser::{Parse, ParserContext}; use parser::{Parse, ParserContext};
use std::fmt::{self, Write}; use std::fmt::{self, Write};
use style_traits::{CssWriter, ParseError, ToCss}; use style_traits::{CssWriter, ParseError, SpecifiedValueInfo, ToCss};
use values::CSSFloat; use values::CSSFloat;
use values::computed::{Context, ToComputedValue}; use values::computed::{Context, ToComputedValue};
use values::computed::angle::Angle as ComputedAngle; use values::computed::angle::Angle as ComputedAngle;
@ -203,3 +203,5 @@ impl Angle {
}.map_err(|()| input.new_unexpected_token_error(token.clone())) }.map_err(|()| input.new_unexpected_token_error(token.clone()))
} }
} }
impl SpecifiedValueInfo for Angle {}

View file

@ -48,7 +48,8 @@ impl BackgroundSize {
} }
/// One of the keywords for `background-repeat`. /// One of the keywords for `background-repeat`.
#[derive(Clone, Copy, Debug, Eq, MallocSizeOf, Parse, PartialEq, ToComputedValue, ToCss)] #[derive(Clone, Copy, Debug, Eq, MallocSizeOf, Parse, PartialEq,
SpecifiedValueInfo, ToComputedValue, ToCss)]
#[allow(missing_docs)] #[allow(missing_docs)]
pub enum BackgroundRepeatKeyword { pub enum BackgroundRepeatKeyword {
Repeat, Repeat,
@ -60,7 +61,8 @@ pub enum BackgroundRepeatKeyword {
/// The specified value for the `background-repeat` property. /// The specified value for the `background-repeat` property.
/// ///
/// https://drafts.csswg.org/css-backgrounds/#the-background-repeat /// https://drafts.csswg.org/css-backgrounds/#the-background-repeat
#[derive(Clone, Copy, Debug, MallocSizeOf, PartialEq, ToCss)] #[derive(Clone, Copy, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo,
ToCss)]
pub enum BackgroundRepeat { pub enum BackgroundRepeat {
/// `repeat-x` /// `repeat-x`
RepeatX, RepeatX,

View file

@ -20,7 +20,7 @@ use values::specified::{AllowQuirks, Number, NumberOrPercentage};
use values::specified::length::{Length, LengthOrPercentage, NonNegativeLength}; use values::specified::length::{Length, LengthOrPercentage, NonNegativeLength};
/// A specified value for a single side of the `border-width` property. /// A specified value for a single side of the `border-width` property.
#[derive(Clone, Debug, MallocSizeOf, PartialEq, ToCss)] #[derive(Clone, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo, ToCss)]
pub enum BorderSideWidth { pub enum BorderSideWidth {
/// `thin` /// `thin`
Thin, Thin,
@ -189,7 +189,8 @@ impl Parse for BorderSpacing {
/// A single border-image-repeat keyword. /// A single border-image-repeat keyword.
#[allow(missing_docs)] #[allow(missing_docs)]
#[cfg_attr(feature = "servo", derive(Deserialize, Serialize))] #[cfg_attr(feature = "servo", derive(Deserialize, Serialize))]
#[derive(Clone, Copy, Debug, Eq, MallocSizeOf, Parse, PartialEq, ToCss)] #[derive(Clone, Copy, Debug, Eq, MallocSizeOf, Parse, PartialEq,
SpecifiedValueInfo, ToCss)]
pub enum BorderImageRepeatKeyword { pub enum BorderImageRepeatKeyword {
Stretch, Stretch,
Repeat, Repeat,
@ -200,7 +201,8 @@ pub enum BorderImageRepeatKeyword {
/// The specified value for the `border-image-repeat` property. /// The specified value for the `border-image-repeat` property.
/// ///
/// https://drafts.csswg.org/css-backgrounds/#the-border-image-repeat /// https://drafts.csswg.org/css-backgrounds/#the-border-image-repeat
#[derive(Clone, Copy, Debug, MallocSizeOf, PartialEq, ToComputedValue)] #[derive(Clone, Copy, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo,
ToComputedValue)]
pub struct BorderImageRepeat(pub BorderImageRepeatKeyword, pub BorderImageRepeatKeyword); pub struct BorderImageRepeat(pub BorderImageRepeatKeyword, pub BorderImageRepeatKeyword);
impl ToCss for BorderImageRepeat { impl ToCss for BorderImageRepeat {

View file

@ -10,8 +10,7 @@ use parser::{Parse, ParserContext};
use selectors::parser::SelectorParseErrorKind; use selectors::parser::SelectorParseErrorKind;
use std::fmt::{self, Write}; use std::fmt::{self, Write};
use style_traits::{CssWriter, ParseError, StyleParseErrorKind, ToCss}; use style_traits::{CssWriter, ParseError, StyleParseErrorKind, ToCss};
use values::CustomIdent; use values::{CustomIdent, KeyframesName};
use values::KeyframesName;
use values::generics::box_::AnimationIterationCount as GenericAnimationIterationCount; use values::generics::box_::AnimationIterationCount as GenericAnimationIterationCount;
use values::generics::box_::Perspective as GenericPerspective; use values::generics::box_::Perspective as GenericPerspective;
use values::generics::box_::VerticalAlign as GenericVerticalAlign; use values::generics::box_::VerticalAlign as GenericVerticalAlign;
@ -19,7 +18,8 @@ use values::specified::{AllowQuirks, Number};
use values::specified::length::{LengthOrPercentage, NonNegativeLength}; use values::specified::length::{LengthOrPercentage, NonNegativeLength};
#[allow(missing_docs)] #[allow(missing_docs)]
#[derive(Clone, Copy, Debug, Eq, Hash, MallocSizeOf, Parse, PartialEq, ToComputedValue, ToCss)] #[derive(Clone, Copy, Debug, Eq, Hash, MallocSizeOf, Parse, PartialEq,
SpecifiedValueInfo, ToComputedValue, ToCss)]
#[cfg_attr(feature = "servo", derive(Deserialize, Serialize))] #[cfg_attr(feature = "servo", derive(Deserialize, Serialize))]
/// Defines an elements display type, which consists of /// Defines an elements display type, which consists of
/// the two basic qualities of how an element generates boxes /// the two basic qualities of how an element generates boxes
@ -296,7 +296,9 @@ impl AnimationIterationCount {
} }
/// A value for the `animation-name` property. /// A value for the `animation-name` property.
#[derive(Clone, Debug, Eq, Hash, MallocSizeOf, PartialEq, ToComputedValue)] #[derive(Clone, Debug, Eq, Hash, MallocSizeOf, PartialEq, SpecifiedValueInfo,
ToComputedValue)]
#[value_info(other_values = "none")]
pub struct AnimationName(pub Option<KeyframesName>); pub struct AnimationName(pub Option<KeyframesName>);
impl AnimationName { impl AnimationName {
@ -339,7 +341,8 @@ impl Parse for AnimationName {
#[allow(missing_docs)] #[allow(missing_docs)]
#[cfg_attr(feature = "servo", derive(Deserialize, Serialize))] #[cfg_attr(feature = "servo", derive(Deserialize, Serialize))]
#[derive(Clone, Copy, Debug, Eq, MallocSizeOf, Parse, PartialEq, ToComputedValue, ToCss)] #[derive(Clone, Copy, Debug, Eq, MallocSizeOf, Parse, PartialEq,
SpecifiedValueInfo, ToComputedValue, ToCss)]
pub enum ScrollSnapType { pub enum ScrollSnapType {
None, None,
Mandatory, Mandatory,
@ -348,7 +351,8 @@ pub enum ScrollSnapType {
#[allow(missing_docs)] #[allow(missing_docs)]
#[cfg_attr(feature = "servo", derive(Deserialize, Serialize))] #[cfg_attr(feature = "servo", derive(Deserialize, Serialize))]
#[derive(Clone, Copy, Debug, Eq, MallocSizeOf, Parse, PartialEq, ToComputedValue, ToCss)] #[derive(Clone, Copy, Debug, Eq, MallocSizeOf, Parse, PartialEq,
SpecifiedValueInfo, ToComputedValue, ToCss)]
pub enum OverscrollBehavior { pub enum OverscrollBehavior {
Auto, Auto,
Contain, Contain,
@ -357,13 +361,15 @@ pub enum OverscrollBehavior {
#[allow(missing_docs)] #[allow(missing_docs)]
#[cfg_attr(feature = "servo", derive(Deserialize, Serialize))] #[cfg_attr(feature = "servo", derive(Deserialize, Serialize))]
#[derive(Clone, Copy, Debug, Eq, MallocSizeOf, Parse, PartialEq, ToComputedValue, ToCss)] #[derive(Clone, Copy, Debug, Eq, MallocSizeOf, Parse, PartialEq,
SpecifiedValueInfo, ToComputedValue, ToCss)]
pub enum OverflowClipBox { pub enum OverflowClipBox {
PaddingBox, PaddingBox,
ContentBox, ContentBox,
} }
#[derive(Clone, Debug, MallocSizeOf, PartialEq, ToComputedValue, ToCss)] #[derive(Clone, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo,
ToComputedValue, ToCss)]
/// Provides a rendering hint to the user agent, /// Provides a rendering hint to the user agent,
/// stating what kinds of changes the author expects /// stating what kinds of changes the author expects
/// to perform on the element /// to perform on the element
@ -415,8 +421,9 @@ impl Parse for WillChange {
bitflags! { bitflags! {
#[cfg_attr(feature = "gecko", derive(MallocSizeOf))] #[cfg_attr(feature = "gecko", derive(MallocSizeOf))]
#[derive(ToComputedValue)] #[derive(SpecifiedValueInfo, ToComputedValue)]
/// These constants match Gecko's `NS_STYLE_TOUCH_ACTION_*` constants. /// These constants match Gecko's `NS_STYLE_TOUCH_ACTION_*` constants.
#[value_info(other_values = "auto,none,manipulation,pan-x,pan-y")]
pub struct TouchAction: u8 { pub struct TouchAction: u8 {
/// `none` variant /// `none` variant
const TOUCH_ACTION_NONE = 1 << 0; const TOUCH_ACTION_NONE = 1 << 0;
@ -515,7 +522,8 @@ pub fn assert_touch_action_matches() {
} }
bitflags! { bitflags! {
#[derive(MallocSizeOf, ToComputedValue)] #[derive(MallocSizeOf, SpecifiedValueInfo, ToComputedValue)]
#[value_info(other_values = "none,strict,layout,style,paint")]
/// Constants for contain: https://drafts.csswg.org/css-contain/#contain-property /// Constants for contain: https://drafts.csswg.org/css-contain/#contain-property
pub struct Contain: u8 { pub struct Contain: u8 {
/// `layout` variant, turns on layout containment /// `layout` variant, turns on layout containment

View file

@ -9,7 +9,7 @@
use cssparser::{AngleOrNumber, NumberOrPercentage, Parser, Token}; use cssparser::{AngleOrNumber, NumberOrPercentage, Parser, Token};
use parser::ParserContext; use parser::ParserContext;
use std::fmt::{self, Write}; use std::fmt::{self, Write};
use style_traits::{CssWriter, ParseError, StyleParseErrorKind, ToCss}; use style_traits::{CssWriter, ParseError, SpecifiedValueInfo, StyleParseErrorKind, ToCss};
use style_traits::values::specified::AllowedNumericType; use style_traits::values::specified::AllowedNumericType;
use values::{CSSFloat, CSSInteger}; use values::{CSSFloat, CSSInteger};
use values::computed; use values::computed;
@ -150,6 +150,8 @@ impl ToCss for CalcLengthOrPercentage {
} }
} }
impl SpecifiedValueInfo for CalcLengthOrPercentage {}
impl CalcNode { impl CalcNode {
/// Tries to parse a single element in the expression, that is, a /// Tries to parse a single element in the expression, that is, a
/// `<length>`, `<angle>`, `<time>`, `<percentage>`, according to /// `<length>`, `<angle>`, `<time>`, `<percentage>`, according to

View file

@ -14,7 +14,8 @@ use parser::{Parse, ParserContext};
use properties::longhands::system_colors::SystemColor; use properties::longhands::system_colors::SystemColor;
use std::fmt::{self, Write}; use std::fmt::{self, Write};
use std::io::Write as IoWrite; use std::io::Write as IoWrite;
use style_traits::{CssWriter, ParseError, StyleParseErrorKind, ToCss, ValueParseErrorKind}; use style_traits::{CssType, CssWriter, KeywordsCollectFn, ParseError, StyleParseErrorKind};
use style_traits::{SpecifiedValueInfo, ToCss, ValueParseErrorKind};
use super::AllowQuirks; use super::AllowQuirks;
use values::computed::{Color as ComputedColor, Context, ToComputedValue}; use values::computed::{Color as ComputedColor, Context, ToComputedValue};
use values::specified::calc::CalcNode; use values::specified::calc::CalcNode;
@ -394,7 +395,7 @@ impl ToComputedValue for Color {
/// Specified color value, but resolved to just RGBA for computed value /// Specified color value, but resolved to just RGBA for computed value
/// with value from color property at the same context. /// with value from color property at the same context.
#[derive(Clone, Debug, MallocSizeOf, PartialEq, ToCss)] #[derive(Clone, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo, ToCss)]
pub struct RGBAColor(pub Color); pub struct RGBAColor(pub Color);
impl Parse for RGBAColor { impl Parse for RGBAColor {
@ -426,10 +427,23 @@ impl From<Color> for RGBAColor {
} }
} }
impl SpecifiedValueInfo for Color {
const SUPPORTED_TYPES: u8 = CssType::COLOR;
fn collect_completion_keywords(f: KeywordsCollectFn) {
// We are not going to insert all the color names here. Caller and
// devtools should take care of them. XXX Actually, transparent
// should probably be handled that way as well.
// XXX `currentColor` should really be `currentcolor`. But let's
// keep it consistent with the old system for now.
f(&["rgb", "rgba", "hsl", "hsla", "currentColor", "transparent"]);
}
}
/// Specified value for the "color" property, which resolves the `currentcolor` /// Specified value for the "color" property, which resolves the `currentcolor`
/// keyword to the parent color instead of self's color. /// keyword to the parent color instead of self's color.
#[cfg_attr(feature = "gecko", derive(MallocSizeOf))] #[cfg_attr(feature = "gecko", derive(MallocSizeOf))]
#[derive(Clone, Debug, PartialEq, ToCss)] #[derive(Clone, Debug, PartialEq, SpecifiedValueInfo, ToCss)]
pub struct ColorPropertyValue(pub Color); pub struct ColorPropertyValue(pub Color);
impl ToComputedValue for ColorPropertyValue { impl ToComputedValue for ColorPropertyValue {

View file

@ -99,7 +99,8 @@ fn is_decimal(counter_type: &CounterStyleType) -> bool {
/// The specified value for the `content` property. /// The specified value for the `content` property.
/// ///
/// https://drafts.csswg.org/css-content/#propdef-content /// https://drafts.csswg.org/css-content/#propdef-content
#[derive(Clone, Debug, Eq, MallocSizeOf, PartialEq, ToComputedValue, ToCss)] #[derive(Clone, Debug, Eq, MallocSizeOf, PartialEq, SpecifiedValueInfo,
ToComputedValue, ToCss)]
pub enum Content { pub enum Content {
/// `normal` reserved keyword. /// `normal` reserved keyword.
Normal, Normal,
@ -113,7 +114,8 @@ pub enum Content {
} }
/// Items for the `content` property. /// Items for the `content` property.
#[derive(Clone, Debug, Eq, MallocSizeOf, PartialEq, ToComputedValue, ToCss)] #[derive(Clone, Debug, Eq, MallocSizeOf, PartialEq, SpecifiedValueInfo,
ToComputedValue, ToCss)]
pub enum ContentItem { pub enum ContentItem {
/// Literal string content. /// Literal string content.
String(Box<str>), String(Box<str>),

View file

@ -35,7 +35,7 @@ pub type Filter = GenericFilter<Angle, Factor, NonNegativeLength, SimpleShadow>;
pub type Filter = GenericFilter<Angle, Factor, NonNegativeLength, Impossible>; pub type Filter = GenericFilter<Angle, Factor, NonNegativeLength, Impossible>;
/// A value for the `<factor>` parts in `Filter`. /// A value for the `<factor>` parts in `Filter`.
#[derive(Clone, Debug, MallocSizeOf, PartialEq, ToCss)] #[derive(Clone, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo, ToCss)]
pub struct Factor(NumberOrPercentage); pub struct Factor(NumberOrPercentage);
impl Factor { impl Factor {

View file

@ -15,7 +15,9 @@ use malloc_size_of::{MallocSizeOf, MallocSizeOfOps};
use parser::{Parse, ParserContext}; use parser::{Parse, ParserContext};
use properties::longhands::system_font::SystemFont; use properties::longhands::system_font::SystemFont;
use std::fmt::{self, Write}; use std::fmt::{self, Write};
use style_traits::{CssWriter, ParseError, StyleParseErrorKind, ToCss}; use style_traits::{CssWriter, KeywordsCollectFn, ParseError};
use style_traits::{SpecifiedValueInfo, StyleParseErrorKind, ToCss};
use style_traits::values::SequenceWriter;
use values::CustomIdent; use values::CustomIdent;
use values::computed::{Angle as ComputedAngle, Percentage as ComputedPercentage}; use values::computed::{Angle as ComputedAngle, Percentage as ComputedPercentage};
use values::computed::{font as computed, Context, Length, NonNegativeLength, ToComputedValue}; use values::computed::{font as computed, Context, Length, NonNegativeLength, ToComputedValue};
@ -77,7 +79,7 @@ pub const MAX_FONT_WEIGHT: f32 = 1000.;
/// A specified font-weight value. /// A specified font-weight value.
/// ///
/// https://drafts.csswg.org/css-fonts-4/#propdef-font-weight /// https://drafts.csswg.org/css-fonts-4/#propdef-font-weight
#[derive(Clone, Copy, Debug, MallocSizeOf, PartialEq, ToCss)] #[derive(Clone, Copy, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo, ToCss)]
pub enum FontWeight { pub enum FontWeight {
/// `<font-weight-absolute>` /// `<font-weight-absolute>`
Absolute(AbsoluteFontWeight), Absolute(AbsoluteFontWeight),
@ -86,6 +88,7 @@ pub enum FontWeight {
/// Lighter variant /// Lighter variant
Lighter, Lighter,
/// System font variant. /// System font variant.
#[css(skip)]
System(SystemFont), System(SystemFont),
} }
@ -154,7 +157,7 @@ impl ToComputedValue for FontWeight {
/// An absolute font-weight value for a @font-face rule. /// An absolute font-weight value for a @font-face rule.
/// ///
/// https://drafts.csswg.org/css-fonts-4/#font-weight-absolute-values /// https://drafts.csswg.org/css-fonts-4/#font-weight-absolute-values
#[derive(Clone, Copy, Debug, MallocSizeOf, PartialEq, ToCss)] #[derive(Clone, Copy, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo, ToCss)]
pub enum AbsoluteFontWeight { pub enum AbsoluteFontWeight {
/// A `<number>`, with the additional constraints specified in: /// A `<number>`, with the additional constraints specified in:
/// ///
@ -333,10 +336,12 @@ impl SpecifiedFontStyle {
} }
/// The specified value of the `font-style` property. /// The specified value of the `font-style` property.
#[derive(Clone, Copy, Debug, MallocSizeOf, PartialEq, ToCss)] #[derive(Clone, Copy, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo,
ToCss)]
#[allow(missing_docs)] #[allow(missing_docs)]
pub enum FontStyle { pub enum FontStyle {
Specified(SpecifiedFontStyle), Specified(SpecifiedFontStyle),
#[css(skip)]
System(SystemFont), System(SystemFont),
} }
@ -378,15 +383,18 @@ impl Parse for FontStyle {
/// ///
/// https://drafts.csswg.org/css-fonts-4/#font-stretch-prop /// https://drafts.csswg.org/css-fonts-4/#font-stretch-prop
#[allow(missing_docs)] #[allow(missing_docs)]
#[derive(Clone, Copy, Debug, MallocSizeOf, PartialEq, ToCss)] #[derive(Clone, Copy, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo,
ToCss)]
pub enum FontStretch { pub enum FontStretch {
Stretch(Percentage), Stretch(Percentage),
Keyword(FontStretchKeyword), Keyword(FontStretchKeyword),
#[css(skip)]
System(SystemFont), System(SystemFont),
} }
/// A keyword value for `font-stretch`. /// A keyword value for `font-stretch`.
#[derive(Clone, Copy, Debug, MallocSizeOf, Parse, PartialEq, ToCss)] #[derive(Clone, Copy, Debug, MallocSizeOf, Parse, PartialEq, SpecifiedValueInfo,
ToCss)]
#[allow(missing_docs)] #[allow(missing_docs)]
pub enum FontStretchKeyword { pub enum FontStretchKeyword {
Normal, Normal,
@ -501,7 +509,7 @@ impl ToComputedValue for FontStretch {
} }
} }
#[derive(Clone, Debug, MallocSizeOf, PartialEq, ToCss)] #[derive(Clone, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo, ToCss)]
/// A specified font-size value /// A specified font-size value
pub enum FontSize { pub enum FontSize {
/// A length; e.g. 10px. /// A length; e.g. 10px.
@ -522,6 +530,7 @@ pub enum FontSize {
/// font-size: larger /// font-size: larger
Larger, Larger,
/// Derived from a specified system font. /// Derived from a specified system font.
#[css(skip)]
System(SystemFont), System(SystemFont),
} }
@ -538,6 +547,7 @@ pub enum FontFamily {
#[css(comma)] #[css(comma)]
Values(#[css(iterable)] FontFamilyList), Values(#[css(iterable)] FontFamilyList),
/// System font /// System font
#[css(skip)]
System(SystemFont), System(SystemFont),
} }
@ -602,6 +612,8 @@ impl Parse for FontFamily {
} }
} }
impl SpecifiedValueInfo for FontFamily {}
/// `FamilyName::parse` is based on `SingleFontFamily::parse` and not the other way around /// `FamilyName::parse` is based on `SingleFontFamily::parse` and not the other way around
/// because we want the former to exclude generic family keywords. /// because we want the former to exclude generic family keywords.
impl Parse for FamilyName { impl Parse for FamilyName {
@ -619,7 +631,7 @@ impl Parse for FamilyName {
} }
} }
#[derive(Clone, Copy, Debug, MallocSizeOf, PartialEq, ToCss)] #[derive(Clone, Copy, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo, ToCss)]
/// Preserve the readability of text when font fallback occurs /// Preserve the readability of text when font fallback occurs
pub enum FontSizeAdjust { pub enum FontSizeAdjust {
/// None variant /// None variant
@ -627,6 +639,7 @@ pub enum FontSizeAdjust {
/// Number variant /// Number variant
Number(Number), Number(Number),
/// system font /// system font
#[css(skip)]
System(SystemFont), System(SystemFont),
} }
@ -704,21 +717,6 @@ impl KeywordInfo {
} }
} }
impl KeywordSize {
/// Parses a keyword size.
pub fn parse<'i, 't>(input: &mut Parser<'i, 't>) -> Result<Self, ParseError<'i>> {
try_match_ident_ignore_ascii_case! { input,
"xx-small" => Ok(KeywordSize::XXSmall),
"x-small" => Ok(KeywordSize::XSmall),
"small" => Ok(KeywordSize::Small),
"medium" => Ok(KeywordSize::Medium),
"large" => Ok(KeywordSize::Large),
"x-large" => Ok(KeywordSize::XLarge),
"xx-large" => Ok(KeywordSize::XXLarge),
}
}
}
/// This is the ratio applied for font-size: larger /// This is the ratio applied for font-size: larger
/// and smaller by both Firefox and Chrome /// and smaller by both Firefox and Chrome
const LARGER_FONT_SIZE_RATIO: f32 = 1.2; const LARGER_FONT_SIZE_RATIO: f32 = 1.2;
@ -1079,7 +1077,7 @@ bitflags! {
} }
} }
#[derive(Clone, Debug, MallocSizeOf, PartialEq, ToCss)] #[derive(Clone, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo, ToCss)]
/// Set of variant alternates /// Set of variant alternates
pub enum VariantAlternates { pub enum VariantAlternates {
/// Enables display of stylistic alternates /// Enables display of stylistic alternates
@ -1104,7 +1102,7 @@ pub enum VariantAlternates {
HistoricalForms, HistoricalForms,
} }
#[derive(Clone, Debug, MallocSizeOf, PartialEq, ToCss)] #[derive(Clone, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo, ToCss)]
/// List of Variant Alternates /// List of Variant Alternates
pub struct VariantAlternatesList( pub struct VariantAlternatesList(
#[css(if_empty = "normal", iterable)] pub Box<[VariantAlternates]>, #[css(if_empty = "normal", iterable)] pub Box<[VariantAlternates]>,
@ -1125,12 +1123,13 @@ impl VariantAlternatesList {
} }
} }
#[derive(Clone, Debug, MallocSizeOf, PartialEq, ToCss)] #[derive(Clone, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo, ToCss)]
/// Control over the selection of these alternate glyphs /// Control over the selection of these alternate glyphs
pub enum FontVariantAlternates { pub enum FontVariantAlternates {
/// Use alternative glyph from value /// Use alternative glyph from value
Value(VariantAlternatesList), Value(VariantAlternatesList),
/// Use system font glyph /// Use system font glyph
#[css(skip)]
System(SystemFont), System(SystemFont),
} }
@ -1263,33 +1262,84 @@ impl Parse for FontVariantAlternates {
} }
} }
bitflags! { macro_rules! impl_variant_east_asian {
#[derive(MallocSizeOf)] {
/// Vairants for east asian variant $(
pub struct VariantEastAsian: u16 { $(#[$($meta:tt)+])*
/// None of the features $ident:ident / $css:expr => $gecko:ident = $value:expr,
const NORMAL = 0; )+
/// Enables rendering of JIS78 forms (OpenType feature: jp78) } => {
const JIS78 = 0x01; bitflags! {
/// Enables rendering of JIS83 forms (OpenType feature: jp83). #[derive(MallocSizeOf)]
const JIS83 = 0x02; /// Vairants for east asian variant
/// Enables rendering of JIS90 forms (OpenType feature: jp90). pub struct VariantEastAsian: u16 {
const JIS90 = 0x04; /// None of the features
/// Enables rendering of JIS2004 forms (OpenType feature: jp04). const NORMAL = 0;
const JIS04 = 0x08; $(
/// Enables rendering of simplified forms (OpenType feature: smpl). $(#[$($meta)+])*
const SIMPLIFIED = 0x10; const $ident = $value;
/// Enables rendering of traditional forms (OpenType feature: trad). )+
const TRADITIONAL = 0x20; }
/// Enables rendering of full-width variants (OpenType feature: fwid). }
const FULL_WIDTH = 0x40;
/// Enables rendering of proportionally-spaced variants (OpenType feature: pwid). impl ToCss for VariantEastAsian {
const PROPORTIONAL_WIDTH = 0x80; fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
/// Enables display of ruby variant glyphs (OpenType feature: ruby). where
const RUBY = 0x100; W: Write,
{
if self.is_empty() {
return dest.write_str("normal");
}
let mut writer = SequenceWriter::new(dest, " ");
$(
if self.intersects(VariantEastAsian::$ident) {
writer.raw_item($css)?;
}
)+
Ok(())
}
}
/// Asserts that all variant-east-asian matches its NS_FONT_VARIANT_EAST_ASIAN_* value.
#[cfg(feature = "gecko")]
#[inline]
pub fn assert_variant_east_asian_matches() {
use gecko_bindings::structs;
$(
debug_assert_eq!(structs::$gecko as u16, VariantEastAsian::$ident.bits());
)+
}
impl SpecifiedValueInfo for VariantEastAsian {
fn collect_completion_keywords(f: KeywordsCollectFn) {
f(&["normal", $($css,)+]);
}
}
} }
} }
impl_variant_east_asian! {
/// Enables rendering of JIS78 forms (OpenType feature: jp78)
JIS78 / "jis78" => NS_FONT_VARIANT_EAST_ASIAN_JIS78 = 0x01,
/// Enables rendering of JIS83 forms (OpenType feature: jp83).
JIS83 / "jis83" => NS_FONT_VARIANT_EAST_ASIAN_JIS83 = 0x02,
/// Enables rendering of JIS90 forms (OpenType feature: jp90).
JIS90 / "jis90" => NS_FONT_VARIANT_EAST_ASIAN_JIS90 = 0x04,
/// Enables rendering of JIS2004 forms (OpenType feature: jp04).
JIS04 / "jis04" => NS_FONT_VARIANT_EAST_ASIAN_JIS04 = 0x08,
/// Enables rendering of simplified forms (OpenType feature: smpl).
SIMPLIFIED / "simplified" => NS_FONT_VARIANT_EAST_ASIAN_SIMPLIFIED = 0x10,
/// Enables rendering of traditional forms (OpenType feature: trad).
TRADITIONAL / "traditional" => NS_FONT_VARIANT_EAST_ASIAN_TRADITIONAL = 0x20,
/// Enables rendering of full-width variants (OpenType feature: fwid).
FULL_WIDTH / "full-width" => NS_FONT_VARIANT_EAST_ASIAN_FULL_WIDTH = 0x40,
/// Enables rendering of proportionally-spaced variants (OpenType feature: pwid).
PROPORTIONAL_WIDTH / "proportional-width" => NS_FONT_VARIANT_EAST_ASIAN_PROP_WIDTH = 0x80,
/// Enables display of ruby variant glyphs (OpenType feature: ruby).
RUBY / "ruby" => NS_FONT_VARIANT_EAST_ASIAN_RUBY = 0x100,
}
#[cfg(feature = "gecko")] #[cfg(feature = "gecko")]
impl VariantEastAsian { impl VariantEastAsian {
/// Obtain a specified value from a Gecko keyword value /// Obtain a specified value from a Gecko keyword value
@ -1305,83 +1355,17 @@ impl VariantEastAsian {
} }
} }
impl ToCss for VariantEastAsian {
fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
where
W: Write,
{
if self.is_empty() {
return dest.write_str("normal");
}
let mut has_any = false;
macro_rules! write_value {
($ident:path => $str:expr) => {
if self.intersects($ident) {
if has_any {
dest.write_str(" ")?;
}
has_any = true;
dest.write_str($str)?;
}
};
}
write_value!(VariantEastAsian::JIS78 => "jis78");
write_value!(VariantEastAsian::JIS83 => "jis83");
write_value!(VariantEastAsian::JIS90 => "jis90");
write_value!(VariantEastAsian::JIS04 => "jis04");
write_value!(VariantEastAsian::SIMPLIFIED => "simplified");
write_value!(VariantEastAsian::TRADITIONAL => "traditional");
write_value!(VariantEastAsian::FULL_WIDTH => "full-width");
write_value!(VariantEastAsian::PROPORTIONAL_WIDTH => "proportional-width");
write_value!(VariantEastAsian::RUBY => "ruby");
debug_assert!(has_any);
Ok(())
}
}
#[cfg(feature = "gecko")] #[cfg(feature = "gecko")]
impl_gecko_keyword_conversions!(VariantEastAsian, u16); impl_gecko_keyword_conversions!(VariantEastAsian, u16);
/// Asserts that all variant-east-asian matches its NS_FONT_VARIANT_EAST_ASIAN_* value.
#[cfg(feature = "gecko")]
#[inline]
pub fn assert_variant_east_asian_matches() {
use gecko_bindings::structs;
macro_rules! check_variant_east_asian {
( $( $a:ident => $b:path),*, ) => {
if cfg!(debug_assertions) {
$(
assert_eq!(structs::$a as u16, $b.bits());
)*
}
}
}
check_variant_east_asian! {
NS_FONT_VARIANT_EAST_ASIAN_FULL_WIDTH => VariantEastAsian::FULL_WIDTH,
NS_FONT_VARIANT_EAST_ASIAN_JIS04 => VariantEastAsian::JIS04,
NS_FONT_VARIANT_EAST_ASIAN_JIS78 => VariantEastAsian::JIS78,
NS_FONT_VARIANT_EAST_ASIAN_JIS83 => VariantEastAsian::JIS83,
NS_FONT_VARIANT_EAST_ASIAN_JIS90 => VariantEastAsian::JIS90,
NS_FONT_VARIANT_EAST_ASIAN_PROP_WIDTH => VariantEastAsian::PROPORTIONAL_WIDTH,
NS_FONT_VARIANT_EAST_ASIAN_RUBY => VariantEastAsian::RUBY,
NS_FONT_VARIANT_EAST_ASIAN_SIMPLIFIED => VariantEastAsian::SIMPLIFIED,
NS_FONT_VARIANT_EAST_ASIAN_TRADITIONAL => VariantEastAsian::TRADITIONAL,
}
}
#[cfg_attr(feature = "gecko", derive(MallocSizeOf))] #[cfg_attr(feature = "gecko", derive(MallocSizeOf))]
#[derive(Clone, Debug, PartialEq, ToCss)] #[derive(Clone, Debug, PartialEq, SpecifiedValueInfo, ToCss)]
/// Allows control of glyph substitution and sizing in East Asian text. /// Allows control of glyph substitution and sizing in East Asian text.
pub enum FontVariantEastAsian { pub enum FontVariantEastAsian {
/// Value variant with `variant-east-asian` /// Value variant with `variant-east-asian`
Value(VariantEastAsian), Value(VariantEastAsian),
/// System font variant /// System font variant
#[css(skip)]
System(SystemFont), System(SystemFont),
} }
@ -1485,34 +1469,88 @@ impl Parse for FontVariantEastAsian {
} }
} }
bitflags! { macro_rules! impl_variant_ligatures {
#[derive(MallocSizeOf)] {
/// Variants of ligatures $(
pub struct VariantLigatures: u16 { $(#[$($meta:tt)+])*
/// Specifies that common default features are enabled $ident:ident / $css:expr => $gecko:ident = $value:expr,
const NORMAL = 0; )+
/// Specifies that all types of ligatures and contextual forms } => {
/// covered by this property are explicitly disabled bitflags! {
const NONE = 0x01; #[derive(MallocSizeOf)]
/// Enables display of common ligatures /// Variants of ligatures
const COMMON_LIGATURES = 0x02; pub struct VariantLigatures: u16 {
/// Disables display of common ligatures /// Specifies that common default features are enabled
const NO_COMMON_LIGATURES = 0x04; const NORMAL = 0;
/// Enables display of discretionary ligatures $(
const DISCRETIONARY_LIGATURES = 0x08; $(#[$($meta)+])*
/// Disables display of discretionary ligatures const $ident = $value;
const NO_DISCRETIONARY_LIGATURES = 0x10; )+
/// Enables display of historical ligatures }
const HISTORICAL_LIGATURES = 0x20; }
/// Disables display of historical ligatures
const NO_HISTORICAL_LIGATURES = 0x40; impl ToCss for VariantLigatures {
/// Enables display of contextual alternates fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
const CONTEXTUAL = 0x80; where
/// Disables display of contextual alternates W: Write,
const NO_CONTEXTUAL = 0x100; {
if self.is_empty() {
return dest.write_str("normal");
}
if self.contains(VariantLigatures::NONE) {
return dest.write_str("none");
}
let mut writer = SequenceWriter::new(dest, " ");
$(
if self.intersects(VariantLigatures::$ident) {
writer.raw_item($css)?;
}
)+
Ok(())
}
}
/// Asserts that all variant-east-asian matches its NS_FONT_VARIANT_EAST_ASIAN_* value.
#[cfg(feature = "gecko")]
#[inline]
pub fn assert_variant_ligatures_matches() {
use gecko_bindings::structs;
$(
debug_assert_eq!(structs::$gecko as u16, VariantLigatures::$ident.bits());
)+
}
impl SpecifiedValueInfo for VariantLigatures {
fn collect_completion_keywords(f: KeywordsCollectFn) {
f(&["normal", $($css,)+]);
}
}
} }
} }
impl_variant_ligatures! {
/// Specifies that all types of ligatures and contextual forms
/// covered by this property are explicitly disabled
NONE / "none" => NS_FONT_VARIANT_LIGATURES_NONE = 0x01,
/// Enables display of common ligatures
COMMON_LIGATURES / "common-ligatures" => NS_FONT_VARIANT_LIGATURES_COMMON = 0x02,
/// Disables display of common ligatures
NO_COMMON_LIGATURES / "no-common-ligatures" => NS_FONT_VARIANT_LIGATURES_NO_COMMON = 0x04,
/// Enables display of discretionary ligatures
DISCRETIONARY_LIGATURES / "discretionary-ligatures" => NS_FONT_VARIANT_LIGATURES_DISCRETIONARY = 0x08,
/// Disables display of discretionary ligatures
NO_DISCRETIONARY_LIGATURES / "no-discretionary-ligatures" => NS_FONT_VARIANT_LIGATURES_NO_DISCRETIONARY = 0x10,
/// Enables display of historical ligatures
HISTORICAL_LIGATURES / "historical-ligatures" => NS_FONT_VARIANT_LIGATURES_HISTORICAL = 0x20,
/// Disables display of historical ligatures
NO_HISTORICAL_LIGATURES / "no-historical-ligatures" => NS_FONT_VARIANT_LIGATURES_NO_HISTORICAL = 0x40,
/// Enables display of contextual alternates
CONTEXTUAL / "contextual" => NS_FONT_VARIANT_LIGATURES_CONTEXTUAL = 0x80,
/// Disables display of contextual alternates
NO_CONTEXTUAL / "no-contextual" => NS_FONT_VARIANT_LIGATURES_NO_CONTEXTUAL = 0x100,
}
#[cfg(feature = "gecko")] #[cfg(feature = "gecko")]
impl VariantLigatures { impl VariantLigatures {
/// Obtain a specified value from a Gecko keyword value /// Obtain a specified value from a Gecko keyword value
@ -1528,86 +1566,18 @@ impl VariantLigatures {
} }
} }
impl ToCss for VariantLigatures {
fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
where
W: Write,
{
if self.is_empty() {
return dest.write_str("normal");
}
if self.contains(VariantLigatures::NONE) {
return dest.write_str("none");
}
let mut has_any = false;
macro_rules! write_value {
($ident:path => $str:expr) => {
if self.intersects($ident) {
if has_any {
dest.write_str(" ")?;
}
has_any = true;
dest.write_str($str)?;
}
};
}
write_value!(VariantLigatures::COMMON_LIGATURES => "common-ligatures");
write_value!(VariantLigatures::NO_COMMON_LIGATURES => "no-common-ligatures");
write_value!(VariantLigatures::DISCRETIONARY_LIGATURES => "discretionary-ligatures");
write_value!(VariantLigatures::NO_DISCRETIONARY_LIGATURES => "no-discretionary-ligatures");
write_value!(VariantLigatures::HISTORICAL_LIGATURES => "historical-ligatures");
write_value!(VariantLigatures::NO_HISTORICAL_LIGATURES => "no-historical-ligatures");
write_value!(VariantLigatures::CONTEXTUAL => "contextual");
write_value!(VariantLigatures::NO_CONTEXTUAL => "no-contextual");
debug_assert!(has_any);
Ok(())
}
}
#[cfg(feature = "gecko")] #[cfg(feature = "gecko")]
impl_gecko_keyword_conversions!(VariantLigatures, u16); impl_gecko_keyword_conversions!(VariantLigatures, u16);
/// Asserts that all variant-east-asian matches its NS_FONT_VARIANT_EAST_ASIAN_* value.
#[cfg(feature = "gecko")]
#[inline]
pub fn assert_variant_ligatures_matches() {
use gecko_bindings::structs;
macro_rules! check_variant_ligatures {
( $( $a:ident => $b:path),*, ) => {
if cfg!(debug_assertions) {
$(
assert_eq!(structs::$a as u16, $b.bits());
)*
}
}
}
check_variant_ligatures! {
NS_FONT_VARIANT_LIGATURES_NONE => VariantLigatures::NONE,
NS_FONT_VARIANT_LIGATURES_COMMON => VariantLigatures::COMMON_LIGATURES,
NS_FONT_VARIANT_LIGATURES_NO_COMMON => VariantLigatures::NO_COMMON_LIGATURES,
NS_FONT_VARIANT_LIGATURES_DISCRETIONARY => VariantLigatures::DISCRETIONARY_LIGATURES,
NS_FONT_VARIANT_LIGATURES_NO_DISCRETIONARY => VariantLigatures::NO_DISCRETIONARY_LIGATURES,
NS_FONT_VARIANT_LIGATURES_HISTORICAL => VariantLigatures::HISTORICAL_LIGATURES,
NS_FONT_VARIANT_LIGATURES_NO_HISTORICAL => VariantLigatures::NO_HISTORICAL_LIGATURES,
NS_FONT_VARIANT_LIGATURES_CONTEXTUAL => VariantLigatures::CONTEXTUAL,
NS_FONT_VARIANT_LIGATURES_NO_CONTEXTUAL => VariantLigatures::NO_CONTEXTUAL,
}
}
#[cfg_attr(feature = "gecko", derive(MallocSizeOf))] #[cfg_attr(feature = "gecko", derive(MallocSizeOf))]
#[derive(Clone, Debug, PartialEq, ToCss)] #[derive(Clone, Debug, PartialEq, SpecifiedValueInfo, ToCss)]
/// Ligatures and contextual forms are ways of combining glyphs /// Ligatures and contextual forms are ways of combining glyphs
/// to produce more harmonized forms /// to produce more harmonized forms
pub enum FontVariantLigatures { pub enum FontVariantLigatures {
/// Value variant with `variant-ligatures` /// Value variant with `variant-ligatures`
Value(VariantLigatures), Value(VariantLigatures),
/// System font variant /// System font variant
#[css(skip)]
System(SystemFont), System(SystemFont),
} }
@ -1721,31 +1691,82 @@ impl Parse for FontVariantLigatures {
} }
} }
bitflags! { macro_rules! impl_variant_numeric {
#[derive(MallocSizeOf)] {
/// Vairants of numeric values $(
pub struct VariantNumeric: u8 { $(#[$($meta:tt)+])*
/// None of other variants are enabled. $ident:ident / $css:expr => $gecko:ident = $value:expr,
const NORMAL = 0; )+
/// Enables display of lining numerals. } => {
const LINING_NUMS = 0x01; bitflags! {
/// Enables display of old-style numerals. #[derive(MallocSizeOf)]
const OLDSTYLE_NUMS = 0x02; /// Vairants of numeric values
/// Enables display of proportional numerals. pub struct VariantNumeric: u8 {
const PROPORTIONAL_NUMS = 0x04; /// None of other variants are enabled.
/// Enables display of tabular numerals. const NORMAL = 0;
const TABULAR_NUMS = 0x08; $(
/// Enables display of lining diagonal fractions. $(#[$($meta)+])*
const DIAGONAL_FRACTIONS = 0x10; const $ident = $value;
/// Enables display of lining stacked fractions. )+
const STACKED_FRACTIONS = 0x20; }
/// Enables display of letter forms used with ordinal numbers. }
const ORDINAL = 0x80;
/// Enables display of slashed zeros. impl ToCss for VariantNumeric {
const SLASHED_ZERO = 0x40; fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
where
W: Write,
{
if self.is_empty() {
return dest.write_str("normal");
}
let mut writer = SequenceWriter::new(dest, " ");
$(
if self.intersects(VariantNumeric::$ident) {
writer.raw_item($css)?;
}
)+
Ok(())
}
}
/// Asserts that all variant-east-asian matches its NS_FONT_VARIANT_EAST_ASIAN_* value.
#[cfg(feature = "gecko")]
#[inline]
pub fn assert_variant_numeric_matches() {
use gecko_bindings::structs;
$(
debug_assert_eq!(structs::$gecko as u8, VariantNumeric::$ident.bits());
)+
}
impl SpecifiedValueInfo for VariantNumeric {
fn collect_completion_keywords(f: KeywordsCollectFn) {
f(&["normal", $($css,)+]);
}
}
} }
} }
impl_variant_numeric! {
/// Enables display of lining numerals.
LINING_NUMS / "lining-nums" => NS_FONT_VARIANT_NUMERIC_LINING = 0x01,
/// Enables display of old-style numerals.
OLDSTYLE_NUMS / "oldstyle-nums" => NS_FONT_VARIANT_NUMERIC_OLDSTYLE = 0x02,
/// Enables display of proportional numerals.
PROPORTIONAL_NUMS / "proportional-nums" => NS_FONT_VARIANT_NUMERIC_PROPORTIONAL = 0x04,
/// Enables display of tabular numerals.
TABULAR_NUMS / "tabular-nums" => NS_FONT_VARIANT_NUMERIC_TABULAR = 0x08,
/// Enables display of lining diagonal fractions.
DIAGONAL_FRACTIONS / "diagonal-fractions" => NS_FONT_VARIANT_NUMERIC_DIAGONAL_FRACTIONS = 0x10,
/// Enables display of lining stacked fractions.
STACKED_FRACTIONS / "stacked-fractions" => NS_FONT_VARIANT_NUMERIC_STACKED_FRACTIONS = 0x20,
/// Enables display of letter forms used with ordinal numbers.
ORDINAL / "ordinal" => NS_FONT_VARIANT_NUMERIC_ORDINAL = 0x80,
/// Enables display of slashed zeros.
SLASHED_ZERO / "slashed-zero" => NS_FONT_VARIANT_NUMERIC_SLASHZERO = 0x40,
}
#[cfg(feature = "gecko")] #[cfg(feature = "gecko")]
impl VariantNumeric { impl VariantNumeric {
/// Obtain a specified value from a Gecko keyword value /// Obtain a specified value from a Gecko keyword value
@ -1761,81 +1782,17 @@ impl VariantNumeric {
} }
} }
impl ToCss for VariantNumeric {
fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
where
W: Write,
{
if self.is_empty() {
return dest.write_str("normal");
}
let mut has_any = false;
macro_rules! write_value {
($ident:path => $str:expr) => {
if self.intersects($ident) {
if has_any {
dest.write_str(" ")?;
}
has_any = true;
dest.write_str($str)?;
}
};
}
write_value!(VariantNumeric::LINING_NUMS => "lining-nums");
write_value!(VariantNumeric::OLDSTYLE_NUMS => "oldstyle-nums");
write_value!(VariantNumeric::PROPORTIONAL_NUMS => "proportional-nums");
write_value!(VariantNumeric::TABULAR_NUMS => "tabular-nums");
write_value!(VariantNumeric::DIAGONAL_FRACTIONS => "diagonal-fractions");
write_value!(VariantNumeric::STACKED_FRACTIONS => "stacked-fractions");
write_value!(VariantNumeric::SLASHED_ZERO => "slashed-zero");
write_value!(VariantNumeric::ORDINAL => "ordinal");
debug_assert!(has_any);
Ok(())
}
}
#[cfg(feature = "gecko")] #[cfg(feature = "gecko")]
impl_gecko_keyword_conversions!(VariantNumeric, u8); impl_gecko_keyword_conversions!(VariantNumeric, u8);
/// Asserts that all variant-east-asian matches its NS_FONT_VARIANT_EAST_ASIAN_* value.
#[cfg(feature = "gecko")]
#[inline]
pub fn assert_variant_numeric_matches() {
use gecko_bindings::structs;
macro_rules! check_variant_numeric {
( $( $a:ident => $b:path),*, ) => {
if cfg!(debug_assertions) {
$(
assert_eq!(structs::$a as u8, $b.bits());
)*
}
}
}
check_variant_numeric! {
NS_FONT_VARIANT_NUMERIC_LINING => VariantNumeric::LINING_NUMS,
NS_FONT_VARIANT_NUMERIC_OLDSTYLE => VariantNumeric::OLDSTYLE_NUMS,
NS_FONT_VARIANT_NUMERIC_PROPORTIONAL => VariantNumeric::PROPORTIONAL_NUMS,
NS_FONT_VARIANT_NUMERIC_TABULAR => VariantNumeric::TABULAR_NUMS,
NS_FONT_VARIANT_NUMERIC_DIAGONAL_FRACTIONS => VariantNumeric::DIAGONAL_FRACTIONS,
NS_FONT_VARIANT_NUMERIC_STACKED_FRACTIONS => VariantNumeric::STACKED_FRACTIONS,
NS_FONT_VARIANT_NUMERIC_SLASHZERO => VariantNumeric::SLASHED_ZERO,
NS_FONT_VARIANT_NUMERIC_ORDINAL => VariantNumeric::ORDINAL,
}
}
#[cfg_attr(feature = "gecko", derive(MallocSizeOf))] #[cfg_attr(feature = "gecko", derive(MallocSizeOf))]
#[derive(Clone, Debug, PartialEq, ToCss)] #[derive(Clone, Debug, PartialEq, SpecifiedValueInfo, ToCss)]
/// Specifies control over numerical forms. /// Specifies control over numerical forms.
pub enum FontVariantNumeric { pub enum FontVariantNumeric {
/// Value variant with `variant-numeric` /// Value variant with `variant-numeric`
Value(VariantNumeric), Value(VariantNumeric),
/// System font /// System font
#[css(skip)]
System(SystemFont), System(SystemFont),
} }
@ -1938,11 +1895,12 @@ pub type SpecifiedFontFeatureSettings = FontSettings<FeatureTagValue<Integer>>;
/// Define initial settings that apply when the font defined by an @font-face /// Define initial settings that apply when the font defined by an @font-face
/// rule is rendered. /// rule is rendered.
#[derive(Clone, Debug, MallocSizeOf, PartialEq, ToCss)] #[derive(Clone, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo, ToCss)]
pub enum FontFeatureSettings { pub enum FontFeatureSettings {
/// Value of `FontSettings` /// Value of `FontSettings`
Value(SpecifiedFontFeatureSettings), Value(SpecifiedFontFeatureSettings),
/// System font /// System font
#[css(skip)]
System(SystemFont), System(SystemFont),
} }
@ -1981,16 +1939,19 @@ impl Parse for FontFeatureSettings {
} }
} }
#[derive(Clone, Copy, Debug, MallocSizeOf, PartialEq, ToComputedValue)] #[derive(Clone, Copy, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo,
ToComputedValue)]
/// Whether user agents are allowed to synthesize bold or oblique font faces /// Whether user agents are allowed to synthesize bold or oblique font faces
/// when a font family lacks bold or italic faces /// when a font family lacks bold or italic faces
pub struct FontSynthesis { pub struct FontSynthesis {
/// If a `font-weight` is requested that the font family does not contain, /// If a `font-weight` is requested that the font family does not contain,
/// the user agent may synthesize the requested weight from the weights /// the user agent may synthesize the requested weight from the weights
/// that do exist in the font family. /// that do exist in the font family.
#[value_info(represents_keyword)]
pub weight: bool, pub weight: bool,
/// If a font-style is requested that the font family does not contain, /// If a font-style is requested that the font family does not contain,
/// the user agent may synthesize the requested style from the normal face in the font family. /// the user agent may synthesize the requested style from the normal face in the font family.
#[value_info(represents_keyword)]
pub style: bool, pub style: bool,
} }
@ -2079,7 +2040,7 @@ impl From<FontSynthesis> for u8 {
} }
} }
#[derive(Clone, Debug, Eq, MallocSizeOf, PartialEq, ToCss)] #[derive(Clone, Debug, Eq, MallocSizeOf, PartialEq, SpecifiedValueInfo, ToCss)]
/// Allows authors to explicitly specify the language system of the font, /// Allows authors to explicitly specify the language system of the font,
/// overriding the language system implied by the content language /// overriding the language system implied by the content language
pub enum FontLanguageOverride { pub enum FontLanguageOverride {
@ -2092,6 +2053,7 @@ pub enum FontLanguageOverride {
/// the language system implied by the language of the element /// the language system implied by the language of the element
Override(Box<str>), Override(Box<str>),
/// Use system font /// Use system font
#[css(skip)]
System(SystemFont), System(SystemFont),
} }
@ -2169,11 +2131,12 @@ pub type SpecifiedFontVariationSettings = FontSettings<VariationValue<Number>>;
/// Define initial settings that apply when the font defined by an @font-face /// Define initial settings that apply when the font defined by an @font-face
/// rule is rendered. /// rule is rendered.
#[derive(Clone, Debug, MallocSizeOf, PartialEq, ToCss)] #[derive(Clone, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo, ToCss)]
pub enum FontVariationSettings { pub enum FontVariationSettings {
/// Value of `FontSettings` /// Value of `FontSettings`
Value(SpecifiedFontVariationSettings), Value(SpecifiedFontVariationSettings),
/// System font /// System font
#[css(skip)]
System(SystemFont), System(SystemFont),
} }
@ -2254,7 +2217,8 @@ impl Parse for VariationValue<Number> {
} }
} }
#[derive(Clone, Copy, Debug, MallocSizeOf, PartialEq, ToComputedValue, ToCss)] #[derive(Clone, Copy, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo,
ToComputedValue, ToCss)]
/// text-zoom. Enable if true, disable if false /// text-zoom. Enable if true, disable if false
pub struct XTextZoom(#[css(skip)] pub bool); pub struct XTextZoom(#[css(skip)] pub bool);
@ -2271,7 +2235,8 @@ impl Parse for XTextZoom {
} }
} }
#[derive(Clone, Debug, MallocSizeOf, PartialEq, ToComputedValue, ToCss)] #[derive(Clone, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo,
ToComputedValue, ToCss)]
/// Internal property that reflects the lang attribute /// Internal property that reflects the lang attribute
pub struct XLang(#[css(skip)] pub Atom); pub struct XLang(#[css(skip)] pub Atom);
@ -2297,7 +2262,7 @@ impl Parse for XLang {
} }
#[cfg_attr(feature = "gecko", derive(MallocSizeOf))] #[cfg_attr(feature = "gecko", derive(MallocSizeOf))]
#[derive(Clone, Copy, Debug, PartialEq, ToCss)] #[derive(Clone, Copy, Debug, PartialEq, SpecifiedValueInfo, ToCss)]
/// Specifies the minimum font size allowed due to changes in scriptlevel. /// Specifies the minimum font size allowed due to changes in scriptlevel.
/// Ref: https://wiki.mozilla.org/MathML:mstyle /// Ref: https://wiki.mozilla.org/MathML:mstyle
pub struct MozScriptMinSize(pub NoCalcLength); pub struct MozScriptMinSize(pub NoCalcLength);
@ -2324,7 +2289,7 @@ impl Parse for MozScriptMinSize {
} }
#[cfg_attr(feature = "gecko", derive(MallocSizeOf))] #[cfg_attr(feature = "gecko", derive(MallocSizeOf))]
#[derive(Clone, Copy, Debug, PartialEq, ToCss)] #[derive(Clone, Copy, Debug, PartialEq, SpecifiedValueInfo, ToCss)]
/// Changes the scriptlevel in effect for the children. /// Changes the scriptlevel in effect for the children.
/// Ref: https://wiki.mozilla.org/MathML:mstyle /// Ref: https://wiki.mozilla.org/MathML:mstyle
/// ///
@ -2359,7 +2324,8 @@ impl Parse for MozScriptLevel {
} }
#[cfg_attr(feature = "gecko", derive(MallocSizeOf))] #[cfg_attr(feature = "gecko", derive(MallocSizeOf))]
#[derive(Clone, Copy, Debug, PartialEq, ToComputedValue, ToCss)] #[derive(Clone, Copy, Debug, PartialEq, SpecifiedValueInfo, ToComputedValue,
ToCss)]
/// Specifies the multiplier to be used to adjust font size /// Specifies the multiplier to be used to adjust font size
/// due to changes in scriptlevel. /// due to changes in scriptlevel.
/// ///

View file

@ -104,7 +104,7 @@ pub fn parse_line_names<'i, 't>(
/// The type of `repeat` function (only used in parsing). /// The type of `repeat` function (only used in parsing).
/// ///
/// <https://drafts.csswg.org/css-grid/#typedef-track-repeat> /// <https://drafts.csswg.org/css-grid/#typedef-track-repeat>
#[derive(Clone, Copy, Debug, PartialEq)] #[derive(Clone, Copy, Debug, PartialEq, SpecifiedValueInfo)]
#[cfg_attr(feature = "servo", derive(MallocSizeOf))] #[cfg_attr(feature = "servo", derive(MallocSizeOf))]
enum RepeatType { enum RepeatType {
/// [`<auto-repeat>`](https://drafts.csswg.org/css-grid/#typedef-auto-repeat) /// [`<auto-repeat>`](https://drafts.csswg.org/css-grid/#typedef-auto-repeat)

View file

@ -17,7 +17,8 @@ use servo_url::ServoUrl;
use std::cmp::Ordering; use std::cmp::Ordering;
use std::f32::consts::PI; use std::f32::consts::PI;
use std::fmt::{self, Write}; use std::fmt::{self, Write};
use style_traits::{CssWriter, ParseError, StyleParseErrorKind, ToCss}; use style_traits::{CssType, CssWriter, KeywordsCollectFn, ParseError};
use style_traits::{StyleParseErrorKind, SpecifiedValueInfo, ToCss};
use values::{Either, None_}; use values::{Either, None_};
#[cfg(feature = "gecko")] #[cfg(feature = "gecko")]
use values::computed::{Context, Position as ComputedPosition, ToComputedValue}; use values::computed::{Context, Position as ComputedPosition, ToComputedValue};
@ -54,6 +55,29 @@ pub type Gradient = generic::Gradient<
Angle, Angle,
>; >;
impl SpecifiedValueInfo for Gradient {
const SUPPORTED_TYPES: u8 = CssType::GRADIENT;
fn collect_completion_keywords(f: KeywordsCollectFn) {
// This list here should keep sync with that in Gradient::parse.
f(&[
"linear-gradient",
"-webkit-linear-gradient",
"-moz-linear-gradient",
"repeating-linear-gradient",
"-webkit-repeating-linear-gradient",
"-moz-repeating-linear-gradient",
"radial-gradient",
"-webkit-radial-gradient",
"-moz-radial-gradient",
"repeating-radial-gradient",
"-webkit-repeating-radial-gradient",
"-moz-repeating-radial-gradient",
"-webkit-gradient",
]);
}
}
/// A specified gradient kind. /// A specified gradient kind.
#[cfg(not(feature = "gecko"))] #[cfg(not(feature = "gecko"))]
pub type GradientKind = pub type GradientKind =

View file

@ -15,12 +15,13 @@ use values::specified::Angle;
/// The specified value of the `image-orientation` property. /// The specified value of the `image-orientation` property.
/// https://drafts.csswg.org/css-images/#propdef-image-orientation /// https://drafts.csswg.org/css-images/#propdef-image-orientation
#[derive(Clone, Copy, Debug, MallocSizeOf, PartialEq)] #[derive(Clone, Copy, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo)]
pub struct ImageOrientation { pub struct ImageOrientation {
/// The angle specified, if any /// The angle specified, if any
pub angle: Option<Angle>, pub angle: Option<Angle>,
/// Whether or not "flip" was specified /// Whether or not "flip" was specified
#[value_info(other_values = "flip,from-image")]
pub flipped: bool, pub flipped: bool,
} }

View file

@ -13,7 +13,7 @@ use font_metrics::FontMetricsQueryResult;
use parser::{Parse, ParserContext}; use parser::{Parse, ParserContext};
use std::cmp; use std::cmp;
use std::ops::{Add, Mul}; use std::ops::{Add, Mul};
use style_traits::{ParseError, StyleParseErrorKind}; use style_traits::{ParseError, SpecifiedValueInfo, StyleParseErrorKind};
use style_traits::values::specified::AllowedNumericType; use style_traits::values::specified::AllowedNumericType;
use super::{AllowQuirks, Number, Percentage, ToComputedValue}; use super::{AllowQuirks, Number, Percentage, ToComputedValue};
use values::{Auto, CSSFloat, Either, Normal}; use values::{Auto, CSSFloat, Either, Normal};
@ -494,11 +494,13 @@ impl NoCalcLength {
} }
} }
impl SpecifiedValueInfo for NoCalcLength {}
/// An extension to `NoCalcLength` to parse `calc` expressions. /// An extension to `NoCalcLength` to parse `calc` expressions.
/// This is commonly used for the `<length>` values. /// This is commonly used for the `<length>` values.
/// ///
/// <https://drafts.csswg.org/css-values/#lengths> /// <https://drafts.csswg.org/css-values/#lengths>
#[derive(Clone, Debug, MallocSizeOf, PartialEq, ToCss)] #[derive(Clone, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo, ToCss)]
pub enum Length { pub enum Length {
/// The internal length type that cannot parse `calc` /// The internal length type that cannot parse `calc`
NoCalc(NoCalcLength), NoCalc(NoCalcLength),
@ -699,7 +701,7 @@ pub type NonNegativeLengthOrAuto = Either<NonNegativeLength, Auto>;
/// A length or a percentage value. /// A length or a percentage value.
#[allow(missing_docs)] #[allow(missing_docs)]
#[derive(Clone, Debug, MallocSizeOf, PartialEq, ToCss)] #[derive(Clone, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo, ToCss)]
pub enum LengthOrPercentage { pub enum LengthOrPercentage {
Length(NoCalcLength), Length(NoCalcLength),
Percentage(computed::Percentage), Percentage(computed::Percentage),
@ -845,7 +847,7 @@ impl LengthOrPercentage {
/// Either a `<length>`, a `<percentage>`, or the `auto` keyword. /// Either a `<length>`, a `<percentage>`, or the `auto` keyword.
#[allow(missing_docs)] #[allow(missing_docs)]
#[derive(Clone, Debug, MallocSizeOf, PartialEq, ToCss)] #[derive(Clone, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo, ToCss)]
pub enum LengthOrPercentageOrAuto { pub enum LengthOrPercentageOrAuto {
Length(NoCalcLength), Length(NoCalcLength),
Percentage(computed::Percentage), Percentage(computed::Percentage),
@ -1015,7 +1017,7 @@ impl Parse for NonNegativeLengthOrPercentageOrAuto {
} }
/// Either a `<length>`, a `<percentage>`, or the `none` keyword. /// Either a `<length>`, a `<percentage>`, or the `none` keyword.
#[derive(Clone, Debug, MallocSizeOf, PartialEq, ToCss)] #[derive(Clone, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo, ToCss)]
#[allow(missing_docs)] #[allow(missing_docs)]
pub enum LengthOrPercentageOrNone { pub enum LengthOrPercentageOrNone {
Length(NoCalcLength), Length(NoCalcLength),
@ -1195,7 +1197,7 @@ impl LengthOrNumber {
/// ///
/// Note that it only accepts non-negative values. /// Note that it only accepts non-negative values.
#[allow(missing_docs)] #[allow(missing_docs)]
#[derive(Clone, Debug, MallocSizeOf, PartialEq, ToCss)] #[derive(Clone, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo, ToCss)]
pub enum MozLength { pub enum MozLength {
LengthOrPercentageOrAuto(LengthOrPercentageOrAuto), LengthOrPercentageOrAuto(LengthOrPercentageOrAuto),
ExtremumLength(ExtremumLength), ExtremumLength(ExtremumLength),
@ -1252,7 +1254,7 @@ impl MozLength {
/// A value suitable for a `max-width` or `max-height` property. /// A value suitable for a `max-width` or `max-height` property.
#[allow(missing_docs)] #[allow(missing_docs)]
#[derive(Clone, Debug, MallocSizeOf, PartialEq, ToCss)] #[derive(Clone, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo, ToCss)]
pub enum MaxLength { pub enum MaxLength {
LengthOrPercentageOrNone(LengthOrPercentageOrNone), LengthOrPercentageOrNone(LengthOrPercentageOrNone),
ExtremumLength(ExtremumLength), ExtremumLength(ExtremumLength),

View file

@ -15,7 +15,8 @@ use values::generics::CounterStyleOrNone;
/// Specified and computed `list-style-type` property. /// Specified and computed `list-style-type` property.
#[cfg(feature = "gecko")] #[cfg(feature = "gecko")]
#[derive(Clone, Debug, Eq, MallocSizeOf, PartialEq, ToComputedValue, ToCss)] #[derive(Clone, Debug, Eq, MallocSizeOf, PartialEq, SpecifiedValueInfo,
ToComputedValue, ToCss)]
pub enum ListStyleType { pub enum ListStyleType {
/// <counter-style> | none /// <counter-style> | none
CounterStyle(CounterStyleOrNone), CounterStyle(CounterStyleOrNone),
@ -77,8 +78,10 @@ impl Parse for ListStyleType {
/// ///
/// FIXME(emilio): It's a shame that this allocates all the time it's computed, /// FIXME(emilio): It's a shame that this allocates all the time it's computed,
/// probably should just be refcounted. /// probably should just be refcounted.
#[derive(Clone, Debug, MallocSizeOf, PartialEq, ToComputedValue)] /// FIXME This can probably derive ToCss.
pub struct Quotes(pub Box<[(Box<str>, Box<str>)]>); #[derive(Clone, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo,
ToComputedValue)]
pub struct Quotes(#[css(if_empty = "none")] pub Box<[(Box<str>, Box<str>)]>);
impl ToCss for Quotes { impl ToCss for Quotes {
fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result

View file

@ -13,7 +13,7 @@ use num_traits::One;
use parser::{Parse, ParserContext}; use parser::{Parse, ParserContext};
use std::f32; use std::f32;
use std::fmt::{self, Write}; use std::fmt::{self, Write};
use style_traits::{CssWriter, ParseError, StyleParseErrorKind, ToCss}; use style_traits::{CssWriter, ParseError, SpecifiedValueInfo, StyleParseErrorKind, ToCss};
use style_traits::values::specified::AllowedNumericType; use style_traits::values::specified::AllowedNumericType;
use super::{Auto, CSSFloat, CSSInteger, Either}; use super::{Auto, CSSFloat, CSSInteger, Either};
use super::computed::{Context, ToComputedValue}; use super::computed::{Context, ToComputedValue};
@ -149,8 +149,8 @@ fn parse_number_with_clamping_mode<'i, 't>(
// FIXME(emilio): Should move to border.rs // FIXME(emilio): Should move to border.rs
#[allow(missing_docs)] #[allow(missing_docs)]
#[cfg_attr(feature = "servo", derive(Deserialize, Serialize))] #[cfg_attr(feature = "servo", derive(Deserialize, Serialize))]
#[derive(Clone, Copy, Debug, Eq, MallocSizeOf, Ord, Parse, PartialEq, PartialOrd, #[derive(Clone, Copy, Debug, Eq, MallocSizeOf, Ord, Parse, PartialEq,
ToComputedValue, ToCss)] PartialOrd, SpecifiedValueInfo, ToComputedValue, ToCss)]
pub enum BorderStyle { pub enum BorderStyle {
None = -1, None = -1,
Solid = 6, Solid = 6,
@ -273,6 +273,8 @@ impl ToCss for Number {
} }
} }
impl SpecifiedValueInfo for Number {}
impl From<Number> for f32 { impl From<Number> for f32 {
#[inline] #[inline]
fn from(n: Number) -> Self { fn from(n: Number) -> Self {
@ -326,7 +328,8 @@ impl Parse for GreaterThanOrEqualToOneNumber {
/// ///
/// FIXME(emilio): Should probably use Either. /// FIXME(emilio): Should probably use Either.
#[allow(missing_docs)] #[allow(missing_docs)]
#[derive(Clone, Copy, Debug, MallocSizeOf, PartialEq, ToCss)] #[derive(Clone, Copy, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo,
ToCss)]
pub enum NumberOrPercentage { pub enum NumberOrPercentage {
Percentage(Percentage), Percentage(Percentage),
Number(Number), Number(Number),
@ -364,7 +367,8 @@ impl Parse for NumberOrPercentage {
} }
#[allow(missing_docs)] #[allow(missing_docs)]
#[derive(Clone, Copy, Debug, MallocSizeOf, PartialEq, PartialOrd, ToCss)] #[derive(Clone, Copy, Debug, MallocSizeOf, PartialEq, PartialOrd,
SpecifiedValueInfo, ToCss)]
pub struct Opacity(Number); pub struct Opacity(Number);
impl Parse for Opacity { impl Parse for Opacity {
@ -533,6 +537,8 @@ impl ToCss for Integer {
} }
} }
impl SpecifiedValueInfo for Integer {}
/// A wrapper of Integer, with value >= 1. /// A wrapper of Integer, with value >= 1.
pub type PositiveInteger = GreaterThanOrEqualToOne<Integer>; pub type PositiveInteger = GreaterThanOrEqualToOne<Integer>;
@ -562,8 +568,9 @@ pub type GridLine = GenericGridLine<Integer>;
/// `<grid-template-rows> | <grid-template-columns>` /// `<grid-template-rows> | <grid-template-columns>`
pub type GridTemplateComponent = GenericGridTemplateComponent<LengthOrPercentage, Integer>; pub type GridTemplateComponent = GenericGridTemplateComponent<LengthOrPercentage, Integer>;
#[derive(Clone, Debug, MallocSizeOf, PartialEq)] #[derive(Clone, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo)]
/// rect(<top>, <left>, <bottom>, <right>) used by clip and image-region /// rect(<top>, <left>, <bottom>, <right>) used by clip and image-region
#[css(function = "rect")]
pub struct ClipRect { pub struct ClipRect {
/// <top> (<length> | <auto>) /// <top> (<length> | <auto>)
pub top: Option<Length>, pub top: Option<Length>,
@ -751,7 +758,9 @@ impl AllowQuirks {
/// An attr(...) rule /// An attr(...) rule
/// ///
/// `[namespace? `|`]? ident` /// `[namespace? `|`]? ident`
#[derive(Clone, Debug, Eq, MallocSizeOf, PartialEq, ToComputedValue)] #[derive(Clone, Debug, Eq, MallocSizeOf, PartialEq, SpecifiedValueInfo,
ToComputedValue)]
#[css(function)]
pub struct Attr { pub struct Attr {
/// Optional namespace prefix and URL. /// Optional namespace prefix and URL.
pub namespace: Option<(Prefix, Namespace)>, pub namespace: Option<(Prefix, Namespace)>,

View file

@ -10,8 +10,8 @@ use selectors::parser::SelectorParseErrorKind;
use style_traits::ParseError; use style_traits::ParseError;
use values::specified::BorderStyle; use values::specified::BorderStyle;
#[derive(Clone, Copy, Debug, Eq, MallocSizeOf, Ord, PartialEq, PartialOrd, ToComputedValue, #[derive(Clone, Copy, Debug, Eq, MallocSizeOf, Ord, PartialEq, PartialOrd,
ToCss)] SpecifiedValueInfo, ToComputedValue, ToCss)]
/// <https://drafts.csswg.org/css-ui/#propdef-outline-style> /// <https://drafts.csswg.org/css-ui/#propdef-outline-style>
pub enum OutlineStyle { pub enum OutlineStyle {
/// auto /// auto

View file

@ -7,7 +7,7 @@
use cssparser::{Parser, Token}; use cssparser::{Parser, Token};
use parser::{Parse, ParserContext}; use parser::{Parse, ParserContext};
use std::fmt::{self, Write}; use std::fmt::{self, Write};
use style_traits::{CssWriter, ParseError, ToCss}; use style_traits::{CssWriter, ParseError, SpecifiedValueInfo, ToCss};
use style_traits::values::specified::AllowedNumericType; use style_traits::values::specified::AllowedNumericType;
use values::{serialize_percentage, CSSFloat}; use values::{serialize_percentage, CSSFloat};
use values::computed::{Context, ToComputedValue}; use values::computed::{Context, ToComputedValue};
@ -158,3 +158,5 @@ impl ToComputedValue for Percentage {
Percentage::new(computed.0) Percentage::new(computed.0)
} }
} }
impl SpecifiedValueInfo for Percentage {}

View file

@ -8,44 +8,15 @@
use cssparser::Parser; use cssparser::Parser;
use parser::{Parse, ParserContext}; use parser::{Parse, ParserContext};
use style_traits::ParseError; use style_traits::{ParseError, StyleParseErrorKind};
use style_traits::cursor::CursorKind; use style_traits::cursor::CursorKind;
use values::generics::pointing::CaretColor as GenericCaretColor; use values::generics::pointing as generics;
use values::specified::Number;
use values::specified::color::Color; use values::specified::color::Color;
#[cfg(feature = "gecko")]
use values::specified::url::SpecifiedImageUrl; use values::specified::url::SpecifiedImageUrl;
/// The specified value for the `cursor` property.
///
/// https://drafts.csswg.org/css-ui/#cursor
#[cfg(feature = "servo")]
#[derive(Clone, Copy, Debug, MallocSizeOf, PartialEq, ToComputedValue, ToCss)]
pub struct Cursor(pub CursorKind);
/// The specified value for the `cursor` property.
///
/// https://drafts.csswg.org/css-ui/#cursor
#[cfg(feature = "gecko")]
#[derive(Clone, Debug, MallocSizeOf, PartialEq, ToComputedValue)]
pub struct Cursor {
/// The parsed images for the cursor.
pub images: Box<[CursorImage]>,
/// The kind of the cursor [default | help | ...].
pub keyword: CursorKind,
}
/// The specified value for the `image cursors`.
#[cfg(feature = "gecko")]
#[derive(Clone, Debug, MallocSizeOf, PartialEq, ToComputedValue)]
pub struct CursorImage {
/// The url to parse images from.
pub url: SpecifiedImageUrl,
/// The <x> and <y> coordinates.
pub hotspot: Option<(f32, f32)>,
}
/// A specified value for the `caret-color` property. /// A specified value for the `caret-color` property.
pub type CaretColor = GenericCaretColor<Color>; pub type CaretColor = generics::CaretColor<Color>;
impl Parse for CaretColor { impl Parse for CaretColor {
fn parse<'i, 't>( fn parse<'i, 't>(
@ -53,8 +24,63 @@ impl Parse for CaretColor {
input: &mut Parser<'i, 't>, input: &mut Parser<'i, 't>,
) -> Result<Self, ParseError<'i>> { ) -> Result<Self, ParseError<'i>> {
if input.try(|i| i.expect_ident_matching("auto")).is_ok() { if input.try(|i| i.expect_ident_matching("auto")).is_ok() {
return Ok(GenericCaretColor::Auto); return Ok(generics::CaretColor::Auto);
} }
Ok(GenericCaretColor::Color(Color::parse(context, input)?)) Ok(generics::CaretColor::Color(Color::parse(context, input)?))
}
}
/// A specified value for the `cursor` property.
pub type Cursor = generics::Cursor<CursorImage>;
/// A specified value for item of `image cursors`.
pub type CursorImage = generics::CursorImage<SpecifiedImageUrl, Number>;
impl Parse for Cursor {
/// cursor: [<url> [<number> <number>]?]# [auto | default | ...]
fn parse<'i, 't>(
context: &ParserContext,
input: &mut Parser<'i, 't>,
) -> Result<Self, ParseError<'i>> {
let mut images = vec![];
loop {
match input.try(|input| CursorImage::parse(context, input)) {
Ok(image) => images.push(image),
Err(_) => break,
}
input.expect_comma()?;
}
Ok(Self {
images: images.into_boxed_slice(),
keyword: CursorKind::parse(context, input)?,
})
}
}
impl Parse for CursorKind {
fn parse<'i, 't>(
_context: &ParserContext,
input: &mut Parser<'i, 't>,
) -> Result<Self, ParseError<'i>> {
let location = input.current_source_location();
let ident = input.expect_ident()?;
CursorKind::from_css_keyword(&ident).map_err(|_| {
location.new_custom_error(StyleParseErrorKind::UnspecifiedError)
})
}
}
impl Parse for CursorImage {
fn parse<'i, 't>(
context: &ParserContext,
input: &mut Parser<'i, 't>,
) -> Result<Self, ParseError<'i>> {
Ok(Self {
url: SpecifiedImageUrl::parse(context, input)?,
hotspot: match input.try(|input| Number::parse(context, input)) {
Ok(number) => Some((number, Number::parse(context, input)?)),
Err(_) => None,
},
})
} }
} }

View file

@ -34,7 +34,7 @@ pub type HorizontalPosition = PositionComponent<X>;
pub type VerticalPosition = PositionComponent<Y>; pub type VerticalPosition = PositionComponent<Y>;
/// The specified value of a component of a CSS `<position>`. /// The specified value of a component of a CSS `<position>`.
#[derive(Clone, Debug, MallocSizeOf, PartialEq, ToCss)] #[derive(Clone, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo, ToCss)]
pub enum PositionComponent<S> { pub enum PositionComponent<S> {
/// `center` /// `center`
Center, Center,
@ -45,7 +45,8 @@ pub enum PositionComponent<S> {
} }
/// A keyword for the X direction. /// A keyword for the X direction.
#[derive(Clone, Copy, Debug, Eq, Hash, MallocSizeOf, Parse, PartialEq, ToComputedValue, ToCss)] #[derive(Clone, Copy, Debug, Eq, Hash, MallocSizeOf, Parse, PartialEq,
SpecifiedValueInfo, ToComputedValue, ToCss)]
#[allow(missing_docs)] #[allow(missing_docs)]
pub enum X { pub enum X {
Left, Left,
@ -53,7 +54,8 @@ pub enum X {
} }
/// A keyword for the Y direction. /// A keyword for the Y direction.
#[derive(Clone, Copy, Debug, Eq, Hash, MallocSizeOf, Parse, PartialEq, ToComputedValue, ToCss)] #[derive(Clone, Copy, Debug, Eq, Hash, MallocSizeOf, Parse, PartialEq,
SpecifiedValueInfo, ToComputedValue, ToCss)]
#[allow(missing_docs)] #[allow(missing_docs)]
pub enum Y { pub enum Y {
Top, Top,
@ -409,7 +411,8 @@ impl ToCss for LegacyPosition {
} }
} }
#[derive(Clone, Copy, Debug, Eq, MallocSizeOf, PartialEq, ToComputedValue, ToCss)] #[derive(Clone, Copy, Debug, Eq, MallocSizeOf, PartialEq, SpecifiedValueInfo,
ToComputedValue, ToCss)]
/// Auto-placement algorithm Option /// Auto-placement algorithm Option
pub enum AutoFlow { pub enum AutoFlow {
/// The auto-placement algorithm places items by filling each row in turn, /// The auto-placement algorithm places items by filling each row in turn,
@ -420,13 +423,15 @@ pub enum AutoFlow {
Column, Column,
} }
#[derive(Clone, Copy, Debug, Eq, MallocSizeOf, PartialEq, ToComputedValue)] #[derive(Clone, Copy, Debug, Eq, MallocSizeOf, PartialEq, SpecifiedValueInfo,
ToComputedValue)]
/// Controls how the auto-placement algorithm works /// Controls how the auto-placement algorithm works
/// specifying exactly how auto-placed items get flowed into the grid /// specifying exactly how auto-placed items get flowed into the grid
pub struct GridAutoFlow { pub struct GridAutoFlow {
/// Specifiy how auto-placement algorithm fills each `row` or `column` in turn /// Specifiy how auto-placement algorithm fills each `row` or `column` in turn
pub autoflow: AutoFlow, pub autoflow: AutoFlow,
/// Specify use `dense` packing algorithm or not /// Specify use `dense` packing algorithm or not
#[value_info(represents_keyword)]
pub dense: bool, pub dense: bool,
} }
@ -533,7 +538,7 @@ impl From<GridAutoFlow> for u8 {
} }
#[cfg_attr(feature = "gecko", derive(MallocSizeOf))] #[cfg_attr(feature = "gecko", derive(MallocSizeOf))]
#[derive(Clone, Debug, PartialEq, ToComputedValue, ToCss)] #[derive(Clone, Debug, PartialEq, SpecifiedValueInfo, ToComputedValue, ToCss)]
/// https://drafts.csswg.org/css-grid/#named-grid-area /// https://drafts.csswg.org/css-grid/#named-grid-area
pub struct TemplateAreas { pub struct TemplateAreas {
/// `named area` containing for each template area /// `named area` containing for each template area
@ -639,7 +644,8 @@ impl Parse for TemplateAreas {
} }
/// Arc type for `Arc<TemplateAreas>` /// Arc type for `Arc<TemplateAreas>`
#[derive(Clone, Debug, MallocSizeOf, PartialEq, ToComputedValue, ToCss)] #[derive(Clone, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo,
ToComputedValue, ToCss)]
pub struct TemplateAreasArc(#[ignore_malloc_size_of = "Arc"] pub Arc<TemplateAreas>); pub struct TemplateAreasArc(#[ignore_malloc_size_of = "Arc"] pub Arc<TemplateAreas>);
impl Parse for TemplateAreasArc { impl Parse for TemplateAreasArc {
@ -654,7 +660,7 @@ impl Parse for TemplateAreasArc {
} }
#[cfg_attr(feature = "gecko", derive(MallocSizeOf))] #[cfg_attr(feature = "gecko", derive(MallocSizeOf))]
#[derive(Clone, Debug, PartialEq)] #[derive(Clone, Debug, PartialEq, SpecifiedValueInfo)]
/// Not associated with any particular grid item, but can /// Not associated with any particular grid item, but can
/// be referenced from the grid-placement properties. /// be referenced from the grid-placement properties.
pub struct NamedArea { pub struct NamedArea {

View file

@ -173,7 +173,8 @@ const PAINT_ORDER_MASK: u8 = 0b11;
/// ///
/// Higher priority values, i.e. the values specified first, /// Higher priority values, i.e. the values specified first,
/// will be painted first (and may be covered by paintings of lower priority) /// will be painted first (and may be covered by paintings of lower priority)
#[derive(Clone, Copy, Debug, MallocSizeOf, PartialEq, ToComputedValue)] #[derive(Clone, Copy, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo,
ToComputedValue)]
pub struct SVGPaintOrder(pub u8); pub struct SVGPaintOrder(pub u8);
impl SVGPaintOrder { impl SVGPaintOrder {
@ -280,7 +281,8 @@ impl ToCss for SVGPaintOrder {
/// Specified MozContextProperties value. /// Specified MozContextProperties value.
/// Nonstandard (https://developer.mozilla.org/en-US/docs/Web/CSS/-moz-context-properties) /// Nonstandard (https://developer.mozilla.org/en-US/docs/Web/CSS/-moz-context-properties)
#[derive(Clone, Debug, MallocSizeOf, PartialEq, ToComputedValue, ToCss)] #[derive(Clone, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo,
ToComputedValue, ToCss)]
pub struct MozContextProperties(pub CustomIdent); pub struct MozContextProperties(pub CustomIdent);
impl Parse for MozContextProperties { impl Parse for MozContextProperties {

View file

@ -8,7 +8,8 @@ use cssparser::Parser;
use parser::{Parse, ParserContext}; use parser::{Parse, ParserContext};
use style_traits::{ParseError, StyleParseErrorKind}; use style_traits::{ParseError, StyleParseErrorKind};
#[derive(Clone, Copy, Debug, MallocSizeOf, PartialEq, ToComputedValue, ToCss)] #[derive(Clone, Copy, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo,
ToComputedValue, ToCss)]
/// span. for `<col span>` pres attr /// span. for `<col span>` pres attr
pub struct XSpan(#[css(skip)] pub i32); pub struct XSpan(#[css(skip)] pub i32);

View file

@ -9,7 +9,9 @@ use parser::{Parse, ParserContext};
use properties::longhands::writing_mode::computed_value::T as SpecifiedWritingMode; use properties::longhands::writing_mode::computed_value::T as SpecifiedWritingMode;
use selectors::parser::SelectorParseErrorKind; use selectors::parser::SelectorParseErrorKind;
use std::fmt::{self, Write}; use std::fmt::{self, Write};
use style_traits::{CssWriter, ParseError, StyleParseErrorKind, ToCss}; use style_traits::{CssWriter, KeywordsCollectFn, ParseError};
use style_traits::{SpecifiedValueInfo, StyleParseErrorKind, ToCss};
use style_traits::values::SequenceWriter;
use unicode_segmentation::UnicodeSegmentation; use unicode_segmentation::UnicodeSegmentation;
use values::computed::{Context, ToComputedValue}; use values::computed::{Context, ToComputedValue};
use values::computed::text::LineHeight as ComputedLineHeight; use values::computed::text::LineHeight as ComputedLineHeight;
@ -158,7 +160,7 @@ impl ToComputedValue for LineHeight {
} }
/// A generic value for the `text-overflow` property. /// A generic value for the `text-overflow` property.
#[derive(Clone, Debug, Eq, MallocSizeOf, PartialEq, ToCss)] #[derive(Clone, Debug, Eq, MallocSizeOf, PartialEq, SpecifiedValueInfo, ToCss)]
pub enum TextOverflowSide { pub enum TextOverflowSide {
/// Clip inline content. /// Clip inline content.
Clip, Clip,
@ -192,7 +194,7 @@ impl Parse for TextOverflowSide {
} }
} }
#[derive(Clone, Debug, Eq, MallocSizeOf, PartialEq, ToCss)] #[derive(Clone, Debug, Eq, MallocSizeOf, PartialEq, SpecifiedValueInfo, ToCss)]
/// text-overflow. Specifies rendering when inline content overflows its line box edge. /// text-overflow. Specifies rendering when inline content overflows its line box edge.
pub struct TextOverflow { pub struct TextOverflow {
/// First value. Applies to end line box edge if no second is supplied; line-left edge otherwise. /// First value. Applies to end line box edge if no second is supplied; line-left edge otherwise.
@ -251,32 +253,117 @@ impl ToComputedValue for TextOverflow {
} }
} }
bitflags! { macro_rules! impl_text_decoration_line {
#[derive(MallocSizeOf, ToComputedValue)] {
/// Specified keyword values for the text-decoration-line property. $(
pub struct TextDecorationLine: u8 { $(#[$($meta:tt)+])*
/// No text decoration line is specified $ident:ident / $css:expr => $value:expr,
const NONE = 0; )+
/// Underline } => {
const UNDERLINE = 0x01; bitflags! {
/// Overline #[derive(MallocSizeOf, ToComputedValue)]
const OVERLINE = 0x02; /// Specified keyword values for the text-decoration-line property.
/// Line through pub struct TextDecorationLine: u8 {
const LINE_THROUGH = 0x04; /// No text decoration line is specified
/// Blink const NONE = 0;
const BLINK = 0x08; $(
#[cfg(feature = "gecko")] $(#[$($meta)+])*
/// Only set by presentation attributes const $ident = $value;
/// )+
/// Setting this will mean that text-decorations use the color #[cfg(feature = "gecko")]
/// specified by `color` in quirks mode. /// Only set by presentation attributes
/// ///
/// For example, this gives <a href=foo><font color="red">text</font></a> /// Setting this will mean that text-decorations use the color
/// a red text decoration /// specified by `color` in quirks mode.
const COLOR_OVERRIDE = 0x10; ///
/// For example, this gives <a href=foo><font color="red">text</font></a>
/// a red text decoration
const COLOR_OVERRIDE = 0x10;
}
}
impl Parse for TextDecorationLine {
/// none | [ underline || overline || line-through || blink ]
fn parse<'i, 't>(
_context: &ParserContext,
input: &mut Parser<'i, 't>,
) -> Result<TextDecorationLine, ParseError<'i>> {
let mut result = TextDecorationLine::NONE;
if input
.try(|input| input.expect_ident_matching("none"))
.is_ok()
{
return Ok(result);
}
loop {
let result = input.try(|input| {
let ident = input.expect_ident().map_err(|_| ())?;
match_ignore_ascii_case! { ident,
$(
$css => {
if result.contains(TextDecorationLine::$ident) {
Err(())
} else {
result.insert(TextDecorationLine::$ident);
Ok(())
}
}
)+
_ => Err(()),
}
});
if result.is_err() {
break;
}
}
if !result.is_empty() {
Ok(result)
} else {
Err(input.new_custom_error(StyleParseErrorKind::UnspecifiedError))
}
}
}
impl ToCss for TextDecorationLine {
fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
where
W: Write,
{
if self.is_empty() {
return dest.write_str("none");
}
let mut writer = SequenceWriter::new(dest, " ");
$(
if self.contains(TextDecorationLine::$ident) {
writer.raw_item($css)?;
}
)+
Ok(())
}
}
impl SpecifiedValueInfo for TextDecorationLine {
fn collect_completion_keywords(f: KeywordsCollectFn) {
f(&["none", $($css,)+]);
}
}
} }
} }
impl_text_decoration_line! {
/// Underline
UNDERLINE / "underline" => 1 << 0,
/// Overline
OVERLINE / "overline" => 1 << 1,
/// Line through
LINE_THROUGH / "line-through" => 1 << 2,
/// Blink
BLINK / "blink" => 1 << 3,
}
#[cfg(feature = "gecko")] #[cfg(feature = "gecko")]
impl_bitflags_conversions!(TextDecorationLine); impl_bitflags_conversions!(TextDecorationLine);
@ -288,79 +375,18 @@ impl TextDecorationLine {
} }
} }
impl Parse for TextDecorationLine {
/// none | [ underline || overline || line-through || blink ]
fn parse<'i, 't>(
_context: &ParserContext,
input: &mut Parser<'i, 't>,
) -> Result<TextDecorationLine, ParseError<'i>> {
let mut result = TextDecorationLine::NONE;
if input
.try(|input| input.expect_ident_matching("none"))
.is_ok()
{
return Ok(result);
}
loop {
let result = input.try(|input| {
let ident = input.expect_ident().map_err(|_| ())?;
match_ignore_ascii_case! { ident,
"underline" => {
if result.contains(TextDecorationLine::UNDERLINE) {
Err(())
} else {
result.insert(TextDecorationLine::UNDERLINE);
Ok(())
}
}
"overline" => {
if result.contains(TextDecorationLine::OVERLINE) {
Err(())
} else {
result.insert(TextDecorationLine::OVERLINE);
Ok(())
}
}
"line-through" => {
if result.contains(TextDecorationLine::LINE_THROUGH) {
Err(())
} else {
result.insert(TextDecorationLine::LINE_THROUGH);
Ok(())
}
}
"blink" => {
if result.contains(TextDecorationLine::BLINK) {
Err(())
} else {
result.insert(TextDecorationLine::BLINK);
Ok(())
}
}
_ => Err(()),
}
});
if result.is_err() {
break;
}
}
if !result.is_empty() {
Ok(result)
} else {
Err(input.new_custom_error(StyleParseErrorKind::UnspecifiedError))
}
}
}
macro_rules! define_text_align_keyword { macro_rules! define_text_align_keyword {
($($name: ident => $discriminant: expr,)+) => { ($(
$(#[$($meta:tt)+])*
$name: ident => $discriminant: expr,
)+) => {
/// Specified value of text-align keyword value. /// Specified value of text-align keyword value.
#[derive(Clone, Copy, Debug, Eq, Hash, MallocSizeOf, Parse, PartialEq, ToComputedValue, ToCss)] #[derive(Clone, Copy, Debug, Eq, Hash, MallocSizeOf, Parse, PartialEq,
SpecifiedValueInfo, ToComputedValue, ToCss)]
#[allow(missing_docs)] #[allow(missing_docs)]
pub enum TextAlignKeyword { pub enum TextAlignKeyword {
$( $(
$(#[$($meta)+])*
$name = $discriminant, $name = $discriminant,
)+ )+
} }
@ -391,6 +417,7 @@ define_text_align_keyword! {
MozCenter => 6, MozCenter => 6,
MozLeft => 7, MozLeft => 7,
MozRight => 8, MozRight => 8,
#[css(skip)]
Char => 10, Char => 10,
} }
@ -417,7 +444,7 @@ impl TextAlignKeyword {
/// Specified value of text-align property. /// Specified value of text-align property.
#[cfg_attr(feature = "gecko", derive(MallocSizeOf))] #[cfg_attr(feature = "gecko", derive(MallocSizeOf))]
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq, SpecifiedValueInfo, ToCss)]
pub enum TextAlign { pub enum TextAlign {
/// Keyword value of text-align property. /// Keyword value of text-align property.
Keyword(TextAlignKeyword), Keyword(TextAlignKeyword),
@ -429,6 +456,7 @@ pub enum TextAlign {
/// only set directly on the elements and it has a different handling /// only set directly on the elements and it has a different handling
/// unlike other values. /// unlike other values.
#[cfg(feature = "gecko")] #[cfg(feature = "gecko")]
#[css(skip)]
MozCenterOrInherit, MozCenterOrInherit,
} }
@ -453,21 +481,6 @@ impl Parse for TextAlign {
} }
} }
impl ToCss for TextAlign {
fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
where
W: Write,
{
match *self {
TextAlign::Keyword(key) => key.to_css(dest),
#[cfg(feature = "gecko")]
TextAlign::MatchParent => dest.write_str("match-parent"),
#[cfg(feature = "gecko")]
TextAlign::MozCenterOrInherit => Ok(()),
}
}
}
impl TextAlign { impl TextAlign {
/// Convert an enumerated value coming from Gecko to a `TextAlign`. /// Convert an enumerated value coming from Gecko to a `TextAlign`.
#[cfg(feature = "gecko")] #[cfg(feature = "gecko")]
@ -534,7 +547,7 @@ impl ToComputedValue for TextAlign {
} }
/// Specified value of text-emphasis-style property. /// Specified value of text-emphasis-style property.
#[derive(Clone, Debug, MallocSizeOf, PartialEq, ToCss)] #[derive(Clone, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo, ToCss)]
pub enum TextEmphasisStyle { pub enum TextEmphasisStyle {
/// <fill> <shape> /// <fill> <shape>
Keyword(TextEmphasisKeywordValue), Keyword(TextEmphasisKeywordValue),
@ -545,7 +558,7 @@ pub enum TextEmphasisStyle {
} }
/// Keyword value for the text-emphasis-style property /// Keyword value for the text-emphasis-style property
#[derive(Clone, Debug, MallocSizeOf, PartialEq, ToCss)] #[derive(Clone, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo, ToCss)]
pub enum TextEmphasisKeywordValue { pub enum TextEmphasisKeywordValue {
/// <fill> /// <fill>
Fill(TextEmphasisFillMode), Fill(TextEmphasisFillMode),
@ -574,7 +587,8 @@ impl TextEmphasisKeywordValue {
} }
/// Fill mode for the text-emphasis-style property /// Fill mode for the text-emphasis-style property
#[derive(Clone, Copy, Debug, MallocSizeOf, Parse, PartialEq, ToCss)] #[derive(Clone, Copy, Debug, MallocSizeOf, Parse, PartialEq, SpecifiedValueInfo,
ToCss)]
pub enum TextEmphasisFillMode { pub enum TextEmphasisFillMode {
/// `filled` /// `filled`
Filled, Filled,
@ -583,7 +597,8 @@ pub enum TextEmphasisFillMode {
} }
/// Shape keyword for the text-emphasis-style property /// Shape keyword for the text-emphasis-style property
#[derive(Clone, Copy, Debug, Eq, MallocSizeOf, Parse, PartialEq, ToCss)] #[derive(Clone, Copy, Debug, Eq, MallocSizeOf, Parse, PartialEq,
SpecifiedValueInfo, ToCss)]
pub enum TextEmphasisShapeKeyword { pub enum TextEmphasisShapeKeyword {
/// `dot` /// `dot`
Dot, Dot,
@ -709,7 +724,8 @@ impl Parse for TextEmphasisStyle {
} }
/// The allowed horizontal values for the `text-emphasis-position` property. /// The allowed horizontal values for the `text-emphasis-position` property.
#[derive(Clone, Copy, Debug, Eq, MallocSizeOf, Parse, PartialEq, ToComputedValue, ToCss)] #[derive(Clone, Copy, Debug, Eq, MallocSizeOf, Parse, PartialEq,
SpecifiedValueInfo, ToComputedValue, ToCss)]
pub enum TextEmphasisHorizontalWritingModeValue { pub enum TextEmphasisHorizontalWritingModeValue {
/// Draw marks over the text in horizontal writing mode. /// Draw marks over the text in horizontal writing mode.
Over, Over,
@ -718,7 +734,8 @@ pub enum TextEmphasisHorizontalWritingModeValue {
} }
/// The allowed vertical values for the `text-emphasis-position` property. /// The allowed vertical values for the `text-emphasis-position` property.
#[derive(Clone, Copy, Debug, Eq, MallocSizeOf, Parse, PartialEq, ToComputedValue, ToCss)] #[derive(Clone, Copy, Debug, Eq, MallocSizeOf, Parse, PartialEq,
SpecifiedValueInfo, ToComputedValue, ToCss)]
pub enum TextEmphasisVerticalWritingModeValue { pub enum TextEmphasisVerticalWritingModeValue {
/// Draws marks to the right of the text in vertical writing mode. /// Draws marks to the right of the text in vertical writing mode.
Right, Right,
@ -727,7 +744,8 @@ pub enum TextEmphasisVerticalWritingModeValue {
} }
/// Specified value of `text-emphasis-position` property. /// Specified value of `text-emphasis-position` property.
#[derive(Clone, Debug, MallocSizeOf, PartialEq, ToComputedValue, ToCss)] #[derive(Clone, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo,
ToComputedValue, ToCss)]
pub struct TextEmphasisPosition( pub struct TextEmphasisPosition(
pub TextEmphasisHorizontalWritingModeValue, pub TextEmphasisHorizontalWritingModeValue,
pub TextEmphasisVerticalWritingModeValue, pub TextEmphasisVerticalWritingModeValue,

View file

@ -7,7 +7,7 @@
use cssparser::{Parser, Token}; use cssparser::{Parser, Token};
use parser::{Parse, ParserContext}; use parser::{Parse, ParserContext};
use std::fmt::{self, Write}; use std::fmt::{self, Write};
use style_traits::{CssWriter, ParseError, StyleParseErrorKind, ToCss}; use style_traits::{CssWriter, ParseError, SpecifiedValueInfo, StyleParseErrorKind, ToCss};
use style_traits::values::specified::AllowedNumericType; use style_traits::values::specified::AllowedNumericType;
use values::CSSFloat; use values::CSSFloat;
use values::computed::{Context, ToComputedValue}; use values::computed::{Context, ToComputedValue};
@ -165,3 +165,5 @@ impl ToCss for Time {
Ok(()) Ok(())
} }
} }
impl SpecifiedValueInfo for Time {}

View file

@ -233,7 +233,7 @@ impl Parse for Transform {
} }
/// The specified value of a component of a CSS `<transform-origin>`. /// The specified value of a component of a CSS `<transform-origin>`.
#[derive(Clone, Debug, MallocSizeOf, PartialEq, ToCss)] #[derive(Clone, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo, ToCss)]
pub enum OriginComponent<S> { pub enum OriginComponent<S> {
/// `center` /// `center`
Center, Center,

View file

@ -10,7 +10,8 @@ use std::fmt::{self, Write};
use style_traits::{CssWriter, ParseError, StyleParseErrorKind, ToCss}; use style_traits::{CssWriter, ParseError, StyleParseErrorKind, ToCss};
/// Specified value of `-moz-force-broken-image-icon` /// Specified value of `-moz-force-broken-image-icon`
#[derive(Clone, Copy, Debug, MallocSizeOf, PartialEq, ToComputedValue)] #[derive(Clone, Copy, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo,
ToComputedValue)]
pub struct MozForceBrokenImageIcon(pub bool); pub struct MozForceBrokenImageIcon(pub bool);
impl MozForceBrokenImageIcon { impl MozForceBrokenImageIcon {

View file

@ -68,7 +68,7 @@ pub fn derive(mut input: DeriveInput) -> Tokens {
} }
fn derive_variant_arm(variant: &VariantInfo) -> Result<Tokens, ()> { fn derive_variant_arm(variant: &VariantInfo) -> Result<Tokens, ()> {
let variant_attrs = cg::parse_variant_attrs::<AnimationVariantAttrs>(&variant.ast()); let variant_attrs = cg::parse_variant_attrs_from_ast::<AnimationVariantAttrs>(&variant.ast());
if variant_attrs.error { if variant_attrs.error {
return Err(()); return Err(());
} }

View file

@ -188,7 +188,7 @@ where
} }
} }
pub fn parse_variant_attrs<A>(variant: &VariantAst) -> A pub fn parse_variant_attrs_from_ast<A>(variant: &VariantAst) -> A
where where
A: FromVariant, A: FromVariant,
{ {
@ -198,7 +198,14 @@ where
fields: variant.fields.clone(), fields: variant.fields.clone(),
discriminant: variant.discriminant.clone(), discriminant: variant.discriminant.clone(),
}; };
match A::from_variant(&v) { parse_variant_attrs(&v)
}
pub fn parse_variant_attrs<A>(variant: &Variant) -> A
where
A: FromVariant
{
match A::from_variant(variant) {
Ok(attrs) => attrs, Ok(attrs) => attrs,
Err(e) => panic!("failed to parse variant attributes: {}", e), Err(e) => panic!("failed to parse variant attributes: {}", e),
} }

View file

@ -26,7 +26,7 @@ pub fn derive(mut input: DeriveInput) -> Tokens {
let mut append_error_clause = s.variants().len() > 1; let mut append_error_clause = s.variants().len() > 1;
let match_body = s.variants().iter().fold(quote!(), |body, variant| { let match_body = s.variants().iter().fold(quote!(), |body, variant| {
let attrs = cg::parse_variant_attrs::<AnimationVariantAttrs>(&variant.ast()); let attrs = cg::parse_variant_attrs_from_ast::<AnimationVariantAttrs>(&variant.ast());
if attrs.error { if attrs.error {
append_error_clause = true; append_error_clause = true;
return body; return body;

View file

@ -16,6 +16,7 @@ mod animate;
mod cg; mod cg;
mod compute_squared_distance; mod compute_squared_distance;
mod parse; mod parse;
mod specified_value_info;
mod to_animated_value; mod to_animated_value;
mod to_animated_zero; mod to_animated_zero;
mod to_computed_value; mod to_computed_value;
@ -62,3 +63,9 @@ pub fn derive_to_css(stream: TokenStream) -> TokenStream {
let input = syn::parse(stream).unwrap(); let input = syn::parse(stream).unwrap();
to_css::derive(input).into() to_css::derive(input).into()
} }
#[proc_macro_derive(SpecifiedValueInfo, attributes(css, value_info))]
pub fn derive_specified_value_info(stream: TokenStream) -> TokenStream {
let input = syn::parse(stream).unwrap();
specified_value_info::derive(input).into()
}

View file

@ -19,7 +19,11 @@ pub fn derive(input: DeriveInput) -> Tokens {
"Parse is only supported for single-variant enums for now" "Parse is only supported for single-variant enums for now"
); );
let variant_attrs = cg::parse_variant_attrs::<CssVariantAttrs>(&variant.ast()); let variant_attrs = cg::parse_variant_attrs_from_ast::<CssVariantAttrs>(&variant.ast());
if variant_attrs.skip {
return match_body;
}
let identifier = cg::to_css_identifier( let identifier = cg::to_css_identifier(
&variant_attrs.keyword.unwrap_or(variant.ast().ident.as_ref().into()), &variant_attrs.keyword.unwrap_or(variant.ast().ident.as_ref().into()),
); );

View file

@ -0,0 +1,181 @@
/* 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/. */
use cg;
use quote::Tokens;
use syn::{Data, DeriveInput, Fields, Ident, Type};
use to_css::{CssFieldAttrs, CssInputAttrs, CssVariantAttrs};
pub fn derive(mut input: DeriveInput) -> Tokens {
let css_attrs = cg::parse_input_attrs::<CssInputAttrs>(&input);
let mut types = vec![];
let mut values = vec![];
let input_ident = input.ident;
let input_name = || cg::to_css_identifier(input_ident.as_ref());
if let Some(function) = css_attrs.function {
values.push(function.explicit().unwrap_or_else(input_name));
// If the whole value is wrapped in a function, value types of
// its fields should not be propagated.
} else {
let mut where_clause = input.generics.where_clause.take();
for param in input.generics.type_params() {
cg::add_predicate(
&mut where_clause,
parse_quote!(#param: ::style_traits::SpecifiedValueInfo),
);
}
input.generics.where_clause = where_clause;
match input.data {
Data::Enum(ref e) => {
for v in e.variants.iter() {
let css_attrs = cg::parse_variant_attrs::<CssVariantAttrs>(&v);
let info_attrs = cg::parse_variant_attrs::<ValueInfoVariantAttrs>(&v);
if css_attrs.skip {
continue;
}
if let Some(aliases) = css_attrs.aliases {
for alias in aliases.split(",") {
values.push(alias.to_string());
}
}
if let Some(other_values) = info_attrs.other_values {
for value in other_values.split(",") {
values.push(value.to_string());
}
}
let ident = &v.ident;
let variant_name = || cg::to_css_identifier(ident.as_ref());
if info_attrs.starts_with_keyword {
values.push(variant_name());
continue;
}
if let Some(keyword) = css_attrs.keyword {
values.push(keyword);
continue;
}
if let Some(function) = css_attrs.function {
values.push(function.explicit().unwrap_or_else(variant_name));
} else {
if !derive_struct_fields(&v.fields, &mut types, &mut values) {
values.push(variant_name());
}
}
}
}
Data::Struct(ref s) => {
if !derive_struct_fields(&s.fields, &mut types, &mut values) {
values.push(input_name());
}
}
Data::Union(_) => unreachable!("union is not supported"),
}
}
let info_attrs = cg::parse_input_attrs::<ValueInfoInputAttrs>(&input);
if let Some(other_values) = info_attrs.other_values {
for value in other_values.split(",") {
values.push(value.to_string());
}
}
let mut types_value = quote!(0);
types_value.append_all(types.iter().map(|ty| quote! {
| <#ty as ::style_traits::SpecifiedValueInfo>::SUPPORTED_TYPES
}));
let mut nested_collects = quote!();
nested_collects.append_all(types.iter().map(|ty| quote! {
<#ty as ::style_traits::SpecifiedValueInfo>::collect_completion_keywords(_f);
}));
if let Some(ty) = info_attrs.ty {
types_value.append_all(quote! {
| ::style_traits::CssType::#ty
});
}
let append_values = if values.is_empty() {
quote!()
} else {
let mut value_list = quote!();
value_list.append_separated(values.iter(), quote! { , });
quote! { _f(&[#value_list]); }
};
let name = &input.ident;
let (impl_generics, ty_generics, where_clause) = input.generics.split_for_impl();
quote! {
impl #impl_generics ::style_traits::SpecifiedValueInfo for #name #ty_generics
#where_clause
{
const SUPPORTED_TYPES: u8 = #types_value;
fn collect_completion_keywords(_f: &mut FnMut(&[&'static str])) {
#nested_collects
#append_values
}
}
}
}
/// Derive from the given fields. Return false if the fields is a Unit,
/// true otherwise.
fn derive_struct_fields<'a>(
fields: &'a Fields,
types: &mut Vec<&'a Type>,
values: &mut Vec<String>,
) -> bool {
let fields = match *fields {
Fields::Unit => return false,
Fields::Named(ref fields) => fields.named.iter(),
Fields::Unnamed(ref fields) => fields.unnamed.iter(),
};
types.extend(fields.filter_map(|field| {
let info_attrs = cg::parse_field_attrs::<ValueInfoFieldAttrs>(field);
if let Some(other_values) = info_attrs.other_values {
for value in other_values.split(",") {
values.push(value.to_string());
}
}
if info_attrs.represents_keyword {
let ident = field.ident.as_ref()
.expect("only named field should use represents_keyword");
values.push(cg::to_css_identifier(ident.as_ref()));
return None;
}
let css_attrs = cg::parse_field_attrs::<CssFieldAttrs>(field);
if let Some(if_empty) = css_attrs.if_empty {
values.push(if_empty);
}
if !css_attrs.skip {
Some(&field.ty)
} else {
None
}
}));
true
}
#[darling(attributes(value_info), default)]
#[derive(Default, FromDeriveInput)]
struct ValueInfoInputAttrs {
ty: Option<Ident>,
other_values: Option<String>,
}
#[darling(attributes(value_info), default)]
#[derive(Default, FromVariant)]
struct ValueInfoVariantAttrs {
starts_with_keyword: bool,
other_values: Option<String>,
}
#[darling(attributes(value_info), default)]
#[derive(Default, FromField)]
struct ValueInfoFieldAttrs {
represents_keyword: bool,
other_values: Option<String>,
}

View file

@ -22,7 +22,7 @@ pub fn derive(mut input: syn::DeriveInput) -> quote::Tokens {
} }
let to_body = synstructure::Structure::new(&input).each_variant(|variant| { let to_body = synstructure::Structure::new(&input).each_variant(|variant| {
let attrs = cg::parse_variant_attrs::<AnimationVariantAttrs>(&variant.ast()); let attrs = cg::parse_variant_attrs_from_ast::<AnimationVariantAttrs>(&variant.ast());
if attrs.error { if attrs.error {
return Some(quote! { Err(()) }); return Some(quote! { Err(()) });
} }

View file

@ -75,9 +75,12 @@ fn derive_variant_arm(
let bindings = variant.bindings(); let bindings = variant.bindings();
let identifier = cg::to_css_identifier(variant.ast().ident.as_ref()); let identifier = cg::to_css_identifier(variant.ast().ident.as_ref());
let ast = variant.ast(); let ast = variant.ast();
let variant_attrs = cg::parse_variant_attrs::<CssVariantAttrs>(&ast); let variant_attrs = cg::parse_variant_attrs_from_ast::<CssVariantAttrs>(&ast);
let separator = if variant_attrs.comma { ", " } else { " " }; let separator = if variant_attrs.comma { ", " } else { " " };
if variant_attrs.skip {
return quote!(Ok(()));
}
if variant_attrs.dimension { if variant_attrs.dimension {
assert_eq!(bindings.len(), 1); assert_eq!(bindings.len(), 1);
assert!( assert!(
@ -207,12 +210,12 @@ fn derive_single_field_expr(
#[darling(attributes(css), default)] #[darling(attributes(css), default)]
#[derive(Default, FromDeriveInput)] #[derive(Default, FromDeriveInput)]
struct CssInputAttrs { pub struct CssInputAttrs {
derive_debug: bool, pub derive_debug: bool,
// Here because structs variants are also their whole type definition. // Here because structs variants are also their whole type definition.
function: Option<Override<String>>, pub function: Option<Override<String>>,
// Here because structs variants are also their whole type definition. // Here because structs variants are also their whole type definition.
comma: bool, pub comma: bool,
} }
#[darling(attributes(css), default)] #[darling(attributes(css), default)]
@ -223,14 +226,15 @@ pub struct CssVariantAttrs {
pub dimension: bool, pub dimension: bool,
pub keyword: Option<String>, pub keyword: Option<String>,
pub aliases: Option<String>, pub aliases: Option<String>,
pub skip: bool,
} }
#[darling(attributes(css), default)] #[darling(attributes(css), default)]
#[derive(Default, FromField)] #[derive(Default, FromField)]
struct CssFieldAttrs { pub struct CssFieldAttrs {
if_empty: Option<String>, pub if_empty: Option<String>,
field_bound: bool, pub field_bound: bool,
iterable: bool, pub iterable: bool,
skip: bool, pub skip: bool,
skip_if: Option<Path>, pub skip_if: Option<Path>,
} }

View file

@ -10,7 +10,7 @@ name = "style_traits"
path = "lib.rs" path = "lib.rs"
[features] [features]
servo = ["serde", "servo_atoms", "cssparser/serde", "webrender_api"] servo = ["serde", "servo_atoms", "cssparser/serde", "webrender_api", "servo_url"]
gecko = [] gecko = []
[dependencies] [dependencies]
@ -24,4 +24,5 @@ selectors = { path = "../selectors" }
serde = {version = "1.0", optional = true} serde = {version = "1.0", optional = true}
webrender_api = {git = "https://github.com/servo/webrender", optional = true} webrender_api = {git = "https://github.com/servo/webrender", optional = true}
servo_atoms = {path = "../atoms", optional = true} servo_atoms = {path = "../atoms", optional = true}
servo_arc = {path = "../servo_arc" } servo_arc = { path = "../servo_arc" }
servo_url = { path = "../url", optional = true }

View file

@ -4,7 +4,7 @@
//! A list of common mouse cursors per CSS3-UI § 8.1.1. //! A list of common mouse cursors per CSS3-UI § 8.1.1.
use super::{CssWriter, ToCss}; use super::{CssWriter, KeywordsCollectFn, SpecifiedValueInfo, ToCss};
macro_rules! define_cursor { macro_rules! define_cursor {
( (
@ -57,6 +57,15 @@ macro_rules! define_cursor {
} }
} }
} }
impl SpecifiedValueInfo for CursorKind {
fn collect_completion_keywords(f: KeywordsCollectFn) {
f(&[
$($c_css,)+
$($g_css,)+
]);
}
}
} }
} }

View file

@ -22,6 +22,7 @@ extern crate selectors;
#[cfg(feature = "servo")] extern crate webrender_api; #[cfg(feature = "servo")] extern crate webrender_api;
extern crate servo_arc; extern crate servo_arc;
#[cfg(feature = "servo")] extern crate servo_atoms; #[cfg(feature = "servo")] extern crate servo_atoms;
#[cfg(feature = "servo")] extern crate servo_url;
#[cfg(feature = "servo")] pub use webrender_api::DevicePixel; #[cfg(feature = "servo")] pub use webrender_api::DevicePixel;
@ -73,11 +74,13 @@ pub enum CSSPixel {}
// / desktop_zoom => CSSPixel // / desktop_zoom => CSSPixel
pub mod cursor; pub mod cursor;
pub mod specified_value_info;
#[macro_use] #[macro_use]
pub mod values; pub mod values;
#[macro_use] #[macro_use]
pub mod viewport; pub mod viewport;
pub use specified_value_info::{CssType, KeywordsCollectFn, SpecifiedValueInfo};
pub use values::{Comma, CommaWithSpace, CssWriter, OneOrMoreSeparated, Separator, Space, ToCss}; pub use values::{Comma, CommaWithSpace, CssWriter, OneOrMoreSeparated, Separator, Space, ToCss};
/// The error type for all CSS parsing routines. /// The error type for all CSS parsing routines.

View file

@ -0,0 +1,134 @@
/* 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/. */
//! Value information for devtools.
use servo_arc::Arc;
use std::ops::Range;
use std::sync::Arc as StdArc;
/// Type of value that a property supports. This is used by Gecko's
/// devtools to make sense about value it parses, and types listed
/// here should match TYPE_* constants in InspectorUtils.webidl.
///
/// XXX This should really be a bitflags rather than a namespace mod,
/// but currently we cannot use bitflags in const.
#[allow(non_snake_case)]
pub mod CssType {
/// <color>
pub const COLOR: u8 = 1 << 0;
/// <gradient>
pub const GRADIENT: u8 = 1 << 1;
/// <timing-function>
pub const TIMING_FUNCTION: u8 = 1 << 2;
}
/// See SpecifiedValueInfo::collect_completion_keywords.
pub type KeywordsCollectFn<'a> = &'a mut FnMut(&[&'static str]);
/// Information of values of a given specified value type.
///
/// This trait is derivable with `#[derive(SpecifiedValueInfo)]`.
///
/// The algorithm traverses the type definition. For `SUPPORTED_TYPES`,
/// it puts an or'ed value of `SUPPORTED_TYPES` of all types it finds.
/// For `collect_completion_keywords`, it recursively invokes this
/// method on types found, and lists all keyword values and function
/// names following the same rule as `ToCss` in that method.
///
/// Some attributes of `ToCss` can affect the behavior, specifically:
/// * If `#[css(function)]` is found, the content inside the annotated
/// variant (or the whole type) isn't traversed, only the function
/// name is listed in `collect_completion_keywords`.
/// * If `#[css(skip)]` is found, the content inside the variant or
/// field is ignored.
/// * Values listed in `#[css(if_empty)]`, `#[css(aliases)]`, and
/// `#[css(keyword)]` are added into `collect_completion_keywords`.
///
/// In addition to `css` attributes, it also has `value_info` helper
/// attributes, including:
/// * `#[value_info(ty = "TYPE")]` can be used to specify a constant
/// from `CssType` to `SUPPORTED_TYPES`.
/// * `#[value_info(other_values = "value1,value2")]` can be used to
/// add other values related to a field, variant, or the type itself
/// into `collect_completion_keywords`.
/// * `#[value_info(starts_with_keyword)]` can be used on variants to
/// add the name of a non-unit variant (serialized like `ToCss`) into
/// `collect_completion_keywords`.
/// * `#[value_info(represents_keyword)]` can be used on fields into
/// `collect_completion_keywords`.
pub trait SpecifiedValueInfo {
/// Supported CssTypes by the given value type.
///
/// XXX This should be typed CssType when that becomes a bitflags.
/// Currently we cannot do so since bitflags cannot be used in constant.
const SUPPORTED_TYPES: u8 = 0;
/// Collect value starting words for the given specified value type.
/// This includes keyword and function names which can appear at the
/// beginning of a value of this type.
///
/// Caller should pass in a callback function to accept the list of
/// values. The callback function can be called multiple times, and
/// some values passed to the callback may be duplicate.
fn collect_completion_keywords(_f: KeywordsCollectFn) {}
}
impl SpecifiedValueInfo for bool {}
impl SpecifiedValueInfo for f32 {}
impl SpecifiedValueInfo for i8 {}
impl SpecifiedValueInfo for i32 {}
impl SpecifiedValueInfo for u8 {}
impl SpecifiedValueInfo for u16 {}
impl SpecifiedValueInfo for u32 {}
impl SpecifiedValueInfo for str {}
impl SpecifiedValueInfo for String {}
#[cfg(feature = "servo")]
impl SpecifiedValueInfo for ::servo_atoms::Atom {}
#[cfg(feature = "servo")]
impl SpecifiedValueInfo for ::servo_url::ServoUrl {}
impl<T: SpecifiedValueInfo + ?Sized> SpecifiedValueInfo for Box<T> {
const SUPPORTED_TYPES: u8 = T::SUPPORTED_TYPES;
fn collect_completion_keywords(f: KeywordsCollectFn) {
T::collect_completion_keywords(f);
}
}
impl<T: SpecifiedValueInfo> SpecifiedValueInfo for [T] {
const SUPPORTED_TYPES: u8 = T::SUPPORTED_TYPES;
fn collect_completion_keywords(f: KeywordsCollectFn) {
T::collect_completion_keywords(f);
}
}
macro_rules! impl_generic_specified_value_info {
($ty:ident<$param:ident>) => {
impl<$param: SpecifiedValueInfo> SpecifiedValueInfo for $ty<$param> {
const SUPPORTED_TYPES: u8 = $param::SUPPORTED_TYPES;
fn collect_completion_keywords(f: KeywordsCollectFn) {
$param::collect_completion_keywords(f);
}
}
}
}
impl_generic_specified_value_info!(Option<T>);
impl_generic_specified_value_info!(Vec<T>);
impl_generic_specified_value_info!(Arc<T>);
impl_generic_specified_value_info!(StdArc<T>);
impl_generic_specified_value_info!(Range<Idx>);
impl<T1, T2> SpecifiedValueInfo for (T1, T2)
where
T1: SpecifiedValueInfo,
T2: SpecifiedValueInfo,
{
const SUPPORTED_TYPES: u8 = T1::SUPPORTED_TYPES | T2::SUPPORTED_TYPES;
fn collect_completion_keywords(f: KeywordsCollectFn) {
T1::collect_completion_keywords(f);
T2::collect_completion_keywords(f);
}
}

View file

@ -173,16 +173,10 @@ where
Self { inner, separator } Self { inner, separator }
} }
/// Serialises a CSS value, writing any separator as necessary.
///
/// The separator is never written before any `item` produces any output,
/// and is written in subsequent calls only if the `item` produces some
/// output on its own again. This lets us handle `Option<T>` fields by
/// just not printing anything on `None`.
#[inline] #[inline]
pub fn item<T>(&mut self, item: &T) -> fmt::Result fn write_item<F>(&mut self, f: F) -> fmt::Result
where where
T: ToCss, F: FnOnce(&mut CssWriter<'b, W>) -> fmt::Result
{ {
let old_prefix = self.inner.prefix; let old_prefix = self.inner.prefix;
if old_prefix.is_none() { if old_prefix.is_none() {
@ -191,7 +185,7 @@ where
// to write the separator next time we produce output again. // to write the separator next time we produce output again.
self.inner.prefix = Some(self.separator); self.inner.prefix = Some(self.separator);
} }
item.to_css(&mut self.inner)?; f(self.inner)?;
match (old_prefix, self.inner.prefix) { match (old_prefix, self.inner.prefix) {
(_, None) => { (_, None) => {
// This call produced output and cleaned up after itself. // This call produced output and cleaned up after itself.
@ -213,6 +207,29 @@ where
} }
Ok(()) Ok(())
} }
/// Serialises a CSS value, writing any separator as necessary.
///
/// The separator is never written before any `item` produces any output,
/// and is written in subsequent calls only if the `item` produces some
/// output on its own again. This lets us handle `Option<T>` fields by
/// just not printing anything on `None`.
#[inline]
pub fn item<T>(&mut self, item: &T) -> fmt::Result
where
T: ToCss,
{
self.write_item(|inner| item.to_css(inner))
}
/// Writes a string as-is (i.e. not escaped or wrapped in quotes)
/// with any separator as necessary.
///
/// See SequenceWriter::item.
#[inline]
pub fn raw_item(&mut self, item: &str) -> fmt::Result {
self.write_item(|inner| inner.write_str(item))
}
} }
/// A wrapper type that implements `ToCss` by printing its inner field. /// A wrapper type that implements `ToCss` by printing its inner field.

View file

@ -17,7 +17,6 @@ gecko_debug = ["style/gecko_debug"]
atomic_refcell = "0.1" atomic_refcell = "0.1"
cssparser = "0.23.0" cssparser = "0.23.0"
cstr = "0.1.2" cstr = "0.1.2"
env_logger = {version = "0.5", default-features = false} # disable `regex` to reduce code size
libc = "0.2" libc = "0.2"
log = {version = "0.4", features = ["release_max_level_info"]} log = {version = "0.4", features = ["release_max_level_info"]}
malloc_size_of = {path = "../../components/malloc_size_of"} malloc_size_of = {path = "../../components/malloc_size_of"}

View file

@ -4,15 +4,14 @@
use cssparser::{ParseErrorKind, Parser, ParserInput, SourceLocation}; use cssparser::{ParseErrorKind, Parser, ParserInput, SourceLocation};
use cssparser::ToCss as ParserToCss; use cssparser::ToCss as ParserToCss;
use env_logger::Builder;
use malloc_size_of::MallocSizeOfOps; use malloc_size_of::MallocSizeOfOps;
use nsstring::nsCString; use nsstring::{nsCString, nsStringRepr};
use selectors::{NthIndexCache, SelectorList}; use selectors::{NthIndexCache, SelectorList};
use selectors::matching::{MatchingContext, MatchingMode, matches_selector}; use selectors::matching::{MatchingContext, MatchingMode, matches_selector};
use servo_arc::{Arc, ArcBorrow, RawOffsetArc}; use servo_arc::{Arc, ArcBorrow, RawOffsetArc};
use smallvec::SmallVec; use smallvec::SmallVec;
use std::cell::RefCell; use std::cell::RefCell;
use std::env; use std::collections::BTreeSet;
use std::fmt::Write; use std::fmt::Write;
use std::iter; use std::iter;
use std::mem; use std::mem;
@ -137,7 +136,7 @@ use style::properties::{parse_one_declaration_into, parse_style_attribute};
use style::properties::animated_properties::AnimationValue; use style::properties::animated_properties::AnimationValue;
use style::properties::animated_properties::compare_property_priority; use style::properties::animated_properties::compare_property_priority;
use style::rule_cache::RuleCacheConditions; use style::rule_cache::RuleCacheConditions;
use style::rule_tree::{CascadeLevel, StrongRuleNode, StyleSource}; use style::rule_tree::{CascadeLevel, StrongRuleNode};
use style::selector_parser::{PseudoElementCascadeType, SelectorImpl}; use style::selector_parser::{PseudoElementCascadeType, SelectorImpl};
use style::shared_lock::{SharedRwLockReadGuard, StylesheetGuards, ToCssWithGuard, Locked}; use style::shared_lock::{SharedRwLockReadGuard, StylesheetGuards, ToCssWithGuard, Locked};
use style::string_cache::{Atom, WeakAtom}; use style::string_cache::{Atom, WeakAtom};
@ -164,7 +163,7 @@ use style::values::generics::rect::Rect;
use style::values::specified; use style::values::specified;
use style::values::specified::gecko::{IntersectionObserverRootMargin, PixelOrPercentage}; use style::values::specified::gecko::{IntersectionObserverRootMargin, PixelOrPercentage};
use style::values::specified::source_size_list::SourceSizeList; use style::values::specified::source_size_list::SourceSizeList;
use style_traits::{CssWriter, ParsingMode, StyleParseErrorKind, ToCss}; use style_traits::{CssType, CssWriter, ParsingMode, StyleParseErrorKind, ToCss};
use super::error_reporter::ErrorReporter; use super::error_reporter::ErrorReporter;
use super::stylesheet_loader::{AsyncStylesheetParser, StylesheetLoader}; use super::stylesheet_loader::{AsyncStylesheetParser, StylesheetLoader};
@ -184,14 +183,6 @@ static mut DUMMY_URL_DATA: *mut URLExtraData = 0 as *mut URLExtraData;
pub extern "C" fn Servo_Initialize(dummy_url_data: *mut URLExtraData) { pub extern "C" fn Servo_Initialize(dummy_url_data: *mut URLExtraData) {
use style::gecko_bindings::sugar::origin_flags; use style::gecko_bindings::sugar::origin_flags;
// Initialize logging.
let mut builder = Builder::new();
let default_level = if cfg!(debug_assertions) { "warn" } else { "error" };
match env::var("RUST_LOG") {
Ok(v) => builder.parse(&v).init(),
_ => builder.parse(default_level).init(),
};
// Pretend that we're a Servo Layout thread, to make some assertions happy. // Pretend that we're a Servo Layout thread, to make some assertions happy.
thread_state::initialize(thread_state::ThreadState::LAYOUT); thread_state::initialize(thread_state::ThreadState::LAYOUT);
@ -938,20 +929,36 @@ pub extern "C" fn Servo_ComputedValues_ExtractAnimationValue(
} }
} }
macro_rules! parse_enabled_property_name {
($prop_name:ident, $found:ident, $default:expr) => {{
let prop_name = $prop_name.as_ref().unwrap().as_str_unchecked();
// XXX This can be simplified once Option::filter is stable.
let prop_id = PropertyId::parse(prop_name).ok().and_then(|p| {
if p.enabled_for_all_content() {
Some(p)
} else {
None
}
});
match prop_id {
Some(p) => {
*$found = true;
p
}
None => {
*$found = false;
return $default;
}
}
}}
}
#[no_mangle] #[no_mangle]
pub unsafe extern "C" fn Servo_Property_IsShorthand( pub unsafe extern "C" fn Servo_Property_IsShorthand(
prop_name: *const nsACString, prop_name: *const nsACString,
found: *mut bool found: *mut bool
) -> bool { ) -> bool {
let prop_id = PropertyId::parse(prop_name.as_ref().unwrap().as_str_unchecked()); let prop_id = parse_enabled_property_name!(prop_name, found, false);
let prop_id = match prop_id {
Ok(ref p) if p.enabled_for_all_content() => p,
_ => {
*found = false;
return false;
}
};
*found = true;
prop_id.is_shorthand() prop_id.is_shorthand()
} }
@ -974,6 +981,53 @@ pub unsafe extern "C" fn Servo_Property_IsInherited(
longhand_id.inherited() longhand_id.inherited()
} }
#[no_mangle]
pub unsafe extern "C" fn Servo_Property_SupportsType(
prop_name: *const nsACString,
ty: u32,
found: *mut bool,
) -> bool {
let prop_id = parse_enabled_property_name!(prop_name, found, false);
// This should match the constants in InspectorUtils.
// (Let's don't bother importing InspectorUtilsBinding into bindings
// because it is not used anywhere else, and issue here would be
// caught by the property-db test anyway.)
let ty = match ty {
1 => CssType::COLOR,
2 => CssType::GRADIENT,
3 => CssType::TIMING_FUNCTION,
_ => unreachable!("unknown CSS type {}", ty),
};
prop_id.supports_type(ty)
}
#[no_mangle]
pub unsafe extern "C" fn Servo_Property_GetCSSValuesForProperty(
prop_name: *const nsACString,
found: *mut bool,
result: *mut nsTArray<nsStringRepr>,
) {
let prop_id = parse_enabled_property_name!(prop_name, found, ());
// Use B-tree set for unique and sorted result.
let mut values = BTreeSet::<&'static str>::new();
prop_id.collect_property_completion_keywords(&mut |list| values.extend(list.iter()));
let mut extras = vec![];
if values.contains("transparent") {
// This is a special value devtools use to avoid inserting the
// long list of color keywords. We need to prepend it to values.
extras.push("COLOR");
}
let result = result.as_mut().unwrap();
let len = extras.len() + values.len();
bindings::Gecko_ResizeTArrayForStrings(result, len as u32);
for (src, dest) in extras.iter().chain(values.iter()).zip(result.iter_mut()) {
dest.write_str(src).unwrap();
}
}
#[no_mangle] #[no_mangle]
pub extern "C" fn Servo_Property_IsAnimatable(property: nsCSSPropertyID) -> bool { pub extern "C" fn Servo_Property_IsAnimatable(property: nsCSSPropertyID) -> bool {
use style::properties::animated_properties; use style::properties::animated_properties;
@ -3123,8 +3177,8 @@ pub extern "C" fn Servo_ComputedValues_GetStyleRuleList(
let mut result = SmallVec::<[_; 10]>::new(); let mut result = SmallVec::<[_; 10]>::new();
for node in rule_node.self_and_ancestors() { for node in rule_node.self_and_ancestors() {
let style_rule = match *node.style_source() { let style_rule = match node.style_source().and_then(|x| x.as_rule()) {
StyleSource::Style(ref rule) => rule, Some(rule) => rule,
_ => continue, _ => continue,
}; };
@ -3141,9 +3195,11 @@ pub extern "C" fn Servo_ComputedValues_GetStyleRuleList(
unsafe { rules.set_len(result.len() as u32) }; unsafe { rules.set_len(result.len() as u32) };
for (ref src, ref mut dest) in result.into_iter().zip(rules.iter_mut()) { for (ref src, ref mut dest) in result.into_iter().zip(rules.iter_mut()) {
src.with_raw_offset_arc(|arc| { src.with_arc(|a| {
**dest = *Locked::<StyleRule>::arc_as_borrowed(arc); a.with_raw_offset_arc(|arc| {
}) **dest = *Locked::<StyleRule>::arc_as_borrowed(arc);
})
});
} }
} }

View file

@ -5,7 +5,6 @@
extern crate cssparser; extern crate cssparser;
#[macro_use] extern crate cstr; #[macro_use] extern crate cstr;
extern crate env_logger;
extern crate libc; extern crate libc;
#[macro_use] extern crate log; #[macro_use] extern crate log;
extern crate malloc_size_of; extern crate malloc_size_of;

View file

@ -49,7 +49,16 @@ fn main() {
// Which is not a problem, but would cause this to not compile. // Which is not a problem, but would cause this to not compile.
// //
// Skip this until libclang is updated there. // Skip this until libclang is updated there.
if &cap[1] == "InvalidateStyleForDocStateChanges" { //
// Also skip Servo_Element_IsDisplayContents because we
// forward-declare it in Element.h without the type bindgen uses
// to replace it by a reference, and it depends on the include
// order in ServoBindings.h. We have the same problem for
// ComputedStyle_{AddRef / Release}, we just don't hit it
// because they're included later...
if &cap[1] == "InvalidateStyleForDocStateChanges" ||
&cap[1] == "Element_IsDisplayContents"
{
continue; continue;
} }
w.write_all(format!(" [ Servo_{0}, bindings::Servo_{0} ];\n", &cap[1]).as_bytes()).unwrap(); w.write_all(format!(" [ Servo_{0}, bindings::Servo_{0} ];\n", &cap[1]).as_bytes()).unwrap();

View file

@ -14,7 +14,6 @@
extern crate atomic_refcell; extern crate atomic_refcell;
extern crate cssparser; extern crate cssparser;
#[macro_use] extern crate cstr; #[macro_use] extern crate cstr;
extern crate env_logger;
extern crate geckoservo; extern crate geckoservo;
#[macro_use] extern crate log; #[macro_use] extern crate log;
extern crate malloc_size_of; extern crate malloc_size_of;

View file

@ -35,8 +35,8 @@ size_of_test!(test_size_of_element_data, ElementData, 24);
size_of_test!(test_size_of_property_declaration, style::properties::PropertyDeclaration, 32); size_of_test!(test_size_of_property_declaration, style::properties::PropertyDeclaration, 32);
size_of_test!(test_size_of_application_declaration_block, ApplicableDeclarationBlock, 24); size_of_test!(test_size_of_application_declaration_block, ApplicableDeclarationBlock, 16);
size_of_test!(test_size_of_rule_node, RuleNode, 80); size_of_test!(test_size_of_rule_node, RuleNode, 72);
// This is huge, but we allocate it on the stack and then never move it, // This is huge, but we allocate it on the stack and then never move it,
// we only pass `&mut SourcePropertyDeclaration` references around. // we only pass `&mut SourcePropertyDeclaration` references around.

View file

@ -487,42 +487,6 @@ mod shorthand_serialization {
} }
} }
mod outline {
use style::values::specified::outline::OutlineStyle;
use super::*;
#[test]
fn outline_should_show_all_properties_when_set() {
let mut properties = Vec::new();
let width = BorderSideWidth::Length(Length::from_px(4f32));
let style = OutlineStyle::Other(BorderStyle::Solid);
let color = RGBA::new(255, 0, 0, 255).into();
properties.push(PropertyDeclaration::OutlineWidth(width));
properties.push(PropertyDeclaration::OutlineStyle(style));
properties.push(PropertyDeclaration::OutlineColor(color));
let serialization = shorthand_properties_to_string(properties);
assert_eq!(serialization, "outline: 4px solid rgb(255, 0, 0);");
}
#[test]
fn outline_should_serialize_correctly_when_style_is_auto() {
let mut properties = Vec::new();
let width = BorderSideWidth::Length(Length::from_px(4f32));
let style = OutlineStyle::Auto;
let color = RGBA::new(255, 0, 0, 255).into();
properties.push(PropertyDeclaration::OutlineWidth(width));
properties.push(PropertyDeclaration::OutlineStyle(style));
properties.push(PropertyDeclaration::OutlineColor(color));
let serialization = shorthand_properties_to_string(properties);
assert_eq!(serialization, "outline: 4px auto rgb(255, 0, 0);");
}
}
mod background { mod background {
use super::*; use super::*;

View file

@ -62,11 +62,12 @@ fn parse_rules(css: &str) -> Vec<(StyleSource, CascadeLevel)> {
let rules = s.contents.rules.read_with(&guard); let rules = s.contents.rules.read_with(&guard);
rules.0.iter().filter_map(|rule| { rules.0.iter().filter_map(|rule| {
match *rule { match *rule {
CssRule::Style(ref style_rule) => Some(style_rule), CssRule::Style(ref style_rule) => Some((
StyleSource::from_rule(style_rule.clone()),
CascadeLevel::UserNormal,
)),
_ => None, _ => None,
} }
}).cloned().map(StyleSource::Style).map(|s| {
(s, CascadeLevel::UserNormal)
}).collect() }).collect()
} }
@ -78,7 +79,7 @@ fn test_insertion_style_attribute(rule_tree: &RuleTree, rules: &[(StyleSource, C
shared_lock: &SharedRwLock) shared_lock: &SharedRwLock)
-> StrongRuleNode { -> StrongRuleNode {
let mut rules = rules.to_vec(); let mut rules = rules.to_vec();
rules.push((StyleSource::Declarations(Arc::new(shared_lock.wrap(PropertyDeclarationBlock::with_one( rules.push((StyleSource::from_declarations(Arc::new(shared_lock.wrap(PropertyDeclarationBlock::with_one(
PropertyDeclaration::Display( PropertyDeclaration::Display(
longhands::display::SpecifiedValue::Block), longhands::display::SpecifiedValue::Block),
Importance::Normal Importance::Normal

View file

@ -26,9 +26,6 @@
[The serialization of border: solid; border-style: dotted should be canonical.] [The serialization of border: solid; border-style: dotted should be canonical.]
expected: FAIL expected: FAIL
[The serialization of outline-width: 2px; outline-style: dotted; outline-color: blue; should be canonical.]
expected: FAIL
[The serialization of list-style-type: circle; list-style-position: inside; list-style-image: initial; should be canonical.] [The serialization of list-style-type: circle; list-style-position: inside; list-style-image: initial; should be canonical.]
expected: FAIL expected: FAIL