Skip to content
Permalink
Browse files

Concurrent rule tree, v1

This patch introduces infrastructure for the rule tree, and constructs it.

We don't use it yet, nor have good heuristics for GC'ing it, but this should not
happen anymore once we store the rule node reference in the node.

I haven't messed up with memory orders because I want to do a try run with it,
then mess with them.

Take down the ApplicableDeclarationsCache, use the rule tree for doing the cascade.
  • Loading branch information
emilio authored and SimonSapin committed Nov 5, 2016
1 parent f7875da commit de4fe6e2b69acebf015e0b154f3ebd0371f530f9
@@ -53,9 +53,6 @@ fn create_or_get_local_context(shared_layout_context: &SharedLayoutContext)
LOCAL_CONTEXT_KEY.with(|r| {
let mut r = r.borrow_mut();
if let Some(context) = r.clone() {
if shared_layout_context.style_context.screen_size_changed {
context.style_context.applicable_declarations_cache.borrow_mut().evict_all();
}
context
} else {
let font_cache_thread = shared_layout_context.font_cache_thread.lock().unwrap().clone();
@@ -1170,6 +1170,16 @@ impl LayoutThread {
node.dump_style();
}

if opts::get().dump_rule_tree {
shared_layout_context.style_context.stylist.rule_tree.dump_stdout();
}

// GC The rule tree.
//
// FIXME(emilio): The whole point of the free list is not always freeing
// the list, find a good heuristic here for that.
unsafe { shared_layout_context.style_context.stylist.rule_tree.gc() }

// Perform post-style recalculation layout passes.
self.perform_post_style_recalc_layout_passes(&data.reflow_info,
Some(&data.query_type),
@@ -328,10 +328,10 @@ impl LayoutElementHelpers for LayoutJS<Element> {
where V: Push<ApplicableDeclarationBlock>
{
#[inline]
fn from_declaration(rule: PropertyDeclaration) -> ApplicableDeclarationBlock {
fn from_declaration(declaration: PropertyDeclaration) -> ApplicableDeclarationBlock {
ApplicableDeclarationBlock::from_declarations(
Arc::new(RwLock::new(PropertyDeclarationBlock {
declarations: vec![(rule, Importance::Normal)],
declarations: vec![(declaration, Importance::Normal)],
important_count: 0,
})),
Importance::Normal)
@@ -814,10 +814,7 @@ impl Element {
}
None
}
}


impl Element {
pub fn is_focusable_area(&self) -> bool {
if self.is_actually_disabled() {
return false;
@@ -856,10 +853,7 @@ impl Element {
_ => false,
}
}
}


impl Element {
pub fn push_new_attribute(&self,
local_name: LocalName,
value: AttrValue,
@@ -375,13 +375,13 @@ pub trait ThreadSafeLayoutElement: Clone + Copy + Sized + Debug +
.borrow()
.current_styles().pseudos.contains_key(&style_pseudo) {
let mut data = self.get_style_data().unwrap().borrow_mut();
let new_style =
let new_style_and_rule_node =
context.stylist.precomputed_values_for_pseudo(
&style_pseudo,
Some(&data.current_styles().primary),
false);
data.current_pseudos_mut()
.insert(style_pseudo.clone(), new_style.unwrap());
.insert(style_pseudo.clone(), new_style_and_rule_node.unwrap());
}
}
PseudoElementCascadeType::Lazy => {
@@ -404,7 +404,7 @@ pub trait ThreadSafeLayoutElement: Clone + Copy + Sized + Debug +

self.get_style_data().unwrap().borrow()
.current_styles().pseudos.get(&style_pseudo)
.unwrap().clone()
.unwrap().0.clone()
}
}
}
@@ -413,7 +413,7 @@ pub trait ThreadSafeLayoutElement: Clone + Copy + Sized + Debug +
fn selected_style(&self) -> Arc<ServoComputedValues> {
let data = self.get_style_data().unwrap().borrow();
data.current_styles().pseudos
.get(&PseudoElement::Selection)
.get(&PseudoElement::Selection).map(|s| &s.0)
.unwrap_or(&data.current_styles().primary)
.clone()
}
@@ -432,7 +432,8 @@ pub trait ThreadSafeLayoutElement: Clone + Copy + Sized + Debug +
PseudoElementType::Normal
=> data.current_styles().primary.clone(),
other
=> data.current_styles().pseudos.get(&other.style_pseudo_element()).unwrap().clone(),
=> data.current_styles().pseudos
.get(&other.style_pseudo_element()).unwrap().0.clone(),
}
}

@@ -7,6 +7,7 @@
use Atom;
use bezier::Bezier;
use context::SharedStyleContext;
use declarations_iterators::RawDeclarationsIterator;
use dom::{OpaqueNode, UnsafeNode};
use euclid::point::Point2D;
use keyframes::{KeyframesStep, KeyframesStepValue};
@@ -17,7 +18,6 @@ use properties::longhands::animation_iteration_count::computed_value::AnimationI
use properties::longhands::animation_play_state::computed_value::AnimationPlayState;
use properties::longhands::transition_timing_function::computed_value::StartEnd;
use properties::longhands::transition_timing_function::computed_value::TransitionTimingFunction;
use selector_matching::ApplicableDeclarationBlock;
use std::sync::Arc;
use std::sync::mpsc::Sender;
use timer::Timer;
@@ -385,23 +385,24 @@ fn compute_style_for_animation_step(context: &SharedStyleContext,
style_from_cascade: &ComputedValues)
-> ComputedValues {
match step.value {
// 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 { block: ref declarations } => {
let declaration_block = ApplicableDeclarationBlock {
mixed_declarations: declarations.clone(),
importance: Importance::Normal,
source_order: 0,
specificity: ::std::u32::MAX,
};
let (computed, _) = properties::cascade(context.viewport_size,
&[declaration_block],
Some(previous_style),
None,
None,
context.error_reporter.clone(),
CascadeFlags::empty());
let guard = declarations.read();

// No !important in keyframes.
debug_assert!(guard.declarations.iter()
.all(|&(_, importance)| importance == Importance::Normal));

let iter = RawDeclarationsIterator::new(&guard.declarations);

let computed =
properties::apply_declarations(context.viewport_size,
/* is_root = */ false,
iter,
previous_style,
/* cascade_info = */ None,
context.error_reporter.clone(),
CascadeFlags::empty());
computed
}
}
@@ -9,7 +9,7 @@ use app_units::Au;
use dom::OpaqueNode;
use error_reporting::ParseErrorReporter;
use euclid::Size2D;
use matching::{ApplicableDeclarationsCache, StyleSharingCandidateCache};
use matching::StyleSharingCandidateCache;
use parking_lot::RwLock;
use selector_matching::Stylist;
use std::cell::RefCell;
@@ -66,7 +66,6 @@ pub struct SharedStyleContext {
}

pub struct LocalStyleContext {
pub applicable_declarations_cache: RefCell<ApplicableDeclarationsCache>,
pub style_sharing_candidate_cache: RefCell<StyleSharingCandidateCache>,
/// A channel on which new animations that have been triggered by style
/// recalculation can be sent.
@@ -76,7 +75,6 @@ pub struct LocalStyleContext {
impl LocalStyleContext {
pub fn new(local_context_creation_data: &LocalStyleContextCreationInfo) -> Self {
LocalStyleContext {
applicable_declarations_cache: RefCell::new(ApplicableDeclarationsCache::new()),
style_sharing_candidate_cache: RefCell::new(StyleSharingCandidateCache::new()),
new_animations_sender: local_context_creation_data.new_animations_sender.clone(),
}
@@ -5,14 +5,15 @@
//! Per-node data used in style calculation.

use properties::ComputedValues;
use rule_tree::StrongRuleNode;
use selector_impl::PseudoElement;
use std::collections::HashMap;
use std::hash::BuildHasherDefault;
use std::mem;
use std::ops::{Deref, DerefMut};
use std::sync::Arc;

type PseudoStylesInner = HashMap<PseudoElement, Arc<ComputedValues>,
type PseudoStylesInner = HashMap<PseudoElement, (Arc<ComputedValues>, StrongRuleNode),
BuildHasherDefault<::fnv::FnvHasher>>;
#[derive(Clone, Debug)]
pub struct PseudoStyles(PseudoStylesInner);
@@ -39,14 +40,18 @@ pub struct ElementStyles {
/// The results of CSS styling for this node.
pub primary: Arc<ComputedValues>,

/// The rule node representing the last rule matched for this node.
pub rule_node: StrongRuleNode,

/// The results of CSS styling for each pseudo-element (if any).
pub pseudos: PseudoStyles,
}

impl ElementStyles {
pub fn new(primary: Arc<ComputedValues>) -> Self {
pub fn new(primary: Arc<ComputedValues>, rule_node: StrongRuleNode) -> Self {
ElementStyles {
primary: primary,
rule_node: rule_node,
pseudos: PseudoStyles::empty(),
}
}
@@ -185,11 +190,6 @@ impl ElementData {
}
}

pub fn style_text_node(&mut self, style: Arc<ComputedValues>) {
self.styles = ElementDataStyles::Current(ElementStyles::new(style));
self.restyle_data = None;
}

pub fn finish_styling(&mut self, styles: ElementStyles) {
debug_assert!(self.styles.is_previous());
self.styles = ElementDataStyles::Current(styles);
@@ -0,0 +1,83 @@
/* 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 set of simple iterators to be reused for doing the cascade.

use properties::{Importance, PropertyDeclaration};


/// An iterator that applies the declarations in a list that matches the given
/// importance.
#[derive(Clone)]
pub struct SimpleDeclarationsIterator<'a> {
declarations: &'a [(PropertyDeclaration, Importance)],
importance: Importance,
index: usize,
}

impl<'a> SimpleDeclarationsIterator<'a> {
pub fn new(declarations: &'a [(PropertyDeclaration, Importance)],
importance: Importance) -> Self {
SimpleDeclarationsIterator {
declarations: declarations,
importance: importance,
index: 0,
}
}
}

impl<'a> Iterator for SimpleDeclarationsIterator<'a> {
type Item = &'a PropertyDeclaration;

fn next(&mut self) -> Option<Self::Item> {
loop {
if self.index == self.declarations.len() {
return None;
}

let (ref decl, importance) =
self.declarations[self.declarations.len() - self.index - 1];

self.index += 1;

if importance == self.importance {
return Some(decl)
}
}
}
}

/// An iterator that applies the declarations in a list without checking any
/// order.
#[derive(Clone)]
pub struct RawDeclarationsIterator<'a> {
declarations: &'a [(PropertyDeclaration, Importance)],
index: usize,
}

impl<'a> RawDeclarationsIterator<'a> {
pub fn new(declarations: &'a [(PropertyDeclaration, Importance)]) -> Self {
RawDeclarationsIterator {
declarations: declarations,
index: 0,
}
}
}

impl<'a> Iterator for RawDeclarationsIterator<'a> {
type Item = &'a PropertyDeclaration;

fn next(&mut self) -> Option<Self::Item> {
if self.index == self.declarations.len() {
return None;
}

let (ref decl, _) =
self.declarations[self.declarations.len() - self.index - 1];

self.index += 1;

return Some(decl)
}
}
@@ -13,9 +13,6 @@ fn create_or_get_local_context(shared: &SharedStyleContext) -> Rc<LocalStyleCont
LOCAL_CONTEXT_KEY.with(|r| {
let mut r = r.borrow_mut();
if let Some(context) = r.clone() {
if shared.screen_size_changed {
context.applicable_declarations_cache.borrow_mut().evict_all();
}
context
} else {
let context = Rc::new(LocalStyleContext::new(&shared.local_context_creation_data.lock().unwrap()));
@@ -334,7 +334,7 @@ impl<'le> GeckoElement<'le> {

pub fn get_pseudo_style(&self, pseudo: &PseudoElement) -> Option<Arc<ComputedValues>> {
self.borrow_data().and_then(|data| data.current_styles().pseudos
.get(pseudo).map(|c| c.clone()))
.get(pseudo).map(|c| c.0.clone()))
}

pub fn ensure_data(&self) -> &AtomicRefCell<ElementData> {
@@ -99,6 +99,7 @@ pub mod cascade_info;
pub mod context;
pub mod custom_properties;
pub mod data;
pub mod declarations_iterators;
pub mod dom;
pub mod element_state;
pub mod error_reporting;
@@ -114,6 +115,7 @@ pub mod parallel;
pub mod parser;
pub mod refcell;
pub mod restyle_hints;
pub mod rule_tree;
pub mod selector_impl;
pub mod selector_matching;
pub mod sequential;

0 comments on commit de4fe6e

Please sign in to comment.
You can’t perform that action at this time.