Use parking_lot::RwLock instead of DOMRefCell for PropertyDeclarationBlock

This commit is contained in:
Simon Sapin 2016-09-27 16:02:36 +02:00
parent d986fd2d2f
commit 89a29a7f12
24 changed files with 121 additions and 106 deletions

View file

@ -17,7 +17,7 @@ servo = ["serde/unstable", "serde", "serde_macros", "heapsize_plugin",
"style_traits/servo", "app_units/plugins",
"cssparser/heap_size", "cssparser/serde-serialization",
"selectors/unstable", "string_cache",
"url/heap_size", "plugins"]
"url/heap_size", "plugins", "parking_lot/nightly"]
testing = []
[dependencies]

View file

@ -383,7 +383,7 @@ fn compute_style_for_animation_step(context: &SharedStyleContext,
// TODO: avoiding this spurious clone might involve having to create
// an Arc in the below (more common case).
KeyframesStepValue::ComputedValues => style_from_cascade.clone(),
KeyframesStepValue::Declarations(ref declarations) => {
KeyframesStepValue::Declarations { block: ref declarations } => {
let declaration_block = ApplicableDeclarationBlock {
mixed_declarations: declarations.clone(),
importance: Importance::Normal,

View file

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

View file

@ -32,6 +32,7 @@ use gecko_bindings::structs::{nsChangeHint, nsIAtom, nsIContent, nsStyleContext}
use gecko_bindings::structs::OpaqueStyleData;
use gecko_bindings::sugar::ownership::{FFIArcHelpers, HasArcFFI, HasFFI};
use libc::uintptr_t;
use parking_lot::RwLock;
use parser::ParserContextExtraData;
use properties::{ComputedValues, parse_style_attribute};
use properties::PropertyDeclarationBlock;
@ -46,7 +47,6 @@ use std::ptr;
use std::sync::Arc;
use std::sync::atomic::{AtomicBool, AtomicPtr};
use string_cache::{Atom, Namespace, WeakAtom, WeakNamespace};
use style::domrefcell::DOMRefCell;
use url::Url;
pub struct NonOpaqueStyleData(AtomicRefCell<PersistentStyleData>);
@ -59,7 +59,7 @@ impl NonOpaqueStyleData {
pub struct GeckoDeclarationBlock {
pub declarations: Option<Arc<PropertyDeclarationBlock>>,
pub declarations: Option<Arc<RwLock<PropertyDeclarationBlock>>>,
// XXX The following two fields are made atomic to work around the
// ownership system so that they can be changed inside a shared
// instance. It wouldn't provide safety as Rust usually promises,
@ -469,7 +469,7 @@ impl<'le> TElement for GeckoElement<'le> {
unsafe { GeckoNode(&*(self.0 as *const _ as *const RawGeckoNode)) }
}
fn style_attribute(&self) -> Option<&Arc<DOMRefCell<PropertyDeclarationBlock>>> {
fn style_attribute(&self) -> Option<&Arc<RwLock<PropertyDeclarationBlock>>> {
let declarations = unsafe { Gecko_GetServoDeclarationBlock(self.0) };
if declarations.is_null() {
None

View file

@ -4,7 +4,7 @@
use cssparser::{AtRuleParser, Parser, QualifiedRuleParser, RuleListParser};
use cssparser::{DeclarationListParser, DeclarationParser};
use domrefcell::DOMRefCell;
use parking_lot::RwLock;
use parser::{ParserContext, log_css_error};
use properties::{Importance, PropertyDeclaration, PropertyDeclarationBlock};
use properties::PropertyDeclarationParseResult;
@ -69,7 +69,7 @@ impl KeyframeSelector {
}
/// A keyframe.
#[derive(Debug, Clone, PartialEq)]
#[derive(Debug, Clone)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
pub struct Keyframe {
pub selector: KeyframeSelector,
@ -79,23 +79,26 @@ pub struct Keyframe {
/// 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<_>`.
#[cfg_attr(feature = "servo", ignore_heap_size_of = "Arc")]
pub block: Arc<DOMRefCell<PropertyDeclarationBlock>>,
pub block: Arc<RwLock<PropertyDeclarationBlock>>,
}
/// A keyframes step value. This can be a synthetised keyframes animation, that
/// is, one autogenerated from the current computed values, or a list of
/// declarations to apply.
// TODO: Find a better name for this?
#[derive(Debug, Clone, PartialEq)]
#[derive(Debug, Clone)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
pub enum KeyframesStepValue {
/// See `Keyframe::declarations`s docs about the presence of `Importance`.
Declarations(Arc<DOMRefCell<PropertyDeclarationBlock>>),
Declarations {
#[cfg_attr(feature = "servo", ignore_heap_size_of = "Arc")]
block: Arc<RwLock<PropertyDeclarationBlock>>
},
ComputedValues,
}
/// A single step from a keyframe animation.
#[derive(Debug, Clone, PartialEq)]
#[derive(Debug, Clone)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
pub struct KeyframesStep {
/// The percentage of the animation duration when this step starts.
@ -116,9 +119,8 @@ impl KeyframesStep {
fn new(percentage: KeyframePercentage,
value: KeyframesStepValue) -> Self {
let declared_timing_function = match value {
KeyframesStepValue::Declarations(ref block) => {
// FIXME: Is this thread-safe?
unsafe { block.borrow_for_layout() }.declarations.iter().any(|&(ref prop_decl, _)| {
KeyframesStepValue::Declarations { ref block } => {
block.read().declarations.iter().any(|&(ref prop_decl, _)| {
match *prop_decl {
PropertyDeclaration::AnimationTimingFunction(..) => true,
_ => false,
@ -140,7 +142,7 @@ impl KeyframesStep {
/// of keyframes, in order.
///
/// It only takes into account animable properties.
#[derive(Debug, Clone, PartialEq)]
#[derive(Debug, Clone)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
pub struct KeyframesAnimation {
pub steps: Vec<KeyframesStep>,
@ -159,8 +161,7 @@ fn get_animated_properties(keyframe: &Keyframe) -> Vec<TransitionProperty> {
let mut ret = vec![];
// NB: declarations are already deduplicated, so we don't have to check for
// it here.
// FIXME: Is this thread-safe?
for &(ref declaration, _) in unsafe { keyframe.block.borrow_for_layout() }.declarations.iter() {
for &(ref declaration, _) in keyframe.block.read().declarations.iter() {
if let Some(property) = TransitionProperty::from_declaration(declaration) {
ret.push(property);
}
@ -184,8 +185,9 @@ impl KeyframesAnimation {
for keyframe in keyframes {
for percentage in keyframe.selector.0.iter() {
steps.push(KeyframesStep::new(*percentage,
KeyframesStepValue::Declarations(keyframe.block.clone())));
steps.push(KeyframesStep::new(*percentage, KeyframesStepValue::Declarations {
block: keyframe.block.clone(),
}));
}
}
@ -271,7 +273,7 @@ impl<'a> QualifiedRuleParser for KeyframeListParser<'a> {
}
Ok(Arc::new(Keyframe {
selector: prelude,
block: Arc::new(DOMRefCell::new(PropertyDeclarationBlock {
block: Arc::new(RwLock::new(PropertyDeclarationBlock {
declarations: declarations,
important_count: 0,
})),

View file

@ -13,7 +13,7 @@ use cascade_info::CascadeInfo;
use context::{SharedStyleContext, StyleContext};
use data::PersistentStyleData;
use dom::{NodeInfo, TElement, TNode, TRestyleDamage, UnsafeNode};
use properties::{ComputedValues, PropertyDeclarationBlock, cascade};
use properties::{ComputedValues, cascade};
use properties::longhands::display::computed_value as display;
use selector_impl::{PseudoElement, TheSelectorImpl};
use selector_matching::{ApplicableDeclarationBlock, Stylist};

View file

@ -29,7 +29,7 @@ use computed_values;
#[cfg(feature = "servo")] use logical_geometry::{LogicalMargin, PhysicalSide};
use logical_geometry::WritingMode;
use parser::{ParserContext, ParserContextExtraData, log_css_error};
use selector_matching::ApplicableDeclarationBlock;
use selector_matching::{ApplicableDeclarationBlock, ApplicableDeclarationBlockReadGuard};
use stylesheets::Origin;
use values::LocalToCss;
use values::HasViewportPercentage;
@ -1725,7 +1725,7 @@ mod lazy_static_module {
#[allow(unused_mut, unused_imports)]
fn cascade_with_cached_declarations(
viewport_size: Size2D<Au>,
applicable_declarations: &[ApplicableDeclarationBlock],
applicable_declarations: &[ApplicableDeclarationBlockReadGuard],
shareable: bool,
parent_style: &ComputedValues,
cached_style: &ComputedValues,
@ -1755,8 +1755,8 @@ fn cascade_with_cached_declarations(
let mut seen = PropertyBitField::new();
// Declaration blocks are stored in increasing precedence order,
// we want them in decreasing order here.
for sub_list in applicable_declarations.iter().rev() {
for declaration in sub_list.iter().rev() {
for block in applicable_declarations.iter().rev() {
for declaration in block.iter().rev() {
match *declaration {
% for style_struct in data.active_style_structs():
% for property in style_struct.longhands:
@ -1883,15 +1883,20 @@ pub fn cascade(viewport_size: Size2D<Au>,
None => (true, initial_values),
};
// Aquire locks for at least the lifetime of `specified_custom_properties`.
let applicable_declarations = applicable_declarations.iter()
.map(|block| block.read())
.collect::<Vec<_>>();
let inherited_custom_properties = inherited_style.custom_properties();
let mut custom_properties = None;
let mut specified_custom_properties = None;
let mut seen_custom = HashSet::new();
for sub_list in applicable_declarations.iter().rev() {
for declaration in sub_list.iter().rev() {
for block in applicable_declarations.iter().rev() {
for declaration in block.iter().rev() {
match *declaration {
PropertyDeclaration::Custom(ref name, ref value) => {
::custom_properties::cascade(
&mut custom_properties, &inherited_custom_properties,
&mut specified_custom_properties, &inherited_custom_properties,
&mut seen_custom, name, value)
}
_ => {}
@ -1899,11 +1904,11 @@ pub fn cascade(viewport_size: Size2D<Au>,
}
}
let custom_properties = ::custom_properties::finish_cascade(
custom_properties, &inherited_custom_properties);
specified_custom_properties, &inherited_custom_properties);
if let (Some(cached_style), Some(parent_style)) = (cached_style, parent_style) {
let style = cascade_with_cached_declarations(viewport_size,
applicable_declarations,
&applicable_declarations,
shareable,
parent_style,
cached_style,
@ -1944,8 +1949,8 @@ pub fn cascade(viewport_size: Size2D<Au>,
// virtual dispatch instead.
ComputedValues::do_cascade_property(|cascade_property| {
% for category_to_cascade_now in ["early", "other"]:
for sub_list in applicable_declarations.iter().rev() {
for declaration in sub_list.iter().rev() {
for block in applicable_declarations.iter().rev() {
for declaration in block.iter().rev() {
if let PropertyDeclaration::Custom(..) = *declaration {
continue
}

View file

@ -5,11 +5,11 @@
//! Selector matching.
use dom::PresentationalHintsSynthetizer;
use domrefcell::DOMRefCell;
use element_state::*;
use error_reporting::StdoutErrorReporter;
use keyframes::KeyframesAnimation;
use media_queries::{Device, MediaType};
use parking_lot::{RwLock, RwLockReadGuard};
use properties::{self, PropertyDeclaration, PropertyDeclarationBlock, ComputedValues, Importance};
use quickersort::sort_by;
use restyle_hints::{RestyleHint, DependencySet};
@ -333,7 +333,7 @@ impl Stylist {
&self,
element: &E,
parent_bf: Option<&BloomFilter>,
style_attribute: Option<&Arc<DOMRefCell<PropertyDeclarationBlock>>>,
style_attribute: Option<&Arc<RwLock<PropertyDeclarationBlock>>>,
pseudo_element: Option<&PseudoElement>,
applicable_declarations: &mut V,
reason: MatchingReason) -> StyleRelations
@ -393,8 +393,7 @@ impl Stylist {
// Step 4: Normal style attributes.
if let Some(sa) = style_attribute {
// FIXME: Is this thread-safe?
if unsafe { sa.borrow_for_layout() }.any_normal() {
if sa.read().any_normal() {
relations |= AFFECTED_BY_STYLE_ATTRIBUTE;
Push::push(
applicable_declarations,
@ -416,8 +415,7 @@ impl Stylist {
// Step 6: `!important` style attributes.
if let Some(sa) = style_attribute {
// FIXME: Is this thread-safe?
if unsafe { sa.borrow_for_layout() }.any_important() {
if sa.read().any_important() {
relations |= AFFECTED_BY_STYLE_ATTRIBUTE;
Push::push(
applicable_declarations,
@ -709,8 +707,7 @@ impl SelectorMap {
for rule in self.other_rules.iter() {
if rule.selector.compound_selector.is_empty() &&
rule.selector.next.is_none() {
// FIXME: Is this thread-safe?
let block = unsafe { rule.declarations.borrow_for_layout() };
let block = rule.declarations.read();
if block.any_normal() {
matching_rules_list.push(
rule.to_applicable_declaration_block(Importance::Normal));
@ -764,8 +761,7 @@ impl SelectorMap {
V: VecLike<ApplicableDeclarationBlock>
{
for rule in rules.iter() {
// FIXME: Is this thread-safe?
let block = unsafe { rule.declarations.borrow_for_layout() };
let block = rule.declarations.read();
let any_declaration_for_importance = if importance.important() {
block.any_important()
} else {
@ -853,7 +849,7 @@ pub struct Rule {
#[cfg_attr(feature = "servo", ignore_heap_size_of = "Arc")]
pub selector: Arc<ComplexSelector<TheSelectorImpl>>,
#[cfg_attr(feature = "servo", ignore_heap_size_of = "Arc")]
pub declarations: Arc<DOMRefCell<PropertyDeclarationBlock>>,
pub declarations: Arc<RwLock<PropertyDeclarationBlock>>,
pub source_order: usize,
pub specificity: u32,
}
@ -878,7 +874,7 @@ pub struct ApplicableDeclarationBlock {
/// Contains declarations of either importance, but only those of self.importance are relevant.
/// Use ApplicableDeclarationBlock::iter
#[cfg_attr(feature = "servo", ignore_heap_size_of = "Arc")]
pub mixed_declarations: Arc<DOMRefCell<PropertyDeclarationBlock>>,
pub mixed_declarations: Arc<RwLock<PropertyDeclarationBlock>>,
pub importance: Importance,
pub source_order: usize,
pub specificity: u32,
@ -886,7 +882,7 @@ pub struct ApplicableDeclarationBlock {
impl ApplicableDeclarationBlock {
#[inline]
pub fn from_declarations(declarations: Arc<DOMRefCell<PropertyDeclarationBlock>>,
pub fn from_declarations(declarations: Arc<RwLock<PropertyDeclarationBlock>>,
importance: Importance)
-> Self {
ApplicableDeclarationBlock {
@ -897,11 +893,24 @@ impl ApplicableDeclarationBlock {
}
}
#[allow(unsafe_code)]
pub fn read(&self) -> ApplicableDeclarationBlockReadGuard {
ApplicableDeclarationBlockReadGuard {
guard: self.mixed_declarations.read(),
importance: self.importance,
}
}
}
pub struct ApplicableDeclarationBlockReadGuard<'a> {
guard: RwLockReadGuard<'a, PropertyDeclarationBlock>,
importance: Importance,
}
impl<'a> ApplicableDeclarationBlockReadGuard<'a> {
pub fn iter(&self) -> ApplicableDeclarationBlockIter {
ApplicableDeclarationBlockIter {
// FIXME: Is this thread-safe?
iter: unsafe { self.mixed_declarations.borrow_for_layout() }.declarations.iter(),
iter: self.guard.declarations.iter(),
importance: self.importance,
}
}

View file

@ -6,12 +6,12 @@
use cssparser::{AtRuleParser, Parser, QualifiedRuleParser, decode_stylesheet_bytes};
use cssparser::{AtRuleType, RuleListParser, Token};
use domrefcell::DOMRefCell;
use encoding::EncodingRef;
use error_reporting::ParseErrorReporter;
use font_face::{FontFaceRule, parse_font_face_block};
use keyframes::{Keyframe, parse_keyframe_list};
use media_queries::{Device, MediaQueryList, parse_media_query_list};
use parking_lot::RwLock;
use parser::{ParserContext, ParserContextExtraData, log_css_error};
use properties::{PropertyDeclarationBlock, parse_property_declaration_list};
use selector_impl::TheSelectorImpl;
@ -43,7 +43,7 @@ pub enum Origin {
}
#[derive(Debug, PartialEq)]
#[derive(Debug)]
pub struct Stylesheet {
/// List of rules in the order they were found (important for
/// cascading order)
@ -62,7 +62,7 @@ pub struct UserAgentStylesheets {
}
#[derive(Debug, PartialEq)]
#[derive(Debug)]
pub enum CSSRule {
// No Charset here, CSSCharsetRule has been removed from CSSOM
// https://drafts.csswg.org/cssom/#changes-from-5-december-2013
@ -84,13 +84,13 @@ pub struct NamespaceRule {
pub url: Namespace,
}
#[derive(Debug, PartialEq)]
#[derive(Debug)]
pub struct KeyframesRule {
pub name: Atom,
pub keyframes: Vec<Arc<Keyframe>>,
}
#[derive(Debug, PartialEq)]
#[derive(Debug)]
pub struct MediaRule {
pub media_queries: Arc<MediaQueryList>,
pub rules: Vec<CSSRule>,
@ -104,10 +104,10 @@ impl MediaRule {
}
}
#[derive(Debug, PartialEq)]
#[derive(Debug)]
pub struct StyleRule {
pub selectors: Vec<Selector<TheSelectorImpl>>,
pub block: Arc<DOMRefCell<PropertyDeclarationBlock>>,
pub block: Arc<RwLock<PropertyDeclarationBlock>>,
}
@ -559,7 +559,7 @@ impl<'a, 'b> QualifiedRuleParser for NestedRuleParser<'a, 'b> {
-> Result<CSSRule, ()> {
Ok(CSSRule::Style(Arc::new(StyleRule {
selectors: prelude,
block: Arc::new(DOMRefCell::new(parse_property_declaration_list(self.context, input)))
block: Arc::new(RwLock::new(parse_property_declaration_list(self.context, input)))
})))
}
}