Use PropertyDeclarationBlock in a DOMRefCell everywhere.

This commit is contained in:
Simon Sapin 2016-08-31 01:56:10 +02:00
parent d4f704cad2
commit d986fd2d2f
14 changed files with 146 additions and 100 deletions

View file

@ -3,6 +3,7 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
use cssparser::ToCss; use cssparser::ToCss;
use dom::bindings::cell::DOMRefCell;
use dom::bindings::codegen::Bindings::CSSStyleDeclarationBinding::{self, CSSStyleDeclarationMethods}; use dom::bindings::codegen::Bindings::CSSStyleDeclarationBinding::{self, CSSStyleDeclarationMethods};
use dom::bindings::error::{Error, ErrorResult, Fallible}; use dom::bindings::error::{Error, ErrorResult, Fallible};
use dom::bindings::global::GlobalRef; use dom::bindings::global::GlobalRef;
@ -14,13 +15,11 @@ use dom::element::Element;
use dom::node::{Node, NodeDamage, window_from_node}; use dom::node::{Node, NodeDamage, window_from_node};
use dom::window::Window; use dom::window::Window;
use std::ascii::AsciiExt; use std::ascii::AsciiExt;
use std::slice;
use std::sync::Arc; use std::sync::Arc;
use string_cache::Atom; use string_cache::Atom;
use style::parser::ParserContextExtraData; use style::parser::ParserContextExtraData;
use style::properties::{PropertyDeclaration, Shorthand, Importance}; use style::properties::{Shorthand, Importance};
use style::properties::{is_supported_property, parse_one_declaration, parse_style_attribute}; use style::properties::{is_supported_property, parse_one_declaration, parse_style_attribute};
use style::refcell::Ref;
use style::selector_impl::PseudoElement; use style::selector_impl::PseudoElement;
// http://dev.w3.org/csswg/cssom/#the-cssstyledeclaration-interface // http://dev.w3.org/csswg/cssom/#the-cssstyledeclaration-interface
@ -93,7 +92,7 @@ impl CSSStyleDeclarationMethods for CSSStyleDeclaration {
fn Length(&self) -> u32 { fn Length(&self) -> u32 {
let elem = self.owner.upcast::<Element>(); let elem = self.owner.upcast::<Element>();
let len = match *elem.style_attribute().borrow() { let len = match *elem.style_attribute().borrow() {
Some(ref declarations) => declarations.declarations.len(), Some(ref declarations) => declarations.borrow().declarations.len(),
None => 0, None => 0,
}; };
len as u32 len as u32
@ -119,43 +118,42 @@ impl CSSStyleDeclarationMethods for CSSStyleDeclaration {
// Step 2 // Step 2
if let Some(shorthand) = Shorthand::from_name(&property) { if let Some(shorthand) = Shorthand::from_name(&property) {
let style_attribute = owner.style_attribute().borrow();
let style_attribute = if let Some(ref style_attribute) = *style_attribute {
style_attribute.borrow()
} else {
// shorthand.longhands() is never empty, so with no style attribute
// step 2.2.2 would do this:
return DOMString::new()
};
// Step 2.1 // Step 2.1
let mut list = vec![]; let mut list = vec![];
// Step 2.2 // Step 2.2
for longhand in shorthand.longhands() { for longhand in shorthand.longhands() {
// Step 2.2.1 // Step 2.2.1
let declaration = owner.get_inline_style_declaration(&Atom::from(*longhand)); let declaration = style_attribute.get(longhand);
// Step 2.2.2 & 2.2.3 // Step 2.2.2 & 2.2.3
match declaration { match declaration {
Some(declaration) => list.push(declaration), Some(&(ref declaration, _importance)) => list.push(declaration),
None => return DOMString::new(), None => return DOMString::new(),
} }
} }
// Step 2.3 // Step 2.3
// Work around closures not being Clone
#[derive(Clone)]
struct Map<'a, 'b: 'a>(slice::Iter<'a, Ref<'b, (PropertyDeclaration, Importance)>>);
impl<'a, 'b> Iterator for Map<'a, 'b> {
type Item = &'a PropertyDeclaration;
fn next(&mut self) -> Option<Self::Item> {
self.0.next().map(|r| &r.0)
}
}
// TODO: important is hardcoded to false because method does not implement it yet // TODO: important is hardcoded to false because method does not implement it yet
let serialized_value = shorthand.serialize_shorthand_value_to_string( let serialized_value = shorthand.serialize_shorthand_value_to_string(
Map(list.iter()), Importance::Normal); list, Importance::Normal);
return DOMString::from(serialized_value); return DOMString::from(serialized_value);
} }
// Step 3 & 4 // Step 3 & 4
match owner.get_inline_style_declaration(&property) { owner.get_inline_style_declaration(&property, |d| match d {
Some(declaration) => DOMString::from(declaration.0.value()), Some(declaration) => DOMString::from(declaration.0.value()),
None => DOMString::new(), None => DOMString::new(),
} })
} }
// https://dev.w3.org/csswg/cssom/#dom-cssstyledeclaration-getpropertypriority // https://dev.w3.org/csswg/cssom/#dom-cssstyledeclaration-getpropertypriority
@ -172,13 +170,18 @@ impl CSSStyleDeclarationMethods for CSSStyleDeclaration {
.all(|priority| priority == "important") { .all(|priority| priority == "important") {
return DOMString::from("important"); return DOMString::from("important");
} }
// Step 3
} else { } else {
if let Some(decl) = self.owner.get_inline_style_declaration(&property) { // Step 3
if decl.1.important() { return self.owner.get_inline_style_declaration(&property, |d| {
return DOMString::from("important"); if let Some(decl) = d {
if decl.1.important() {
return DOMString::from("important");
}
} }
}
// Step 4
DOMString::new()
})
} }
// Step 4 // Step 4
@ -328,13 +331,14 @@ impl CSSStyleDeclarationMethods for CSSStyleDeclaration {
let elem = self.owner.upcast::<Element>(); let elem = self.owner.upcast::<Element>();
let style_attribute = elem.style_attribute().borrow(); let style_attribute = elem.style_attribute().borrow();
style_attribute.as_ref().and_then(|declarations| { style_attribute.as_ref().and_then(|declarations| {
declarations.declarations.get(index) declarations.borrow().declarations.get(index).map(|entry| {
}).map(|&(ref declaration, importance)| { let (ref declaration, importance) = *entry;
let mut css = declaration.to_css_string(); let mut css = declaration.to_css_string();
if importance.important() { if importance.important() {
css += " !important"; css += " !important";
} }
DOMString::from(css) DOMString::from(css)
})
}) })
} }
@ -344,7 +348,7 @@ impl CSSStyleDeclarationMethods for CSSStyleDeclaration {
let style_attribute = elem.style_attribute().borrow(); let style_attribute = elem.style_attribute().borrow();
if let Some(declarations) = style_attribute.as_ref() { if let Some(declarations) = style_attribute.as_ref() {
DOMString::from(declarations.to_css_string()) DOMString::from(declarations.borrow().to_css_string())
} else { } else {
DOMString::new() DOMString::new()
} }
@ -366,7 +370,7 @@ impl CSSStyleDeclarationMethods for CSSStyleDeclaration {
*element.style_attribute().borrow_mut() = if decl_block.declarations.is_empty() { *element.style_attribute().borrow_mut() = if decl_block.declarations.is_empty() {
None // Step 2 None // Step 2
} else { } else {
Some(Arc::new(decl_block)) Some(Arc::new(DOMRefCell::new(decl_block)))
}; };
element.sync_property_with_attrs_style(); element.sync_property_with_attrs_style();
let node = element.upcast::<Node>(); let node = element.upcast::<Node>();

View file

@ -110,7 +110,7 @@ pub struct Element {
attrs: DOMRefCell<Vec<JS<Attr>>>, attrs: DOMRefCell<Vec<JS<Attr>>>,
id_attribute: DOMRefCell<Option<Atom>>, id_attribute: DOMRefCell<Option<Atom>>,
#[ignore_heap_size_of = "Arc"] #[ignore_heap_size_of = "Arc"]
style_attribute: DOMRefCell<Option<Arc<PropertyDeclarationBlock>>>, style_attribute: DOMRefCell<Option<Arc<DOMRefCell<PropertyDeclarationBlock>>>>,
attr_list: MutNullableHeap<JS<NamedNodeMap>>, attr_list: MutNullableHeap<JS<NamedNodeMap>>,
class_list: MutNullableHeap<JS<DOMTokenList>>, class_list: MutNullableHeap<JS<DOMTokenList>>,
state: Cell<ElementState>, state: Cell<ElementState>,
@ -298,7 +298,7 @@ pub trait LayoutElementHelpers {
#[allow(unsafe_code)] #[allow(unsafe_code)]
unsafe fn html_element_in_html_document_for_layout(&self) -> bool; unsafe fn html_element_in_html_document_for_layout(&self) -> bool;
fn id_attribute(&self) -> *const Option<Atom>; fn id_attribute(&self) -> *const Option<Atom>;
fn style_attribute(&self) -> *const Option<Arc<PropertyDeclarationBlock>>; fn style_attribute(&self) -> *const Option<Arc<DOMRefCell<PropertyDeclarationBlock>>>;
fn local_name(&self) -> &Atom; fn local_name(&self) -> &Atom;
fn namespace(&self) -> &Namespace; fn namespace(&self) -> &Namespace;
fn get_checked_state_for_layout(&self) -> bool; fn get_checked_state_for_layout(&self) -> bool;
@ -330,10 +330,10 @@ impl LayoutElementHelpers for LayoutJS<Element> {
#[inline] #[inline]
fn from_declaration(rule: PropertyDeclaration) -> ApplicableDeclarationBlock { fn from_declaration(rule: PropertyDeclaration) -> ApplicableDeclarationBlock {
ApplicableDeclarationBlock::from_declarations( ApplicableDeclarationBlock::from_declarations(
Arc::new(PropertyDeclarationBlock { Arc::new(DOMRefCell::new(PropertyDeclarationBlock {
declarations: vec![(rule, Importance::Normal)], declarations: vec![(rule, Importance::Normal)],
important_count: 0, important_count: 0,
}), })),
Importance::Normal) Importance::Normal)
} }
@ -619,7 +619,7 @@ impl LayoutElementHelpers for LayoutJS<Element> {
} }
#[allow(unsafe_code)] #[allow(unsafe_code)]
fn style_attribute(&self) -> *const Option<Arc<PropertyDeclarationBlock>> { fn style_attribute(&self) -> *const Option<Arc<DOMRefCell<PropertyDeclarationBlock>>> {
unsafe { unsafe {
(*self.unsafe_get()).style_attribute.borrow_for_layout() (*self.unsafe_get()).style_attribute.borrow_for_layout()
} }
@ -708,7 +708,7 @@ impl Element {
self.attrs.borrow() self.attrs.borrow()
} }
pub fn style_attribute(&self) -> &DOMRefCell<Option<Arc<PropertyDeclarationBlock>>> { pub fn style_attribute(&self) -> &DOMRefCell<Option<Arc<DOMRefCell<PropertyDeclarationBlock>>>> {
&self.style_attribute &self.style_attribute
} }
@ -738,7 +738,7 @@ impl Element {
// therefore, it should not trigger subsequent mutation events // therefore, it should not trigger subsequent mutation events
pub fn sync_property_with_attrs_style(&self) { pub fn sync_property_with_attrs_style(&self) {
let style_str = if let &Some(ref declarations) = &*self.style_attribute().borrow() { let style_str = if let &Some(ref declarations) = &*self.style_attribute().borrow() {
declarations.to_css_string() declarations.borrow().to_css_string()
} else { } else {
String::new() String::new()
}; };
@ -770,7 +770,7 @@ impl Element {
let mut inline_declarations = element.style_attribute.borrow_mut(); let mut inline_declarations = element.style_attribute.borrow_mut();
if let &mut Some(ref mut declarations) = &mut *inline_declarations { if let &mut Some(ref mut declarations) = &mut *inline_declarations {
let mut importance = None; let mut importance = None;
let index = declarations.declarations.iter().position(|&(ref decl, i)| { let index = declarations.borrow().declarations.iter().position(|&(ref decl, i)| {
let matching = decl.matches(property); let matching = decl.matches(property);
if matching { if matching {
importance = Some(i) importance = Some(i)
@ -778,7 +778,7 @@ impl Element {
matching matching
}); });
if let Some(index) = index { if let Some(index) = index {
let declarations = Arc::make_mut(declarations); let mut declarations = Arc::make_mut(declarations).borrow_mut();
declarations.declarations.remove(index); declarations.declarations.remove(index);
if importance.unwrap().important() { if importance.unwrap().important() {
declarations.important_count -= 1; declarations.important_count -= 1;
@ -801,7 +801,8 @@ impl Element {
{ {
// Usually, the reference count will be 1 here. But transitions could make it greater // Usually, the reference count will be 1 here. But transitions could make it greater
// than that. // than that.
let declaration_block = Arc::make_mut(declaration_block); let mut declaration_block = Arc::make_mut(declaration_block).borrow_mut();
let declaration_block = &mut *declaration_block;
let existing_declarations = &mut declaration_block.declarations; let existing_declarations = &mut declaration_block.declarations;
'outer: for incoming_declaration in declarations { 'outer: for incoming_declaration in declarations {
@ -835,10 +836,10 @@ impl Element {
0 0
}; };
*inline_declarations = Some(Arc::new(PropertyDeclarationBlock { *inline_declarations = Some(Arc::new(DOMRefCell::new(PropertyDeclarationBlock {
declarations: declarations.into_iter().map(|d| (d, importance)).collect(), declarations: declarations.into_iter().map(|d| (d, importance)).collect(),
important_count: important_count, important_count: important_count,
})); })));
} }
update(self, declarations, importance); update(self, declarations, importance);
@ -853,7 +854,8 @@ impl Element {
if let &mut Some(ref mut block) = &mut *inline_declarations { if let &mut Some(ref mut block) = &mut *inline_declarations {
// Usually, the reference counts of `from` and `to` will be 1 here. But transitions // Usually, the reference counts of `from` and `to` will be 1 here. But transitions
// could make them greater than that. // could make them greater than that.
let block = Arc::make_mut(block); let mut block = Arc::make_mut(block).borrow_mut();
let block = &mut *block;
let declarations = &mut block.declarations; let declarations = &mut block.declarations;
for &mut (ref declaration, ref mut importance) in declarations { for &mut (ref declaration, ref mut importance) in declarations {
if properties.iter().any(|p| declaration.name() == **p) { if properties.iter().any(|p| declaration.name() == **p) {
@ -875,16 +877,15 @@ impl Element {
self.sync_property_with_attrs_style(); self.sync_property_with_attrs_style();
} }
pub fn get_inline_style_declaration(&self, pub fn get_inline_style_declaration<F, R>(&self, property: &str, f: F) -> R
property: &Atom) where F: FnOnce(Option<&(PropertyDeclaration, Importance)>) -> R {
-> Option<Ref<(PropertyDeclaration, Importance)>> { let style_attr = self.style_attribute.borrow();
Ref::filter_map(self.style_attribute.borrow(), |inline_declarations| { if let Some(ref block) = *style_attr {
inline_declarations.as_ref().and_then(|declarations| { let block = block.borrow();
declarations.declarations f(block.get(property))
.iter() } else {
.find(|&&(ref decl, _)| decl.matches(&property)) f(None)
}) }
})
} }
pub fn serialize(&self, traversal_scope: TraversalScope) -> Fallible<DOMString> { pub fn serialize(&self, traversal_scope: TraversalScope) -> Fallible<DOMString> {
@ -2130,11 +2131,11 @@ impl VirtualMethods for Element {
*self.style_attribute.borrow_mut() = *self.style_attribute.borrow_mut() =
mutation.new_value(attr).map(|value| { mutation.new_value(attr).map(|value| {
let win = window_from_node(self); let win = window_from_node(self);
Arc::new(parse_style_attribute( Arc::new(DOMRefCell::new(parse_style_attribute(
&value, &value,
&doc.base_url(), &doc.base_url(),
win.css_error_reporter(), win.css_error_reporter(),
ParserContextExtraData::default())) ParserContextExtraData::default())))
}); });
if node.is_in_doc() { if node.is_in_doc() {
node.dirty(NodeDamage::NodeStyleDamaged); node.dirty(NodeDamage::NodeStyleDamaged);

View file

@ -30,6 +30,7 @@
#![allow(unsafe_code)] #![allow(unsafe_code)]
use dom::bindings::cell::DOMRefCell;
use dom::bindings::inheritance::{CharacterDataTypeId, ElementTypeId}; use dom::bindings::inheritance::{CharacterDataTypeId, ElementTypeId};
use dom::bindings::inheritance::{HTMLElementTypeId, NodeTypeId}; use dom::bindings::inheritance::{HTMLElementTypeId, NodeTypeId};
use dom::bindings::js::LayoutJS; use dom::bindings::js::LayoutJS;
@ -461,7 +462,7 @@ impl<'le> TElement for ServoLayoutElement<'le> {
ServoLayoutNode::from_layout_js(self.element.upcast()) ServoLayoutNode::from_layout_js(self.element.upcast())
} }
fn style_attribute(&self) -> Option<&Arc<PropertyDeclarationBlock>> { fn style_attribute(&self) -> Option<&Arc<DOMRefCell<PropertyDeclarationBlock>>> {
unsafe { unsafe {
(*self.element.style_attribute()).as_ref() (*self.element.style_attribute()).as_ref()
} }

View file

@ -8,6 +8,7 @@
use atomic_refcell::{AtomicRef, AtomicRefMut}; use atomic_refcell::{AtomicRef, AtomicRefMut};
use data::PersistentStyleData; use data::PersistentStyleData;
use domrefcell::DOMRefCell;
use element_state::ElementState; use element_state::ElementState;
use properties::{ComputedValues, PropertyDeclarationBlock}; use properties::{ComputedValues, PropertyDeclarationBlock};
use restyle_hints::{RESTYLE_DESCENDANTS, RESTYLE_LATER_SIBLINGS, RESTYLE_SELF, RestyleHint}; use restyle_hints::{RESTYLE_DESCENDANTS, RESTYLE_LATER_SIBLINGS, RESTYLE_SELF, RestyleHint};
@ -202,7 +203,7 @@ pub trait TElement : PartialEq + Debug + Sized + Copy + Clone + ElementExt + Pre
fn as_node(&self) -> Self::ConcreteNode; fn as_node(&self) -> Self::ConcreteNode;
fn style_attribute(&self) -> Option<&Arc<PropertyDeclarationBlock>>; fn style_attribute(&self) -> Option<&Arc<DOMRefCell<PropertyDeclarationBlock>>>;
fn get_state(&self) -> ElementState; fn get_state(&self) -> ElementState;

View file

@ -11,12 +11,19 @@ use thread_state;
/// ///
/// This extends the API of `core::cell::RefCell` to allow unsafe access in /// This extends the API of `core::cell::RefCell` to allow unsafe access in
/// certain situations, with dynamic checking in debug builds. /// certain situations, with dynamic checking in debug builds.
#[derive(Clone)] #[derive(Clone, PartialEq, Debug)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf))] #[cfg_attr(feature = "servo", derive(HeapSizeOf))]
pub struct DOMRefCell<T> { pub struct DOMRefCell<T> {
value: RefCell<T>, value: RefCell<T>,
} }
// FIXME: These two impls make promises that are not quite true,
// but maybe the debug_assert! makes it close enough.
#[allow(unsafe_code)]
unsafe impl<T: Send> Send for DOMRefCell<T> {}
#[allow(unsafe_code)]
unsafe impl<T: Sync> Sync for DOMRefCell<T> {}
// Functionality specific to Servo's `DOMRefCell` type // Functionality specific to Servo's `DOMRefCell` type
// =================================================== // ===================================================

View file

@ -46,6 +46,7 @@ use std::ptr;
use std::sync::Arc; use std::sync::Arc;
use std::sync::atomic::{AtomicBool, AtomicPtr}; use std::sync::atomic::{AtomicBool, AtomicPtr};
use string_cache::{Atom, Namespace, WeakAtom, WeakNamespace}; use string_cache::{Atom, Namespace, WeakAtom, WeakNamespace};
use style::domrefcell::DOMRefCell;
use url::Url; use url::Url;
pub struct NonOpaqueStyleData(AtomicRefCell<PersistentStyleData>); pub struct NonOpaqueStyleData(AtomicRefCell<PersistentStyleData>);
@ -468,7 +469,7 @@ impl<'le> TElement for GeckoElement<'le> {
unsafe { GeckoNode(&*(self.0 as *const _ as *const RawGeckoNode)) } unsafe { GeckoNode(&*(self.0 as *const _ as *const RawGeckoNode)) }
} }
fn style_attribute(&self) -> Option<&Arc<PropertyDeclarationBlock>> { fn style_attribute(&self) -> Option<&Arc<DOMRefCell<PropertyDeclarationBlock>>> {
let declarations = unsafe { Gecko_GetServoDeclarationBlock(self.0) }; let declarations = unsafe { Gecko_GetServoDeclarationBlock(self.0) };
if declarations.is_null() { if declarations.is_null() {
None None

View file

@ -4,6 +4,7 @@
use cssparser::{AtRuleParser, Parser, QualifiedRuleParser, RuleListParser}; use cssparser::{AtRuleParser, Parser, QualifiedRuleParser, RuleListParser};
use cssparser::{DeclarationListParser, DeclarationParser}; use cssparser::{DeclarationListParser, DeclarationParser};
use domrefcell::DOMRefCell;
use parser::{ParserContext, log_css_error}; use parser::{ParserContext, log_css_error};
use properties::{Importance, PropertyDeclaration, PropertyDeclarationBlock}; use properties::{Importance, PropertyDeclaration, PropertyDeclarationBlock};
use properties::PropertyDeclarationParseResult; use properties::PropertyDeclarationParseResult;
@ -78,7 +79,7 @@ pub struct Keyframe {
/// But including them enables `compute_style_for_animation_step` to create a `ApplicableDeclarationBlock` /// But including them enables `compute_style_for_animation_step` to create a `ApplicableDeclarationBlock`
/// by cloning an `Arc<_>` (incrementing a reference count) rather than re-creating a `Vec<_>`. /// by cloning an `Arc<_>` (incrementing a reference count) rather than re-creating a `Vec<_>`.
#[cfg_attr(feature = "servo", ignore_heap_size_of = "Arc")] #[cfg_attr(feature = "servo", ignore_heap_size_of = "Arc")]
pub block: Arc<PropertyDeclarationBlock>, pub block: Arc<DOMRefCell<PropertyDeclarationBlock>>,
} }
/// A keyframes step value. This can be a synthetised keyframes animation, that /// A keyframes step value. This can be a synthetised keyframes animation, that
@ -89,7 +90,7 @@ pub struct Keyframe {
#[cfg_attr(feature = "servo", derive(HeapSizeOf))] #[cfg_attr(feature = "servo", derive(HeapSizeOf))]
pub enum KeyframesStepValue { pub enum KeyframesStepValue {
/// See `Keyframe::declarations`s docs about the presence of `Importance`. /// See `Keyframe::declarations`s docs about the presence of `Importance`.
Declarations(Arc<PropertyDeclarationBlock>), Declarations(Arc<DOMRefCell<PropertyDeclarationBlock>>),
ComputedValues, ComputedValues,
} }
@ -110,12 +111,14 @@ pub struct KeyframesStep {
} }
impl KeyframesStep { impl KeyframesStep {
#[allow(unsafe_code)]
#[inline] #[inline]
fn new(percentage: KeyframePercentage, fn new(percentage: KeyframePercentage,
value: KeyframesStepValue) -> Self { value: KeyframesStepValue) -> Self {
let declared_timing_function = match value { let declared_timing_function = match value {
KeyframesStepValue::Declarations(ref block) => { KeyframesStepValue::Declarations(ref block) => {
block.declarations.iter().any(|&(ref prop_decl, _)| { // FIXME: Is this thread-safe?
unsafe { block.borrow_for_layout() }.declarations.iter().any(|&(ref prop_decl, _)| {
match *prop_decl { match *prop_decl {
PropertyDeclaration::AnimationTimingFunction(..) => true, PropertyDeclaration::AnimationTimingFunction(..) => true,
_ => false, _ => false,
@ -151,11 +154,13 @@ pub struct KeyframesAnimation {
/// ///
/// In practice, browsers seem to try to do their best job at it, so we might /// In practice, browsers seem to try to do their best job at it, so we might
/// want to go through all the actual keyframes and deduplicate properties. /// want to go through all the actual keyframes and deduplicate properties.
#[allow(unsafe_code)]
fn get_animated_properties(keyframe: &Keyframe) -> Vec<TransitionProperty> { fn get_animated_properties(keyframe: &Keyframe) -> Vec<TransitionProperty> {
let mut ret = vec![]; let mut ret = vec![];
// NB: declarations are already deduplicated, so we don't have to check for // NB: declarations are already deduplicated, so we don't have to check for
// it here. // it here.
for &(ref declaration, _) in keyframe.block.declarations.iter() { // FIXME: Is this thread-safe?
for &(ref declaration, _) in unsafe { keyframe.block.borrow_for_layout() }.declarations.iter() {
if let Some(property) = TransitionProperty::from_declaration(declaration) { if let Some(property) = TransitionProperty::from_declaration(declaration) {
ret.push(property); ret.push(property);
} }
@ -266,10 +271,10 @@ impl<'a> QualifiedRuleParser for KeyframeListParser<'a> {
} }
Ok(Arc::new(Keyframe { Ok(Arc::new(Keyframe {
selector: prelude, selector: prelude,
block: Arc::new(PropertyDeclarationBlock { block: Arc::new(DOMRefCell::new(PropertyDeclarationBlock {
declarations: declarations, declarations: declarations,
important_count: 0, important_count: 0,
}), })),
})) }))
} }
} }

View file

@ -24,6 +24,7 @@ use sink::ForgetfulSink;
use smallvec::SmallVec; use smallvec::SmallVec;
use std::collections::HashMap; use std::collections::HashMap;
use std::hash::{BuildHasherDefault, Hash, Hasher}; use std::hash::{BuildHasherDefault, Hash, Hasher};
use std::ops::Deref;
use std::slice::IterMut; use std::slice::IterMut;
use std::sync::Arc; use std::sync::Arc;
use string_cache::Atom; use string_cache::Atom;
@ -139,7 +140,7 @@ impl<'a> Hash for ApplicableDeclarationsCacheQuery<'a> {
for declaration in self.declarations { for declaration in self.declarations {
// Each declaration contians an Arc, which is a stable // Each declaration contians an Arc, which is a stable
// pointer; we use that for hashing and equality. // pointer; we use that for hashing and equality.
let ptr: *const PropertyDeclarationBlock = &*declaration.mixed_declarations; let ptr: *const _ = Arc::deref(&declaration.mixed_declarations);
ptr.hash(state); ptr.hash(state);
declaration.importance.hash(state); declaration.importance.hash(state);
} }

View file

@ -311,6 +311,10 @@ impl PropertyDeclarationBlock {
pub fn any_normal(&self) -> bool { pub fn any_normal(&self) -> bool {
self.declarations.len() > self.important_count as usize self.declarations.len() > self.important_count as usize
} }
pub fn get(&self, property_name: &str) -> Option< &(PropertyDeclaration, Importance)> {
self.declarations.iter().find(|&&(ref decl, _)| decl.matches(property_name))
}
} }
impl ToCss for PropertyDeclarationBlock { impl ToCss for PropertyDeclarationBlock {
@ -741,7 +745,7 @@ impl Shorthand {
/// Serializes possible shorthand value to String. /// Serializes possible shorthand value to String.
pub fn serialize_shorthand_value_to_string<'a, I>(self, declarations: I, importance: Importance) -> String pub fn serialize_shorthand_value_to_string<'a, I>(self, declarations: I, importance: Importance) -> String
where I: Iterator<Item=&'a PropertyDeclaration> + Clone { where I: IntoIterator<Item=&'a PropertyDeclaration>, I::IntoIter: Clone {
let appendable_value = self.get_shorthand_appendable_value(declarations).unwrap(); let appendable_value = self.get_shorthand_appendable_value(declarations).unwrap();
let mut result = String::new(); let mut result = String::new();
append_declaration_value(&mut result, appendable_value, importance).unwrap(); append_declaration_value(&mut result, appendable_value, importance).unwrap();
@ -755,7 +759,7 @@ impl Shorthand {
declarations: I, declarations: I,
is_first_serialization: &mut bool) is_first_serialization: &mut bool)
-> Result<bool, fmt::Error> -> Result<bool, fmt::Error>
where W: Write, I: Iterator<Item=&'a PropertyDeclaration> + Clone { where W: Write, I: IntoIterator<Item=&'a PropertyDeclaration>, I::IntoIter: Clone {
match self.get_shorthand_appendable_value(declarations) { match self.get_shorthand_appendable_value(declarations) {
None => Ok(false), None => Ok(false),
Some(appendable_value) => { Some(appendable_value) => {
@ -772,8 +776,10 @@ impl Shorthand {
} }
} }
fn get_shorthand_appendable_value<'a, I>(self, declarations: I) -> Option<AppendableValue<'a, I>> fn get_shorthand_appendable_value<'a, I>(self, declarations: I)
where I: Iterator<Item=&'a PropertyDeclaration> + Clone { -> Option<AppendableValue<'a, I::IntoIter>>
where I: IntoIterator<Item=&'a PropertyDeclaration>, I::IntoIter: Clone {
let declarations = declarations.into_iter();
// Only cloning iterators (a few pointers each) not declarations. // Only cloning iterators (a few pointers each) not declarations.
let mut declarations2 = declarations.clone(); let mut declarations2 = declarations.clone();

View file

@ -5,6 +5,7 @@
//! Selector matching. //! Selector matching.
use dom::PresentationalHintsSynthetizer; use dom::PresentationalHintsSynthetizer;
use domrefcell::DOMRefCell;
use element_state::*; use element_state::*;
use error_reporting::StdoutErrorReporter; use error_reporting::StdoutErrorReporter;
use keyframes::KeyframesAnimation; use keyframes::KeyframesAnimation;
@ -178,7 +179,7 @@ impl Stylist {
map.insert(Rule { map.insert(Rule {
selector: selector.complex_selector.clone(), selector: selector.complex_selector.clone(),
declarations: style_rule.declarations.clone(), declarations: style_rule.block.clone(),
specificity: selector.specificity, specificity: selector.specificity,
source_order: rules_source_order, source_order: rules_source_order,
}); });
@ -327,11 +328,12 @@ impl Stylist {
/// that is, whether the matched selectors are simple enough to allow the /// that is, whether the matched selectors are simple enough to allow the
/// matching logic to be reduced to the logic in /// matching logic to be reduced to the logic in
/// `css::matching::PrivateMatchMethods::candidate_element_allows_for_style_sharing`. /// `css::matching::PrivateMatchMethods::candidate_element_allows_for_style_sharing`.
#[allow(unsafe_code)]
pub fn push_applicable_declarations<E, V>( pub fn push_applicable_declarations<E, V>(
&self, &self,
element: &E, element: &E,
parent_bf: Option<&BloomFilter>, parent_bf: Option<&BloomFilter>,
style_attribute: Option<&Arc<PropertyDeclarationBlock>>, style_attribute: Option<&Arc<DOMRefCell<PropertyDeclarationBlock>>>,
pseudo_element: Option<&PseudoElement>, pseudo_element: Option<&PseudoElement>,
applicable_declarations: &mut V, applicable_declarations: &mut V,
reason: MatchingReason) -> StyleRelations reason: MatchingReason) -> StyleRelations
@ -390,8 +392,9 @@ impl Stylist {
debug!("author normal: {:?}", relations); debug!("author normal: {:?}", relations);
// Step 4: Normal style attributes. // Step 4: Normal style attributes.
if let Some(sa) = style_attribute { if let Some(sa) = style_attribute {
if sa.any_normal() { // FIXME: Is this thread-safe?
if unsafe { sa.borrow_for_layout() }.any_normal() {
relations |= AFFECTED_BY_STYLE_ATTRIBUTE; relations |= AFFECTED_BY_STYLE_ATTRIBUTE;
Push::push( Push::push(
applicable_declarations, applicable_declarations,
@ -413,7 +416,8 @@ impl Stylist {
// Step 6: `!important` style attributes. // Step 6: `!important` style attributes.
if let Some(sa) = style_attribute { if let Some(sa) = style_attribute {
if sa.any_important() { // FIXME: Is this thread-safe?
if unsafe { sa.borrow_for_layout() }.any_important() {
relations |= AFFECTED_BY_STYLE_ATTRIBUTE; relations |= AFFECTED_BY_STYLE_ATTRIBUTE;
Push::push( Push::push(
applicable_declarations, applicable_declarations,
@ -691,6 +695,7 @@ impl SelectorMap {
/// Append to `rule_list` all universal Rules (rules with selector `*|*`) in /// Append to `rule_list` all universal Rules (rules with selector `*|*`) in
/// `self` sorted by specifity and source order. /// `self` sorted by specifity and source order.
#[allow(unsafe_code)]
pub fn get_universal_rules<V>(&self, pub fn get_universal_rules<V>(&self,
matching_rules_list: &mut V) matching_rules_list: &mut V)
where V: VecLike<ApplicableDeclarationBlock> where V: VecLike<ApplicableDeclarationBlock>
@ -704,11 +709,13 @@ impl SelectorMap {
for rule in self.other_rules.iter() { for rule in self.other_rules.iter() {
if rule.selector.compound_selector.is_empty() && if rule.selector.compound_selector.is_empty() &&
rule.selector.next.is_none() { rule.selector.next.is_none() {
if rule.declarations.any_normal() { // FIXME: Is this thread-safe?
let block = unsafe { rule.declarations.borrow_for_layout() };
if block.any_normal() {
matching_rules_list.push( matching_rules_list.push(
rule.to_applicable_declaration_block(Importance::Normal)); rule.to_applicable_declaration_block(Importance::Normal));
} }
if rule.declarations.any_important() { if block.any_important() {
matching_rules_list.push( matching_rules_list.push(
rule.to_applicable_declaration_block(Importance::Important)); rule.to_applicable_declaration_block(Importance::Important));
} }
@ -745,6 +752,7 @@ impl SelectorMap {
} }
/// Adds rules in `rules` that match `element` to the `matching_rules` list. /// Adds rules in `rules` that match `element` to the `matching_rules` list.
#[allow(unsafe_code)]
fn get_matching_rules<E, V>(element: &E, fn get_matching_rules<E, V>(element: &E,
parent_bf: Option<&BloomFilter>, parent_bf: Option<&BloomFilter>,
rules: &[Rule], rules: &[Rule],
@ -756,7 +764,8 @@ impl SelectorMap {
V: VecLike<ApplicableDeclarationBlock> V: VecLike<ApplicableDeclarationBlock>
{ {
for rule in rules.iter() { for rule in rules.iter() {
let block = &rule.declarations; // FIXME: Is this thread-safe?
let block = unsafe { rule.declarations.borrow_for_layout() };
let any_declaration_for_importance = if importance.important() { let any_declaration_for_importance = if importance.important() {
block.any_important() block.any_important()
} else { } else {
@ -844,7 +853,7 @@ pub struct Rule {
#[cfg_attr(feature = "servo", ignore_heap_size_of = "Arc")] #[cfg_attr(feature = "servo", ignore_heap_size_of = "Arc")]
pub selector: Arc<ComplexSelector<TheSelectorImpl>>, pub selector: Arc<ComplexSelector<TheSelectorImpl>>,
#[cfg_attr(feature = "servo", ignore_heap_size_of = "Arc")] #[cfg_attr(feature = "servo", ignore_heap_size_of = "Arc")]
pub declarations: Arc<PropertyDeclarationBlock>, pub declarations: Arc<DOMRefCell<PropertyDeclarationBlock>>,
pub source_order: usize, pub source_order: usize,
pub specificity: u32, pub specificity: u32,
} }
@ -869,7 +878,7 @@ pub struct ApplicableDeclarationBlock {
/// Contains declarations of either importance, but only those of self.importance are relevant. /// Contains declarations of either importance, but only those of self.importance are relevant.
/// Use ApplicableDeclarationBlock::iter /// Use ApplicableDeclarationBlock::iter
#[cfg_attr(feature = "servo", ignore_heap_size_of = "Arc")] #[cfg_attr(feature = "servo", ignore_heap_size_of = "Arc")]
pub mixed_declarations: Arc<PropertyDeclarationBlock>, pub mixed_declarations: Arc<DOMRefCell<PropertyDeclarationBlock>>,
pub importance: Importance, pub importance: Importance,
pub source_order: usize, pub source_order: usize,
pub specificity: u32, pub specificity: u32,
@ -877,7 +886,7 @@ pub struct ApplicableDeclarationBlock {
impl ApplicableDeclarationBlock { impl ApplicableDeclarationBlock {
#[inline] #[inline]
pub fn from_declarations(declarations: Arc<PropertyDeclarationBlock>, pub fn from_declarations(declarations: Arc<DOMRefCell<PropertyDeclarationBlock>>,
importance: Importance) importance: Importance)
-> Self { -> Self {
ApplicableDeclarationBlock { ApplicableDeclarationBlock {
@ -888,9 +897,11 @@ impl ApplicableDeclarationBlock {
} }
} }
#[allow(unsafe_code)]
pub fn iter(&self) -> ApplicableDeclarationBlockIter { pub fn iter(&self) -> ApplicableDeclarationBlockIter {
ApplicableDeclarationBlockIter { ApplicableDeclarationBlockIter {
iter: self.mixed_declarations.declarations.iter(), // FIXME: Is this thread-safe?
iter: unsafe { self.mixed_declarations.borrow_for_layout() }.declarations.iter(),
importance: self.importance, importance: self.importance,
} }
} }

View file

@ -6,6 +6,7 @@
use cssparser::{AtRuleParser, Parser, QualifiedRuleParser, decode_stylesheet_bytes}; use cssparser::{AtRuleParser, Parser, QualifiedRuleParser, decode_stylesheet_bytes};
use cssparser::{AtRuleType, RuleListParser, Token}; use cssparser::{AtRuleType, RuleListParser, Token};
use domrefcell::DOMRefCell;
use encoding::EncodingRef; use encoding::EncodingRef;
use error_reporting::ParseErrorReporter; use error_reporting::ParseErrorReporter;
use font_face::{FontFaceRule, parse_font_face_block}; use font_face::{FontFaceRule, parse_font_face_block};
@ -106,7 +107,7 @@ impl MediaRule {
#[derive(Debug, PartialEq)] #[derive(Debug, PartialEq)]
pub struct StyleRule { pub struct StyleRule {
pub selectors: Vec<Selector<TheSelectorImpl>>, pub selectors: Vec<Selector<TheSelectorImpl>>,
pub declarations: Arc<PropertyDeclarationBlock>, pub block: Arc<DOMRefCell<PropertyDeclarationBlock>>,
} }
@ -558,7 +559,7 @@ impl<'a, 'b> QualifiedRuleParser for NestedRuleParser<'a, 'b> {
-> Result<CSSRule, ()> { -> Result<CSSRule, ()> {
Ok(CSSRule::Style(Arc::new(StyleRule { Ok(CSSRule::Style(Arc::new(StyleRule {
selectors: prelude, selectors: prelude,
declarations: Arc::new(parse_property_declaration_list(self.context, input)) block: Arc::new(DOMRefCell::new(parse_property_declaration_list(self.context, input)))
}))) })))
} }
} }

View file

@ -16,6 +16,7 @@ use std::sync::atomic::{AtomicBool, AtomicPtr, Ordering};
use style::arc_ptr_eq; use style::arc_ptr_eq;
use style::context::{LocalStyleContextCreationInfo, ReflowGoal, SharedStyleContext}; use style::context::{LocalStyleContextCreationInfo, ReflowGoal, SharedStyleContext};
use style::dom::{NodeInfo, TDocument, TElement, TNode}; use style::dom::{NodeInfo, TDocument, TElement, TNode};
use style::domrefcell::DOMRefCell;
use style::error_reporting::StdoutErrorReporter; use style::error_reporting::StdoutErrorReporter;
use style::gecko::data::{NUM_THREADS, PerDocumentStyleData}; use style::gecko::data::{NUM_THREADS, PerDocumentStyleData};
use style::gecko::selector_impl::{GeckoSelectorImpl, PseudoElement}; use style::gecko::selector_impl::{GeckoSelectorImpl, PseudoElement};
@ -344,7 +345,9 @@ pub extern "C" fn Servo_ParseStyleAttribute(bytes: *const u8, length: u32,
-> ServoDeclarationBlockStrong { -> ServoDeclarationBlockStrong {
let value = unsafe { from_utf8_unchecked(slice::from_raw_parts(bytes, length as usize)) }; let value = unsafe { from_utf8_unchecked(slice::from_raw_parts(bytes, length as usize)) };
Arc::new(GeckoDeclarationBlock { Arc::new(GeckoDeclarationBlock {
declarations: GeckoElement::parse_style_attribute(value).map(Arc::new), declarations: GeckoElement::parse_style_attribute(value).map(|block| {
Arc::new(DOMRefCell::new(block))
}),
cache: AtomicPtr::new(cache), cache: AtomicPtr::new(cache),
immutable: AtomicBool::new(false), immutable: AtomicBool::new(false),
}).into_strong() }).into_strong()

View file

@ -6,9 +6,11 @@ use cssparser::Parser;
use selectors::parser::{LocalName, ParserContext, parse_selector_list}; use selectors::parser::{LocalName, ParserContext, parse_selector_list};
use std::sync::Arc; use std::sync::Arc;
use string_cache::Atom; use string_cache::Atom;
use style::domrefcell::DOMRefCell;
use style::properties::{PropertyDeclarationBlock, PropertyDeclaration, DeclaredValue}; use style::properties::{PropertyDeclarationBlock, PropertyDeclaration, DeclaredValue};
use style::properties::{longhands, Importance}; use style::properties::{longhands, Importance};
use style::selector_matching::{Rule, SelectorMap}; use style::selector_matching::{Rule, SelectorMap};
use style::thread_state;
/// Helper method to get some Rules from selector strings. /// Helper method to get some Rules from selector strings.
/// Each sublist of the result contains the Rules for one StyleRule. /// Each sublist of the result contains the Rules for one StyleRule.
@ -19,14 +21,14 @@ fn get_mock_rules(css_selectors: &[&str]) -> Vec<Vec<Rule>> {
.unwrap().into_iter().map(|s| { .unwrap().into_iter().map(|s| {
Rule { Rule {
selector: s.complex_selector.clone(), selector: s.complex_selector.clone(),
declarations: Arc::new(PropertyDeclarationBlock { declarations: Arc::new(DOMRefCell::new(PropertyDeclarationBlock {
declarations: vec![ declarations: vec![
(PropertyDeclaration::Display(DeclaredValue::Value( (PropertyDeclaration::Display(DeclaredValue::Value(
longhands::display::SpecifiedValue::block)), longhands::display::SpecifiedValue::block)),
Importance::Normal), Importance::Normal),
], ],
important_count: 0, important_count: 0,
}), })),
specificity: s.specificity, specificity: s.specificity,
source_order: i, source_order: i,
} }
@ -99,6 +101,7 @@ fn test_insert() {
#[test] #[test]
fn test_get_universal_rules() { fn test_get_universal_rules() {
thread_state::initialize(thread_state::LAYOUT);
let map = get_mock_map(&["*|*", "#foo > *|*", ".klass", "#id"]); let map = get_mock_map(&["*|*", "#foo > *|*", ".klass", "#id"]);
let mut decls = vec![]; let mut decls = vec![];

View file

@ -9,6 +9,7 @@ use std::borrow::ToOwned;
use std::sync::Arc; use std::sync::Arc;
use std::sync::Mutex; use std::sync::Mutex;
use string_cache::{Atom, Namespace as NsAtom}; use string_cache::{Atom, Namespace as NsAtom};
use style::domrefcell::DOMRefCell;
use style::error_reporting::ParseErrorReporter; use style::error_reporting::ParseErrorReporter;
use style::keyframes::{Keyframe, KeyframeSelector, KeyframePercentage}; use style::keyframes::{Keyframe, KeyframeSelector, KeyframePercentage};
use style::parser::ParserContextExtraData; use style::parser::ParserContextExtraData;
@ -97,7 +98,7 @@ fn test_parse_stylesheet() {
specificity: (0 << 20) + (1 << 10) + (1 << 0), specificity: (0 << 20) + (1 << 10) + (1 << 0),
}, },
], ],
declarations: Arc::new(PropertyDeclarationBlock { block: Arc::new(DOMRefCell::new(PropertyDeclarationBlock {
declarations: vec![ declarations: vec![
(PropertyDeclaration::Display(DeclaredValue::Value( (PropertyDeclaration::Display(DeclaredValue::Value(
longhands::display::SpecifiedValue::none)), longhands::display::SpecifiedValue::none)),
@ -106,7 +107,7 @@ fn test_parse_stylesheet() {
Importance::Important), Importance::Important),
], ],
important_count: 2, important_count: 2,
}), })),
})), })),
CSSRule::Style(Arc::new(StyleRule { CSSRule::Style(Arc::new(StyleRule {
selectors: vec![ selectors: vec![
@ -145,14 +146,14 @@ fn test_parse_stylesheet() {
specificity: (0 << 20) + (0 << 10) + (1 << 0), specificity: (0 << 20) + (0 << 10) + (1 << 0),
}, },
], ],
declarations: Arc::new(PropertyDeclarationBlock { block: Arc::new(DOMRefCell::new(PropertyDeclarationBlock {
declarations: vec![ declarations: vec![
(PropertyDeclaration::Display(DeclaredValue::Value( (PropertyDeclaration::Display(DeclaredValue::Value(
longhands::display::SpecifiedValue::block)), longhands::display::SpecifiedValue::block)),
Importance::Normal), Importance::Normal),
], ],
important_count: 0, important_count: 0,
}), })),
})), })),
CSSRule::Style(Arc::new(StyleRule { CSSRule::Style(Arc::new(StyleRule {
selectors: vec![ selectors: vec![
@ -180,7 +181,7 @@ fn test_parse_stylesheet() {
specificity: (1 << 20) + (1 << 10) + (0 << 0), specificity: (1 << 20) + (1 << 10) + (0 << 0),
}, },
], ],
declarations: Arc::new(PropertyDeclarationBlock { block: Arc::new(DOMRefCell::new(PropertyDeclarationBlock {
declarations: vec![ declarations: vec![
(PropertyDeclaration::BackgroundColor(DeclaredValue::Value( (PropertyDeclaration::BackgroundColor(DeclaredValue::Value(
longhands::background_color::SpecifiedValue { longhands::background_color::SpecifiedValue {
@ -228,7 +229,7 @@ fn test_parse_stylesheet() {
Importance::Normal), Importance::Normal),
], ],
important_count: 0, important_count: 0,
}), })),
})), })),
CSSRule::Keyframes(Arc::new(KeyframesRule { CSSRule::Keyframes(Arc::new(KeyframesRule {
name: "foo".into(), name: "foo".into(),
@ -236,19 +237,19 @@ fn test_parse_stylesheet() {
Arc::new(Keyframe { Arc::new(Keyframe {
selector: KeyframeSelector::new_for_unit_testing( selector: KeyframeSelector::new_for_unit_testing(
vec![KeyframePercentage::new(0.)]), vec![KeyframePercentage::new(0.)]),
block: Arc::new(PropertyDeclarationBlock { block: Arc::new(DOMRefCell::new(PropertyDeclarationBlock {
declarations: vec![ declarations: vec![
(PropertyDeclaration::Width(DeclaredValue::Value( (PropertyDeclaration::Width(DeclaredValue::Value(
LengthOrPercentageOrAuto::Percentage(Percentage(0.)))), LengthOrPercentageOrAuto::Percentage(Percentage(0.)))),
Importance::Normal), Importance::Normal),
], ],
important_count: 0, important_count: 0,
}) }))
}), }),
Arc::new(Keyframe { Arc::new(Keyframe {
selector: KeyframeSelector::new_for_unit_testing( selector: KeyframeSelector::new_for_unit_testing(
vec![KeyframePercentage::new(1.)]), vec![KeyframePercentage::new(1.)]),
block: Arc::new(PropertyDeclarationBlock { block: Arc::new(DOMRefCell::new(PropertyDeclarationBlock {
declarations: vec![ declarations: vec![
(PropertyDeclaration::Width(DeclaredValue::Value( (PropertyDeclaration::Width(DeclaredValue::Value(
LengthOrPercentageOrAuto::Percentage(Percentage(1.)))), LengthOrPercentageOrAuto::Percentage(Percentage(1.)))),
@ -259,7 +260,7 @@ fn test_parse_stylesheet() {
Importance::Normal), Importance::Normal),
], ],
important_count: 0, important_count: 0,
}), })),
}), }),
] ]
})) }))