aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorbors-servo <lbergstrom+bors@mozilla.com>2018-01-22 16:58:30 -0600
committerGitHub <noreply@github.com>2018-01-22 16:58:30 -0600
commit6f543d3de1658e3cacf7fc2caed7b9bda69e1d23 (patch)
treed3c6f128f283a3c0f65008e8726ed3e5f99cd2e0
parent65f549094f4664c5fb1cd8a17dd2cab0ebcf1806 (diff)
parent5526947500ff7ee736806cfaf4ebd70c1c689212 (diff)
downloadservo-6f543d3de1658e3cacf7fc2caed7b9bda69e1d23.tar.gz
servo-6f543d3de1658e3cacf7fc2caed7b9bda69e1d23.zip
Auto merge of #19841 - bholley:single_tocss, r=emilio
stylo: Avoid separate monomorphizations of CSS serialization for utf-8 and utf-16 https://bugzilla.mozilla.org/show_bug.cgi?id=1431268 <!-- 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/19841) <!-- Reviewable:end -->
-rw-r--r--components/script/dom/cssstyledeclaration.rs12
-rw-r--r--components/style/counter_style/mod.rs6
-rw-r--r--components/style/font_face.rs6
-rw-r--r--components/style/gecko/rules.rs10
-rw-r--r--components/style/properties/declaration_block.rs71
-rw-r--r--components/style/properties/properties.mako.rs26
-rw-r--r--components/style/shared_lock.rs11
-rw-r--r--components/style/str.rs99
-rw-r--r--components/style/stylesheets/document_rule.rs6
-rw-r--r--components/style/stylesheets/font_feature_values_rule.rs7
-rw-r--r--components/style/stylesheets/import_rule.rs7
-rw-r--r--components/style/stylesheets/keyframes_rule.rs10
-rw-r--r--components/style/stylesheets/media_rule.rs6
-rw-r--r--components/style/stylesheets/mod.rs4
-rw-r--r--components/style/stylesheets/namespace_rule.rs6
-rw-r--r--components/style/stylesheets/page_rule.rs8
-rw-r--r--components/style/stylesheets/rule_list.rs7
-rw-r--r--components/style/stylesheets/style_rule.rs8
-rw-r--r--components/style/stylesheets/supports_rule.rs6
-rw-r--r--components/style/stylesheets/viewport_rule.rs6
-rw-r--r--ports/geckolib/glue.rs16
-rw-r--r--tests/unit/style/properties/serialization.rs13
22 files changed, 231 insertions, 120 deletions
diff --git a/components/script/dom/cssstyledeclaration.rs b/components/script/dom/cssstyledeclaration.rs
index b9bf61c1924..2699bda9b07 100644
--- a/components/script/dom/cssstyledeclaration.rs
+++ b/components/script/dom/cssstyledeclaration.rs
@@ -21,7 +21,7 @@ use style::properties::{DeclarationSource, Importance, PropertyDeclarationBlock,
use style::properties::{parse_one_declaration_into, parse_style_attribute, SourcePropertyDeclaration};
use style::selector_parser::PseudoElement;
use style::shared_lock::Locked;
-use style_traits::{ParsingMode, ToCss};
+use style_traits::ParsingMode;
// http://dev.w3.org/csswg/cssom/#the-cssstyledeclaration-interface
#[dom_struct]
@@ -85,7 +85,8 @@ impl CSSStyleOwner {
// [1]: https://github.com/whatwg/html/issues/2306
if let Some(pdb) = attr {
let guard = shared_lock.read();
- let serialization = pdb.read_with(&guard).to_css_string();
+ let mut serialization = String::new();
+ pdb.read_with(&guard).to_css(&mut serialization).unwrap();
el.set_attribute(&local_name!("style"),
AttrValue::Declaration(serialization,
pdb));
@@ -415,7 +416,8 @@ impl CSSStyleDeclarationMethods for CSSStyleDeclaration {
self.owner.with_block(|pdb| {
pdb.declarations().get(index as usize).map(|declaration| {
let important = pdb.declarations_importance().get(index);
- let mut css = declaration.to_css_string();
+ let mut css = String::new();
+ declaration.to_css(&mut css).unwrap();
if important {
css += " !important";
}
@@ -427,7 +429,9 @@ impl CSSStyleDeclarationMethods for CSSStyleDeclaration {
// https://drafts.csswg.org/cssom/#dom-cssstyledeclaration-csstext
fn CssText(&self) -> DOMString {
self.owner.with_block(|pdb| {
- DOMString::from(pdb.to_css_string())
+ let mut serialization = String::new();
+ pdb.to_css(&mut serialization).unwrap();
+ DOMString::from(serialization)
})
}
diff --git a/components/style/counter_style/mod.rs b/components/style/counter_style/mod.rs
index f0fa18fda92..8b1c3085523 100644
--- a/components/style/counter_style/mod.rs
+++ b/components/style/counter_style/mod.rs
@@ -17,8 +17,9 @@ use selectors::parser::SelectorParseErrorKind;
use shared_lock::{SharedRwLockReadGuard, ToCssWithGuard};
#[allow(unused_imports)] use std::ascii::AsciiExt;
use std::borrow::Cow;
-use std::fmt;
+use std::fmt::{self, Write};
use std::ops::Range;
+use str::CssStringWriter;
use style_traits::{Comma, OneOrMoreSeparated, ParseError, StyleParseErrorKind, ToCss};
use values::CustomIdent;
@@ -228,8 +229,7 @@ macro_rules! counter_style_descriptors {
}
impl ToCssWithGuard for CounterStyleRuleData {
- fn to_css<W>(&self, _guard: &SharedRwLockReadGuard, dest: &mut W) -> fmt::Result
- where W: fmt::Write {
+ fn to_css(&self, _guard: &SharedRwLockReadGuard, dest: &mut CssStringWriter) -> fmt::Result {
dest.write_str("@counter-style ")?;
self.name.to_css(dest)?;
dest.write_str(" {\n")?;
diff --git a/components/style/font_face.rs b/components/style/font_face.rs
index 80c32a552e7..e74064a9625 100644
--- a/components/style/font_face.rs
+++ b/components/style/font_face.rs
@@ -20,7 +20,8 @@ use parser::{ParserContext, ParserErrorContext, Parse};
use properties::longhands::font_language_override;
use selectors::parser::SelectorParseErrorKind;
use shared_lock::{SharedRwLockReadGuard, ToCssWithGuard};
-use std::fmt;
+use std::fmt::{self, Write};
+use str::CssStringWriter;
use style_traits::{Comma, OneOrMoreSeparated, ParseError, StyleParseErrorKind, ToCss};
use values::computed::font::FamilyName;
use values::specified::url::SpecifiedUrl;
@@ -272,8 +273,7 @@ macro_rules! font_face_descriptors_common {
impl ToCssWithGuard for FontFaceRuleData {
// Serialization of FontFaceRule is not specced.
- fn to_css<W>(&self, _guard: &SharedRwLockReadGuard, dest: &mut W) -> fmt::Result
- where W: fmt::Write {
+ fn to_css(&self, _guard: &SharedRwLockReadGuard, dest: &mut CssStringWriter) -> fmt::Result {
dest.write_str("@font-face {\n")?;
$(
if let Some(ref value) = self.$ident {
diff --git a/components/style/gecko/rules.rs b/components/style/gecko/rules.rs
index 64d30b44883..75701476827 100644
--- a/components/style/gecko/rules.rs
+++ b/components/style/gecko/rules.rs
@@ -17,7 +17,9 @@ use gecko_bindings::sugar::refptr::{RefPtr, UniqueRefPtr};
use nsstring::nsString;
use properties::longhands::font_language_override;
use shared_lock::{ToCssWithGuard, SharedRwLockReadGuard};
-use std::{fmt, str};
+use std::fmt::{self, Write};
+use std::str;
+use str::CssStringWriter;
use values::computed::font::FamilyName;
use values::generics::FontSettings;
@@ -200,8 +202,7 @@ impl From<FontFaceRuleData> for FontFaceRule {
}
impl ToCssWithGuard for FontFaceRule {
- fn to_css<W>(&self, _guard: &SharedRwLockReadGuard, dest: &mut W) -> fmt::Result
- where W: fmt::Write {
+ fn to_css(&self, _guard: &SharedRwLockReadGuard, dest: &mut CssStringWriter) -> fmt::Result {
let mut css_text = nsString::new();
unsafe {
bindings::Gecko_CSSFontFaceRule_GetCssText(self.get(), &mut *css_text);
@@ -237,8 +238,7 @@ impl From<counter_style::CounterStyleRuleData> for CounterStyleRule {
}
impl ToCssWithGuard for CounterStyleRule {
- fn to_css<W>(&self, _guard: &SharedRwLockReadGuard, dest: &mut W) -> fmt::Result
- where W: fmt::Write {
+ fn to_css(&self, _guard: &SharedRwLockReadGuard, dest: &mut CssStringWriter) -> fmt::Result {
let mut css_text = nsString::new();
unsafe {
bindings::Gecko_CSSCounterStyle_GetCssText(self.get(), &mut *css_text);
diff --git a/components/style/properties/declaration_block.rs b/components/style/properties/declaration_block.rs
index c28ed5555f7..48b1eb3717d 100644
--- a/components/style/properties/declaration_block.rs
+++ b/components/style/properties/declaration_block.rs
@@ -19,6 +19,7 @@ use smallvec::SmallVec;
use std::fmt;
use std::iter::{DoubleEndedIterator, Zip};
use std::slice::Iter;
+use str::{CssString, CssStringBorrow, CssStringWriter};
use style_traits::{ToCss, ParseError, ParsingMode, StyleParseErrorKind};
use stylesheets::{CssRuleType, Origin, UrlExtraData};
use super::*;
@@ -306,9 +307,7 @@ impl PropertyDeclarationBlock {
/// Find the value of the given property in this block and serialize it
///
/// <https://dev.w3.org/csswg/cssom/#dom-cssstyledeclaration-getpropertyvalue>
- pub fn property_value_to_css<W>(&self, property: &PropertyId, dest: &mut W) -> fmt::Result
- where W: fmt::Write,
- {
+ pub fn property_value_to_css(&self, property: &PropertyId, dest: &mut CssStringWriter) -> fmt::Result {
// Step 1.1: done when parsing a string to PropertyId
// Step 1.2
@@ -608,15 +607,13 @@ impl PropertyDeclarationBlock {
}
/// Take a declaration block known to contain a single property and serialize it.
- pub fn single_value_to_css<W>(
+ pub fn single_value_to_css(
&self,
property: &PropertyId,
- dest: &mut W,
+ dest: &mut CssStringWriter,
computed_values: Option<&ComputedValues>,
custom_properties_block: Option<&PropertyDeclarationBlock>,
) -> fmt::Result
- where
- W: fmt::Write,
{
match property.as_shorthand() {
Err(_longhand_or_custom) => {
@@ -664,7 +661,7 @@ impl PropertyDeclarationBlock {
let iter = self.declarations.iter();
match shorthand.get_shorthand_appendable_value(iter) {
Some(AppendableValue::Css { css, .. }) => {
- dest.write_str(css)
+ css.append_to(dest)
},
Some(AppendableValue::DeclarationsForShorthand(_, decls)) => {
shorthand.longhands_to_css(decls, dest)
@@ -738,11 +735,13 @@ impl PropertyDeclarationBlock {
}
}
-impl ToCss for PropertyDeclarationBlock {
- // https://drafts.csswg.org/cssom/#serialize-a-css-declaration-block
- fn to_css<W>(&self, dest: &mut W) -> fmt::Result
- where W: fmt::Write,
- {
+impl PropertyDeclarationBlock {
+ /// Like the method on ToCss, but without the type parameter to avoid
+ /// accidentally monomorphizing this large function multiple times for
+ /// different writers.
+ ///
+ /// https://drafts.csswg.org/cssom/#serialize-a-css-declaration-block
+ pub fn to_css(&self, dest: &mut CssStringWriter) -> fmt::Result {
let mut is_first_serialization = true; // trailing serializations should have a prepended space
// Step 1 -> dest = result list
@@ -835,7 +834,7 @@ impl ToCss for PropertyDeclarationBlock {
// We avoid re-serializing if we're already an
// AppendableValue::Css.
- let mut v = String::new();
+ let mut v = CssString::new();
let value = match (appendable_value, found_system) {
(AppendableValue::Css { css, with_variables }, _) => {
debug_assert!(!css.is_empty());
@@ -848,7 +847,7 @@ impl ToCss for PropertyDeclarationBlock {
(_, Some(sys)) => {
sys.to_css(&mut v)?;
AppendableValue::Css {
- css: &v,
+ css: CssStringBorrow::from(&v),
with_variables: false,
}
}
@@ -861,7 +860,7 @@ impl ToCss for PropertyDeclarationBlock {
}
AppendableValue::Css {
- css: &v,
+ css: CssStringBorrow::from(&v),
with_variables: false,
}
}
@@ -871,14 +870,14 @@ impl ToCss for PropertyDeclarationBlock {
// We need to check the shorthand whether it's an alias property or not.
// If it's an alias property, it should be serialized like its longhand.
if shorthand.flags().contains(PropertyFlags::SHORTHAND_ALIAS_PROPERTY) {
- append_serialization::<_, Cloned<slice::Iter< _>>, _>(
+ append_serialization::<Cloned<slice::Iter< _>>, _>(
dest,
&property,
value,
importance,
&mut is_first_serialization)?;
} else {
- append_serialization::<_, Cloned<slice::Iter< _>>, _>(
+ append_serialization::<Cloned<slice::Iter< _>>, _>(
dest,
&shorthand,
value,
@@ -913,7 +912,7 @@ impl ToCss for PropertyDeclarationBlock {
// "error: unable to infer enough type information about `_`;
// type annotations or generic parameter binding required [E0282]"
// Use the same type as earlier call to reuse generated code.
- append_serialization::<_, Cloned<slice::Iter<_>>, _>(
+ append_serialization::<Cloned<slice::Iter<_>>, _>(
dest,
&property,
AppendableValue::Declaration(declaration),
@@ -945,7 +944,7 @@ pub enum AppendableValue<'a, I>
/// or when storing a serialized shorthand value before appending directly.
Css {
/// The raw CSS string.
- css: &'a str,
+ css: CssStringBorrow<'a>,
/// Whether the original serialization contained variables or not.
with_variables: bool,
}
@@ -966,15 +965,16 @@ fn handle_first_serialization<W>(dest: &mut W,
}
/// Append a given kind of appendable value to a serialization.
-pub fn append_declaration_value<'a, W, I>(dest: &mut W,
- appendable_value: AppendableValue<'a, I>)
- -> fmt::Result
- where W: fmt::Write,
- I: Iterator<Item=&'a PropertyDeclaration>,
+pub fn append_declaration_value<'a, I>(
+ dest: &mut CssStringWriter,
+ appendable_value: AppendableValue<'a, I>,
+) -> fmt::Result
+where
+ I: Iterator<Item=&'a PropertyDeclaration>,
{
match appendable_value {
AppendableValue::Css { css, .. } => {
- dest.write_str(css)
+ css.append_to(dest)
},
AppendableValue::Declaration(decl) => {
decl.to_css(dest)
@@ -986,15 +986,16 @@ pub fn append_declaration_value<'a, W, I>(dest: &mut W,
}
/// Append a given property and value pair to a serialization.
-pub fn append_serialization<'a, W, I, N>(dest: &mut W,
- property_name: &N,
- appendable_value: AppendableValue<'a, I>,
- importance: Importance,
- is_first_serialization: &mut bool)
- -> fmt::Result
- where W: fmt::Write,
- I: Iterator<Item=&'a PropertyDeclaration>,
- N: ToCss,
+pub fn append_serialization<'a, I, N>(
+ dest: &mut CssStringWriter,
+ property_name: &N,
+ appendable_value: AppendableValue<'a, I>,
+ importance: Importance,
+ is_first_serialization: &mut bool
+) -> fmt::Result
+where
+ I: Iterator<Item=&'a PropertyDeclaration>,
+ N: ToCss,
{
handle_first_serialization(dest, is_first_serialization)?;
diff --git a/components/style/properties/properties.mako.rs b/components/style/properties/properties.mako.rs
index 738a07bedd0..a30fa6c0e0a 100644
--- a/components/style/properties/properties.mako.rs
+++ b/components/style/properties/properties.mako.rs
@@ -16,8 +16,10 @@ use custom_properties::CustomPropertiesBuilder;
use servo_arc::{Arc, UniqueArc};
use smallbitvec::SmallBitVec;
use std::borrow::Cow;
-use std::{fmt, mem, ops};
use std::cell::RefCell;
+use std::fmt::{self, Write};
+use std::mem;
+use std::ops;
#[cfg(feature = "servo")] use cssparser::RGBA;
use cssparser::{CowRcStr, Parser, TokenSerializationType, serialize_identifier};
@@ -46,6 +48,7 @@ use values::computed;
use values::computed::NonNegativeLength;
use rule_tree::{CascadeLevel, StrongRuleNode};
use self::computed_value_flags::*;
+use str::{CssString, CssStringBorrow, CssStringWriter};
use style_adjuster::StyleAdjuster;
pub use self::declaration_block::*;
@@ -898,7 +901,7 @@ impl ShorthandId {
if let Some(css) = first_declaration.with_variables_from_shorthand(self) {
if declarations2.all(|d| d.with_variables_from_shorthand(self) == Some(css)) {
return Some(AppendableValue::Css {
- css: css,
+ css: CssStringBorrow::from(css),
with_variables: true,
});
}
@@ -909,7 +912,7 @@ impl ShorthandId {
if let Some(keyword) = first_declaration.get_css_wide_keyword() {
if declarations2.all(|d| d.get_css_wide_keyword() == Some(keyword)) {
return Some(AppendableValue::Css {
- css: keyword.to_str(),
+ css: CssStringBorrow::from(keyword.to_str()),
with_variables: false,
});
}
@@ -1463,14 +1466,21 @@ impl fmt::Debug for PropertyDeclaration {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
self.id().to_css(f)?;
f.write_str(": ")?;
- self.to_css(f)
+
+ // Because PropertyDeclaration::to_css requires CssStringWriter, we can't write
+ // it directly to f, and need to allocate an intermediate string. This is
+ // fine for debug-only code.
+ let mut s = CssString::new();
+ self.to_css(&mut s)?;
+ write!(f, "{}", s)
}
}
-impl ToCss for PropertyDeclaration {
- fn to_css<W>(&self, dest: &mut W) -> fmt::Result
- where W: fmt::Write,
- {
+impl PropertyDeclaration {
+ /// Like the method on ToCss, but without the type parameter to avoid
+ /// accidentally monomorphizing this large function multiple times for
+ /// different writers.
+ pub fn to_css(&self, dest: &mut CssStringWriter) -> fmt::Result {
match *self {
% for property in data.longhands:
PropertyDeclaration::${property.camel_case}(ref value) =>
diff --git a/components/style/shared_lock.rs b/components/style/shared_lock.rs
index 29b92b29d36..fac98e98b6b 100644
--- a/components/style/shared_lock.rs
+++ b/components/style/shared_lock.rs
@@ -13,6 +13,7 @@ use std::cell::UnsafeCell;
use std::fmt;
#[cfg(feature = "gecko")]
use std::ptr;
+use str::{CssString, CssStringWriter};
use stylesheets::Origin;
/// A shared read/write lock that can protect multiple objects.
@@ -219,18 +220,18 @@ mod compile_time_assert {
impl<'a> Marker2 for SharedRwLockWriteGuard<'a> {} // Assert SharedRwLockWriteGuard: !Copy
}
-/// Like ToCss, but with a lock guard given by the caller.
+/// Like ToCss, but with a lock guard given by the caller, and with the writer specified
+/// concretely rather than with a parameter.
pub trait ToCssWithGuard {
/// Serialize `self` in CSS syntax, writing to `dest`, using the given lock guard.
- fn to_css<W>(&self, guard: &SharedRwLockReadGuard, dest: &mut W) -> fmt::Result
- where W: fmt::Write;
+ fn to_css(&self, guard: &SharedRwLockReadGuard, dest: &mut CssStringWriter) -> fmt::Result;
/// Serialize `self` in CSS syntax using the given lock guard and return a string.
///
/// (This is a convenience wrapper for `to_css` and probably should not be overridden.)
#[inline]
- fn to_css_string(&self, guard: &SharedRwLockReadGuard) -> String {
- let mut s = String::new();
+ fn to_css_string(&self, guard: &SharedRwLockReadGuard) -> CssString {
+ let mut s = CssString::new();
self.to_css(guard, &mut s).unwrap();
s
}
diff --git a/components/style/str.rs b/components/style/str.rs
index 641f5501d89..a91505ae6ed 100644
--- a/components/style/str.rs
+++ b/components/style/str.rs
@@ -10,6 +10,7 @@ use num_traits::ToPrimitive;
#[allow(unused_imports)] use std::ascii::AsciiExt;
use std::borrow::Cow;
use std::convert::AsRef;
+use std::fmt::{self, Write};
use std::iter::{Filter, Peekable};
use std::str::Split;
@@ -163,3 +164,101 @@ pub fn string_as_ascii_lowercase<'a>(input: &'a str) -> Cow<'a, str> {
Cow::Borrowed(input)
}
}
+
+/// To avoid accidentally instantiating multiple monomorphizations of large
+/// serialization routines, we define explicit concrete types and require
+/// them in those routines. This primarily avoids accidental mixing of UTF8
+/// with UTF16 serializations in Gecko.
+#[cfg(feature = "gecko")]
+pub type CssStringWriter = ::nsstring::nsAString;
+
+/// String type that coerces to CssStringWriter, used when serialization code
+/// needs to allocate a temporary string.
+#[cfg(feature = "gecko")]
+pub type CssString = ::nsstring::nsString;
+
+/// Certain serialization code needs to interact with borrowed strings, which
+/// are sometimes native UTF8 Rust strings, and other times serialized UTF16
+/// strings. This enum multiplexes the two cases.
+#[cfg(feature = "gecko")]
+pub enum CssStringBorrow<'a> {
+ /// A borrow of a UTF16 CssString.
+ UTF16(&'a ::nsstring::nsString),
+ /// A borrow of a regular Rust UTF8 string.
+ UTF8(&'a str),
+}
+
+#[cfg(feature = "gecko")]
+impl<'a> CssStringBorrow<'a> {
+ /// Writes the borrowed string to the provided writer.
+ pub fn append_to(&self, dest: &mut CssStringWriter) -> fmt::Result {
+ match *self {
+ CssStringBorrow::UTF16(s) => {
+ dest.append(s);
+ Ok(())
+ },
+ CssStringBorrow::UTF8(s) => dest.write_str(s),
+ }
+ }
+
+ /// Returns true of the borrowed string is empty.
+ pub fn is_empty(&self) -> bool {
+ match *self {
+ CssStringBorrow::UTF16(s) => s.is_empty(),
+ CssStringBorrow::UTF8(s) => s.is_empty(),
+ }
+ }
+}
+
+#[cfg(feature = "gecko")]
+impl<'a> From<&'a str> for CssStringBorrow<'a> {
+ fn from(s: &'a str) -> Self {
+ CssStringBorrow::UTF8(s)
+ }
+}
+
+#[cfg(feature = "gecko")]
+impl<'a> From<&'a ::nsstring::nsString> for CssStringBorrow<'a> {
+ fn from(s: &'a ::nsstring::nsString) -> Self {
+ CssStringBorrow::UTF16(s)
+ }
+}
+
+/// String. The comments for the Gecko types explain the need for this abstraction.
+#[cfg(feature = "servo")]
+pub type CssStringWriter = String;
+
+/// String. The comments for the Gecko types explain the need for this abstraction.
+#[cfg(feature = "servo")]
+pub type CssString = String;
+
+/// Borrowed string. The comments for the Gecko types explain the need for this abstraction.
+#[cfg(feature = "servo")]
+pub struct CssStringBorrow<'a>(&'a str);
+
+#[cfg(feature = "servo")]
+impl<'a> CssStringBorrow<'a> {
+ /// Appends the borrowed string to the given string.
+ pub fn append_to(&self, dest: &mut CssStringWriter) -> fmt::Result {
+ dest.write_str(self.0)
+ }
+
+ /// Returns true if the borrowed string is empty.
+ pub fn is_empty(&self) -> bool {
+ self.0.is_empty()
+ }
+}
+
+#[cfg(feature = "servo")]
+impl<'a> From<&'a str> for CssStringBorrow<'a> {
+ fn from(s: &'a str) -> Self {
+ CssStringBorrow(s)
+ }
+}
+
+#[cfg(feature = "servo")]
+impl<'a> From<&'a String> for CssStringBorrow<'a> {
+ fn from(s: &'a String) -> Self {
+ CssStringBorrow(&*s)
+ }
+}
diff --git a/components/style/stylesheets/document_rule.rs b/components/style/stylesheets/document_rule.rs
index 61c8f2762ef..ea140849be3 100644
--- a/components/style/stylesheets/document_rule.rs
+++ b/components/style/stylesheets/document_rule.rs
@@ -13,7 +13,8 @@ use media_queries::Device;
use parser::{Parse, ParserContext};
use servo_arc::Arc;
use shared_lock::{DeepCloneParams, DeepCloneWithLock, Locked, SharedRwLock, SharedRwLockReadGuard, ToCssWithGuard};
-use std::fmt;
+use std::fmt::{self, Write};
+use str::CssStringWriter;
use style_traits::{ToCss, ParseError, StyleParseErrorKind};
use stylesheets::CssRules;
use values::specified::url::SpecifiedUrl;
@@ -40,8 +41,7 @@ impl DocumentRule {
}
impl ToCssWithGuard for DocumentRule {
- fn to_css<W>(&self, guard: &SharedRwLockReadGuard, dest: &mut W) -> fmt::Result
- where W: fmt::Write {
+ fn to_css(&self, guard: &SharedRwLockReadGuard, dest: &mut CssStringWriter) -> fmt::Result {
dest.write_str("@-moz-document ")?;
self.condition.to_css(dest)?;
dest.write_str(" {")?;
diff --git a/components/style/stylesheets/font_feature_values_rule.rs b/components/style/stylesheets/font_feature_values_rule.rs
index d2e6f7c87a1..ba3396f589e 100644
--- a/components/style/stylesheets/font_feature_values_rule.rs
+++ b/components/style/stylesheets/font_feature_values_rule.rs
@@ -16,7 +16,8 @@ use gecko_bindings::bindings::Gecko_AppendFeatureValueHashEntry;
use gecko_bindings::structs::{self, gfxFontFeatureValueSet, nsTArray};
use parser::{ParserContext, ParserErrorContext, Parse};
use shared_lock::{SharedRwLockReadGuard, ToCssWithGuard};
-use std::fmt;
+use std::fmt::{self, Write};
+use str::CssStringWriter;
use style_traits::{ParseError, StyleParseErrorKind, ToCss};
use stylesheets::CssRuleType;
use values::computed::font::FamilyName;
@@ -347,9 +348,7 @@ macro_rules! font_feature_values_blocks {
}
impl ToCssWithGuard for FontFeatureValuesRule {
- fn to_css<W>(&self, _guard: &SharedRwLockReadGuard, dest: &mut W) -> fmt::Result
- where W: fmt::Write
- {
+ fn to_css(&self, _guard: &SharedRwLockReadGuard, dest: &mut CssStringWriter) -> fmt::Result {
dest.write_str("@font-feature-values ")?;
self.font_family_to_css(dest)?;
dest.write_str(" {\n")?;
diff --git a/components/style/stylesheets/import_rule.rs b/components/style/stylesheets/import_rule.rs
index 8568012099a..c9fcd8d2c8a 100644
--- a/components/style/stylesheets/import_rule.rs
+++ b/components/style/stylesheets/import_rule.rs
@@ -9,7 +9,8 @@
use cssparser::SourceLocation;
use media_queries::MediaList;
use shared_lock::{DeepCloneWithLock, DeepCloneParams, SharedRwLock, SharedRwLockReadGuard, ToCssWithGuard};
-use std::fmt;
+use std::fmt::{self, Write};
+use str::CssStringWriter;
use style_traits::ToCss;
use stylesheets::{StylesheetContents, StylesheetInDocument};
use values::specified::url::SpecifiedUrl;
@@ -107,9 +108,7 @@ impl DeepCloneWithLock for ImportRule {
}
impl ToCssWithGuard for ImportRule {
- fn to_css<W>(&self, guard: &SharedRwLockReadGuard, dest: &mut W) -> fmt::Result
- where W: fmt::Write,
- {
+ fn to_css(&self, guard: &SharedRwLockReadGuard, dest: &mut CssStringWriter) -> fmt::Result {
dest.write_str("@import ")?;
self.url.to_css(dest)?;
diff --git a/components/style/stylesheets/keyframes_rule.rs b/components/style/stylesheets/keyframes_rule.rs
index 60d7ee3f175..b7f28704b1a 100644
--- a/components/style/stylesheets/keyframes_rule.rs
+++ b/components/style/stylesheets/keyframes_rule.rs
@@ -14,7 +14,8 @@ use properties::LonghandIdSet;
use properties::longhands::transition_timing_function::single_value::SpecifiedValue as SpecifiedTimingFunction;
use servo_arc::Arc;
use shared_lock::{DeepCloneParams, DeepCloneWithLock, SharedRwLock, SharedRwLockReadGuard, Locked, ToCssWithGuard};
-use std::fmt;
+use std::fmt::{self, Write};
+use str::CssStringWriter;
use style_traits::{ParsingMode, ToCss, ParseError, StyleParseErrorKind};
use stylesheets::{CssRuleType, StylesheetContents};
use stylesheets::rule_parser::VendorPrefix;
@@ -37,9 +38,7 @@ pub struct KeyframesRule {
impl ToCssWithGuard for KeyframesRule {
// Serialization of KeyframesRule is not specced.
- fn to_css<W>(&self, guard: &SharedRwLockReadGuard, dest: &mut W) -> fmt::Result
- where W: fmt::Write,
- {
+ fn to_css(&self, guard: &SharedRwLockReadGuard, dest: &mut CssStringWriter) -> fmt::Result {
dest.write_str("@keyframes ")?;
self.name.to_css(dest)?;
dest.write_str(" {")?;
@@ -194,8 +193,7 @@ pub struct Keyframe {
}
impl ToCssWithGuard for Keyframe {
- fn to_css<W>(&self, guard: &SharedRwLockReadGuard, dest: &mut W) -> fmt::Result
- where W: fmt::Write {
+ fn to_css(&self, guard: &SharedRwLockReadGuard, dest: &mut CssStringWriter) -> fmt::Result {
self.selector.to_css(dest)?;
dest.write_str(" { ")?;
self.block.read_with(guard).to_css(dest)?;
diff --git a/components/style/stylesheets/media_rule.rs b/components/style/stylesheets/media_rule.rs
index 4c468b44cf6..d9c8e72ffb9 100644
--- a/components/style/stylesheets/media_rule.rs
+++ b/components/style/stylesheets/media_rule.rs
@@ -12,7 +12,8 @@ use malloc_size_of::{MallocSizeOfOps, MallocUnconditionalShallowSizeOf};
use media_queries::MediaList;
use servo_arc::Arc;
use shared_lock::{DeepCloneParams, DeepCloneWithLock, Locked, SharedRwLock, SharedRwLockReadGuard, ToCssWithGuard};
-use std::fmt;
+use std::fmt::{self, Write};
+use str::CssStringWriter;
use style_traits::ToCss;
use stylesheets::CssRules;
@@ -42,8 +43,7 @@ impl MediaRule {
impl ToCssWithGuard for MediaRule {
// Serialization of MediaRule is not specced.
// https://drafts.csswg.org/cssom/#serialize-a-css-rule CSSMediaRule
- fn to_css<W>(&self, guard: &SharedRwLockReadGuard, dest: &mut W) -> fmt::Result
- where W: fmt::Write {
+ fn to_css(&self, guard: &SharedRwLockReadGuard, dest: &mut CssStringWriter) -> fmt::Result {
dest.write_str("@media ")?;
self.media_queries.read_with(guard).to_css(dest)?;
self.rules.read_with(guard).to_css_block(guard, dest)
diff --git a/components/style/stylesheets/mod.rs b/components/style/stylesheets/mod.rs
index f419b9602ed..a5873c8eb48 100644
--- a/components/style/stylesheets/mod.rs
+++ b/components/style/stylesheets/mod.rs
@@ -31,6 +31,7 @@ use parser::{ParserContext, ParserErrorContext};
use servo_arc::Arc;
use shared_lock::{DeepCloneParams, DeepCloneWithLock, Locked, SharedRwLock, SharedRwLockReadGuard, ToCssWithGuard};
use std::fmt;
+use str::CssStringWriter;
use style_traits::ParsingMode;
pub use self::counter_style_rule::CounterStyleRule;
@@ -347,8 +348,7 @@ impl DeepCloneWithLock for CssRule {
impl ToCssWithGuard for CssRule {
// https://drafts.csswg.org/cssom/#serialize-a-css-rule
- fn to_css<W>(&self, guard: &SharedRwLockReadGuard, dest: &mut W) -> fmt::Result
- where W: fmt::Write {
+ fn to_css(&self, guard: &SharedRwLockReadGuard, dest: &mut CssStringWriter) -> fmt::Result {
match *self {
CssRule::Namespace(ref lock) => lock.read_with(guard).to_css(guard, dest),
CssRule::Import(ref lock) => lock.read_with(guard).to_css(guard, dest),
diff --git a/components/style/stylesheets/namespace_rule.rs b/components/style/stylesheets/namespace_rule.rs
index 6cfba1d7234..f28f2ba0881 100644
--- a/components/style/stylesheets/namespace_rule.rs
+++ b/components/style/stylesheets/namespace_rule.rs
@@ -7,7 +7,8 @@
use {Namespace, Prefix};
use cssparser::SourceLocation;
use shared_lock::{SharedRwLockReadGuard, ToCssWithGuard};
-use std::fmt;
+use std::fmt::{self, Write};
+use str::CssStringWriter;
/// A `@namespace` rule.
#[derive(Clone, Debug, PartialEq)]
@@ -23,8 +24,7 @@ pub struct NamespaceRule {
impl ToCssWithGuard for NamespaceRule {
// https://drafts.csswg.org/cssom/#serialize-a-css-rule CSSNamespaceRule
- fn to_css<W>(&self, _guard: &SharedRwLockReadGuard, dest: &mut W) -> fmt::Result
- where W: fmt::Write {
+ fn to_css(&self, _guard: &SharedRwLockReadGuard, dest: &mut CssStringWriter) -> fmt::Result {
dest.write_str("@namespace ")?;
if let Some(ref prefix) = self.prefix {
dest.write_str(&*prefix.to_string())?;
diff --git a/components/style/stylesheets/page_rule.rs b/components/style/stylesheets/page_rule.rs
index ea8b93b1b8b..7b72f3e60c3 100644
--- a/components/style/stylesheets/page_rule.rs
+++ b/components/style/stylesheets/page_rule.rs
@@ -12,8 +12,8 @@ use malloc_size_of::{MallocSizeOf, MallocSizeOfOps, MallocUnconditionalShallowSi
use properties::PropertyDeclarationBlock;
use servo_arc::Arc;
use shared_lock::{DeepCloneParams, DeepCloneWithLock, Locked, SharedRwLock, SharedRwLockReadGuard, ToCssWithGuard};
-use std::fmt;
-use style_traits::ToCss;
+use std::fmt::{self, Write};
+use str::CssStringWriter;
/// A [`@page`][page] rule.
///
@@ -44,9 +44,7 @@ impl PageRule {
impl ToCssWithGuard for PageRule {
/// Serialization of PageRule is not specced, adapted from steps for
/// StyleRule.
- fn to_css<W>(&self, guard: &SharedRwLockReadGuard, dest: &mut W) -> fmt::Result
- where W: fmt::Write,
- {
+ fn to_css(&self, guard: &SharedRwLockReadGuard, dest: &mut CssStringWriter) -> fmt::Result {
dest.write_str("@page { ")?;
let declaration_block = self.block.read_with(guard);
declaration_block.to_css(dest)?;
diff --git a/components/style/stylesheets/rule_list.rs b/components/style/stylesheets/rule_list.rs
index fbceb6c1a0b..a6638e8bb17 100644
--- a/components/style/stylesheets/rule_list.rs
+++ b/components/style/stylesheets/rule_list.rs
@@ -9,7 +9,8 @@ use malloc_size_of::{MallocShallowSizeOf, MallocSizeOfOps};
use servo_arc::{Arc, RawOffsetArc};
use shared_lock::{DeepCloneParams, DeepCloneWithLock, Locked};
use shared_lock::{SharedRwLock, SharedRwLockReadGuard, ToCssWithGuard};
-use std::fmt;
+use std::fmt::{self, Write};
+use str::CssStringWriter;
use stylesheets::{CssRule, RulesMutateError};
use stylesheets::loader::StylesheetLoader;
use stylesheets::rule_parser::State;
@@ -95,9 +96,7 @@ impl CssRules {
///
/// This should be speced into CSSOM spec at some point. See
/// <https://github.com/w3c/csswg-drafts/issues/1985>
- pub fn to_css_block<W>(&self, guard: &SharedRwLockReadGuard, dest: &mut W)
- -> fmt::Result where W: fmt::Write
- {
+ pub fn to_css_block(&self, guard: &SharedRwLockReadGuard, dest: &mut CssStringWriter) -> fmt::Result {
dest.write_str(" {")?;
for rule in self.0.iter() {
dest.write_str("\n ")?;
diff --git a/components/style/stylesheets/style_rule.rs b/components/style/stylesheets/style_rule.rs
index fbc391f6d2b..4a4ab3d58ed 100644
--- a/components/style/stylesheets/style_rule.rs
+++ b/components/style/stylesheets/style_rule.rs
@@ -12,8 +12,8 @@ use selector_parser::SelectorImpl;
use selectors::SelectorList;
use servo_arc::Arc;
use shared_lock::{DeepCloneParams, DeepCloneWithLock, Locked, SharedRwLock, SharedRwLockReadGuard, ToCssWithGuard};
-use std::fmt;
-use style_traits::ToCss;
+use std::fmt::{self, Write};
+use str::CssStringWriter;
/// A style rule, with selectors and declarations.
#[derive(Debug)]
@@ -67,9 +67,7 @@ impl StyleRule {
impl ToCssWithGuard for StyleRule {
/// https://drafts.csswg.org/cssom/#serialize-a-css-rule CSSStyleRule
- fn to_css<W>(&self, guard: &SharedRwLockReadGuard, dest: &mut W) -> fmt::Result
- where W: fmt::Write,
- {
+ fn to_css(&self, guard: &SharedRwLockReadGuard, dest: &mut CssStringWriter) -> fmt::Result {
use cssparser::ToCss;
// Step 1
diff --git a/components/style/stylesheets/supports_rule.rs b/components/style/stylesheets/supports_rule.rs
index d9870641e43..641fc5f5603 100644
--- a/components/style/stylesheets/supports_rule.rs
+++ b/components/style/stylesheets/supports_rule.rs
@@ -15,8 +15,9 @@ use servo_arc::Arc;
use shared_lock::{DeepCloneParams, DeepCloneWithLock, Locked, SharedRwLock, SharedRwLockReadGuard, ToCssWithGuard};
#[allow(unused_imports)] use std::ascii::AsciiExt;
use std::ffi::{CStr, CString};
-use std::fmt;
+use std::fmt::{self, Write};
use std::str;
+use str::CssStringWriter;
use style_traits::{ToCss, ParseError};
use stylesheets::{CssRuleType, CssRules};
@@ -46,8 +47,7 @@ impl SupportsRule {
}
impl ToCssWithGuard for SupportsRule {
- fn to_css<W>(&self, guard: &SharedRwLockReadGuard, dest: &mut W) -> fmt::Result
- where W: fmt::Write {
+ fn to_css(&self, guard: &SharedRwLockReadGuard, dest: &mut CssStringWriter) -> fmt::Result {
dest.write_str("@supports ")?;
self.condition.to_css(dest)?;
self.rules.read_with(guard).to_css_block(guard, dest)
diff --git a/components/style/stylesheets/viewport_rule.rs b/components/style/stylesheets/viewport_rule.rs
index 6220d858745..1b8b9fd2f8b 100644
--- a/components/style/stylesheets/viewport_rule.rs
+++ b/components/style/stylesheets/viewport_rule.rs
@@ -23,9 +23,10 @@ use shared_lock::{SharedRwLockReadGuard, StylesheetGuards, ToCssWithGuard};
#[allow(unused_imports)] use std::ascii::AsciiExt;
use std::borrow::Cow;
use std::cell::RefCell;
-use std::fmt;
+use std::fmt::{self, Write};
use std::iter::Enumerate;
use std::str::Chars;
+use str::CssStringWriter;
use style_traits::{PinchZoomFactor, ToCss, ParseError, StyleParseErrorKind};
use style_traits::viewport::{Orientation, UserZoom, ViewportConstraints, Zoom};
use stylesheets::{StylesheetInDocument, Origin};
@@ -520,8 +521,7 @@ impl ViewportRule {
impl ToCssWithGuard for ViewportRule {
// Serialization of ViewportRule is not specced.
- fn to_css<W>(&self, _guard: &SharedRwLockReadGuard, dest: &mut W) -> fmt::Result
- where W: fmt::Write {
+ fn to_css(&self, _guard: &SharedRwLockReadGuard, dest: &mut CssStringWriter) -> fmt::Result {
dest.write_str("@viewport { ")?;
let mut iter = self.declarations.iter();
iter.next().unwrap().to_css(dest)?;
diff --git a/ports/geckolib/glue.rs b/ports/geckolib/glue.rs
index f155903ac5e..06c76f3e7f0 100644
--- a/ports/geckolib/glue.rs
+++ b/ports/geckolib/glue.rs
@@ -705,14 +705,11 @@ pub extern "C" fn Servo_AnimationValue_Serialize(value: RawServoAnimationValueBo
buffer: *mut nsAString)
{
let uncomputed_value = AnimationValue::as_arc(&value).uncompute();
- let mut string = String::new();
+ let buffer = unsafe { buffer.as_mut().unwrap() };
let rv = PropertyDeclarationBlock::with_one(uncomputed_value, Importance::Normal)
- .single_value_to_css(&get_property_id_from_nscsspropertyid!(property, ()), &mut string,
+ .single_value_to_css(&get_property_id_from_nscsspropertyid!(property, ()), buffer,
None, None /* No extra custom properties */);
debug_assert!(rv.is_ok());
-
- let buffer = unsafe { buffer.as_mut().unwrap() };
- buffer.assign_utf8(&string);
}
#[no_mangle]
@@ -2677,16 +2674,11 @@ pub extern "C" fn Servo_DeclarationBlock_SerializeOneValue(
let guard = global_style_data.shared_lock.read();
let decls = Locked::<PropertyDeclarationBlock>::as_arc(&declarations).read_with(&guard);
- let mut string = String::new();
-
let custom_properties = Locked::<PropertyDeclarationBlock>::arc_from_borrowed(&custom_properties);
let custom_properties = custom_properties.map(|block| block.read_with(&guard));
- let rv = decls.single_value_to_css(
- &property_id, &mut string, computed_values, custom_properties);
- debug_assert!(rv.is_ok());
-
let buffer = unsafe { buffer.as_mut().unwrap() };
- buffer.assign_utf8(&string);
+ let rv = decls.single_value_to_css(&property_id, buffer, computed_values, custom_properties);
+ debug_assert!(rv.is_ok());
}
#[no_mangle]
diff --git a/tests/unit/style/properties/serialization.rs b/tests/unit/style/properties/serialization.rs
index 7f8d6478c25..282051d8779 100644
--- a/tests/unit/style/properties/serialization.rs
+++ b/tests/unit/style/properties/serialization.rs
@@ -5,6 +5,7 @@
use properties::{parse, parse_input};
use style::computed_values::display::T as Display;
use style::properties::{PropertyDeclaration, Importance};
+use style::properties::declaration_block::PropertyDeclarationBlock;
use style::properties::parse_property_declaration_list;
use style::values::{CustomIdent, RGBA};
use style::values::generics::flex::FlexBasis;
@@ -15,6 +16,18 @@ use style::values::specified::url::SpecifiedUrl;
use style_traits::ToCss;
use stylesheets::block_from;
+trait ToCssString {
+ fn to_css_string(&self) -> String;
+}
+
+impl ToCssString for PropertyDeclarationBlock {
+ fn to_css_string(&self) -> String {
+ let mut css = String::new();
+ self.to_css(&mut css).unwrap();
+ css
+ }
+}
+
#[test]
fn property_declaration_block_should_serialize_correctly() {
use style::properties::longhands::overflow_x::SpecifiedValue as OverflowValue;