mirror of
https://github.com/servo/servo.git
synced 2025-08-05 21:50:18 +01:00
Replace RwLock<StyleRule> with Locked<StyleRule>
This commit is contained in:
parent
57724e5a37
commit
aeffca2a59
33 changed files with 279 additions and 334 deletions
|
@ -40,7 +40,6 @@ nsstring_vendor = {path = "gecko_bindings/nsstring_vendor", optional = true}
|
|||
num-integer = "0.1.32"
|
||||
num-traits = "0.1.32"
|
||||
ordered-float = "0.4"
|
||||
owning_ref = "0.2.2"
|
||||
parking_lot = "0.3.3"
|
||||
pdqsort = "0.1.0"
|
||||
rayon = "0.6"
|
||||
|
|
|
@ -17,6 +17,7 @@ use parking_lot::RwLock;
|
|||
use selector_parser::PseudoElement;
|
||||
use selectors::matching::ElementSelectorFlags;
|
||||
use servo_config::opts;
|
||||
use shared_lock::ReadGuards;
|
||||
use std::collections::HashMap;
|
||||
use std::env;
|
||||
use std::fmt;
|
||||
|
@ -61,10 +62,13 @@ pub enum QuirksMode {
|
|||
///
|
||||
/// There's exactly one of these during a given restyle traversal, and it's
|
||||
/// shared among the worker threads.
|
||||
pub struct SharedStyleContext {
|
||||
pub struct SharedStyleContext<'a> {
|
||||
/// The CSS selector stylist.
|
||||
pub stylist: Arc<Stylist>,
|
||||
|
||||
/// Guards for pre-acquired locks
|
||||
pub guards: ReadGuards<'a>,
|
||||
|
||||
/// The animations that are currently running.
|
||||
pub running_animations: Arc<RwLock<HashMap<OpaqueNode, Vec<Animation>>>>,
|
||||
|
||||
|
@ -85,7 +89,7 @@ pub struct SharedStyleContext {
|
|||
pub quirks_mode: QuirksMode,
|
||||
}
|
||||
|
||||
impl SharedStyleContext {
|
||||
impl<'a> SharedStyleContext<'a> {
|
||||
/// Return a suitable viewport size in order to be used for viewport units.
|
||||
pub fn viewport_size(&self) -> Size2D<Au> {
|
||||
self.stylist.device.au_viewport_size()
|
||||
|
@ -306,7 +310,7 @@ impl<E: TElement> Drop for ThreadLocalStyleContext<E> {
|
|||
/// shared style context, and a mutable reference to a local one.
|
||||
pub struct StyleContext<'a, E: TElement + 'a> {
|
||||
/// The shared style context reference.
|
||||
pub shared: &'a SharedStyleContext,
|
||||
pub shared: &'a SharedStyleContext<'a>,
|
||||
/// The thread-local style context (mutable) reference.
|
||||
pub thread_local: &'a mut ThreadLocalStyleContext<E>,
|
||||
}
|
||||
|
|
|
@ -51,18 +51,7 @@ impl_arc_ffi!(ComputedValues => ServoComputedValues
|
|||
impl_arc_ffi!(RwLock<PropertyDeclarationBlock> => RawServoDeclarationBlock
|
||||
[Servo_DeclarationBlock_AddRef, Servo_DeclarationBlock_Release]);
|
||||
|
||||
/// FIXME: Remove once StyleRule is actually in Locked<_>
|
||||
pub trait HackHackHack {
|
||||
fn as_arc<'a>(ptr: &'a &RawServoStyleRule) -> &'a ::std::sync::Arc<RwLock<StyleRule>>;
|
||||
}
|
||||
|
||||
impl HackHackHack for Locked<StyleRule> {
|
||||
fn as_arc<'a>(ptr: &'a &RawServoStyleRule) -> &'a ::std::sync::Arc<RwLock<StyleRule>> {
|
||||
RwLock::<StyleRule>::as_arc(ptr)
|
||||
}
|
||||
}
|
||||
|
||||
impl_arc_ffi!(RwLock<StyleRule> => RawServoStyleRule
|
||||
impl_arc_ffi!(Locked<StyleRule> => RawServoStyleRule
|
||||
[Servo_StyleRule_AddRef, Servo_StyleRule_Release]);
|
||||
|
||||
impl_arc_ffi!(Locked<ImportRule> => RawServoImportRule
|
||||
|
|
|
@ -13,7 +13,7 @@ use gecko_bindings::sugar::ownership::{HasBoxFFI, HasFFI, HasSimpleFFI};
|
|||
use media_queries::Device;
|
||||
use parking_lot::RwLock;
|
||||
use properties::ComputedValues;
|
||||
use shared_lock::SharedRwLockReadGuard;
|
||||
use shared_lock::{ReadGuards, SharedRwLockReadGuard};
|
||||
use std::collections::HashMap;
|
||||
use std::sync::Arc;
|
||||
use std::sync::mpsc::{Receiver, Sender, channel};
|
||||
|
@ -97,7 +97,7 @@ impl PerDocumentStyleDataImpl {
|
|||
pub fn flush_stylesheets(&mut self, guard: &SharedRwLockReadGuard) {
|
||||
if self.stylesheets_changed {
|
||||
let mut stylist = Arc::get_mut(&mut self.stylist).unwrap();
|
||||
stylist.update(&self.stylesheets, guard, None, true);
|
||||
stylist.update(&self.stylesheets, &ReadGuards::same(guard), None, true);
|
||||
self.stylesheets_changed = false;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -13,14 +13,14 @@ use traversal::{DomTraversal, PerLevelTraversalData, TraversalDriver, recalc_sty
|
|||
|
||||
/// This is the simple struct that Gecko uses to encapsulate a DOM traversal for
|
||||
/// styling.
|
||||
pub struct RecalcStyleOnly {
|
||||
shared: SharedStyleContext,
|
||||
pub struct RecalcStyleOnly<'a> {
|
||||
shared: SharedStyleContext<'a>,
|
||||
driver: TraversalDriver,
|
||||
}
|
||||
|
||||
impl RecalcStyleOnly {
|
||||
impl<'a> RecalcStyleOnly<'a> {
|
||||
/// Create a `RecalcStyleOnly` traversal from a `SharedStyleContext`.
|
||||
pub fn new(shared: SharedStyleContext, driver: TraversalDriver) -> Self {
|
||||
pub fn new(shared: SharedStyleContext<'a>, driver: TraversalDriver) -> Self {
|
||||
RecalcStyleOnly {
|
||||
shared: shared,
|
||||
driver: driver,
|
||||
|
@ -28,10 +28,11 @@ impl RecalcStyleOnly {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'le> DomTraversal<GeckoElement<'le>> for RecalcStyleOnly {
|
||||
impl<'recalc, 'le> DomTraversal<GeckoElement<'le>> for RecalcStyleOnly<'recalc> {
|
||||
type ThreadLocalContext = ThreadLocalStyleContext<GeckoElement<'le>>;
|
||||
|
||||
fn process_preorder(&self, traversal_data: &mut PerLevelTraversalData,
|
||||
fn process_preorder(&self,
|
||||
traversal_data: &mut PerLevelTraversalData,
|
||||
thread_local: &mut Self::ThreadLocalContext,
|
||||
node: GeckoNode<'le>)
|
||||
{
|
||||
|
|
|
@ -60,7 +60,6 @@ extern crate matches;
|
|||
extern crate num_integer;
|
||||
extern crate num_traits;
|
||||
extern crate ordered_float;
|
||||
extern crate owning_ref;
|
||||
extern crate parking_lot;
|
||||
extern crate pdqsort;
|
||||
extern crate rayon;
|
||||
|
@ -99,7 +98,6 @@ pub mod keyframes;
|
|||
pub mod logical_geometry;
|
||||
pub mod matching;
|
||||
pub mod media_queries;
|
||||
pub mod owning_handle;
|
||||
pub mod parallel;
|
||||
pub mod parser;
|
||||
pub mod restyle_hints;
|
||||
|
|
|
@ -541,6 +541,7 @@ trait PrivateMatchMethods: TElement {
|
|||
let values =
|
||||
Arc::new(cascade(&shared_context.stylist.device,
|
||||
rule_node,
|
||||
&shared_context.guards,
|
||||
inherited_values,
|
||||
layout_parent_style,
|
||||
Some(&mut cascade_info),
|
||||
|
@ -784,6 +785,7 @@ pub trait MatchMethods : TElement {
|
|||
style_attribute,
|
||||
animation_rules,
|
||||
None,
|
||||
&context.shared.guards,
|
||||
&mut applicable_declarations,
|
||||
&mut flags);
|
||||
let primary_rule_node = compute_rule_node(context, &mut applicable_declarations);
|
||||
|
@ -809,6 +811,7 @@ pub trait MatchMethods : TElement {
|
|||
Some(context.thread_local.bloom_filter.filter()),
|
||||
None, pseudo_animation_rules,
|
||||
Some(&pseudo),
|
||||
&context.shared.guards,
|
||||
&mut applicable_declarations,
|
||||
&mut flags);
|
||||
|
||||
|
|
|
@ -1,89 +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/. */
|
||||
|
||||
#![allow(unsafe_code)]
|
||||
#![deny(missing_docs)]
|
||||
|
||||
//! A handle that encapsulate a reference to a given data along with its owner.
|
||||
|
||||
use owning_ref::StableAddress;
|
||||
use std::ops::{Deref, DerefMut};
|
||||
|
||||
/// `OwningHandle` is a complement to `OwningRef`. Where `OwningRef` allows
|
||||
/// consumers to pass around an owned object and a dependent reference,
|
||||
/// `OwningHandle` contains an owned object and a dependent _object_.
|
||||
///
|
||||
/// `OwningHandle` can encapsulate a `RefMut` along with its associated
|
||||
/// `RefCell`, or an `RwLockReadGuard` along with its associated `RwLock`.
|
||||
/// However, the API is completely generic and there are no restrictions on
|
||||
/// what types of owning and dependent objects may be used.
|
||||
///
|
||||
/// `OwningHandle` is created by passing an owner object (which dereferences
|
||||
/// to a stable address) along with a callback which receives a pointer to
|
||||
/// that stable location. The callback may then dereference the pointer and
|
||||
/// mint a dependent object, with the guarantee that the returned object will
|
||||
/// not outlive the referent of the pointer.
|
||||
///
|
||||
/// This does foist some unsafety onto the callback, which needs an `unsafe`
|
||||
/// block to dereference the pointer. It would be almost good enough for
|
||||
/// OwningHandle to pass a transmuted &'static reference to the callback
|
||||
/// since the lifetime is infinite as far as the minted handle is concerned.
|
||||
/// However, even an `Fn` callback can still allow the reference to escape
|
||||
/// via a `StaticMutex` or similar, which technically violates the safety
|
||||
/// contract. Some sort of language support in the lifetime system could
|
||||
/// make this API a bit nicer.
|
||||
pub struct OwningHandle<O, H>
|
||||
where O: StableAddress,
|
||||
H: Deref,
|
||||
{
|
||||
handle: H,
|
||||
_owner: O,
|
||||
}
|
||||
|
||||
impl<O, H> Deref for OwningHandle<O, H>
|
||||
where O: StableAddress,
|
||||
H: Deref,
|
||||
{
|
||||
type Target = H::Target;
|
||||
fn deref(&self) -> &H::Target {
|
||||
self.handle.deref()
|
||||
}
|
||||
}
|
||||
|
||||
unsafe impl<O, H> StableAddress for OwningHandle<O, H>
|
||||
where O: StableAddress,
|
||||
H: StableAddress,
|
||||
{}
|
||||
|
||||
impl<O, H> DerefMut for OwningHandle<O, H>
|
||||
where O: StableAddress,
|
||||
H: DerefMut,
|
||||
{
|
||||
fn deref_mut(&mut self) -> &mut H::Target {
|
||||
self.handle.deref_mut()
|
||||
}
|
||||
}
|
||||
|
||||
impl<O, H> OwningHandle<O, H>
|
||||
where O: StableAddress,
|
||||
H: Deref,
|
||||
{
|
||||
/// Create a new OwningHandle. The provided callback will be invoked with
|
||||
/// a pointer to the object owned by `o`, and the returned value is stored
|
||||
/// as the object to which this `OwningHandle` will forward `Deref` and
|
||||
/// `DerefMut`.
|
||||
pub fn new<F>(o: O, f: F) -> Self
|
||||
where F: Fn(*const O::Target) -> H,
|
||||
{
|
||||
let h: H;
|
||||
{
|
||||
h = f(o.deref() as *const O::Target);
|
||||
}
|
||||
|
||||
OwningHandle {
|
||||
handle: h,
|
||||
_owner: o,
|
||||
}
|
||||
}
|
||||
}
|
|
@ -31,6 +31,7 @@ use parser::{Parse, ParserContext, ParserContextExtraData};
|
|||
use properties::animated_properties::TransitionProperty;
|
||||
#[cfg(feature = "servo")] use servo_config::prefs::PREFS;
|
||||
use servo_url::ServoUrl;
|
||||
use shared_lock::ReadGuards;
|
||||
use style_traits::ToCss;
|
||||
use stylesheets::Origin;
|
||||
#[cfg(feature = "servo")] use values::Either;
|
||||
|
@ -1860,6 +1861,7 @@ bitflags! {
|
|||
///
|
||||
pub fn cascade(device: &Device,
|
||||
rule_node: &StrongRuleNode,
|
||||
guards: &ReadGuards,
|
||||
parent_style: Option<<&ComputedValues>,
|
||||
layout_parent_style: Option<<&ComputedValues>,
|
||||
cascade_info: Option<<&mut CascadeInfo>,
|
||||
|
@ -1882,11 +1884,12 @@ pub fn cascade(device: &Device,
|
|||
|
||||
// Hold locks until after the apply_declarations() call returns.
|
||||
// Use filter_map because the root node has no style source.
|
||||
let lock_guards = rule_node.self_and_ancestors().filter_map(|node| {
|
||||
node.style_source().map(|source| (source.read(), node.importance()))
|
||||
let declaration_blocks = rule_node.self_and_ancestors().filter_map(|node| {
|
||||
let guard = node.cascade_level().guard(guards);
|
||||
node.style_source().map(|source| (source.read(guard), node.importance()))
|
||||
}).collect::<Vec<_>>();
|
||||
let iter_declarations = || {
|
||||
lock_guards.iter().flat_map(|&(ref source, source_importance)| {
|
||||
declaration_blocks.iter().flat_map(|&(ref source, source_importance)| {
|
||||
source.declarations().iter()
|
||||
// Yield declarations later in source order (with more precedence) first.
|
||||
.rev()
|
||||
|
|
|
@ -10,9 +10,9 @@
|
|||
use arc_ptr_eq;
|
||||
#[cfg(feature = "servo")]
|
||||
use heapsize::HeapSizeOf;
|
||||
use owning_handle::OwningHandle;
|
||||
use parking_lot::{RwLock, RwLockReadGuard};
|
||||
use properties::{Importance, PropertyDeclarationBlock};
|
||||
use shared_lock::{Locked, ReadGuards, SharedRwLockReadGuard};
|
||||
use std::io::{self, Write};
|
||||
use std::ptr;
|
||||
use std::sync::Arc;
|
||||
|
@ -52,35 +52,11 @@ pub struct RuleTree {
|
|||
#[derive(Debug, Clone)]
|
||||
pub enum StyleSource {
|
||||
/// A style rule stable pointer.
|
||||
Style(Arc<RwLock<StyleRule>>),
|
||||
Style(Arc<Locked<StyleRule>>),
|
||||
/// A declaration block stable pointer.
|
||||
Declarations(Arc<RwLock<PropertyDeclarationBlock>>),
|
||||
}
|
||||
|
||||
type StyleSourceGuardHandle<'a> =
|
||||
OwningHandle<
|
||||
RwLockReadGuard<'a, StyleRule>,
|
||||
RwLockReadGuard<'a, PropertyDeclarationBlock>>;
|
||||
|
||||
/// A guard for a given style source.
|
||||
pub enum StyleSourceGuard<'a> {
|
||||
/// A guard for a style rule.
|
||||
Style(StyleSourceGuardHandle<'a>),
|
||||
/// A guard for a declaration block.
|
||||
Declarations(RwLockReadGuard<'a, PropertyDeclarationBlock>),
|
||||
}
|
||||
|
||||
impl<'a> ::std::ops::Deref for StyleSourceGuard<'a> {
|
||||
type Target = PropertyDeclarationBlock;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
match *self {
|
||||
StyleSourceGuard::Declarations(ref block) => &*block,
|
||||
StyleSourceGuard::Style(ref handle) => &*handle,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl StyleSource {
|
||||
#[inline]
|
||||
fn ptr_equals(&self, other: &Self) -> bool {
|
||||
|
@ -92,28 +68,27 @@ impl StyleSource {
|
|||
}
|
||||
}
|
||||
|
||||
fn dump<W: Write>(&self, writer: &mut W) {
|
||||
fn dump<W: Write>(&self, guard: &SharedRwLockReadGuard, writer: &mut W) {
|
||||
use self::StyleSource::*;
|
||||
|
||||
if let Style(ref rule) = *self {
|
||||
let _ = write!(writer, "{:?}", rule.read().selectors);
|
||||
let rule = rule.read_with(guard);
|
||||
let _ = write!(writer, "{:?}", rule.selectors);
|
||||
}
|
||||
|
||||
let _ = write!(writer, " -> {:?}", self.read().declarations());
|
||||
let _ = write!(writer, " -> {:?}", self.read(guard).declarations());
|
||||
}
|
||||
|
||||
/// Read the style source guard, and obtain thus read access to the
|
||||
/// underlying property declaration block.
|
||||
#[inline]
|
||||
pub fn read<'a>(&'a self) -> StyleSourceGuard<'a> {
|
||||
use self::StyleSource::*;
|
||||
match *self {
|
||||
Style(ref rule) => {
|
||||
let owning_ref = OwningHandle::new(rule.read(), |r| unsafe { &*r }.block.read());
|
||||
StyleSourceGuard::Style(owning_ref)
|
||||
}
|
||||
Declarations(ref block) => StyleSourceGuard::Declarations(block.read()),
|
||||
}
|
||||
pub fn read<'a>(&'a self, guard: &'a SharedRwLockReadGuard)
|
||||
-> RwLockReadGuard<'a, PropertyDeclarationBlock> {
|
||||
let block = match *self {
|
||||
StyleSource::Style(ref rule) => &rule.read_with(guard).block,
|
||||
StyleSource::Declarations(ref block) => block,
|
||||
};
|
||||
block.read()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -137,15 +112,15 @@ impl RuleTree {
|
|||
self.root.clone()
|
||||
}
|
||||
|
||||
fn dump<W: Write>(&self, writer: &mut W) {
|
||||
fn dump<W: Write>(&self, guards: &ReadGuards, writer: &mut W) {
|
||||
let _ = writeln!(writer, " + RuleTree");
|
||||
self.root.get().dump(writer, 0);
|
||||
self.root.get().dump(guards, writer, 0);
|
||||
}
|
||||
|
||||
/// Dump the rule tree to stdout.
|
||||
pub fn dump_stdout(&self) {
|
||||
pub fn dump_stdout(&self, guards: &ReadGuards) {
|
||||
let mut stdout = io::stdout();
|
||||
self.dump(&mut stdout);
|
||||
self.dump(guards, &mut stdout);
|
||||
}
|
||||
|
||||
/// Insert the given rules, that must be in proper order by specifity, and
|
||||
|
@ -307,6 +282,17 @@ pub enum CascadeLevel {
|
|||
}
|
||||
|
||||
impl CascadeLevel {
|
||||
/// Select a lock guard for this level
|
||||
pub fn guard<'a>(&self, guards: &'a ReadGuards<'a>) -> &'a SharedRwLockReadGuard<'a> {
|
||||
match *self {
|
||||
CascadeLevel::UANormal |
|
||||
CascadeLevel::UserNormal |
|
||||
CascadeLevel::UserImportant |
|
||||
CascadeLevel::UAImportant => guards.ua_or_user,
|
||||
_ => guards.author,
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns whether this cascade level is unique per element, in which case
|
||||
/// we can replace the path in the cascade without fear.
|
||||
pub fn is_unique_per_element(&self) -> bool {
|
||||
|
@ -450,7 +436,7 @@ impl RuleNode {
|
|||
}
|
||||
}
|
||||
|
||||
fn dump<W: Write>(&self, writer: &mut W, indent: usize) {
|
||||
fn dump<W: Write>(&self, guards: &ReadGuards, writer: &mut W, indent: usize) {
|
||||
const INDENT_INCREMENT: usize = 4;
|
||||
|
||||
for _ in 0..indent {
|
||||
|
@ -467,7 +453,7 @@ impl RuleNode {
|
|||
|
||||
match self.source {
|
||||
Some(ref source) => {
|
||||
source.dump(writer);
|
||||
source.dump(self.level.guard(guards), writer);
|
||||
}
|
||||
None => {
|
||||
if indent != 0 {
|
||||
|
@ -479,7 +465,7 @@ impl RuleNode {
|
|||
|
||||
let _ = write!(writer, "\n");
|
||||
for child in self.iter_children() {
|
||||
child.get().dump(writer, indent + INDENT_INCREMENT);
|
||||
child.get().dump(guards, writer, indent + INDENT_INCREMENT);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -627,6 +613,11 @@ impl StrongRuleNode {
|
|||
self.get().source.as_ref()
|
||||
}
|
||||
|
||||
/// The cascade level for this node
|
||||
pub fn cascade_level(&self) -> CascadeLevel {
|
||||
self.get().level
|
||||
}
|
||||
|
||||
/// Get the importance that this rule node represents.
|
||||
pub fn importance(&self) -> Importance {
|
||||
self.get().level.importance()
|
||||
|
|
|
@ -9,3 +9,13 @@
|
|||
pub mod media_queries;
|
||||
pub mod restyle_damage;
|
||||
pub mod selector_parser;
|
||||
|
||||
use shared_lock::SharedRwLock;
|
||||
|
||||
lazy_static! {
|
||||
/// Per-process shared lock for author-origin stylesheets
|
||||
///
|
||||
/// FIXME: make it per-document or per-pipeline instead:
|
||||
/// https://github.com/servo/servo/issues/16027
|
||||
pub static ref AUTHOR_SHARED_LOCK: SharedRwLock = SharedRwLock::new();
|
||||
}
|
||||
|
|
|
@ -177,3 +177,23 @@ pub trait ToCssWithGuard {
|
|||
s
|
||||
}
|
||||
}
|
||||
|
||||
/// Guards for a document
|
||||
#[derive(Clone)]
|
||||
pub struct ReadGuards<'a> {
|
||||
/// For author-origin stylesheets
|
||||
pub author: &'a SharedRwLockReadGuard<'a>,
|
||||
|
||||
/// For user-agent-origin and user-origin stylesheets
|
||||
pub ua_or_user: &'a SharedRwLockReadGuard<'a>,
|
||||
}
|
||||
|
||||
impl<'a> ReadGuards<'a> {
|
||||
/// Same guard for all origins
|
||||
pub fn same(guard: &'a SharedRwLockReadGuard<'a>) -> Self {
|
||||
ReadGuards {
|
||||
author: guard,
|
||||
ua_or_user: guard,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -215,7 +215,7 @@ pub enum CssRule {
|
|||
|
||||
Namespace(Arc<Locked<NamespaceRule>>),
|
||||
Import(Arc<Locked<ImportRule>>),
|
||||
Style(Arc<RwLock<StyleRule>>),
|
||||
Style(Arc<Locked<StyleRule>>),
|
||||
Media(Arc<Locked<MediaRule>>),
|
||||
FontFace(Arc<Locked<FontFaceRule>>),
|
||||
Viewport(Arc<Locked<ViewportRule>>),
|
||||
|
@ -380,7 +380,7 @@ impl ToCssWithGuard for CssRule {
|
|||
match *self {
|
||||
CssRule::Namespace(ref lock) => lock.read_with(guard).to_css(guard, dest),
|
||||
CssRule::Import(ref lock) => lock.read_with(guard).to_css(guard, dest),
|
||||
CssRule::Style(ref lock) => lock.read().to_css(guard, dest),
|
||||
CssRule::Style(ref lock) => lock.read_with(guard).to_css(guard, dest),
|
||||
CssRule::FontFace(ref lock) => lock.read_with(guard).to_css(guard, dest),
|
||||
CssRule::Viewport(ref lock) => lock.read_with(guard).to_css(guard, dest),
|
||||
CssRule::Keyframes(ref lock) => lock.read_with(guard).to_css(guard, dest),
|
||||
|
@ -736,18 +736,6 @@ rule_filter! {
|
|||
effective_supports_rules(Supports => SupportsRule),
|
||||
}
|
||||
|
||||
/// FIXME: Remove once StyleRule is actually in Locked<_>
|
||||
pub trait RwLockStyleRulePretendLockedStyleRule<T> {
|
||||
/// Pretend we’re Locked<_>
|
||||
fn read_with(&self, guard: &SharedRwLockReadGuard) -> ::parking_lot::RwLockReadGuard<T>;
|
||||
}
|
||||
|
||||
impl RwLockStyleRulePretendLockedStyleRule<StyleRule> for RwLock<StyleRule> {
|
||||
fn read_with(&self, _: &SharedRwLockReadGuard) -> ::parking_lot::RwLockReadGuard<StyleRule> {
|
||||
self.read()
|
||||
}
|
||||
}
|
||||
|
||||
/// The stylesheet loader is the abstraction used to trigger network requests
|
||||
/// for `@import` rules.
|
||||
pub trait StylesheetLoader {
|
||||
|
@ -1030,7 +1018,7 @@ impl<'a, 'b> QualifiedRuleParser for NestedRuleParser<'a, 'b> {
|
|||
|
||||
fn parse_block(&mut self, prelude: SelectorList<SelectorImpl>, input: &mut Parser)
|
||||
-> Result<CssRule, ()> {
|
||||
Ok(CssRule::Style(Arc::new(RwLock::new(StyleRule {
|
||||
Ok(CssRule::Style(Arc::new(self.shared_lock.wrap(StyleRule {
|
||||
selectors: prelude,
|
||||
block: Arc::new(RwLock::new(parse_property_declaration_list(self.context, input)))
|
||||
}))))
|
||||
|
|
|
@ -28,7 +28,7 @@ use selectors::matching::{AFFECTED_BY_STYLE_ATTRIBUTE, AFFECTED_BY_PRESENTATIONA
|
|||
use selectors::matching::{ElementSelectorFlags, StyleRelations, matches_complex_selector};
|
||||
use selectors::parser::{Selector, SimpleSelector, LocalName as LocalNameSelector, ComplexSelector};
|
||||
use selectors::parser::SelectorMethods;
|
||||
use shared_lock::SharedRwLockReadGuard;
|
||||
use shared_lock::{Locked, SharedRwLockReadGuard, ReadGuards};
|
||||
use sink::Push;
|
||||
use smallvec::VecLike;
|
||||
use std::borrow::Borrow;
|
||||
|
@ -159,7 +159,7 @@ impl Stylist {
|
|||
/// device is dirty, which means we need to re-evaluate media queries.
|
||||
pub fn update(&mut self,
|
||||
doc_stylesheets: &[Arc<Stylesheet>],
|
||||
doc_guard: &SharedRwLockReadGuard,
|
||||
guards: &ReadGuards,
|
||||
ua_stylesheets: Option<&UserAgentStylesheets>,
|
||||
stylesheets_changed: bool) -> bool {
|
||||
if !(self.is_device_dirty || stylesheets_changed) {
|
||||
|
@ -168,7 +168,7 @@ impl Stylist {
|
|||
|
||||
let cascaded_rule = ViewportRule {
|
||||
declarations: viewport::Cascade::from_stylesheets(
|
||||
doc_stylesheets, doc_guard, &self.device
|
||||
doc_stylesheets, guards.author, &self.device
|
||||
).finish(),
|
||||
};
|
||||
|
||||
|
@ -196,18 +196,17 @@ impl Stylist {
|
|||
self.non_common_style_affecting_attributes_selectors.clear();
|
||||
|
||||
if let Some(ua_stylesheets) = ua_stylesheets {
|
||||
let ua_guard = ua_stylesheets.shared_lock.read();
|
||||
for stylesheet in &ua_stylesheets.user_or_user_agent_stylesheets {
|
||||
self.add_stylesheet(&stylesheet, &ua_guard);
|
||||
self.add_stylesheet(&stylesheet, guards.ua_or_user);
|
||||
}
|
||||
|
||||
if self.quirks_mode {
|
||||
self.add_stylesheet(&ua_stylesheets.quirks_mode_stylesheet, &ua_guard);
|
||||
self.add_stylesheet(&ua_stylesheets.quirks_mode_stylesheet, guards.ua_or_user);
|
||||
}
|
||||
}
|
||||
|
||||
for ref stylesheet in doc_stylesheets.iter() {
|
||||
self.add_stylesheet(stylesheet, doc_guard);
|
||||
self.add_stylesheet(stylesheet, guards.author);
|
||||
}
|
||||
|
||||
debug!("Stylist stats:");
|
||||
|
@ -221,8 +220,9 @@ impl Stylist {
|
|||
SelectorImpl::each_precomputed_pseudo_element(|pseudo| {
|
||||
if let Some(map) = self.pseudos_map.remove(&pseudo) {
|
||||
let declarations =
|
||||
map.user_agent.get_universal_rules(CascadeLevel::UANormal,
|
||||
CascadeLevel::UAImportant);
|
||||
map.user_agent.get_universal_rules(
|
||||
guards.ua_or_user, CascadeLevel::UANormal, CascadeLevel::UAImportant
|
||||
);
|
||||
self.precomputed_pseudo_element_decls.insert(pseudo, declarations);
|
||||
}
|
||||
});
|
||||
|
@ -241,9 +241,9 @@ impl Stylist {
|
|||
|
||||
stylesheet.effective_rules(&device, guard, |rule| {
|
||||
match *rule {
|
||||
CssRule::Style(ref style_rule) => {
|
||||
let guard = style_rule.read();
|
||||
for selector in &guard.selectors.0 {
|
||||
CssRule::Style(ref locked) => {
|
||||
let style_rule = locked.read_with(&guard);
|
||||
for selector in &style_rule.selectors.0 {
|
||||
let map = if let Some(ref pseudo) = selector.pseudo_element {
|
||||
self.pseudos_map
|
||||
.entry(pseudo.clone())
|
||||
|
@ -255,14 +255,14 @@ impl Stylist {
|
|||
|
||||
map.insert(Rule {
|
||||
selector: selector.complex_selector.clone(),
|
||||
style_rule: style_rule.clone(),
|
||||
style_rule: locked.clone(),
|
||||
specificity: selector.specificity,
|
||||
source_order: self.rules_source_order,
|
||||
});
|
||||
}
|
||||
self.rules_source_order += 1;
|
||||
|
||||
for selector in &guard.selectors.0 {
|
||||
for selector in &style_rule.selectors.0 {
|
||||
self.state_deps.note_selector(&selector.complex_selector);
|
||||
if selector.affects_siblings() {
|
||||
self.sibling_affecting_selectors.push(selector.clone());
|
||||
|
@ -300,6 +300,7 @@ impl Stylist {
|
|||
/// values. The flow constructor uses this flag when constructing anonymous
|
||||
/// flows.
|
||||
pub fn precomputed_values_for_pseudo(&self,
|
||||
guards: &ReadGuards,
|
||||
pseudo: &PseudoElement,
|
||||
parent: Option<&Arc<ComputedValues>>,
|
||||
cascade_flags: CascadeFlags)
|
||||
|
@ -333,6 +334,7 @@ impl Stylist {
|
|||
let computed =
|
||||
properties::cascade(&self.device,
|
||||
&rule_node,
|
||||
guards,
|
||||
parent.map(|p| &**p),
|
||||
parent.map(|p| &**p),
|
||||
None,
|
||||
|
@ -344,6 +346,7 @@ impl Stylist {
|
|||
/// Returns the style for an anonymous box of the given type.
|
||||
#[cfg(feature = "servo")]
|
||||
pub fn style_for_anonymous_box(&self,
|
||||
guards: &ReadGuards,
|
||||
pseudo: &PseudoElement,
|
||||
parent_style: &Arc<ComputedValues>)
|
||||
-> Arc<ComputedValues> {
|
||||
|
@ -368,7 +371,7 @@ impl Stylist {
|
|||
if inherit_all {
|
||||
cascade_flags.insert(INHERIT_ALL);
|
||||
}
|
||||
self.precomputed_values_for_pseudo(&pseudo, Some(parent_style), cascade_flags)
|
||||
self.precomputed_values_for_pseudo(guards, &pseudo, Some(parent_style), cascade_flags)
|
||||
.values.unwrap()
|
||||
}
|
||||
|
||||
|
@ -380,6 +383,7 @@ impl Stylist {
|
|||
/// Check the documentation on lazy pseudo-elements in
|
||||
/// docs/components/style.md
|
||||
pub fn lazily_compute_pseudo_element_style<E>(&self,
|
||||
guards: &ReadGuards,
|
||||
element: &E,
|
||||
pseudo: &PseudoElement,
|
||||
parent: &Arc<ComputedValues>)
|
||||
|
@ -401,6 +405,7 @@ impl Stylist {
|
|||
None,
|
||||
AnimationRules(None, None),
|
||||
Some(pseudo),
|
||||
guards,
|
||||
&mut declarations,
|
||||
&mut flags);
|
||||
|
||||
|
@ -415,6 +420,7 @@ impl Stylist {
|
|||
let computed =
|
||||
properties::cascade(&self.device,
|
||||
&rule_node,
|
||||
guards,
|
||||
Some(&**parent),
|
||||
Some(&**parent),
|
||||
None,
|
||||
|
@ -539,6 +545,7 @@ impl Stylist {
|
|||
style_attribute: Option<&Arc<RwLock<PropertyDeclarationBlock>>>,
|
||||
animation_rules: AnimationRules,
|
||||
pseudo_element: Option<&PseudoElement>,
|
||||
guards: &ReadGuards,
|
||||
applicable_declarations: &mut V,
|
||||
flags: &mut ElementSelectorFlags) -> StyleRelations
|
||||
where E: TElement +
|
||||
|
@ -564,6 +571,7 @@ impl Stylist {
|
|||
// Step 1: Normal user-agent rules.
|
||||
map.user_agent.get_all_matching_rules(element,
|
||||
parent_bf,
|
||||
guards.ua_or_user,
|
||||
applicable_declarations,
|
||||
&mut relations,
|
||||
flags,
|
||||
|
@ -588,6 +596,7 @@ impl Stylist {
|
|||
// Step 3: User and author normal rules.
|
||||
map.user.get_all_matching_rules(element,
|
||||
parent_bf,
|
||||
guards.ua_or_user,
|
||||
applicable_declarations,
|
||||
&mut relations,
|
||||
flags,
|
||||
|
@ -595,6 +604,7 @@ impl Stylist {
|
|||
debug!("user normal: {:?}", relations);
|
||||
map.author.get_all_matching_rules(element,
|
||||
parent_bf,
|
||||
guards.author,
|
||||
applicable_declarations,
|
||||
&mut relations,
|
||||
flags,
|
||||
|
@ -629,6 +639,7 @@ impl Stylist {
|
|||
// Step 6: Author-supplied `!important` rules.
|
||||
map.author.get_all_matching_rules(element,
|
||||
parent_bf,
|
||||
guards.author,
|
||||
applicable_declarations,
|
||||
&mut relations,
|
||||
flags,
|
||||
|
@ -652,6 +663,7 @@ impl Stylist {
|
|||
// Step 8: User `!important` rules.
|
||||
map.user.get_all_matching_rules(element,
|
||||
parent_bf,
|
||||
guards.ua_or_user,
|
||||
applicable_declarations,
|
||||
&mut relations,
|
||||
flags,
|
||||
|
@ -665,6 +677,7 @@ impl Stylist {
|
|||
// Step 9: UA `!important` rules.
|
||||
map.user_agent.get_all_matching_rules(element,
|
||||
parent_bf,
|
||||
guards.ua_or_user,
|
||||
applicable_declarations,
|
||||
&mut relations,
|
||||
flags,
|
||||
|
@ -903,6 +916,7 @@ impl SelectorMap {
|
|||
pub fn get_all_matching_rules<E, V>(&self,
|
||||
element: &E,
|
||||
parent_bf: Option<&BloomFilter>,
|
||||
guard: &SharedRwLockReadGuard,
|
||||
matching_rules_list: &mut V,
|
||||
relations: &mut StyleRelations,
|
||||
flags: &mut ElementSelectorFlags,
|
||||
|
@ -921,6 +935,7 @@ impl SelectorMap {
|
|||
parent_bf,
|
||||
&self.id_hash,
|
||||
&id,
|
||||
guard,
|
||||
matching_rules_list,
|
||||
relations,
|
||||
flags,
|
||||
|
@ -932,6 +947,7 @@ impl SelectorMap {
|
|||
parent_bf,
|
||||
&self.class_hash,
|
||||
class,
|
||||
guard,
|
||||
matching_rules_list,
|
||||
relations,
|
||||
flags,
|
||||
|
@ -947,6 +963,7 @@ impl SelectorMap {
|
|||
parent_bf,
|
||||
local_name_hash,
|
||||
element.get_local_name(),
|
||||
guard,
|
||||
matching_rules_list,
|
||||
relations,
|
||||
flags,
|
||||
|
@ -955,6 +972,7 @@ impl SelectorMap {
|
|||
SelectorMap::get_matching_rules(element,
|
||||
parent_bf,
|
||||
&self.other_rules,
|
||||
guard,
|
||||
matching_rules_list,
|
||||
relations,
|
||||
flags,
|
||||
|
@ -968,6 +986,7 @@ impl SelectorMap {
|
|||
/// Append to `rule_list` all universal Rules (rules with selector `*|*`) in
|
||||
/// `self` sorted by specificity and source order.
|
||||
pub fn get_universal_rules(&self,
|
||||
guard: &SharedRwLockReadGuard,
|
||||
cascade_level: CascadeLevel,
|
||||
important_cascade_level: CascadeLevel)
|
||||
-> Vec<ApplicableDeclarationBlock> {
|
||||
|
@ -985,8 +1004,8 @@ impl SelectorMap {
|
|||
for rule in self.other_rules.iter() {
|
||||
if rule.selector.compound_selector.is_empty() &&
|
||||
rule.selector.next.is_none() {
|
||||
let guard = rule.style_rule.read();
|
||||
let block = guard.block.read();
|
||||
let style_rule = rule.style_rule.read_with(guard);
|
||||
let block = style_rule.block.read();
|
||||
if block.any_normal() {
|
||||
matching_rules_list.push(
|
||||
rule.to_applicable_declaration_block(cascade_level));
|
||||
|
@ -1014,6 +1033,7 @@ impl SelectorMap {
|
|||
parent_bf: Option<&BloomFilter>,
|
||||
hash: &FnvHashMap<Str, Vec<Rule>>,
|
||||
key: &BorrowedStr,
|
||||
guard: &SharedRwLockReadGuard,
|
||||
matching_rules: &mut Vector,
|
||||
relations: &mut StyleRelations,
|
||||
flags: &mut ElementSelectorFlags,
|
||||
|
@ -1027,6 +1047,7 @@ impl SelectorMap {
|
|||
SelectorMap::get_matching_rules(element,
|
||||
parent_bf,
|
||||
rules,
|
||||
guard,
|
||||
matching_rules,
|
||||
relations,
|
||||
flags,
|
||||
|
@ -1038,6 +1059,7 @@ impl SelectorMap {
|
|||
fn get_matching_rules<E, V>(element: &E,
|
||||
parent_bf: Option<&BloomFilter>,
|
||||
rules: &[Rule],
|
||||
guard: &SharedRwLockReadGuard,
|
||||
matching_rules: &mut V,
|
||||
relations: &mut StyleRelations,
|
||||
flags: &mut ElementSelectorFlags,
|
||||
|
@ -1046,8 +1068,8 @@ impl SelectorMap {
|
|||
V: VecLike<ApplicableDeclarationBlock>
|
||||
{
|
||||
for rule in rules.iter() {
|
||||
let guard = rule.style_rule.read();
|
||||
let block = guard.block.read();
|
||||
let style_rule = rule.style_rule.read_with(guard);
|
||||
let block = style_rule.block.read();
|
||||
let any_declaration_for_importance = if cascade_level.is_important() {
|
||||
block.any_important()
|
||||
} else {
|
||||
|
@ -1145,7 +1167,7 @@ pub struct Rule {
|
|||
pub selector: Arc<ComplexSelector<SelectorImpl>>,
|
||||
/// The actual style rule.
|
||||
#[cfg_attr(feature = "servo", ignore_heap_size_of = "Arc")]
|
||||
pub style_rule: Arc<RwLock<StyleRule>>,
|
||||
pub style_rule: Arc<Locked<StyleRule>>,
|
||||
/// The source order this style rule appears in.
|
||||
pub source_order: usize,
|
||||
/// The specificity of the rule this selector represents.
|
||||
|
|
|
@ -312,7 +312,8 @@ pub trait DomTraversal<E: TElement> : Sync {
|
|||
}
|
||||
|
||||
/// Helper for the function below.
|
||||
fn resolve_style_internal<E, F>(context: &mut StyleContext<E>, element: E, ensure_data: &F)
|
||||
fn resolve_style_internal<E, F>(context: &mut StyleContext<E>,
|
||||
element: E, ensure_data: &F)
|
||||
-> Option<E>
|
||||
where E: TElement,
|
||||
F: Fn(E),
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue