stylo: Use namespace ids for content: attr(..)

MozReview-Commit-ID: FZ9YEpHQCBh
This commit is contained in:
Manish Goregaokar 2017-05-31 18:03:33 -07:00 committed by Manish Goregaokar
parent 7deeccf4cb
commit 25d193ba34
7 changed files with 57 additions and 16 deletions

View file

@ -1399,6 +1399,9 @@ extern "C" {
pub fn Gecko_AddPropertyToSet(arg1: nsCSSPropertyIDSetBorrowedMut, pub fn Gecko_AddPropertyToSet(arg1: nsCSSPropertyIDSetBorrowedMut,
arg2: nsCSSPropertyID); arg2: nsCSSPropertyID);
} }
extern "C" {
pub fn Gecko_RegisterNamespace(ns: *mut nsIAtom) -> i32;
}
extern "C" { extern "C" {
pub fn Gecko_Construct_Default_nsStyleFont(ptr: *mut nsStyleFont, pub fn Gecko_Construct_Default_nsStyleFont(ptr: *mut nsStyleFont,
pres_context: pres_context:

View file

@ -273,11 +273,11 @@ impl<'a> ::selectors::Parser for SelectorParser<'a> {
} }
fn default_namespace(&self) -> Option<Namespace> { fn default_namespace(&self) -> Option<Namespace> {
self.namespaces.default.clone() self.namespaces.default.clone().as_ref().map(|&(ref ns, _)| ns.clone())
} }
fn namespace_for_prefix(&self, prefix: &Atom) -> Option<Namespace> { fn namespace_for_prefix(&self, prefix: &Atom) -> Option<Namespace> {
self.namespaces.prefixes.get(prefix).cloned() self.namespaces.prefixes.get(prefix).map(|&(ref ns, _)| ns.clone())
} }
} }

View file

@ -7,9 +7,9 @@
use context::QuirksMode; use context::QuirksMode;
use cssparser::{Parser, SourcePosition, UnicodeRange}; use cssparser::{Parser, SourcePosition, UnicodeRange};
use error_reporting::ParseErrorReporter; use error_reporting::ParseErrorReporter;
use parking_lot::RwLock;
use style_traits::OneOrMoreCommaSeparated; use style_traits::OneOrMoreCommaSeparated;
use stylesheets::{CssRuleType, Origin, UrlExtraData, Namespaces}; use stylesheets::{CssRuleType, Origin, UrlExtraData, Namespaces};
use parking_lot::RwLock;
bitflags! { bitflags! {
/// The mode to use when parsing values. /// The mode to use when parsing values.

View file

@ -4403,10 +4403,10 @@ clip-path
} }
ContentItem::Attr(ns, val) => { ContentItem::Attr(ns, val) => {
self.gecko.mContents[i].mType = eStyleContentType_Attr; self.gecko.mContents[i].mType = eStyleContentType_Attr;
let s = if let Some(ns) = ns { let s = if let Some((_, ns)) = ns {
format!("{}|{}", ns, val) format!("{}|{}", ns, val)
} else { } else {
val val.into()
}; };
unsafe { unsafe {
// NB: we share allocators, so doing this is fine. // NB: we share allocators, so doing this is fine.

View file

@ -14,6 +14,8 @@
use values::generics::CounterStyleOrNone; use values::generics::CounterStyleOrNone;
#[cfg(feature = "gecko")] #[cfg(feature = "gecko")]
use values::specified::url::SpecifiedUrl; use values::specified::url::SpecifiedUrl;
#[cfg(feature = "gecko")]
use gecko_string_cache::namespace::Namespace;
#[cfg(feature = "servo")] #[cfg(feature = "servo")]
use super::list_style_type; use super::list_style_type;
@ -35,6 +37,8 @@
type CounterStyleType = super::super::list_style_type::computed_value::T; type CounterStyleType = super::super::list_style_type::computed_value::T;
#[cfg(feature = "gecko")] #[cfg(feature = "gecko")]
type CounterStyleType = ::values::generics::CounterStyleOrNone; type CounterStyleType = ::values::generics::CounterStyleOrNone;
#[cfg(feature = "gecko")]
use gecko_string_cache::namespace::Namespace;
#[derive(Debug, PartialEq, Eq, Clone)] #[derive(Debug, PartialEq, Eq, Clone)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf))] #[cfg_attr(feature = "servo", derive(HeapSizeOf))]
@ -56,7 +60,7 @@
% if product == "gecko": % if product == "gecko":
/// `attr([namespace? `|`]? ident)` /// `attr([namespace? `|`]? ident)`
Attr(Option<String>, String), Attr(Option<(Namespace, u32)>, String),
/// `url(url)` /// `url(url)`
Url(SpecifiedUrl), Url(SpecifiedUrl),
% endif % endif
@ -93,7 +97,7 @@
ContentItem::Attr(ref ns, ref attr) => { ContentItem::Attr(ref ns, ref attr) => {
dest.write_str("attr(")?; dest.write_str("attr(")?;
if let Some(ref ns) = *ns { if let Some(ref ns) = *ns {
cssparser::Token::Ident((&**ns).into()).to_css(dest)?; cssparser::Token::Ident(ns.0.to_string().into()).to_css(dest)?;
dest.write_str("|")?; dest.write_str("|")?;
} }
cssparser::Token::Ident((&**attr).into()).to_css(dest)?; cssparser::Token::Ident((&**attr).into()).to_css(dest)?;
@ -208,14 +212,29 @@
// FIXME (bug 1346693) we should be checking that // FIXME (bug 1346693) we should be checking that
// this is a valid namespace and encoding it as a namespace // this is a valid namespace and encoding it as a namespace
// number from the map // number from the map
let first = input.try(|i| i.expect_ident()).ok().map(|i| i.into_owned()); let first = input.try(|i| i.expect_ident()).ok();
if let Ok(token) = input.try(|i| i.next_including_whitespace()) { if let Ok(token) = input.try(|i| i.next_including_whitespace()) {
match token { match token {
Token::Delim('|') => { Token::Delim('|') => {
// must be followed by an ident // must be followed by an ident
let tok2 = input.next_including_whitespace()?; let tok2 = input.next_including_whitespace()?;
if let Token::Ident(second) = tok2 { if let Token::Ident(second) = tok2 {
return Ok(ContentItem::Attr(first, second.into_owned())) let first: Option<Namespace> = first.map(|i| i.into());
let first_with_id = match (first, context.namespaces) {
(Some(prefix), Some(map)) => {
let map = map.read();
if let Some(ref entry) = map.prefixes.get(&prefix.0) {
Some((prefix, entry.1))
} else {
return Err(())
}
}
// if we don't have a namespace map (e.g. in CSSOM)
// we can't parse namespaces
(Some(_), None) => return Err(()),
_ => None
};
return Ok(ContentItem::Attr(first_with_id, second.into_owned()))
} else { } else {
return Err(()) return Err(())
} }
@ -224,7 +243,7 @@
} }
} }
if let Some(first) = first { if let Some(first) = first {
Ok(ContentItem::Attr(None, first)) Ok(ContentItem::Attr(None, first.into_owned()))
} else { } else {
Err(()) Err(())
} }

View file

@ -430,11 +430,11 @@ impl<'a> ::selectors::Parser for SelectorParser<'a> {
} }
fn default_namespace(&self) -> Option<Namespace> { fn default_namespace(&self) -> Option<Namespace> {
self.namespaces.default.clone() self.namespaces.default.as_ref().map(|&(ref ns, _)| ns.clone())
} }
fn namespace_for_prefix(&self, prefix: &Prefix) -> Option<Namespace> { fn namespace_for_prefix(&self, prefix: &Prefix) -> Option<Namespace> {
self.namespaces.prefixes.get(prefix).cloned() self.namespaces.prefixes.get(prefix).map(|&(ref ns, _)| ns.clone())
} }
} }

View file

@ -96,11 +96,13 @@ pub enum Origin {
} }
/// A set of namespaces applying to a given stylesheet. /// A set of namespaces applying to a given stylesheet.
///
/// The u32 is the namespace id, used in gecko
#[derive(Clone, Default, Debug)] #[derive(Clone, Default, Debug)]
#[allow(missing_docs)] #[allow(missing_docs)]
pub struct Namespaces { pub struct Namespaces {
pub default: Option<Namespace>, pub default: Option<(Namespace, u32)>,
pub prefixes: FnvHashMap<Prefix , Namespace>, pub prefixes: FnvHashMap<Prefix, (Namespace, u32)>,
} }
/// Like gecko_bindings::structs::MallocSizeOf, but without the Option<> wrapper. Note that /// Like gecko_bindings::structs::MallocSizeOf, but without the Option<> wrapper. Note that
@ -1526,6 +1528,21 @@ enum AtRulePrelude {
} }
#[cfg(feature = "gecko")]
fn register_namespace(ns: &Namespace) -> Result<u32, ()> {
let id = unsafe { ::gecko_bindings::bindings::Gecko_RegisterNamespace(ns.0.as_ptr()) };
if id == -1 {
Err(())
} else {
Ok(id as u32)
}
}
#[cfg(feature = "servo")]
fn register_namespace(ns: &Namespace) -> Result<u32, ()> {
Ok(1) // servo doesn't use namespace ids
}
impl<'a> AtRuleParser for TopLevelRuleParser<'a> { impl<'a> AtRuleParser for TopLevelRuleParser<'a> {
type Prelude = AtRulePrelude; type Prelude = AtRulePrelude;
type AtRule = CssRule; type AtRule = CssRule;
@ -1584,14 +1601,16 @@ impl<'a> AtRuleParser for TopLevelRuleParser<'a> {
let prefix_result = input.try(|input| input.expect_ident()); let prefix_result = input.try(|input| input.expect_ident());
let url = Namespace::from(try!(input.expect_url_or_string())); let url = Namespace::from(try!(input.expect_url_or_string()));
let id = register_namespace(&url)?;
let opt_prefix = if let Ok(prefix) = prefix_result { let opt_prefix = if let Ok(prefix) = prefix_result {
let prefix = Prefix::from(prefix); let prefix = Prefix::from(prefix);
self.context.namespaces.expect("namespaces must be set whilst parsing rules") self.context.namespaces.expect("namespaces must be set whilst parsing rules")
.write().prefixes.insert(prefix.clone(), url.clone()); .write().prefixes.insert(prefix.clone(), (url.clone(), id));
Some(prefix) Some(prefix)
} else { } else {
self.context.namespaces.expect("namespaces must be set whilst parsing rules") self.context.namespaces.expect("namespaces must be set whilst parsing rules")
.write().default = Some(url.clone()); .write().default = Some((url.clone(), id));
None None
}; };