diff --git a/components/style/counter_style/mod.rs b/components/style/counter_style/mod.rs index 25cdc3f8737..d131f350393 100644 --- a/components/style/counter_style/mod.rs +++ b/components/style/counter_style/mod.rs @@ -409,6 +409,7 @@ impl ToCss for System { /// #[derive(Clone, Debug, Eq, MallocSizeOf, PartialEq, ToComputedValue, ToCss, ToShmem)] +#[repr(u8)] pub enum Symbol { /// String(crate::OwnedStr), @@ -554,6 +555,7 @@ impl Parse for Fallback { /// #[derive(Clone, Debug, Eq, MallocSizeOf, PartialEq, ToComputedValue, ToCss, ToShmem)] +#[repr(C)] pub struct Symbols(#[css(iterable)] pub crate::OwnedSlice); impl Parse for Symbols { diff --git a/components/style/gecko/values.rs b/components/style/gecko/values.rs index b31485345b6..a755556e850 100644 --- a/components/style/gecko/values.rs +++ b/components/style/gecko/values.rs @@ -7,13 +7,13 @@ //! Different kind of helpers to interact with Gecko values. use crate::counter_style::{Symbol, Symbols}; +use crate::gecko_bindings::bindings; use crate::gecko_bindings::structs::CounterStylePtr; use crate::values::generics::CounterStyle; use crate::values::Either; use crate::Atom; use app_units::Au; use cssparser::RGBA; -use nsstring::{nsACString, nsCStr}; use std::cmp::max; /// 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 { /// Convert this counter style to a Gecko CounterStylePtr. - pub fn to_gecko_value(self, gecko_value: &mut CounterStylePtr) { - use crate::gecko_bindings::bindings::Gecko_SetCounterStyleToName as set_name; - use crate::gecko_bindings::bindings::Gecko_SetCounterStyleToSymbols as set_symbols; - 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, - ) - }; - }, - } + #[inline] + pub fn to_gecko_value(&self, gecko_value: &mut CounterStylePtr) { + unsafe { bindings::Gecko_CounterStyle_ToPtr(self, gecko_value) } } /// Convert Gecko CounterStylePtr to CounterStyle or String. pub fn from_gecko_value(gecko_value: &CounterStylePtr) -> Either { - use crate::gecko_bindings::bindings; - use crate::values::generics::SymbolsType; use crate::values::CustomIdent; let name = unsafe { bindings::Gecko_CounterStyle_GetName(gecko_value) }; @@ -103,7 +73,7 @@ impl CounterStyle { debug_assert_eq!(symbols.len(), 1); Either::Second(symbols[0].to_string()) } else { - let symbol_type = SymbolsType::from_gecko_keyword(anonymous.mSystem as u32); + let symbol_type = anonymous.mSymbolsType; let symbols = symbols .iter() .map(|gecko_symbol| Symbol::String(gecko_symbol.to_string().into())) diff --git a/components/style/gecko_string_cache/namespace.rs b/components/style/gecko_string_cache/namespace.rs index 33883e66941..2dba484e002 100644 --- a/components/style/gecko_string_cache/namespace.rs +++ b/components/style/gecko_string_cache/namespace.rs @@ -25,6 +25,7 @@ macro_rules! ns { /// A Gecko namespace is just a wrapped atom. #[derive(Clone, Debug, Default, Eq, Hash, MallocSizeOf, PartialEq, ToShmem)] +#[repr(transparent)] pub struct Namespace(pub Atom); impl PrecomputedHash for Namespace { diff --git a/components/style/lib.rs b/components/style/lib.rs index 354950f9c15..33862461aa9 100644 --- a/components/style/lib.rs +++ b/components/style/lib.rs @@ -173,10 +173,12 @@ pub mod values; pub use crate::gecko_string_cache as string_cache; #[cfg(feature = "gecko")] pub use crate::gecko_string_cache::Atom; +/// The namespace prefix type for Gecko, which is just an atom. #[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")] -pub use crate::gecko_string_cache::Atom as LocalName; +pub type LocalName = crate::gecko_string_cache::Atom; #[cfg(feature = "gecko")] pub use crate::gecko_string_cache::Namespace; diff --git a/components/style/properties/gecko.mako.rs b/components/style/properties/gecko.mako.rs index 14262e7a074..874bf1a83cb 100644 --- a/components/style/properties/gecko.mako.rs +++ b/components/style/properties/gecko.mako.rs @@ -36,7 +36,6 @@ use crate::gecko_bindings::bindings::Gecko_SetNullImageValue; use crate::gecko_bindings::structs; use crate::gecko_bindings::structs::nsCSSPropertyID; 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::logical_geometry::WritingMode; use crate::media_queries::Device; @@ -45,7 +44,6 @@ use crate::properties::longhands; use crate::rule_tree::StrongRuleNode; use crate::selector_parser::PseudoElement; use servo_arc::{Arc, RawOffsetArc, UniqueArc}; -use std::marker::PhantomData; use std::mem::{forget, MaybeUninit}; use std::{cmp, ops, ptr}; 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) { - use crate::gecko_bindings::bindings::Gecko_SetCounterStyleToName; - use crate::gecko_bindings::bindings::Gecko_SetCounterStyleToString; use nsstring::{nsACString, nsCStr}; use self::longhands::list_style_type::computed_value::T; match v { T::None => unsafe { - Gecko_SetCounterStyleToName(&mut self.gecko.mCounterStyle, - atom!("none").into_addrefed()); + bindings::Gecko_SetCounterStyleToNone(&mut self.gecko.mCounterStyle) } T::CounterStyle(s) => s.to_gecko_value(&mut self.gecko.mCounterStyle), T::String(s) => unsafe { - Gecko_SetCounterStyleToString(&mut self.gecko.mCounterStyle, - &nsCStr::from(&s) as &nsACString) + bindings::Gecko_SetCounterStyleToString( + &mut self.gecko.mCounterStyle, + &nsCStr::from(&s) as &nsACString, + ) } } } @@ -2580,236 +2577,9 @@ clip-path ${impl_simple('column_rule_style', 'mColumnRuleStyle')} -<%self:impl_trait style_struct_name="Counters" skip_longhands="content"> +<%self:impl_trait style_struct_name="Counters"> pub fn ineffective_content_property(&self) -> bool { - self.gecko.mContents.is_empty() - } - - 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.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::>().into_boxed_slice() - ) + !self.gecko.mContent.is_items() } diff --git a/components/style/values/computed/counters.rs b/components/style/values/computed/counters.rs index 3a083632eb9..40cfe46efa6 100644 --- a/components/style/values/computed/counters.rs +++ b/components/style/values/computed/counters.rs @@ -16,7 +16,7 @@ pub type CounterIncrement = GenericCounterIncrement; pub type CounterSetOrReset = GenericCounterSetOrReset; /// A computed value for the `content` property. -pub type Content = generics::Content; +pub type Content = generics::GenericContent; /// A computed content item. -pub type ContentItem = generics::ContentItem; +pub type ContentItem = generics::GenericContentItem; diff --git a/components/style/values/computed/mod.rs b/components/style/values/computed/mod.rs index f5b3440f426..958deaaf44e 100644 --- a/components/style/values/computed/mod.rs +++ b/components/style/values/computed/mod.rs @@ -471,6 +471,7 @@ trivial_to_computed_value!(Atom); trivial_to_computed_value!(Prefix); trivial_to_computed_value!(String); trivial_to_computed_value!(Box); +trivial_to_computed_value!(crate::OwnedStr); /// A `` value. pub type Number = CSSFloat; diff --git a/components/style/values/generics/counters.rs b/components/style/values/generics/counters.rs index 69893c75561..9ed8cdba68b 100644 --- a/components/style/values/generics/counters.rs +++ b/components/style/values/generics/counters.rs @@ -153,22 +153,26 @@ fn is_decimal(counter_type: &CounterStyleType) -> bool { SpecifiedValueInfo, ToComputedValue, ToCss, - ToResolvedValue, ToShmem, )] -pub enum Content { +#[repr(u8)] +pub enum GenericContent { /// `normal` reserved keyword. Normal, /// `none` reserved keyword. None, - /// `-moz-alt-content`. - #[cfg(feature = "gecko")] - MozAltContent, /// Content items. - Items(#[css(iterable)] Box<[ContentItem]>), + Items(#[css(iterable)] crate::OwnedSlice>), } +pub use self::GenericContent as Content; + impl Content { + #[inline] + pub(crate) fn is_items(&self) -> bool { + matches!(*self, Self::Items(..)) + } + /// Set `content` property to `normal`. #[inline] pub fn normal() -> Self { @@ -189,9 +193,10 @@ impl Content { ToResolvedValue, ToShmem, )] -pub enum ContentItem { +#[repr(u8)] +pub enum GenericContentItem { /// Literal string content. - String(Box), + String(crate::OwnedStr), /// `counter(name, style)`. #[css(comma, function)] Counter(CustomIdent, #[css(skip_if = "is_decimal")] CounterStyleType), @@ -199,7 +204,7 @@ pub enum ContentItem { #[css(comma, function)] Counters( CustomIdent, - Box, + crate::OwnedStr, #[css(skip_if = "is_decimal")] CounterStyleType, ), /// `open-quote`. @@ -210,9 +215,14 @@ pub enum ContentItem { NoOpenQuote, /// `no-close-quote`. NoCloseQuote, + /// `-moz-alt-content`. + #[cfg(feature = "gecko")] + MozAltContent, /// `attr([namespace? `|`]? ident)` #[cfg(feature = "gecko")] Attr(Attr), /// `url(url)` Url(ImageUrl), } + +pub use self::GenericContentItem as ContentItem; diff --git a/components/style/values/generics/mod.rs b/components/style/values/generics/mod.rs index 4db80abc8a8..a97d9e1018a 100644 --- a/components/style/values/generics/mod.rs +++ b/components/style/values/generics/mod.rs @@ -39,7 +39,7 @@ pub mod transform; pub mod ui; 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)] #[cfg_attr(feature = "servo", derive(Deserialize, Serialize))] #[derive( @@ -55,6 +55,7 @@ pub mod url; ToResolvedValue, ToShmem, )] +#[repr(u8)] pub enum SymbolsType { Cyclic, Numeric, @@ -63,39 +64,12 @@ pub enum SymbolsType { 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), - } - } -} - /// /// /// Note that 'none' is not a valid name. #[cfg_attr(feature = "gecko", derive(MallocSizeOf))] #[derive(Clone, Debug, Eq, PartialEq, ToComputedValue, ToCss, ToResolvedValue, ToShmem)] +#[repr(u8)] pub enum CounterStyle { /// `` Name(CustomIdent), diff --git a/components/style/values/resolved/counters.rs b/components/style/values/resolved/counters.rs new file mode 100644 index 00000000000..daf70359061 --- /dev/null +++ b/components/style/values/resolved/counters.rs @@ -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 + } +} + diff --git a/components/style/values/resolved/mod.rs b/components/style/values/resolved/mod.rs index e64178a1c95..f50f58b5db4 100644 --- a/components/style/values/resolved/mod.rs +++ b/components/style/values/resolved/mod.rs @@ -10,6 +10,7 @@ use cssparser; use smallvec::SmallVec; mod color; +mod counters; use crate::values::computed; @@ -68,6 +69,7 @@ trivial_to_resolved_value!(u32); trivial_to_resolved_value!(usize); trivial_to_resolved_value!(String); trivial_to_resolved_value!(Box); +trivial_to_resolved_value!(crate::OwnedStr); trivial_to_resolved_value!(cssparser::RGBA); trivial_to_resolved_value!(crate::Atom); trivial_to_resolved_value!(app_units::Au); diff --git a/components/style/values/specified/counters.rs b/components/style/values/specified/counters.rs index 09020e73448..15898b58f47 100644 --- a/components/style/values/specified/counters.rs +++ b/components/style/values/specified/counters.rs @@ -9,8 +9,6 @@ use crate::computed_values::list_style_type::T as ListStyleType; use crate::parser::{Parse, ParserContext}; use crate::values::generics::counters as generics; use crate::values::generics::counters::CounterPair; -use crate::values::generics::counters::GenericCounterIncrement; -use crate::values::generics::counters::GenericCounterSetOrReset; #[cfg(feature = "gecko")] use crate::values::generics::CounterStyle; use crate::values::specified::url::SpecifiedImageUrl; @@ -23,7 +21,7 @@ use selectors::parser::SelectorParseErrorKind; use style_traits::{ParseError, StyleParseErrorKind}; /// A specified value for the `counter-increment` property. -pub type CounterIncrement = GenericCounterIncrement; +pub type CounterIncrement = generics::GenericCounterIncrement; impl Parse for CounterIncrement { fn parse<'i, 't>( @@ -35,7 +33,7 @@ impl Parse for CounterIncrement { } /// A specified value for the `counter-set` and `counter-reset` properties. -pub type CounterSetOrReset = GenericCounterSetOrReset; +pub type CounterSetOrReset = generics::GenericCounterSetOrReset; impl Parse for CounterSetOrReset { fn parse<'i, 't>( @@ -84,10 +82,10 @@ fn parse_counters<'i, 't>( } /// The specified value for the `content` property. -pub type Content = generics::Content; +pub type Content = generics::GenericContent; /// The specified value for a content item in the `content` property. -pub type ContentItem = generics::ContentItem; +pub type ContentItem = generics::GenericContentItem; impl Content { #[cfg(feature = "servo")] @@ -131,17 +129,9 @@ impl Parse for Content { { 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 has_alt_content = false; loop { #[cfg(feature = "gecko")] { @@ -153,7 +143,7 @@ impl Parse for Content { match input.next() { Ok(&Token::QuotedString(ref value)) => { content.push(generics::ContentItem::String( - value.as_ref().to_owned().into_boxed_str(), + value.as_ref().to_owned().into(), )); }, Ok(&Token::Function(ref name)) => { @@ -168,7 +158,7 @@ impl Parse for Content { let location = input.current_source_location(); let name = CustomIdent::from_ident(location, input.expect_ident()?, &[])?; 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); Ok(generics::ContentItem::Counters(name, separator, style)) }), @@ -191,6 +181,11 @@ impl Parse for Content { "close-quote" => generics::ContentItem::CloseQuote, "no-open-quote" => generics::ContentItem::NoOpenQuote, "no-close-quote" => generics::ContentItem::NoCloseQuote, + #[cfg(feature = "gecko")] + "-moz-alt-content" => { + has_alt_content = true; + generics::ContentItem::MozAltContent + }, _ =>{ let ident = ident.clone(); 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)); } - Ok(generics::Content::Items(content.into_boxed_slice())) + Ok(generics::Content::Items(content.into())) } } diff --git a/components/style/values/specified/mod.rs b/components/style/values/specified/mod.rs index 7f3ecfb96b3..7e16ba09601 100644 --- a/components/style/values/specified/mod.rs +++ b/components/style/values/specified/mod.rs @@ -767,9 +767,12 @@ impl AllowQuirks { ToShmem, )] #[css(function)] +#[repr(C)] pub struct Attr { - /// Optional namespace prefix and URL. - pub namespace: Option<(Prefix, Namespace)>, + /// Optional namespace prefix. + pub namespace_prefix: Prefix, + /// Optional namespace URL. + pub namespace_url: Namespace, /// Attribute name pub attribute: Atom, } @@ -814,7 +817,7 @@ impl Attr { 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 ns = match get_namespace_for_prefix(&prefix, context) { Some(ns) => ns, @@ -823,17 +826,18 @@ impl Attr { .new_custom_error(StyleParseErrorKind::UnspecifiedError)); }, }; - Some((prefix, ns)) + (prefix, ns) } else { - None + (Prefix::default(), Namespace::default()) }; return Ok(Attr { - namespace: prefix_and_ns, + namespace_prefix, + namespace_url, attribute: Atom::from(second_token.as_ref()), }); }, // 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(..) => {}, ref t => return Err(input.new_unexpected_token_error(t.clone())), } @@ -841,7 +845,8 @@ impl Attr { if let Some(first) = first { Ok(Attr { - namespace: None, + namespace_prefix: Prefix::default(), + namespace_url: Namespace::default(), attribute: Atom::from(first.as_ref()), }) } else { @@ -856,8 +861,8 @@ impl ToCss for Attr { W: Write, { dest.write_str("attr(")?; - if let Some((ref prefix, ref _url)) = self.namespace { - serialize_atom_identifier(prefix, dest)?; + if !self.namespace_prefix.is_empty() { + serialize_atom_identifier(&self.namespace_prefix, dest)?; dest.write_str("|")?; } serialize_atom_identifier(&self.attribute, dest)?;