mirror of
https://github.com/servo/servo.git
synced 2025-08-05 05:30:08 +01:00
style: Use cbindgen for content property.
This cleans up and also allows us to keep the distinction between content: none and content: normal, which allows us to fix the computed style we return from getComputedStyle(). Do this last bit from the resolved value instead of StyleAdjuster, because otherwise we need to tweak every initial struct for ::before / ::after. Differential Revision: https://phabricator.services.mozilla.com/D58276
This commit is contained in:
parent
07d0eea5fb
commit
219c0f6328
13 changed files with 122 additions and 343 deletions
|
@ -409,6 +409,7 @@ impl ToCss for System {
|
||||||
|
|
||||||
/// <https://drafts.csswg.org/css-counter-styles/#typedef-symbol>
|
/// <https://drafts.csswg.org/css-counter-styles/#typedef-symbol>
|
||||||
#[derive(Clone, Debug, Eq, MallocSizeOf, PartialEq, ToComputedValue, ToCss, ToShmem)]
|
#[derive(Clone, Debug, Eq, MallocSizeOf, PartialEq, ToComputedValue, ToCss, ToShmem)]
|
||||||
|
#[repr(u8)]
|
||||||
pub enum Symbol {
|
pub enum Symbol {
|
||||||
/// <string>
|
/// <string>
|
||||||
String(crate::OwnedStr),
|
String(crate::OwnedStr),
|
||||||
|
@ -554,6 +555,7 @@ impl Parse for Fallback {
|
||||||
|
|
||||||
/// <https://drafts.csswg.org/css-counter-styles/#descdef-counter-style-symbols>
|
/// <https://drafts.csswg.org/css-counter-styles/#descdef-counter-style-symbols>
|
||||||
#[derive(Clone, Debug, Eq, MallocSizeOf, PartialEq, ToComputedValue, ToCss, ToShmem)]
|
#[derive(Clone, Debug, Eq, MallocSizeOf, PartialEq, ToComputedValue, ToCss, ToShmem)]
|
||||||
|
#[repr(C)]
|
||||||
pub struct Symbols(#[css(iterable)] pub crate::OwnedSlice<Symbol>);
|
pub struct Symbols(#[css(iterable)] pub crate::OwnedSlice<Symbol>);
|
||||||
|
|
||||||
impl Parse for Symbols {
|
impl Parse for Symbols {
|
||||||
|
|
|
@ -7,13 +7,13 @@
|
||||||
//! Different kind of helpers to interact with Gecko values.
|
//! Different kind of helpers to interact with Gecko values.
|
||||||
|
|
||||||
use crate::counter_style::{Symbol, Symbols};
|
use crate::counter_style::{Symbol, Symbols};
|
||||||
|
use crate::gecko_bindings::bindings;
|
||||||
use crate::gecko_bindings::structs::CounterStylePtr;
|
use crate::gecko_bindings::structs::CounterStylePtr;
|
||||||
use crate::values::generics::CounterStyle;
|
use crate::values::generics::CounterStyle;
|
||||||
use crate::values::Either;
|
use crate::values::Either;
|
||||||
use crate::Atom;
|
use crate::Atom;
|
||||||
use app_units::Au;
|
use app_units::Au;
|
||||||
use cssparser::RGBA;
|
use cssparser::RGBA;
|
||||||
use nsstring::{nsACString, nsCStr};
|
|
||||||
use std::cmp::max;
|
use std::cmp::max;
|
||||||
|
|
||||||
/// Convert a given RGBA value to `nscolor`.
|
/// Convert a given RGBA value to `nscolor`.
|
||||||
|
@ -51,43 +51,13 @@ pub fn round_border_to_device_pixels(width: Au, au_per_device_px: Au) -> Au {
|
||||||
|
|
||||||
impl CounterStyle {
|
impl CounterStyle {
|
||||||
/// Convert this counter style to a Gecko CounterStylePtr.
|
/// Convert this counter style to a Gecko CounterStylePtr.
|
||||||
pub fn to_gecko_value(self, gecko_value: &mut CounterStylePtr) {
|
#[inline]
|
||||||
use crate::gecko_bindings::bindings::Gecko_SetCounterStyleToName as set_name;
|
pub fn to_gecko_value(&self, gecko_value: &mut CounterStylePtr) {
|
||||||
use crate::gecko_bindings::bindings::Gecko_SetCounterStyleToSymbols as set_symbols;
|
unsafe { bindings::Gecko_CounterStyle_ToPtr(self, gecko_value) }
|
||||||
match self {
|
|
||||||
CounterStyle::Name(name) => unsafe {
|
|
||||||
debug_assert_ne!(name.0, atom!("none"));
|
|
||||||
set_name(gecko_value, name.0.into_addrefed());
|
|
||||||
},
|
|
||||||
CounterStyle::Symbols(symbols_type, symbols) => {
|
|
||||||
let symbols: Vec<_> = symbols
|
|
||||||
.0
|
|
||||||
.iter()
|
|
||||||
.map(|symbol| match *symbol {
|
|
||||||
Symbol::String(ref s) => nsCStr::from(&**s),
|
|
||||||
Symbol::Ident(_) => unreachable!("Should not have identifier in symbols()"),
|
|
||||||
})
|
|
||||||
.collect();
|
|
||||||
let symbols: Vec<_> = symbols
|
|
||||||
.iter()
|
|
||||||
.map(|symbol| symbol as &nsACString as *const _)
|
|
||||||
.collect();
|
|
||||||
unsafe {
|
|
||||||
set_symbols(
|
|
||||||
gecko_value,
|
|
||||||
symbols_type.to_gecko_keyword(),
|
|
||||||
symbols.as_ptr(),
|
|
||||||
symbols.len() as u32,
|
|
||||||
)
|
|
||||||
};
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Convert Gecko CounterStylePtr to CounterStyle or String.
|
/// Convert Gecko CounterStylePtr to CounterStyle or String.
|
||||||
pub fn from_gecko_value(gecko_value: &CounterStylePtr) -> Either<Self, String> {
|
pub fn from_gecko_value(gecko_value: &CounterStylePtr) -> Either<Self, String> {
|
||||||
use crate::gecko_bindings::bindings;
|
|
||||||
use crate::values::generics::SymbolsType;
|
|
||||||
use crate::values::CustomIdent;
|
use crate::values::CustomIdent;
|
||||||
|
|
||||||
let name = unsafe { bindings::Gecko_CounterStyle_GetName(gecko_value) };
|
let name = unsafe { bindings::Gecko_CounterStyle_GetName(gecko_value) };
|
||||||
|
@ -103,7 +73,7 @@ impl CounterStyle {
|
||||||
debug_assert_eq!(symbols.len(), 1);
|
debug_assert_eq!(symbols.len(), 1);
|
||||||
Either::Second(symbols[0].to_string())
|
Either::Second(symbols[0].to_string())
|
||||||
} else {
|
} else {
|
||||||
let symbol_type = SymbolsType::from_gecko_keyword(anonymous.mSystem as u32);
|
let symbol_type = anonymous.mSymbolsType;
|
||||||
let symbols = symbols
|
let symbols = symbols
|
||||||
.iter()
|
.iter()
|
||||||
.map(|gecko_symbol| Symbol::String(gecko_symbol.to_string().into()))
|
.map(|gecko_symbol| Symbol::String(gecko_symbol.to_string().into()))
|
||||||
|
|
|
@ -25,6 +25,7 @@ macro_rules! ns {
|
||||||
|
|
||||||
/// A Gecko namespace is just a wrapped atom.
|
/// A Gecko namespace is just a wrapped atom.
|
||||||
#[derive(Clone, Debug, Default, Eq, Hash, MallocSizeOf, PartialEq, ToShmem)]
|
#[derive(Clone, Debug, Default, Eq, Hash, MallocSizeOf, PartialEq, ToShmem)]
|
||||||
|
#[repr(transparent)]
|
||||||
pub struct Namespace(pub Atom);
|
pub struct Namespace(pub Atom);
|
||||||
|
|
||||||
impl PrecomputedHash for Namespace {
|
impl PrecomputedHash for Namespace {
|
||||||
|
|
|
@ -173,10 +173,12 @@ pub mod values;
|
||||||
pub use crate::gecko_string_cache as string_cache;
|
pub use crate::gecko_string_cache as string_cache;
|
||||||
#[cfg(feature = "gecko")]
|
#[cfg(feature = "gecko")]
|
||||||
pub use crate::gecko_string_cache::Atom;
|
pub use crate::gecko_string_cache::Atom;
|
||||||
|
/// The namespace prefix type for Gecko, which is just an atom.
|
||||||
#[cfg(feature = "gecko")]
|
#[cfg(feature = "gecko")]
|
||||||
pub use crate::gecko_string_cache::Atom as Prefix;
|
pub type Prefix = crate::gecko_string_cache::Atom;
|
||||||
|
/// The local name of an element for Gecko, which is just an atom.
|
||||||
#[cfg(feature = "gecko")]
|
#[cfg(feature = "gecko")]
|
||||||
pub use crate::gecko_string_cache::Atom as LocalName;
|
pub type LocalName = crate::gecko_string_cache::Atom;
|
||||||
#[cfg(feature = "gecko")]
|
#[cfg(feature = "gecko")]
|
||||||
pub use crate::gecko_string_cache::Namespace;
|
pub use crate::gecko_string_cache::Namespace;
|
||||||
|
|
||||||
|
|
|
@ -36,7 +36,6 @@ use crate::gecko_bindings::bindings::Gecko_SetNullImageValue;
|
||||||
use crate::gecko_bindings::structs;
|
use crate::gecko_bindings::structs;
|
||||||
use crate::gecko_bindings::structs::nsCSSPropertyID;
|
use crate::gecko_bindings::structs::nsCSSPropertyID;
|
||||||
use crate::gecko_bindings::structs::mozilla::PseudoStyleType;
|
use crate::gecko_bindings::structs::mozilla::PseudoStyleType;
|
||||||
use crate::gecko_bindings::sugar::refptr::RefPtr;
|
|
||||||
use crate::gecko::values::round_border_to_device_pixels;
|
use crate::gecko::values::round_border_to_device_pixels;
|
||||||
use crate::logical_geometry::WritingMode;
|
use crate::logical_geometry::WritingMode;
|
||||||
use crate::media_queries::Device;
|
use crate::media_queries::Device;
|
||||||
|
@ -45,7 +44,6 @@ use crate::properties::longhands;
|
||||||
use crate::rule_tree::StrongRuleNode;
|
use crate::rule_tree::StrongRuleNode;
|
||||||
use crate::selector_parser::PseudoElement;
|
use crate::selector_parser::PseudoElement;
|
||||||
use servo_arc::{Arc, RawOffsetArc, UniqueArc};
|
use servo_arc::{Arc, RawOffsetArc, UniqueArc};
|
||||||
use std::marker::PhantomData;
|
|
||||||
use std::mem::{forget, MaybeUninit};
|
use std::mem::{forget, MaybeUninit};
|
||||||
use std::{cmp, ops, ptr};
|
use std::{cmp, ops, ptr};
|
||||||
use crate::values::{self, CustomIdent, Either, KeyframesName, None_};
|
use crate::values::{self, CustomIdent, Either, KeyframesName, None_};
|
||||||
|
@ -2200,19 +2198,18 @@ fn static_assert() {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_list_style_type(&mut self, v: longhands::list_style_type::computed_value::T) {
|
pub fn set_list_style_type(&mut self, v: longhands::list_style_type::computed_value::T) {
|
||||||
use crate::gecko_bindings::bindings::Gecko_SetCounterStyleToName;
|
|
||||||
use crate::gecko_bindings::bindings::Gecko_SetCounterStyleToString;
|
|
||||||
use nsstring::{nsACString, nsCStr};
|
use nsstring::{nsACString, nsCStr};
|
||||||
use self::longhands::list_style_type::computed_value::T;
|
use self::longhands::list_style_type::computed_value::T;
|
||||||
match v {
|
match v {
|
||||||
T::None => unsafe {
|
T::None => unsafe {
|
||||||
Gecko_SetCounterStyleToName(&mut self.gecko.mCounterStyle,
|
bindings::Gecko_SetCounterStyleToNone(&mut self.gecko.mCounterStyle)
|
||||||
atom!("none").into_addrefed());
|
|
||||||
}
|
}
|
||||||
T::CounterStyle(s) => s.to_gecko_value(&mut self.gecko.mCounterStyle),
|
T::CounterStyle(s) => s.to_gecko_value(&mut self.gecko.mCounterStyle),
|
||||||
T::String(s) => unsafe {
|
T::String(s) => unsafe {
|
||||||
Gecko_SetCounterStyleToString(&mut self.gecko.mCounterStyle,
|
bindings::Gecko_SetCounterStyleToString(
|
||||||
&nsCStr::from(&s) as &nsACString)
|
&mut self.gecko.mCounterStyle,
|
||||||
|
&nsCStr::from(&s) as &nsACString,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2580,236 +2577,9 @@ clip-path
|
||||||
${impl_simple('column_rule_style', 'mColumnRuleStyle')}
|
${impl_simple('column_rule_style', 'mColumnRuleStyle')}
|
||||||
</%self:impl_trait>
|
</%self:impl_trait>
|
||||||
|
|
||||||
<%self:impl_trait style_struct_name="Counters" skip_longhands="content">
|
<%self:impl_trait style_struct_name="Counters">
|
||||||
pub fn ineffective_content_property(&self) -> bool {
|
pub fn ineffective_content_property(&self) -> bool {
|
||||||
self.gecko.mContents.is_empty()
|
!self.gecko.mContent.is_items()
|
||||||
}
|
|
||||||
|
|
||||||
pub fn set_content(&mut self, v: longhands::content::computed_value::T) {
|
|
||||||
use crate::values::CustomIdent;
|
|
||||||
use crate::values::generics::counters::{Content, ContentItem};
|
|
||||||
use crate::values::generics::CounterStyle;
|
|
||||||
use crate::gecko_bindings::structs::nsStyleContentData;
|
|
||||||
use crate::gecko_bindings::structs::nsStyleContentAttr;
|
|
||||||
use crate::gecko_bindings::structs::StyleContentType;
|
|
||||||
use crate::gecko_bindings::bindings::Gecko_ClearAndResizeStyleContents;
|
|
||||||
|
|
||||||
// Converts a string as utf16, and returns an owned, zero-terminated raw buffer.
|
|
||||||
fn as_utf16_and_forget(s: &str) -> *mut u16 {
|
|
||||||
use std::mem;
|
|
||||||
let mut vec = s.encode_utf16().collect::<Vec<_>>();
|
|
||||||
vec.push(0u16);
|
|
||||||
let ptr = vec.as_mut_ptr();
|
|
||||||
mem::forget(vec);
|
|
||||||
ptr
|
|
||||||
}
|
|
||||||
|
|
||||||
fn set_counter_function(
|
|
||||||
data: &mut nsStyleContentData,
|
|
||||||
content_type: StyleContentType,
|
|
||||||
name: CustomIdent,
|
|
||||||
sep: &str,
|
|
||||||
style: CounterStyle,
|
|
||||||
) {
|
|
||||||
debug_assert!(content_type == StyleContentType::Counter ||
|
|
||||||
content_type == StyleContentType::Counters);
|
|
||||||
let counter_func = unsafe {
|
|
||||||
bindings::Gecko_SetCounterFunction(data, content_type).as_mut().unwrap()
|
|
||||||
};
|
|
||||||
counter_func.mIdent.set_move(unsafe {
|
|
||||||
RefPtr::from_addrefed(name.0.into_addrefed())
|
|
||||||
});
|
|
||||||
if content_type == StyleContentType::Counters {
|
|
||||||
counter_func.mSeparator.assign_str(sep);
|
|
||||||
}
|
|
||||||
style.to_gecko_value(&mut counter_func.mCounterStyle);
|
|
||||||
}
|
|
||||||
|
|
||||||
match v {
|
|
||||||
Content::None |
|
|
||||||
Content::Normal => {
|
|
||||||
// Ensure destructors run, otherwise we could leak.
|
|
||||||
if !self.gecko.mContents.is_empty() {
|
|
||||||
unsafe {
|
|
||||||
Gecko_ClearAndResizeStyleContents(&mut *self.gecko, 0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
Content::MozAltContent => {
|
|
||||||
unsafe {
|
|
||||||
Gecko_ClearAndResizeStyleContents(&mut *self.gecko, 1);
|
|
||||||
*self.gecko.mContents[0].mContent.mString.as_mut() = ptr::null_mut();
|
|
||||||
}
|
|
||||||
self.gecko.mContents[0].mType = StyleContentType::AltContent;
|
|
||||||
},
|
|
||||||
Content::Items(items) => {
|
|
||||||
unsafe {
|
|
||||||
Gecko_ClearAndResizeStyleContents(&mut *self.gecko,
|
|
||||||
items.len() as u32);
|
|
||||||
}
|
|
||||||
for (i, item) in items.into_vec().into_iter().enumerate() {
|
|
||||||
// NB: Gecko compares the mString value if type is not image
|
|
||||||
// or URI independently of whatever gets there. In the quote
|
|
||||||
// cases, they set it to null, so do the same here.
|
|
||||||
unsafe {
|
|
||||||
*self.gecko.mContents[i].mContent.mString.as_mut() = ptr::null_mut();
|
|
||||||
}
|
|
||||||
match item {
|
|
||||||
ContentItem::String(ref value) => {
|
|
||||||
self.gecko.mContents[i].mType = StyleContentType::String;
|
|
||||||
unsafe {
|
|
||||||
// NB: we share allocators, so doing this is fine.
|
|
||||||
*self.gecko.mContents[i].mContent.mString.as_mut() =
|
|
||||||
as_utf16_and_forget(&value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ContentItem::Attr(ref attr) => {
|
|
||||||
self.gecko.mContents[i].mType = StyleContentType::Attr;
|
|
||||||
unsafe {
|
|
||||||
// NB: we share allocators, so doing this is fine.
|
|
||||||
let maybe_ns = attr.namespace.clone();
|
|
||||||
let attr_struct = Box::new(nsStyleContentAttr {
|
|
||||||
mName: structs::RefPtr {
|
|
||||||
mRawPtr: attr.attribute.clone().into_addrefed(),
|
|
||||||
_phantom_0: PhantomData,
|
|
||||||
},
|
|
||||||
mNamespaceURL: structs::RefPtr {
|
|
||||||
mRawPtr: maybe_ns.map_or(ptr::null_mut(), |x| (x.1).0.into_addrefed()),
|
|
||||||
_phantom_0: PhantomData,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
*self.gecko.mContents[i].mContent.mAttr.as_mut() =
|
|
||||||
Box::into_raw(attr_struct);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ContentItem::OpenQuote
|
|
||||||
=> self.gecko.mContents[i].mType = StyleContentType::OpenQuote,
|
|
||||||
ContentItem::CloseQuote
|
|
||||||
=> self.gecko.mContents[i].mType = StyleContentType::CloseQuote,
|
|
||||||
ContentItem::NoOpenQuote
|
|
||||||
=> self.gecko.mContents[i].mType = StyleContentType::NoOpenQuote,
|
|
||||||
ContentItem::NoCloseQuote
|
|
||||||
=> self.gecko.mContents[i].mType = StyleContentType::NoCloseQuote,
|
|
||||||
ContentItem::Counter(name, style) => {
|
|
||||||
set_counter_function(
|
|
||||||
&mut self.gecko.mContents[i],
|
|
||||||
StyleContentType::Counter,
|
|
||||||
name,
|
|
||||||
"",
|
|
||||||
style,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
ContentItem::Counters(name, sep, style) => {
|
|
||||||
set_counter_function(
|
|
||||||
&mut self.gecko.mContents[i],
|
|
||||||
StyleContentType::Counters,
|
|
||||||
name,
|
|
||||||
&sep,
|
|
||||||
style,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
ContentItem::Url(ref url) => {
|
|
||||||
unsafe {
|
|
||||||
bindings::Gecko_SetContentDataImageValue(
|
|
||||||
&mut self.gecko.mContents[i],
|
|
||||||
url,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn copy_content_from(&mut self, other: &Self) {
|
|
||||||
use crate::gecko_bindings::bindings::Gecko_CopyStyleContentsFrom;
|
|
||||||
unsafe {
|
|
||||||
Gecko_CopyStyleContentsFrom(&mut *self.gecko, &*other.gecko)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn reset_content(&mut self, other: &Self) {
|
|
||||||
self.copy_content_from(other)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn clone_content(&self) -> longhands::content::computed_value::T {
|
|
||||||
use {Atom, Namespace};
|
|
||||||
use crate::gecko::conversions::string_from_chars_pointer;
|
|
||||||
use crate::gecko_bindings::structs::StyleContentType;
|
|
||||||
use crate::values::generics::counters::{Content, ContentItem};
|
|
||||||
use crate::values::{CustomIdent, Either};
|
|
||||||
use crate::values::generics::CounterStyle;
|
|
||||||
use crate::values::specified::Attr;
|
|
||||||
|
|
||||||
if self.gecko.mContents.is_empty() {
|
|
||||||
return Content::None;
|
|
||||||
}
|
|
||||||
|
|
||||||
if self.gecko.mContents.len() == 1 &&
|
|
||||||
self.gecko.mContents[0].mType == StyleContentType::AltContent {
|
|
||||||
return Content::MozAltContent;
|
|
||||||
}
|
|
||||||
|
|
||||||
Content::Items(
|
|
||||||
self.gecko.mContents.iter().map(|gecko_content| {
|
|
||||||
match gecko_content.mType {
|
|
||||||
StyleContentType::OpenQuote => ContentItem::OpenQuote,
|
|
||||||
StyleContentType::CloseQuote => ContentItem::CloseQuote,
|
|
||||||
StyleContentType::NoOpenQuote => ContentItem::NoOpenQuote,
|
|
||||||
StyleContentType::NoCloseQuote => ContentItem::NoCloseQuote,
|
|
||||||
StyleContentType::String => {
|
|
||||||
let gecko_chars = unsafe { gecko_content.mContent.mString.as_ref() };
|
|
||||||
let string = unsafe { string_from_chars_pointer(*gecko_chars) };
|
|
||||||
ContentItem::String(string.into_boxed_str())
|
|
||||||
},
|
|
||||||
StyleContentType::Attr => {
|
|
||||||
let (namespace, attribute) = unsafe {
|
|
||||||
let s = &**gecko_content.mContent.mAttr.as_ref();
|
|
||||||
let ns = if s.mNamespaceURL.mRawPtr.is_null() {
|
|
||||||
None
|
|
||||||
} else {
|
|
||||||
// FIXME(bholley): We don't have any way to get the prefix here. :-(
|
|
||||||
let prefix = atom!("");
|
|
||||||
Some((prefix, Namespace(Atom::from_raw(s.mNamespaceURL.mRawPtr))))
|
|
||||||
};
|
|
||||||
(ns, Atom::from_raw(s.mName.mRawPtr))
|
|
||||||
};
|
|
||||||
ContentItem::Attr(Attr { namespace, attribute })
|
|
||||||
},
|
|
||||||
StyleContentType::Counter | StyleContentType::Counters => {
|
|
||||||
let gecko_function =
|
|
||||||
unsafe { &**gecko_content.mContent.mCounters.as_ref() };
|
|
||||||
let ident = CustomIdent(unsafe {
|
|
||||||
Atom::from_raw(gecko_function.mIdent.mRawPtr)
|
|
||||||
});
|
|
||||||
let style =
|
|
||||||
CounterStyle::from_gecko_value(&gecko_function.mCounterStyle);
|
|
||||||
let style = match style {
|
|
||||||
Either::First(counter_style) => counter_style,
|
|
||||||
Either::Second(_) =>
|
|
||||||
unreachable!("counter function shouldn't have single string type"),
|
|
||||||
};
|
|
||||||
if gecko_content.mType == StyleContentType::Counter {
|
|
||||||
ContentItem::Counter(ident, style)
|
|
||||||
} else {
|
|
||||||
let separator = gecko_function.mSeparator.to_string();
|
|
||||||
ContentItem::Counters(ident, separator.into_boxed_str(), style)
|
|
||||||
}
|
|
||||||
},
|
|
||||||
StyleContentType::Image => {
|
|
||||||
unsafe {
|
|
||||||
let gecko_image_request =
|
|
||||||
&**gecko_content.mContent.mImage.as_ref();
|
|
||||||
ContentItem::Url(
|
|
||||||
ComputedImageUrl::from_image_request(gecko_image_request)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
},
|
|
||||||
_ => panic!("Found unexpected value in style struct for content property"),
|
|
||||||
}
|
|
||||||
}).collect::<Vec<_>>().into_boxed_slice()
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
</%self:impl_trait>
|
</%self:impl_trait>
|
||||||
|
|
||||||
|
|
|
@ -16,7 +16,7 @@ pub type CounterIncrement = GenericCounterIncrement<i32>;
|
||||||
pub type CounterSetOrReset = GenericCounterSetOrReset<i32>;
|
pub type CounterSetOrReset = GenericCounterSetOrReset<i32>;
|
||||||
|
|
||||||
/// A computed value for the `content` property.
|
/// A computed value for the `content` property.
|
||||||
pub type Content = generics::Content<ComputedImageUrl>;
|
pub type Content = generics::GenericContent<ComputedImageUrl>;
|
||||||
|
|
||||||
/// A computed content item.
|
/// A computed content item.
|
||||||
pub type ContentItem = generics::ContentItem<ComputedImageUrl>;
|
pub type ContentItem = generics::GenericContentItem<ComputedImageUrl>;
|
||||||
|
|
|
@ -471,6 +471,7 @@ trivial_to_computed_value!(Atom);
|
||||||
trivial_to_computed_value!(Prefix);
|
trivial_to_computed_value!(Prefix);
|
||||||
trivial_to_computed_value!(String);
|
trivial_to_computed_value!(String);
|
||||||
trivial_to_computed_value!(Box<str>);
|
trivial_to_computed_value!(Box<str>);
|
||||||
|
trivial_to_computed_value!(crate::OwnedStr);
|
||||||
|
|
||||||
/// A `<number>` value.
|
/// A `<number>` value.
|
||||||
pub type Number = CSSFloat;
|
pub type Number = CSSFloat;
|
||||||
|
|
|
@ -153,22 +153,26 @@ fn is_decimal(counter_type: &CounterStyleType) -> bool {
|
||||||
SpecifiedValueInfo,
|
SpecifiedValueInfo,
|
||||||
ToComputedValue,
|
ToComputedValue,
|
||||||
ToCss,
|
ToCss,
|
||||||
ToResolvedValue,
|
|
||||||
ToShmem,
|
ToShmem,
|
||||||
)]
|
)]
|
||||||
pub enum Content<ImageUrl> {
|
#[repr(u8)]
|
||||||
|
pub enum GenericContent<ImageUrl> {
|
||||||
/// `normal` reserved keyword.
|
/// `normal` reserved keyword.
|
||||||
Normal,
|
Normal,
|
||||||
/// `none` reserved keyword.
|
/// `none` reserved keyword.
|
||||||
None,
|
None,
|
||||||
/// `-moz-alt-content`.
|
|
||||||
#[cfg(feature = "gecko")]
|
|
||||||
MozAltContent,
|
|
||||||
/// Content items.
|
/// Content items.
|
||||||
Items(#[css(iterable)] Box<[ContentItem<ImageUrl>]>),
|
Items(#[css(iterable)] crate::OwnedSlice<GenericContentItem<ImageUrl>>),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub use self::GenericContent as Content;
|
||||||
|
|
||||||
impl<ImageUrl> Content<ImageUrl> {
|
impl<ImageUrl> Content<ImageUrl> {
|
||||||
|
#[inline]
|
||||||
|
pub(crate) fn is_items(&self) -> bool {
|
||||||
|
matches!(*self, Self::Items(..))
|
||||||
|
}
|
||||||
|
|
||||||
/// Set `content` property to `normal`.
|
/// Set `content` property to `normal`.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn normal() -> Self {
|
pub fn normal() -> Self {
|
||||||
|
@ -189,9 +193,10 @@ impl<ImageUrl> Content<ImageUrl> {
|
||||||
ToResolvedValue,
|
ToResolvedValue,
|
||||||
ToShmem,
|
ToShmem,
|
||||||
)]
|
)]
|
||||||
pub enum ContentItem<ImageUrl> {
|
#[repr(u8)]
|
||||||
|
pub enum GenericContentItem<ImageUrl> {
|
||||||
/// Literal string content.
|
/// Literal string content.
|
||||||
String(Box<str>),
|
String(crate::OwnedStr),
|
||||||
/// `counter(name, style)`.
|
/// `counter(name, style)`.
|
||||||
#[css(comma, function)]
|
#[css(comma, function)]
|
||||||
Counter(CustomIdent, #[css(skip_if = "is_decimal")] CounterStyleType),
|
Counter(CustomIdent, #[css(skip_if = "is_decimal")] CounterStyleType),
|
||||||
|
@ -199,7 +204,7 @@ pub enum ContentItem<ImageUrl> {
|
||||||
#[css(comma, function)]
|
#[css(comma, function)]
|
||||||
Counters(
|
Counters(
|
||||||
CustomIdent,
|
CustomIdent,
|
||||||
Box<str>,
|
crate::OwnedStr,
|
||||||
#[css(skip_if = "is_decimal")] CounterStyleType,
|
#[css(skip_if = "is_decimal")] CounterStyleType,
|
||||||
),
|
),
|
||||||
/// `open-quote`.
|
/// `open-quote`.
|
||||||
|
@ -210,9 +215,14 @@ pub enum ContentItem<ImageUrl> {
|
||||||
NoOpenQuote,
|
NoOpenQuote,
|
||||||
/// `no-close-quote`.
|
/// `no-close-quote`.
|
||||||
NoCloseQuote,
|
NoCloseQuote,
|
||||||
|
/// `-moz-alt-content`.
|
||||||
|
#[cfg(feature = "gecko")]
|
||||||
|
MozAltContent,
|
||||||
/// `attr([namespace? `|`]? ident)`
|
/// `attr([namespace? `|`]? ident)`
|
||||||
#[cfg(feature = "gecko")]
|
#[cfg(feature = "gecko")]
|
||||||
Attr(Attr),
|
Attr(Attr),
|
||||||
/// `url(url)`
|
/// `url(url)`
|
||||||
Url(ImageUrl),
|
Url(ImageUrl),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub use self::GenericContentItem as ContentItem;
|
||||||
|
|
|
@ -39,7 +39,7 @@ pub mod transform;
|
||||||
pub mod ui;
|
pub mod ui;
|
||||||
pub mod url;
|
pub mod url;
|
||||||
|
|
||||||
// https://drafts.csswg.org/css-counter-styles/#typedef-symbols-type
|
/// https://drafts.csswg.org/css-counter-styles/#typedef-symbols-type
|
||||||
#[allow(missing_docs)]
|
#[allow(missing_docs)]
|
||||||
#[cfg_attr(feature = "servo", derive(Deserialize, Serialize))]
|
#[cfg_attr(feature = "servo", derive(Deserialize, Serialize))]
|
||||||
#[derive(
|
#[derive(
|
||||||
|
@ -55,6 +55,7 @@ pub mod url;
|
||||||
ToResolvedValue,
|
ToResolvedValue,
|
||||||
ToShmem,
|
ToShmem,
|
||||||
)]
|
)]
|
||||||
|
#[repr(u8)]
|
||||||
pub enum SymbolsType {
|
pub enum SymbolsType {
|
||||||
Cyclic,
|
Cyclic,
|
||||||
Numeric,
|
Numeric,
|
||||||
|
@ -63,39 +64,12 @@ pub enum SymbolsType {
|
||||||
Fixed,
|
Fixed,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "gecko")]
|
|
||||||
impl SymbolsType {
|
|
||||||
/// Convert symbols type to their corresponding Gecko values.
|
|
||||||
pub fn to_gecko_keyword(self) -> u8 {
|
|
||||||
use crate::gecko_bindings::structs;
|
|
||||||
match self {
|
|
||||||
SymbolsType::Cyclic => structs::NS_STYLE_COUNTER_SYSTEM_CYCLIC as u8,
|
|
||||||
SymbolsType::Numeric => structs::NS_STYLE_COUNTER_SYSTEM_NUMERIC as u8,
|
|
||||||
SymbolsType::Alphabetic => structs::NS_STYLE_COUNTER_SYSTEM_ALPHABETIC as u8,
|
|
||||||
SymbolsType::Symbolic => structs::NS_STYLE_COUNTER_SYSTEM_SYMBOLIC as u8,
|
|
||||||
SymbolsType::Fixed => structs::NS_STYLE_COUNTER_SYSTEM_FIXED as u8,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Convert Gecko value to symbol type.
|
|
||||||
pub fn from_gecko_keyword(gecko_value: u32) -> SymbolsType {
|
|
||||||
use crate::gecko_bindings::structs;
|
|
||||||
match gecko_value {
|
|
||||||
structs::NS_STYLE_COUNTER_SYSTEM_CYCLIC => SymbolsType::Cyclic,
|
|
||||||
structs::NS_STYLE_COUNTER_SYSTEM_NUMERIC => SymbolsType::Numeric,
|
|
||||||
structs::NS_STYLE_COUNTER_SYSTEM_ALPHABETIC => SymbolsType::Alphabetic,
|
|
||||||
structs::NS_STYLE_COUNTER_SYSTEM_SYMBOLIC => SymbolsType::Symbolic,
|
|
||||||
structs::NS_STYLE_COUNTER_SYSTEM_FIXED => SymbolsType::Fixed,
|
|
||||||
x => panic!("Unexpected value for symbol type {}", x),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <https://drafts.csswg.org/css-counter-styles/#typedef-counter-style>
|
/// <https://drafts.csswg.org/css-counter-styles/#typedef-counter-style>
|
||||||
///
|
///
|
||||||
/// Note that 'none' is not a valid name.
|
/// Note that 'none' is not a valid name.
|
||||||
#[cfg_attr(feature = "gecko", derive(MallocSizeOf))]
|
#[cfg_attr(feature = "gecko", derive(MallocSizeOf))]
|
||||||
#[derive(Clone, Debug, Eq, PartialEq, ToComputedValue, ToCss, ToResolvedValue, ToShmem)]
|
#[derive(Clone, Debug, Eq, PartialEq, ToComputedValue, ToCss, ToResolvedValue, ToShmem)]
|
||||||
|
#[repr(u8)]
|
||||||
pub enum CounterStyle {
|
pub enum CounterStyle {
|
||||||
/// `<counter-style-name>`
|
/// `<counter-style-name>`
|
||||||
Name(CustomIdent),
|
Name(CustomIdent),
|
||||||
|
|
46
components/style/values/resolved/counters.rs
Normal file
46
components/style/values/resolved/counters.rs
Normal file
|
@ -0,0 +1,46 @@
|
||||||
|
/* 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 https://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
|
//! Resolved values for counter properties
|
||||||
|
|
||||||
|
use super::{Context, ToResolvedValue};
|
||||||
|
use crate::values::computed;
|
||||||
|
|
||||||
|
/// https://drafts.csswg.org/css-content/#content-property
|
||||||
|
///
|
||||||
|
/// We implement this at resolved value time because otherwise it causes us to
|
||||||
|
/// allocate a bunch of useless initial structs for ::before / ::after, which is
|
||||||
|
/// a bit unfortunate.
|
||||||
|
///
|
||||||
|
/// Though these should be temporary, mostly, so if this causes complexity in
|
||||||
|
/// other places, it should be fine to move to `StyleAdjuster`.
|
||||||
|
///
|
||||||
|
/// See https://github.com/w3c/csswg-drafts/issues/4632 for where some related
|
||||||
|
/// issues are being discussed.
|
||||||
|
impl ToResolvedValue for computed::Content {
|
||||||
|
type ResolvedValue = Self;
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn to_resolved_value(self, context: &Context) -> Self {
|
||||||
|
let is_before_or_after =
|
||||||
|
context.style.pseudo().map_or(false, |p| p.is_before_or_after());
|
||||||
|
|
||||||
|
match self {
|
||||||
|
Self::Normal if is_before_or_after => Self::None,
|
||||||
|
// For now, make `content: none` compute to `normal` on other
|
||||||
|
// elements, as we don't respect it.
|
||||||
|
//
|
||||||
|
// FIXME(emilio, bug 1605473): for marker this should be preserved
|
||||||
|
// and respected, probably.
|
||||||
|
Self::None if !is_before_or_after => Self::Normal,
|
||||||
|
other => other,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn from_resolved_value(resolved: Self) -> Self {
|
||||||
|
resolved
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -10,6 +10,7 @@ use cssparser;
|
||||||
use smallvec::SmallVec;
|
use smallvec::SmallVec;
|
||||||
|
|
||||||
mod color;
|
mod color;
|
||||||
|
mod counters;
|
||||||
|
|
||||||
use crate::values::computed;
|
use crate::values::computed;
|
||||||
|
|
||||||
|
@ -68,6 +69,7 @@ trivial_to_resolved_value!(u32);
|
||||||
trivial_to_resolved_value!(usize);
|
trivial_to_resolved_value!(usize);
|
||||||
trivial_to_resolved_value!(String);
|
trivial_to_resolved_value!(String);
|
||||||
trivial_to_resolved_value!(Box<str>);
|
trivial_to_resolved_value!(Box<str>);
|
||||||
|
trivial_to_resolved_value!(crate::OwnedStr);
|
||||||
trivial_to_resolved_value!(cssparser::RGBA);
|
trivial_to_resolved_value!(cssparser::RGBA);
|
||||||
trivial_to_resolved_value!(crate::Atom);
|
trivial_to_resolved_value!(crate::Atom);
|
||||||
trivial_to_resolved_value!(app_units::Au);
|
trivial_to_resolved_value!(app_units::Au);
|
||||||
|
|
|
@ -9,8 +9,6 @@ use crate::computed_values::list_style_type::T as ListStyleType;
|
||||||
use crate::parser::{Parse, ParserContext};
|
use crate::parser::{Parse, ParserContext};
|
||||||
use crate::values::generics::counters as generics;
|
use crate::values::generics::counters as generics;
|
||||||
use crate::values::generics::counters::CounterPair;
|
use crate::values::generics::counters::CounterPair;
|
||||||
use crate::values::generics::counters::GenericCounterIncrement;
|
|
||||||
use crate::values::generics::counters::GenericCounterSetOrReset;
|
|
||||||
#[cfg(feature = "gecko")]
|
#[cfg(feature = "gecko")]
|
||||||
use crate::values::generics::CounterStyle;
|
use crate::values::generics::CounterStyle;
|
||||||
use crate::values::specified::url::SpecifiedImageUrl;
|
use crate::values::specified::url::SpecifiedImageUrl;
|
||||||
|
@ -23,7 +21,7 @@ use selectors::parser::SelectorParseErrorKind;
|
||||||
use style_traits::{ParseError, StyleParseErrorKind};
|
use style_traits::{ParseError, StyleParseErrorKind};
|
||||||
|
|
||||||
/// A specified value for the `counter-increment` property.
|
/// A specified value for the `counter-increment` property.
|
||||||
pub type CounterIncrement = GenericCounterIncrement<Integer>;
|
pub type CounterIncrement = generics::GenericCounterIncrement<Integer>;
|
||||||
|
|
||||||
impl Parse for CounterIncrement {
|
impl Parse for CounterIncrement {
|
||||||
fn parse<'i, 't>(
|
fn parse<'i, 't>(
|
||||||
|
@ -35,7 +33,7 @@ impl Parse for CounterIncrement {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A specified value for the `counter-set` and `counter-reset` properties.
|
/// A specified value for the `counter-set` and `counter-reset` properties.
|
||||||
pub type CounterSetOrReset = GenericCounterSetOrReset<Integer>;
|
pub type CounterSetOrReset = generics::GenericCounterSetOrReset<Integer>;
|
||||||
|
|
||||||
impl Parse for CounterSetOrReset {
|
impl Parse for CounterSetOrReset {
|
||||||
fn parse<'i, 't>(
|
fn parse<'i, 't>(
|
||||||
|
@ -84,10 +82,10 @@ fn parse_counters<'i, 't>(
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The specified value for the `content` property.
|
/// The specified value for the `content` property.
|
||||||
pub type Content = generics::Content<SpecifiedImageUrl>;
|
pub type Content = generics::GenericContent<SpecifiedImageUrl>;
|
||||||
|
|
||||||
/// The specified value for a content item in the `content` property.
|
/// The specified value for a content item in the `content` property.
|
||||||
pub type ContentItem = generics::ContentItem<SpecifiedImageUrl>;
|
pub type ContentItem = generics::GenericContentItem<SpecifiedImageUrl>;
|
||||||
|
|
||||||
impl Content {
|
impl Content {
|
||||||
#[cfg(feature = "servo")]
|
#[cfg(feature = "servo")]
|
||||||
|
@ -131,17 +129,9 @@ impl Parse for Content {
|
||||||
{
|
{
|
||||||
return Ok(generics::Content::None);
|
return Ok(generics::Content::None);
|
||||||
}
|
}
|
||||||
#[cfg(feature = "gecko")]
|
|
||||||
{
|
|
||||||
if input
|
|
||||||
.try(|input| input.expect_ident_matching("-moz-alt-content"))
|
|
||||||
.is_ok()
|
|
||||||
{
|
|
||||||
return Ok(generics::Content::MozAltContent);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut content = vec![];
|
let mut content = vec![];
|
||||||
|
let mut has_alt_content = false;
|
||||||
loop {
|
loop {
|
||||||
#[cfg(feature = "gecko")]
|
#[cfg(feature = "gecko")]
|
||||||
{
|
{
|
||||||
|
@ -153,7 +143,7 @@ impl Parse for Content {
|
||||||
match input.next() {
|
match input.next() {
|
||||||
Ok(&Token::QuotedString(ref value)) => {
|
Ok(&Token::QuotedString(ref value)) => {
|
||||||
content.push(generics::ContentItem::String(
|
content.push(generics::ContentItem::String(
|
||||||
value.as_ref().to_owned().into_boxed_str(),
|
value.as_ref().to_owned().into(),
|
||||||
));
|
));
|
||||||
},
|
},
|
||||||
Ok(&Token::Function(ref name)) => {
|
Ok(&Token::Function(ref name)) => {
|
||||||
|
@ -168,7 +158,7 @@ impl Parse for Content {
|
||||||
let location = input.current_source_location();
|
let location = input.current_source_location();
|
||||||
let name = CustomIdent::from_ident(location, input.expect_ident()?, &[])?;
|
let name = CustomIdent::from_ident(location, input.expect_ident()?, &[])?;
|
||||||
input.expect_comma()?;
|
input.expect_comma()?;
|
||||||
let separator = input.expect_string()?.as_ref().to_owned().into_boxed_str();
|
let separator = input.expect_string()?.as_ref().to_owned().into();
|
||||||
let style = Content::parse_counter_style(context, input);
|
let style = Content::parse_counter_style(context, input);
|
||||||
Ok(generics::ContentItem::Counters(name, separator, style))
|
Ok(generics::ContentItem::Counters(name, separator, style))
|
||||||
}),
|
}),
|
||||||
|
@ -191,6 +181,11 @@ impl Parse for Content {
|
||||||
"close-quote" => generics::ContentItem::CloseQuote,
|
"close-quote" => generics::ContentItem::CloseQuote,
|
||||||
"no-open-quote" => generics::ContentItem::NoOpenQuote,
|
"no-open-quote" => generics::ContentItem::NoOpenQuote,
|
||||||
"no-close-quote" => generics::ContentItem::NoCloseQuote,
|
"no-close-quote" => generics::ContentItem::NoCloseQuote,
|
||||||
|
#[cfg(feature = "gecko")]
|
||||||
|
"-moz-alt-content" => {
|
||||||
|
has_alt_content = true;
|
||||||
|
generics::ContentItem::MozAltContent
|
||||||
|
},
|
||||||
_ =>{
|
_ =>{
|
||||||
let ident = ident.clone();
|
let ident = ident.clone();
|
||||||
return Err(input.new_custom_error(
|
return Err(input.new_custom_error(
|
||||||
|
@ -206,9 +201,10 @@ impl Parse for Content {
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if content.is_empty() {
|
// We don't allow to parse `-moz-alt-content in multiple positions.
|
||||||
|
if content.is_empty() || (has_alt_content && content.len() != 1) {
|
||||||
return Err(input.new_custom_error(StyleParseErrorKind::UnspecifiedError));
|
return Err(input.new_custom_error(StyleParseErrorKind::UnspecifiedError));
|
||||||
}
|
}
|
||||||
Ok(generics::Content::Items(content.into_boxed_slice()))
|
Ok(generics::Content::Items(content.into()))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -767,9 +767,12 @@ impl AllowQuirks {
|
||||||
ToShmem,
|
ToShmem,
|
||||||
)]
|
)]
|
||||||
#[css(function)]
|
#[css(function)]
|
||||||
|
#[repr(C)]
|
||||||
pub struct Attr {
|
pub struct Attr {
|
||||||
/// Optional namespace prefix and URL.
|
/// Optional namespace prefix.
|
||||||
pub namespace: Option<(Prefix, Namespace)>,
|
pub namespace_prefix: Prefix,
|
||||||
|
/// Optional namespace URL.
|
||||||
|
pub namespace_url: Namespace,
|
||||||
/// Attribute name
|
/// Attribute name
|
||||||
pub attribute: Atom,
|
pub attribute: Atom,
|
||||||
}
|
}
|
||||||
|
@ -814,7 +817,7 @@ impl Attr {
|
||||||
ref t => return Err(location.new_unexpected_token_error(t.clone())),
|
ref t => return Err(location.new_unexpected_token_error(t.clone())),
|
||||||
};
|
};
|
||||||
|
|
||||||
let prefix_and_ns = if let Some(ns) = first {
|
let (namespace_prefix, namespace_url) = if let Some(ns) = first {
|
||||||
let prefix = Prefix::from(ns.as_ref());
|
let prefix = Prefix::from(ns.as_ref());
|
||||||
let ns = match get_namespace_for_prefix(&prefix, context) {
|
let ns = match get_namespace_for_prefix(&prefix, context) {
|
||||||
Some(ns) => ns,
|
Some(ns) => ns,
|
||||||
|
@ -823,17 +826,18 @@ impl Attr {
|
||||||
.new_custom_error(StyleParseErrorKind::UnspecifiedError));
|
.new_custom_error(StyleParseErrorKind::UnspecifiedError));
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
Some((prefix, ns))
|
(prefix, ns)
|
||||||
} else {
|
} else {
|
||||||
None
|
(Prefix::default(), Namespace::default())
|
||||||
};
|
};
|
||||||
return Ok(Attr {
|
return Ok(Attr {
|
||||||
namespace: prefix_and_ns,
|
namespace_prefix,
|
||||||
|
namespace_url,
|
||||||
attribute: Atom::from(second_token.as_ref()),
|
attribute: Atom::from(second_token.as_ref()),
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
// In the case of attr(foobar ) we don't want to error out
|
// In the case of attr(foobar ) we don't want to error out
|
||||||
// because of the trailing whitespace
|
// because of the trailing whitespace.
|
||||||
Token::WhiteSpace(..) => {},
|
Token::WhiteSpace(..) => {},
|
||||||
ref t => return Err(input.new_unexpected_token_error(t.clone())),
|
ref t => return Err(input.new_unexpected_token_error(t.clone())),
|
||||||
}
|
}
|
||||||
|
@ -841,7 +845,8 @@ impl Attr {
|
||||||
|
|
||||||
if let Some(first) = first {
|
if let Some(first) = first {
|
||||||
Ok(Attr {
|
Ok(Attr {
|
||||||
namespace: None,
|
namespace_prefix: Prefix::default(),
|
||||||
|
namespace_url: Namespace::default(),
|
||||||
attribute: Atom::from(first.as_ref()),
|
attribute: Atom::from(first.as_ref()),
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
|
@ -856,8 +861,8 @@ impl ToCss for Attr {
|
||||||
W: Write,
|
W: Write,
|
||||||
{
|
{
|
||||||
dest.write_str("attr(")?;
|
dest.write_str("attr(")?;
|
||||||
if let Some((ref prefix, ref _url)) = self.namespace {
|
if !self.namespace_prefix.is_empty() {
|
||||||
serialize_atom_identifier(prefix, dest)?;
|
serialize_atom_identifier(&self.namespace_prefix, dest)?;
|
||||||
dest.write_str("|")?;
|
dest.write_str("|")?;
|
||||||
}
|
}
|
||||||
serialize_atom_identifier(&self.attribute, dest)?;
|
serialize_atom_identifier(&self.attribute, dest)?;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue