diff --git a/components/layout/generated_content.rs b/components/layout/generated_content.rs index 004bcf5d9de..e838bde6b95 100644 --- a/components/layout/generated_content.rs +++ b/components/layout/generated_content.rs @@ -311,9 +311,9 @@ impl<'a, 'b> ResolveGeneratedContentFragmentMutator<'a, 'b> { "es.0[self.traversal.quote as usize] }; if close { - close_quote.clone() + close_quote.to_string() } else { - open_quote.clone() + open_quote.to_string() } } } diff --git a/components/style/properties/gecko.mako.rs b/components/style/properties/gecko.mako.rs index fcf045e1de8..5b46f784d99 100644 --- a/components/style/properties/gecko.mako.rs +++ b/components/style/properties/gecko.mako.rs @@ -4229,8 +4229,11 @@ fn static_assert() { let ref gecko_quote_values = *self.gecko.mQuotes.mRawPtr; longhands::quotes::computed_value::T( gecko_quote_values.mQuotePairs.iter().map(|gecko_pair| { - (gecko_pair.first.to_string(), gecko_pair.second.to_string()) - }).collect() + ( + gecko_pair.first.to_string().into_boxed_str(), + gecko_pair.second.to_string().into_boxed_str(), + ) + }).collect::>().into_boxed_slice() ) } } diff --git a/components/style/values/computed/list.rs b/components/style/values/computed/list.rs index 5dcba715cc5..49234f92ed9 100644 --- a/components/style/values/computed/list.rs +++ b/components/style/values/computed/list.rs @@ -7,12 +7,20 @@ pub use values::specified::list::Quotes; impl Quotes { - /// Initial value for `quotes` + /// Initial value for `quotes`. + /// + /// FIXME(emilio): This should ideally not allocate. #[inline] pub fn get_initial_value() -> Quotes { Quotes(vec![ - ("\u{201c}".to_owned(), "\u{201d}".to_owned()), - ("\u{2018}".to_owned(), "\u{2019}".to_owned()), - ]) + ( + "\u{201c}".to_owned().into_boxed_str(), + "\u{201d}".to_owned().into_boxed_str(), + ), + ( + "\u{2018}".to_owned().into_boxed_str(), + "\u{2019}".to_owned().into_boxed_str(), + ), + ].into_boxed_slice()) } } diff --git a/components/style/values/computed/mod.rs b/components/style/values/computed/mod.rs index 36c750dc963..dc8952cb4bc 100644 --- a/components/style/values/computed/mod.rs +++ b/components/style/values/computed/mod.rs @@ -401,6 +401,7 @@ trivial_to_computed_value!(BorderStyle); trivial_to_computed_value!(Cursor); trivial_to_computed_value!(Namespace); trivial_to_computed_value!(String); +trivial_to_computed_value!(Box); /// A `` value. pub type Number = CSSFloat; diff --git a/components/style/values/specified/list.rs b/components/style/values/specified/list.rs index 68c894b97e5..11a29ea14a8 100644 --- a/components/style/values/specified/list.rs +++ b/components/style/values/specified/list.rs @@ -4,31 +4,38 @@ //! `list` specified values. -use cssparser::{Parser, Token, serialize_string}; +use cssparser::{Parser, Token}; use parser::{Parse, ParserContext}; use std::fmt; use style_traits::{ParseError, StyleParseErrorKind, ToCss}; -/// Specified and computed `quote` property +/// Specified and computed `quote` property. +/// +/// FIXME(emilio): It's a shame that this allocates all the time it's computed, +/// probably should just be refcounted. #[derive(Clone, Debug, MallocSizeOf, PartialEq, ToComputedValue)] -pub struct Quotes(pub Vec<(String, String)>); +pub struct Quotes(pub Box<[(Box, Box)]>); impl ToCss for Quotes { fn to_css(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { - if self.0.is_empty() { - return dest.write_str("none") + let mut iter = self.0.iter(); + + match iter.next() { + Some(&(ref l, ref r)) => { + l.to_css(dest)?; + dest.write_char(' ')?; + r.to_css(dest)?; + } + None => return dest.write_str("none"), } - let mut first = true; - for pair in &self.0 { - if !first { - dest.write_str(" ")?; - } - first = false; - serialize_string(&*pair.0, dest)?; - dest.write_str(" ")?; - serialize_string(&*pair.1, dest)?; + for &(ref l, ref r) in iter { + dest.write_char(' ')?; + l.to_css(dest)?; + dest.write_char(' ')?; + r.to_css(dest)?; } + Ok(()) } } @@ -36,27 +43,27 @@ impl ToCss for Quotes { impl Parse for Quotes { fn parse<'i, 't>(_: &ParserContext, input: &mut Parser<'i, 't>) -> Result> { if input.try(|input| input.expect_ident_matching("none")).is_ok() { - return Ok(Quotes(Vec::new())) + return Ok(Quotes(Vec::new().into_boxed_slice())) } let mut quotes = Vec::new(); loop { let location = input.current_source_location(); let first = match input.next() { - Ok(&Token::QuotedString(ref value)) => value.as_ref().to_owned(), + Ok(&Token::QuotedString(ref value)) => { + value.as_ref().to_owned().into_boxed_str() + }, Ok(t) => return Err(location.new_unexpected_token_error(t.clone())), Err(_) => break, }; - let location = input.current_source_location(); - let second = match input.next() { - Ok(&Token::QuotedString(ref value)) => value.as_ref().to_owned(), - Ok(t) => return Err(location.new_unexpected_token_error(t.clone())), - Err(e) => return Err(e.into()), - }; + + let second = + input.expect_string()?.as_ref().to_owned().into_boxed_str(); quotes.push((first, second)) } + if !quotes.is_empty() { - Ok(Quotes(quotes)) + Ok(Quotes(quotes.into_boxed_slice())) } else { Err(input.new_custom_error(StyleParseErrorKind::UnspecifiedError)) }