mirror of
https://github.com/servo/servo.git
synced 2025-08-10 07:55:33 +01:00
Auto merge of #13459 - servo:no-arc-heapsize, r=emilio
Use parking_lot::RwLock for PropertyDeclarationBlock <!-- Please describe your changes on the following line: --> As discussed in https://bugzilla.mozilla.org/show_bug.cgi?id=1305141 Closes #13176 --- Original PR title: Stop relying on `impl<T: HeapSizeOf> HeapSizeOf for Arc<T>` https://github.com/servo/heapsize/issues/37#issuecomment-249861171 This builds on top of that. --- <!-- Thank you for contributing to Servo! Please replace each `[ ]` by `[X]` when the step is complete, and replace `__` with appropriate data: --> - [x] `./mach build -d` does not report any errors - [x] `./mach test-tidy` does not report any errors - [ ] These changes fix #__ (github issue number if applicable). <!-- Either: --> - [ ] There are tests for these changes OR - [x] These changes do not require tests because refactor <!-- Pull requests that do not address these steps are welcome, but they will require additional verification as part of the review process. --> <!-- 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/13459) <!-- Reviewable:end -->
This commit is contained in:
commit
aea9545e16
46 changed files with 313 additions and 265 deletions
|
@ -16,8 +16,8 @@ gecko = []
|
|||
servo = ["serde/unstable", "serde", "serde_macros", "heapsize_plugin",
|
||||
"style_traits/servo", "app_units/plugins",
|
||||
"cssparser/heap_size", "cssparser/serde-serialization",
|
||||
"selectors/heap_size", "selectors/unstable", "string_cache",
|
||||
"url/heap_size", "plugins"]
|
||||
"selectors/unstable", "string_cache",
|
||||
"url/heap_size", "plugins", "parking_lot/nightly"]
|
||||
testing = []
|
||||
|
||||
[dependencies]
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
use atomic_refcell::{AtomicRef, AtomicRefMut};
|
||||
use data::PersistentStyleData;
|
||||
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};
|
||||
|
@ -202,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<PropertyDeclarationBlock>>;
|
||||
fn style_attribute(&self) -> Option<&Arc<RwLock<PropertyDeclarationBlock>>>;
|
||||
|
||||
fn get_state(&self) -> ElementState;
|
||||
|
||||
|
|
|
@ -1,129 +0,0 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
//! A shareable mutable container for the DOM.
|
||||
|
||||
use refcell::{BorrowError, BorrowMutError, Ref, RefCell, RefMut};
|
||||
use thread_state;
|
||||
|
||||
/// A mutable field in the DOM.
|
||||
///
|
||||
/// This extends the API of `core::cell::RefCell` to allow unsafe access in
|
||||
/// certain situations, with dynamic checking in debug builds.
|
||||
#[derive(Clone)]
|
||||
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
|
||||
pub struct DOMRefCell<T> {
|
||||
value: RefCell<T>,
|
||||
}
|
||||
|
||||
// Functionality specific to Servo's `DOMRefCell` type
|
||||
// ===================================================
|
||||
|
||||
impl<T> DOMRefCell<T> {
|
||||
/// Return a reference to the contents.
|
||||
///
|
||||
/// For use in the layout thread only.
|
||||
#[allow(unsafe_code)]
|
||||
pub unsafe fn borrow_for_layout(&self) -> &T {
|
||||
debug_assert!(thread_state::get().is_layout());
|
||||
&*self.value.as_ptr()
|
||||
}
|
||||
|
||||
/// Borrow the contents for the purpose of GC tracing.
|
||||
///
|
||||
/// This succeeds even if the object is mutably borrowed,
|
||||
/// so you have to be careful in trace code!
|
||||
#[allow(unsafe_code)]
|
||||
pub unsafe fn borrow_for_gc_trace(&self) -> &T {
|
||||
// FIXME: IN_GC isn't reliable enough - doesn't catch minor GCs
|
||||
// https://github.com/servo/servo/issues/6389
|
||||
// debug_assert!(thread_state::get().contains(SCRIPT | IN_GC));
|
||||
&*self.value.as_ptr()
|
||||
}
|
||||
|
||||
/// Borrow the contents for the purpose of script deallocation.
|
||||
///
|
||||
#[allow(unsafe_code)]
|
||||
pub unsafe fn borrow_for_script_deallocation(&self) -> &mut T {
|
||||
debug_assert!(thread_state::get().contains(thread_state::SCRIPT));
|
||||
&mut *self.value.as_ptr()
|
||||
}
|
||||
|
||||
/// Version of the above that we use during restyle while the script thread
|
||||
/// is blocked.
|
||||
pub fn borrow_mut_for_layout(&self) -> RefMut<T> {
|
||||
debug_assert!(thread_state::get().is_layout());
|
||||
self.value.borrow_mut()
|
||||
}
|
||||
}
|
||||
|
||||
// Functionality duplicated with `core::cell::RefCell`
|
||||
// ===================================================
|
||||
impl<T> DOMRefCell<T> {
|
||||
/// Create a new `DOMRefCell` containing `value`.
|
||||
pub fn new(value: T) -> DOMRefCell<T> {
|
||||
DOMRefCell {
|
||||
value: RefCell::new(value),
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// Immutably borrows the wrapped value.
|
||||
///
|
||||
/// The borrow lasts until the returned `Ref` exits scope. Multiple
|
||||
/// immutable borrows can be taken out at the same time.
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// Panics if this is called off the script thread.
|
||||
///
|
||||
/// Panics if the value is currently mutably borrowed.
|
||||
pub fn borrow(&self) -> Ref<T> {
|
||||
self.try_borrow().expect("DOMRefCell<T> already mutably borrowed")
|
||||
}
|
||||
|
||||
/// Mutably borrows the wrapped value.
|
||||
///
|
||||
/// The borrow lasts until the returned `RefMut` exits scope. The value
|
||||
/// cannot be borrowed while this borrow is active.
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// Panics if this is called off the script thread.
|
||||
///
|
||||
/// Panics if the value is currently borrowed.
|
||||
pub fn borrow_mut(&self) -> RefMut<T> {
|
||||
self.try_borrow_mut().expect("DOMRefCell<T> already borrowed")
|
||||
}
|
||||
|
||||
/// Attempts to immutably borrow the wrapped value.
|
||||
///
|
||||
/// The borrow lasts until the returned `Ref` exits scope. Multiple
|
||||
/// immutable borrows can be taken out at the same time.
|
||||
///
|
||||
/// Returns `None` if the value is currently mutably borrowed.
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// Panics if this is called off the script thread.
|
||||
pub fn try_borrow(&self) -> Result<Ref<T>, BorrowError<T>> {
|
||||
debug_assert!(thread_state::get().is_script());
|
||||
self.value.try_borrow()
|
||||
}
|
||||
|
||||
/// Mutably borrows the wrapped value.
|
||||
///
|
||||
/// The borrow lasts until the returned `RefMut` exits scope. The value
|
||||
/// cannot be borrowed while this borrow is active.
|
||||
///
|
||||
/// Returns `None` if the value is currently borrowed.
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// Panics if this is called off the script thread.
|
||||
pub fn try_borrow_mut(&self) -> Result<RefMut<T>, BorrowMutError<T>> {
|
||||
debug_assert!(thread_state::get().is_script());
|
||||
self.value.try_borrow_mut()
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
|
@ -58,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,
|
||||
|
@ -468,7 +469,7 @@ impl<'le> TElement for GeckoElement<'le> {
|
|||
unsafe { GeckoNode(&*(self.0 as *const _ as *const RawGeckoNode)) }
|
||||
}
|
||||
|
||||
fn style_attribute(&self) -> Option<&Arc<PropertyDeclarationBlock>> {
|
||||
fn style_attribute(&self) -> Option<&Arc<RwLock<PropertyDeclarationBlock>>> {
|
||||
let declarations = unsafe { Gecko_GetServoDeclarationBlock(self.0) };
|
||||
if declarations.is_null() {
|
||||
None
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
|
||||
use cssparser::{AtRuleParser, Parser, QualifiedRuleParser, RuleListParser};
|
||||
use cssparser::{DeclarationListParser, DeclarationParser};
|
||||
use parking_lot::RwLock;
|
||||
use parser::{ParserContext, log_css_error};
|
||||
use properties::{Importance, PropertyDeclaration, PropertyDeclarationBlock};
|
||||
use properties::PropertyDeclarationParseResult;
|
||||
|
@ -68,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,
|
||||
|
@ -77,23 +78,27 @@ pub struct Keyframe {
|
|||
/// so the second value of these tuples is always `Importance::Normal`.
|
||||
/// 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<_>`.
|
||||
pub block: Arc<PropertyDeclarationBlock>,
|
||||
#[cfg_attr(feature = "servo", ignore_heap_size_of = "Arc")]
|
||||
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<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.
|
||||
|
@ -109,12 +114,13 @@ pub struct KeyframesStep {
|
|||
}
|
||||
|
||||
impl KeyframesStep {
|
||||
#[allow(unsafe_code)]
|
||||
#[inline]
|
||||
fn new(percentage: KeyframePercentage,
|
||||
value: KeyframesStepValue) -> Self {
|
||||
let declared_timing_function = match value {
|
||||
KeyframesStepValue::Declarations(ref block) => {
|
||||
block.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,
|
||||
|
@ -136,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>,
|
||||
|
@ -150,11 +156,12 @@ pub struct KeyframesAnimation {
|
|||
///
|
||||
/// 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.
|
||||
#[allow(unsafe_code)]
|
||||
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.
|
||||
for &(ref declaration, _) in keyframe.block.declarations.iter() {
|
||||
for &(ref declaration, _) in keyframe.block.read().declarations.iter() {
|
||||
if let Some(property) = TransitionProperty::from_declaration(declaration) {
|
||||
ret.push(property);
|
||||
}
|
||||
|
@ -178,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(),
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -265,10 +273,10 @@ impl<'a> QualifiedRuleParser for KeyframeListParser<'a> {
|
|||
}
|
||||
Ok(Arc::new(Keyframe {
|
||||
selector: prelude,
|
||||
block: Arc::new(PropertyDeclarationBlock {
|
||||
block: Arc::new(RwLock::new(PropertyDeclarationBlock {
|
||||
declarations: declarations,
|
||||
important_count: 0,
|
||||
}),
|
||||
})),
|
||||
}))
|
||||
}
|
||||
}
|
||||
|
|
|
@ -90,7 +90,6 @@ pub mod context;
|
|||
pub mod custom_properties;
|
||||
pub mod data;
|
||||
pub mod dom;
|
||||
pub mod domrefcell;
|
||||
pub mod element_state;
|
||||
pub mod error_reporting;
|
||||
pub mod font_face;
|
||||
|
|
|
@ -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};
|
||||
|
@ -24,6 +24,7 @@ use sink::ForgetfulSink;
|
|||
use smallvec::SmallVec;
|
||||
use std::collections::HashMap;
|
||||
use std::hash::{BuildHasherDefault, Hash, Hasher};
|
||||
use std::ops::Deref;
|
||||
use std::slice::IterMut;
|
||||
use std::sync::Arc;
|
||||
use string_cache::Atom;
|
||||
|
@ -139,7 +140,7 @@ impl<'a> Hash for ApplicableDeclarationsCacheQuery<'a> {
|
|||
for declaration in self.declarations {
|
||||
// Each declaration contians an Arc, which is a stable
|
||||
// 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);
|
||||
declaration.importance.hash(state);
|
||||
}
|
||||
|
@ -502,7 +503,13 @@ trait PrivateMatchMethods: TNode {
|
|||
-> Arc<ComputedValues>
|
||||
where Ctx: StyleContext<'a>
|
||||
{
|
||||
let mut cacheable = true;
|
||||
// Don’t cache applicable declarations for elements with a style attribute.
|
||||
// Since the style attribute contributes to that set, no other element would have the same set
|
||||
// and the cache would not be effective anyway.
|
||||
// This also works around the test failures at
|
||||
// https://github.com/servo/servo/pull/13459#issuecomment-250717584
|
||||
let has_style_attribute = self.as_element().map_or(false, |e| e.style_attribute().is_some());
|
||||
let mut cacheable = !has_style_attribute;
|
||||
let shared_context = context.shared_context();
|
||||
if animate_properties {
|
||||
cacheable = !self.update_animations_for_cascade(shared_context,
|
||||
|
|
|
@ -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;
|
||||
|
@ -311,6 +311,10 @@ impl PropertyDeclarationBlock {
|
|||
pub fn any_normal(&self) -> bool {
|
||||
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 {
|
||||
|
@ -741,7 +745,7 @@ impl Shorthand {
|
|||
|
||||
/// Serializes possible shorthand value to 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 mut result = String::new();
|
||||
append_declaration_value(&mut result, appendable_value, importance).unwrap();
|
||||
|
@ -755,7 +759,7 @@ impl Shorthand {
|
|||
declarations: I,
|
||||
is_first_serialization: &mut bool)
|
||||
-> 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) {
|
||||
None => Ok(false),
|
||||
Some(appendable_value) => {
|
||||
|
@ -772,8 +776,10 @@ impl Shorthand {
|
|||
}
|
||||
}
|
||||
|
||||
fn get_shorthand_appendable_value<'a, I>(self, declarations: I) -> Option<AppendableValue<'a, I>>
|
||||
where I: Iterator<Item=&'a PropertyDeclaration> + Clone {
|
||||
fn get_shorthand_appendable_value<'a, I>(self, declarations: I)
|
||||
-> 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.
|
||||
let mut declarations2 = declarations.clone();
|
||||
|
@ -1378,7 +1384,7 @@ pub use gecko_properties::ComputedValues;
|
|||
pub type ServoComputedValues = ComputedValues;
|
||||
|
||||
#[cfg(feature = "servo")]
|
||||
#[cfg_attr(feature = "servo", derive(Clone, Debug, HeapSizeOf))]
|
||||
#[cfg_attr(feature = "servo", derive(Clone, Debug))]
|
||||
pub struct ComputedValues {
|
||||
% for style_struct in data.active_style_structs():
|
||||
${style_struct.ident}: Arc<style_structs::${style_struct.name}>,
|
||||
|
@ -1719,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,
|
||||
|
@ -1749,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:
|
||||
|
@ -1877,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)
|
||||
}
|
||||
_ => {}
|
||||
|
@ -1893,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,
|
||||
|
@ -1938,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
|
||||
}
|
||||
|
|
|
@ -15,7 +15,6 @@
|
|||
|
||||
#![allow(unsafe_code)]
|
||||
|
||||
#[cfg(feature = "servo")] use heapsize::HeapSizeOf;
|
||||
use std::cell::{UnsafeCell, Cell};
|
||||
use std::cmp::Ordering;
|
||||
use std::fmt::{self, Debug, Display};
|
||||
|
@ -32,13 +31,6 @@ pub struct RefCell<T: ?Sized> {
|
|||
value: UnsafeCell<T>,
|
||||
}
|
||||
|
||||
#[cfg(feature = "servo")]
|
||||
impl<T: HeapSizeOf> HeapSizeOf for RefCell<T> {
|
||||
fn heap_size_of_children(&self) -> usize {
|
||||
self.borrow().heap_size_of_children()
|
||||
}
|
||||
}
|
||||
|
||||
/// An enumeration of values returned from the `state` method on a `RefCell<T>`.
|
||||
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
|
||||
pub enum BorrowState {
|
||||
|
@ -535,18 +527,6 @@ impl<'b, T: ?Sized> Ref<'b, T> {
|
|||
borrow: orig.borrow,
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn filter_map<U: ?Sized, F>(orig: Ref<'b, T>, f: F) -> Option<Ref<'b, U>>
|
||||
where F: FnOnce(&T) -> Option<&U>
|
||||
{
|
||||
f(orig.value).map(move |new_value| {
|
||||
Ref {
|
||||
value: new_value,
|
||||
borrow: orig.borrow,
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl<'b, T: ?Sized> RefMut<'b, T> {
|
||||
|
|
|
@ -340,6 +340,7 @@ impl Sensitivities {
|
|||
#[derive(Debug)]
|
||||
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
|
||||
struct Dependency {
|
||||
#[cfg_attr(feature = "servo", ignore_heap_size_of = "Arc")]
|
||||
selector: Arc<ComplexSelector<TheSelectorImpl>>,
|
||||
hint: RestyleHint,
|
||||
sensitivities: Sensitivities,
|
||||
|
|
|
@ -9,6 +9,7 @@ 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};
|
||||
|
@ -78,10 +79,12 @@ pub struct Stylist {
|
|||
state_deps: DependencySet,
|
||||
|
||||
/// Selectors in the page affecting siblings
|
||||
#[cfg_attr(feature = "servo", ignore_heap_size_of = "Arc")]
|
||||
sibling_affecting_selectors: Vec<Selector<TheSelectorImpl>>,
|
||||
|
||||
/// Selectors in the page matching elements with non-common style-affecting
|
||||
/// attributes.
|
||||
#[cfg_attr(feature = "servo", ignore_heap_size_of = "Arc")]
|
||||
non_common_style_affecting_attributes_selectors: Vec<Selector<TheSelectorImpl>>,
|
||||
}
|
||||
|
||||
|
@ -176,7 +179,7 @@ impl Stylist {
|
|||
|
||||
map.insert(Rule {
|
||||
selector: selector.complex_selector.clone(),
|
||||
declarations: style_rule.declarations.clone(),
|
||||
declarations: style_rule.block.clone(),
|
||||
specificity: selector.specificity,
|
||||
source_order: rules_source_order,
|
||||
});
|
||||
|
@ -325,11 +328,12 @@ impl Stylist {
|
|||
/// that is, whether the matched selectors are simple enough to allow the
|
||||
/// matching logic to be reduced to the logic in
|
||||
/// `css::matching::PrivateMatchMethods::candidate_element_allows_for_style_sharing`.
|
||||
#[allow(unsafe_code)]
|
||||
pub fn push_applicable_declarations<E, V>(
|
||||
&self,
|
||||
element: &E,
|
||||
parent_bf: Option<&BloomFilter>,
|
||||
style_attribute: Option<&Arc<PropertyDeclarationBlock>>,
|
||||
style_attribute: Option<&Arc<RwLock<PropertyDeclarationBlock>>>,
|
||||
pseudo_element: Option<&PseudoElement>,
|
||||
applicable_declarations: &mut V,
|
||||
reason: MatchingReason) -> StyleRelations
|
||||
|
@ -388,8 +392,8 @@ impl Stylist {
|
|||
debug!("author normal: {:?}", relations);
|
||||
|
||||
// Step 4: Normal style attributes.
|
||||
if let Some(sa) = style_attribute {
|
||||
if sa.any_normal() {
|
||||
if let Some(sa) = style_attribute {
|
||||
if sa.read().any_normal() {
|
||||
relations |= AFFECTED_BY_STYLE_ATTRIBUTE;
|
||||
Push::push(
|
||||
applicable_declarations,
|
||||
|
@ -411,7 +415,7 @@ impl Stylist {
|
|||
|
||||
// Step 6: `!important` style attributes.
|
||||
if let Some(sa) = style_attribute {
|
||||
if sa.any_important() {
|
||||
if sa.read().any_important() {
|
||||
relations |= AFFECTED_BY_STYLE_ATTRIBUTE;
|
||||
Push::push(
|
||||
applicable_declarations,
|
||||
|
@ -689,6 +693,7 @@ impl SelectorMap {
|
|||
|
||||
/// Append to `rule_list` all universal Rules (rules with selector `*|*`) in
|
||||
/// `self` sorted by specifity and source order.
|
||||
#[allow(unsafe_code)]
|
||||
pub fn get_universal_rules<V>(&self,
|
||||
matching_rules_list: &mut V)
|
||||
where V: VecLike<ApplicableDeclarationBlock>
|
||||
|
@ -702,11 +707,12 @@ impl SelectorMap {
|
|||
for rule in self.other_rules.iter() {
|
||||
if rule.selector.compound_selector.is_empty() &&
|
||||
rule.selector.next.is_none() {
|
||||
if rule.declarations.any_normal() {
|
||||
let block = rule.declarations.read();
|
||||
if block.any_normal() {
|
||||
matching_rules_list.push(
|
||||
rule.to_applicable_declaration_block(Importance::Normal));
|
||||
}
|
||||
if rule.declarations.any_important() {
|
||||
if block.any_important() {
|
||||
matching_rules_list.push(
|
||||
rule.to_applicable_declaration_block(Importance::Important));
|
||||
}
|
||||
|
@ -743,6 +749,7 @@ impl SelectorMap {
|
|||
}
|
||||
|
||||
/// Adds rules in `rules` that match `element` to the `matching_rules` list.
|
||||
#[allow(unsafe_code)]
|
||||
fn get_matching_rules<E, V>(element: &E,
|
||||
parent_bf: Option<&BloomFilter>,
|
||||
rules: &[Rule],
|
||||
|
@ -754,7 +761,7 @@ impl SelectorMap {
|
|||
V: VecLike<ApplicableDeclarationBlock>
|
||||
{
|
||||
for rule in rules.iter() {
|
||||
let block = &rule.declarations;
|
||||
let block = rule.declarations.read();
|
||||
let any_declaration_for_importance = if importance.important() {
|
||||
block.any_important()
|
||||
} else {
|
||||
|
@ -839,8 +846,10 @@ pub struct Rule {
|
|||
// This is an Arc because Rule will essentially be cloned for every element
|
||||
// that it matches. Selector contains an owned vector (through
|
||||
// ComplexSelector) and we want to avoid the allocation.
|
||||
#[cfg_attr(feature = "servo", ignore_heap_size_of = "Arc")]
|
||||
pub selector: Arc<ComplexSelector<TheSelectorImpl>>,
|
||||
pub declarations: Arc<PropertyDeclarationBlock>,
|
||||
#[cfg_attr(feature = "servo", ignore_heap_size_of = "Arc")]
|
||||
pub declarations: Arc<RwLock<PropertyDeclarationBlock>>,
|
||||
pub source_order: usize,
|
||||
pub specificity: u32,
|
||||
}
|
||||
|
@ -864,7 +873,8 @@ impl Rule {
|
|||
pub struct ApplicableDeclarationBlock {
|
||||
/// Contains declarations of either importance, but only those of self.importance are relevant.
|
||||
/// Use ApplicableDeclarationBlock::iter
|
||||
pub mixed_declarations: Arc<PropertyDeclarationBlock>,
|
||||
#[cfg_attr(feature = "servo", ignore_heap_size_of = "Arc")]
|
||||
pub mixed_declarations: Arc<RwLock<PropertyDeclarationBlock>>,
|
||||
pub importance: Importance,
|
||||
pub source_order: usize,
|
||||
pub specificity: u32,
|
||||
|
@ -872,7 +882,7 @@ pub struct ApplicableDeclarationBlock {
|
|||
|
||||
impl ApplicableDeclarationBlock {
|
||||
#[inline]
|
||||
pub fn from_declarations(declarations: Arc<PropertyDeclarationBlock>,
|
||||
pub fn from_declarations(declarations: Arc<RwLock<PropertyDeclarationBlock>>,
|
||||
importance: Importance)
|
||||
-> Self {
|
||||
ApplicableDeclarationBlock {
|
||||
|
@ -883,9 +893,24 @@ impl ApplicableDeclarationBlock {
|
|||
}
|
||||
}
|
||||
|
||||
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 {
|
||||
iter: self.mixed_declarations.declarations.iter(),
|
||||
iter: self.guard.declarations.iter(),
|
||||
importance: self.importance,
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,6 +11,7 @@ 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;
|
||||
|
@ -42,8 +43,7 @@ pub enum Origin {
|
|||
}
|
||||
|
||||
|
||||
#[derive(Debug, PartialEq)]
|
||||
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
|
||||
#[derive(Debug)]
|
||||
pub struct Stylesheet {
|
||||
/// List of rules in the order they were found (important for
|
||||
/// cascading order)
|
||||
|
@ -62,8 +62,7 @@ pub struct UserAgentStylesheets {
|
|||
}
|
||||
|
||||
|
||||
#[derive(Debug, PartialEq)]
|
||||
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
|
||||
#[derive(Debug)]
|
||||
pub enum CSSRule {
|
||||
// No Charset here, CSSCharsetRule has been removed from CSSOM
|
||||
// https://drafts.csswg.org/cssom/#changes-from-5-december-2013
|
||||
|
@ -85,15 +84,13 @@ pub struct NamespaceRule {
|
|||
pub url: Namespace,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq)]
|
||||
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
|
||||
#[derive(Debug)]
|
||||
pub struct KeyframesRule {
|
||||
pub name: Atom,
|
||||
pub keyframes: Vec<Arc<Keyframe>>,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq)]
|
||||
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
|
||||
#[derive(Debug)]
|
||||
pub struct MediaRule {
|
||||
pub media_queries: Arc<MediaQueryList>,
|
||||
pub rules: Vec<CSSRule>,
|
||||
|
@ -107,11 +104,10 @@ impl MediaRule {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq)]
|
||||
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
|
||||
#[derive(Debug)]
|
||||
pub struct StyleRule {
|
||||
pub selectors: Vec<Selector<TheSelectorImpl>>,
|
||||
pub declarations: Arc<PropertyDeclarationBlock>,
|
||||
pub block: Arc<RwLock<PropertyDeclarationBlock>>,
|
||||
}
|
||||
|
||||
|
||||
|
@ -563,7 +559,7 @@ impl<'a, 'b> QualifiedRuleParser for NestedRuleParser<'a, 'b> {
|
|||
-> Result<CSSRule, ()> {
|
||||
Ok(CSSRule::Style(Arc::new(StyleRule {
|
||||
selectors: prelude,
|
||||
declarations: Arc::new(parse_property_declaration_list(self.context, input))
|
||||
block: Arc::new(RwLock::new(parse_property_declaration_list(self.context, input)))
|
||||
})))
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue