Auto merge of #19974 - emilio:atom-serialization, r=nox

style: Optimize serialization of identifiers of length <= 16 🐉🐲

Much like we optimize to_ascii_lowercase.

<!-- 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/19974)
<!-- Reviewable:end -->
This commit is contained in:
bors-servo 2018-02-07 13:33:36 -05:00 committed by GitHub
commit a0e4ea9f56
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
13 changed files with 96 additions and 65 deletions

View file

@ -461,6 +461,7 @@ impl SingleFontFamily {
/// Get the corresponding font-family with family name
fn from_font_family_name(family: &structs::FontFamilyName) -> SingleFontFamily {
use gecko_bindings::structs::FontFamilyType;
use values::serialize_atom_identifier;
match family.mType {
FontFamilyType::eFamily_sans_serif => SingleFontFamily::Generic(atom!("sans-serif")),
@ -472,7 +473,7 @@ impl SingleFontFamily {
FontFamilyType::eFamily_named => {
let name = Atom::from(&*family.mName);
let mut serialization = String::new();
serialize_identifier(&name.to_string(), &mut serialization).unwrap();
serialize_atom_identifier(&name, &mut serialization).unwrap();
SingleFontFamily::FamilyName(FamilyName {
name: name.clone(),
syntax: FamilyNameSyntax::Identifiers(serialization),

View file

@ -4,7 +4,9 @@
//! Computed values.
use {Atom, Namespace};
use Atom;
#[cfg(feature = "servo")]
use Prefix;
use context::QuirksMode;
use euclid::Size2D;
use font_metrics::{FontMetricsProvider, get_metrics_provider_for_product};
@ -414,7 +416,8 @@ trivial_to_computed_value!(u32);
trivial_to_computed_value!(Atom);
trivial_to_computed_value!(BorderStyle);
trivial_to_computed_value!(CursorKind);
trivial_to_computed_value!(Namespace);
#[cfg(feature = "servo")]
trivial_to_computed_value!(Prefix);
trivial_to_computed_value!(String);
trivial_to_computed_value!(Box<str>);

View file

@ -7,11 +7,11 @@
//! [images]: https://drafts.csswg.org/css-images/#image-values
use Atom;
use cssparser::serialize_identifier;
use custom_properties;
use servo_arc::Arc;
use std::fmt::{self, Write};
use style_traits::{CssWriter, ToCss};
use values::serialize_atom_identifier;
/// An [image].
///
@ -151,7 +151,7 @@ impl ToCss for PaintWorklet {
W: Write,
{
dest.write_str("paint(")?;
serialize_identifier(&*self.name.to_string(), dest)?;
serialize_atom_identifier(&self.name, dest)?;
for argument in &self.arguments {
dest.write_str(", ")?;
argument.to_css(dest)?;
@ -200,7 +200,7 @@ impl<G, R, U> ToCss for Image<G, R, U>
Image::PaintWorklet(ref paint_worklet) => paint_worklet.to_css(dest),
Image::Element(ref selector) => {
dest.write_str("-moz-element(#")?;
serialize_identifier(&selector.to_string(), dest)?;
serialize_atom_identifier(selector, dest)?;
dest.write_str(")")
},
}

View file

@ -33,6 +33,25 @@ define_keyword_type!(None_, "none");
define_keyword_type!(Auto, "auto");
define_keyword_type!(Normal, "normal");
/// Serialize an identifier which is represented as an atom.
#[cfg(feature = "gecko")]
pub fn serialize_atom_identifier<W>(ident: &Atom, dest: &mut W) -> fmt::Result
where
W: Write,
{
ident.with_str(|s| serialize_identifier(s, dest))
}
/// Serialize an identifier which is represented as an atom.
#[cfg(feature = "servo")]
pub fn serialize_atom_identifier<Static, W>(ident: &::string_cache::Atom<Static>, dest: &mut W) -> fmt::Result
where
Static: ::string_cache::StaticAtomSet,
W: Write,
{
serialize_identifier(&ident, dest)
}
/// Serialize a normalized value into percentage.
pub fn serialize_percentage<W>(value: CSSFloat, dest: &mut CssWriter<W>) -> fmt::Result
where
@ -114,7 +133,7 @@ impl ToCss for CustomIdent {
where
W: Write,
{
serialize_identifier(&self.0.to_string(), dest)
serialize_atom_identifier(&self.0, dest)
}
}

View file

@ -6,7 +6,7 @@
//!
//! TODO(emilio): Enhance docs.
use Namespace;
use Prefix;
use context::QuirksMode;
use cssparser::{Parser, Token, serialize_identifier};
use num_traits::One;
@ -22,6 +22,7 @@ use super::computed::{Context, ToComputedValue};
use super::generics::{GreaterThanOrEqualToOne, NonNegative};
use super::generics::grid::{GridLine as GenericGridLine, TrackBreadth as GenericTrackBreadth};
use super::generics::grid::{TrackSize as GenericTrackSize, TrackList as GenericTrackList};
use values::serialize_atom_identifier;
use values::specified::calc::CalcNode;
pub use properties::animated_properties::TransitionProperty;
@ -748,8 +749,8 @@ pub type NamespaceId = ();
/// `[namespace? `|`]? ident`
#[derive(Clone, Debug, Eq, MallocSizeOf, PartialEq, ToComputedValue)]
pub struct Attr {
/// Optional namespace
pub namespace: Option<(Namespace, NamespaceId)>,
/// Optional namespace prefix, with the actual namespace id.
pub namespace: Option<(Prefix, NamespaceId)>,
/// Attribute name
pub attribute: String,
}
@ -761,35 +762,18 @@ impl Parse for Attr {
}
}
#[cfg(feature = "gecko")]
/// Get the namespace id from the namespace map
fn get_id_for_namespace(namespace: &Namespace, context: &ParserContext) -> Result<NamespaceId, ()> {
let namespaces_map = match context.namespaces {
Some(map) => map,
None => {
// If we don't have a namespace map (e.g. in inline styles)
// we can't parse namespaces
return Err(());
}
};
match namespaces_map.prefixes.get(&namespace.0) {
Some(entry) => Ok(entry.1),
None => Err(()),
}
}
#[cfg(feature = "servo")]
/// Get the namespace id from the namespace map
fn get_id_for_namespace(_: &Namespace, _: &ParserContext) -> Result<NamespaceId, ()> {
Ok(())
/// Get the Namespace id from the namespace map.
fn get_id_for_namespace(prefix: &Prefix, context: &ParserContext) -> Option<NamespaceId> {
Some(context.namespaces.as_ref()?.prefixes.get(prefix)?.1)
}
impl Attr {
/// Parse contents of attr() assuming we have already parsed `attr` and are
/// within a parse_nested_block()
pub fn parse_function<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>)
-> Result<Attr, ParseError<'i>> {
pub fn parse_function<'i, 't>(
context: &ParserContext,
input: &mut Parser<'i, 't>,
) -> Result<Attr, ParseError<'i>> {
// Syntax is `[namespace? `|`]? ident`
// no spaces allowed
let first = input.try(|i| i.expect_ident_cloned()).ok();
@ -804,11 +788,14 @@ impl Attr {
};
let ns_with_id = if let Some(ns) = first {
let ns = Namespace::from(ns.as_ref());
let id: Result<_, ParseError> =
get_id_for_namespace(&ns, context)
.map_err(|()| location.new_custom_error(StyleParseErrorKind::UnspecifiedError));
Some((ns, id?))
let ns = Prefix::from(ns.as_ref());
let id = match get_id_for_namespace(&ns, context) {
Some(id) => id,
None => return Err(location.new_custom_error(
StyleParseErrorKind::UnspecifiedError
)),
};
Some((ns, id))
} else {
None
};
@ -819,7 +806,7 @@ impl Attr {
}
// In the case of attr(foobar ) we don't want to error out
// because of the trailing whitespace
Token::WhiteSpace(_) => (),
Token::WhiteSpace(..) => {},
ref t => return Err(input.new_unexpected_token_error(t.clone())),
}
}
@ -841,8 +828,8 @@ impl ToCss for Attr {
W: Write,
{
dest.write_str("attr(")?;
if let Some(ref ns) = self.namespace {
serialize_identifier(&ns.0.to_string(), dest)?;
if let Some((ref prefix, _id)) = self.namespace {
serialize_atom_identifier(prefix, dest)?;
dest.write_str("|")?;
}
serialize_identifier(&self.attribute, dest)?;