mirror of
https://github.com/servo/servo.git
synced 2025-07-24 15:50:21 +01:00
Cargoify servo
This commit is contained in:
parent
db2f642c32
commit
c6ab60dbfc
1761 changed files with 8423 additions and 2294 deletions
558
components/layout/css/matching.rs
Normal file
558
components/layout/css/matching.rs
Normal file
|
@ -0,0 +1,558 @@
|
|||
/* 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/. */
|
||||
|
||||
// High-level interface to CSS selector matching.
|
||||
|
||||
use css::node_style::StyledNode;
|
||||
use construct::FlowConstructor;
|
||||
use context::LayoutContext;
|
||||
use extra::LayoutAuxMethods;
|
||||
use util::{LayoutDataAccess, LayoutDataWrapper};
|
||||
use wrapper::{LayoutElement, LayoutNode, PostorderNodeMutTraversal, ThreadSafeLayoutNode};
|
||||
|
||||
use servo_util::atom::Atom;
|
||||
use servo_util::cache::{Cache, LRUCache, SimpleHashCache};
|
||||
use servo_util::namespace::Null;
|
||||
use servo_util::smallvec::{SmallVec, SmallVec16};
|
||||
use servo_util::str::DOMString;
|
||||
use std::mem;
|
||||
use std::hash::{Hash, sip};
|
||||
use std::slice::Items;
|
||||
use style::{After, Before, ComputedValues, DeclarationBlock, Stylist, TElement, TNode, cascade};
|
||||
use sync::Arc;
|
||||
|
||||
pub struct ApplicableDeclarations {
|
||||
pub normal: SmallVec16<DeclarationBlock>,
|
||||
pub before: Vec<DeclarationBlock>,
|
||||
pub after: Vec<DeclarationBlock>,
|
||||
|
||||
/// Whether the `normal` declarations are shareable with other nodes.
|
||||
pub normal_shareable: bool,
|
||||
}
|
||||
|
||||
impl ApplicableDeclarations {
|
||||
pub fn new() -> ApplicableDeclarations {
|
||||
ApplicableDeclarations {
|
||||
normal: SmallVec16::new(),
|
||||
before: Vec::new(),
|
||||
after: Vec::new(),
|
||||
normal_shareable: false,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn clear(&mut self) {
|
||||
self.normal = SmallVec16::new();
|
||||
self.before = Vec::new();
|
||||
self.after = Vec::new();
|
||||
self.normal_shareable = false;
|
||||
}
|
||||
}
|
||||
|
||||
#[deriving(Clone)]
|
||||
pub struct ApplicableDeclarationsCacheEntry {
|
||||
pub declarations: Vec<DeclarationBlock>,
|
||||
}
|
||||
|
||||
impl ApplicableDeclarationsCacheEntry {
|
||||
fn new(slice: &[DeclarationBlock]) -> ApplicableDeclarationsCacheEntry {
|
||||
let mut entry_declarations = Vec::new();
|
||||
for declarations in slice.iter() {
|
||||
entry_declarations.push(declarations.clone());
|
||||
}
|
||||
ApplicableDeclarationsCacheEntry {
|
||||
declarations: entry_declarations,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq for ApplicableDeclarationsCacheEntry {
|
||||
fn eq(&self, other: &ApplicableDeclarationsCacheEntry) -> bool {
|
||||
let this_as_query = ApplicableDeclarationsCacheQuery::new(self.declarations.as_slice());
|
||||
this_as_query.equiv(other)
|
||||
}
|
||||
}
|
||||
|
||||
impl Hash for ApplicableDeclarationsCacheEntry {
|
||||
fn hash(&self, state: &mut sip::SipState) {
|
||||
let tmp = ApplicableDeclarationsCacheQuery::new(self.declarations.as_slice());
|
||||
tmp.hash(state);
|
||||
}
|
||||
}
|
||||
|
||||
struct ApplicableDeclarationsCacheQuery<'a> {
|
||||
declarations: &'a [DeclarationBlock],
|
||||
}
|
||||
|
||||
impl<'a> ApplicableDeclarationsCacheQuery<'a> {
|
||||
fn new(declarations: &'a [DeclarationBlock]) -> ApplicableDeclarationsCacheQuery<'a> {
|
||||
ApplicableDeclarationsCacheQuery {
|
||||
declarations: declarations,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Workaround for lack of `ptr_eq` on Arcs...
|
||||
#[inline]
|
||||
fn arc_ptr_eq<T>(a: &Arc<T>, b: &Arc<T>) -> bool {
|
||||
unsafe {
|
||||
let a: uint = mem::transmute_copy(a);
|
||||
let b: uint = mem::transmute_copy(b);
|
||||
a == b
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Equiv<ApplicableDeclarationsCacheEntry> for ApplicableDeclarationsCacheQuery<'a> {
|
||||
fn equiv(&self, other: &ApplicableDeclarationsCacheEntry) -> bool {
|
||||
if self.declarations.len() != other.declarations.len() {
|
||||
return false
|
||||
}
|
||||
for (this, other) in self.declarations.iter().zip(other.declarations.iter()) {
|
||||
if !arc_ptr_eq(&this.declarations, &other.declarations) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
impl<'a> Hash for ApplicableDeclarationsCacheQuery<'a> {
|
||||
fn hash(&self, state: &mut sip::SipState) {
|
||||
for declaration in self.declarations.iter() {
|
||||
let ptr: uint = unsafe {
|
||||
mem::transmute_copy(declaration)
|
||||
};
|
||||
ptr.hash(state);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static APPLICABLE_DECLARATIONS_CACHE_SIZE: uint = 32;
|
||||
|
||||
pub struct ApplicableDeclarationsCache {
|
||||
cache: SimpleHashCache<ApplicableDeclarationsCacheEntry,Arc<ComputedValues>>,
|
||||
}
|
||||
|
||||
impl ApplicableDeclarationsCache {
|
||||
pub fn new() -> ApplicableDeclarationsCache {
|
||||
ApplicableDeclarationsCache {
|
||||
cache: SimpleHashCache::new(APPLICABLE_DECLARATIONS_CACHE_SIZE),
|
||||
}
|
||||
}
|
||||
|
||||
fn find(&self, declarations: &[DeclarationBlock]) -> Option<Arc<ComputedValues>> {
|
||||
match self.cache.find_equiv(&ApplicableDeclarationsCacheQuery::new(declarations)) {
|
||||
None => None,
|
||||
Some(ref values) => Some((*values).clone()),
|
||||
}
|
||||
}
|
||||
|
||||
fn insert(&mut self, declarations: &[DeclarationBlock], style: Arc<ComputedValues>) {
|
||||
self.cache.insert(ApplicableDeclarationsCacheEntry::new(declarations), style)
|
||||
}
|
||||
}
|
||||
|
||||
/// An LRU cache of the last few nodes seen, so that we can aggressively try to reuse their styles.
|
||||
pub struct StyleSharingCandidateCache {
|
||||
cache: LRUCache<StyleSharingCandidate,()>,
|
||||
}
|
||||
|
||||
#[deriving(Clone)]
|
||||
pub struct StyleSharingCandidate {
|
||||
pub style: Arc<ComputedValues>,
|
||||
pub parent_style: Arc<ComputedValues>,
|
||||
pub local_name: Atom,
|
||||
pub class: Option<DOMString>,
|
||||
}
|
||||
|
||||
impl PartialEq for StyleSharingCandidate {
|
||||
fn eq(&self, other: &StyleSharingCandidate) -> bool {
|
||||
arc_ptr_eq(&self.style, &other.style) &&
|
||||
arc_ptr_eq(&self.parent_style, &other.parent_style) &&
|
||||
self.local_name == other.local_name &&
|
||||
self.class == other.class
|
||||
}
|
||||
}
|
||||
|
||||
impl StyleSharingCandidate {
|
||||
/// Attempts to create a style sharing candidate from this node. Returns
|
||||
/// the style sharing candidate or `None` if this node is ineligible for
|
||||
/// style sharing.
|
||||
fn new(node: &LayoutNode) -> Option<StyleSharingCandidate> {
|
||||
let parent_node = match node.parent_node() {
|
||||
None => return None,
|
||||
Some(parent_node) => parent_node,
|
||||
};
|
||||
if !parent_node.is_element() {
|
||||
return None
|
||||
}
|
||||
|
||||
let style = unsafe {
|
||||
match *node.borrow_layout_data_unchecked() {
|
||||
None => return None,
|
||||
Some(ref layout_data_ref) => {
|
||||
match layout_data_ref.shared_data.style {
|
||||
None => return None,
|
||||
Some(ref data) => (*data).clone(),
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
let parent_style = unsafe {
|
||||
match *parent_node.borrow_layout_data_unchecked() {
|
||||
None => return None,
|
||||
Some(ref parent_layout_data_ref) => {
|
||||
match parent_layout_data_ref.shared_data.style {
|
||||
None => return None,
|
||||
Some(ref data) => (*data).clone(),
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
let mut style = Some(style);
|
||||
let mut parent_style = Some(parent_style);
|
||||
let element = node.as_element();
|
||||
if element.style_attribute().is_some() {
|
||||
return None
|
||||
}
|
||||
|
||||
Some(StyleSharingCandidate {
|
||||
style: style.take_unwrap(),
|
||||
parent_style: parent_style.take_unwrap(),
|
||||
local_name: element.get_local_name().clone(),
|
||||
class: element.get_attr(&Null, "class")
|
||||
.map(|string| string.to_string()),
|
||||
})
|
||||
}
|
||||
|
||||
fn can_share_style_with(&self, element: &LayoutElement) -> bool {
|
||||
if *element.get_local_name() != self.local_name {
|
||||
return false
|
||||
}
|
||||
match (&self.class, element.get_attr(&Null, "class")) {
|
||||
(&None, Some(_)) | (&Some(_), None) => return false,
|
||||
(&Some(ref this_class), Some(element_class)) if element_class != this_class.as_slice() => {
|
||||
return false
|
||||
}
|
||||
(&Some(_), Some(_)) | (&None, None) => {}
|
||||
}
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
static STYLE_SHARING_CANDIDATE_CACHE_SIZE: uint = 40;
|
||||
|
||||
impl StyleSharingCandidateCache {
|
||||
pub fn new() -> StyleSharingCandidateCache {
|
||||
StyleSharingCandidateCache {
|
||||
cache: LRUCache::new(STYLE_SHARING_CANDIDATE_CACHE_SIZE),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn iter<'a>(&'a self) -> Items<'a,(StyleSharingCandidate,())> {
|
||||
self.cache.iter()
|
||||
}
|
||||
|
||||
pub fn insert_if_possible(&mut self, node: &LayoutNode) {
|
||||
match StyleSharingCandidate::new(node) {
|
||||
None => {}
|
||||
Some(candidate) => self.cache.insert(candidate, ())
|
||||
}
|
||||
}
|
||||
|
||||
pub fn touch(&mut self, index: uint) {
|
||||
self.cache.touch(index)
|
||||
}
|
||||
}
|
||||
|
||||
/// The results of attempting to share a style.
|
||||
pub enum StyleSharingResult<'ln> {
|
||||
/// We didn't find anybody to share the style with. The boolean indicates whether the style
|
||||
/// is shareable at all.
|
||||
CannotShare(bool),
|
||||
/// The node's style can be shared. The integer specifies the index in the LRU cache that was
|
||||
/// hit.
|
||||
StyleWasShared(uint),
|
||||
}
|
||||
|
||||
pub trait MatchMethods {
|
||||
/// Performs aux initialization, selector matching, cascading, and flow construction
|
||||
/// sequentially.
|
||||
fn recalc_style_for_subtree(&self,
|
||||
stylist: &Stylist,
|
||||
layout_context: &LayoutContext,
|
||||
applicable_declarations: &mut ApplicableDeclarations,
|
||||
parent: Option<LayoutNode>);
|
||||
|
||||
fn match_node(&self,
|
||||
stylist: &Stylist,
|
||||
applicable_declarations: &mut ApplicableDeclarations,
|
||||
shareable: &mut bool);
|
||||
|
||||
/// Attempts to share a style with another node. This method is unsafe because it depends on
|
||||
/// the `style_sharing_candidate_cache` having only live nodes in it, and we have no way to
|
||||
/// guarantee that at the type system level yet.
|
||||
unsafe fn share_style_if_possible(&self,
|
||||
style_sharing_candidate_cache:
|
||||
&mut StyleSharingCandidateCache,
|
||||
parent: Option<LayoutNode>)
|
||||
-> StyleSharingResult;
|
||||
|
||||
unsafe fn cascade_node(&self,
|
||||
parent: Option<LayoutNode>,
|
||||
applicable_declarations: &ApplicableDeclarations,
|
||||
applicable_declarations_cache: &mut ApplicableDeclarationsCache);
|
||||
}
|
||||
|
||||
trait PrivateMatchMethods {
|
||||
fn cascade_node_pseudo_element(&self,
|
||||
parent_style: Option<&Arc<ComputedValues>>,
|
||||
applicable_declarations: &[DeclarationBlock],
|
||||
style: &mut Option<Arc<ComputedValues>>,
|
||||
applicable_declarations_cache: &mut
|
||||
ApplicableDeclarationsCache,
|
||||
shareable: bool);
|
||||
|
||||
fn share_style_with_candidate_if_possible(&self,
|
||||
parent_node: Option<LayoutNode>,
|
||||
candidate: &StyleSharingCandidate)
|
||||
-> Option<Arc<ComputedValues>>;
|
||||
}
|
||||
|
||||
impl<'ln> PrivateMatchMethods for LayoutNode<'ln> {
|
||||
fn cascade_node_pseudo_element(&self,
|
||||
parent_style: Option<&Arc<ComputedValues>>,
|
||||
applicable_declarations: &[DeclarationBlock],
|
||||
style: &mut Option<Arc<ComputedValues>>,
|
||||
applicable_declarations_cache: &mut
|
||||
ApplicableDeclarationsCache,
|
||||
shareable: bool) {
|
||||
let this_style;
|
||||
let cacheable;
|
||||
match parent_style {
|
||||
Some(ref parent_style) => {
|
||||
let cache_entry = applicable_declarations_cache.find(applicable_declarations);
|
||||
let cached_computed_values = match cache_entry {
|
||||
None => None,
|
||||
Some(ref style) => Some(&**style),
|
||||
};
|
||||
let (the_style, is_cacheable) = cascade(applicable_declarations,
|
||||
shareable,
|
||||
Some(&***parent_style),
|
||||
cached_computed_values);
|
||||
cacheable = is_cacheable;
|
||||
this_style = Arc::new(the_style);
|
||||
}
|
||||
None => {
|
||||
let (the_style, is_cacheable) = cascade(applicable_declarations,
|
||||
shareable,
|
||||
None,
|
||||
None);
|
||||
cacheable = is_cacheable;
|
||||
this_style = Arc::new(the_style);
|
||||
}
|
||||
};
|
||||
|
||||
// Cache the resolved style if it was cacheable.
|
||||
if cacheable {
|
||||
applicable_declarations_cache.insert(applicable_declarations, this_style.clone());
|
||||
}
|
||||
|
||||
*style = Some(this_style);
|
||||
}
|
||||
|
||||
|
||||
fn share_style_with_candidate_if_possible(&self,
|
||||
parent_node: Option<LayoutNode>,
|
||||
candidate: &StyleSharingCandidate)
|
||||
-> Option<Arc<ComputedValues>> {
|
||||
assert!(self.is_element());
|
||||
|
||||
let parent_node = match parent_node {
|
||||
Some(ref parent_node) if parent_node.is_element() => parent_node,
|
||||
Some(_) | None => return None,
|
||||
};
|
||||
|
||||
let parent_layout_data: &Option<LayoutDataWrapper> = unsafe {
|
||||
mem::transmute(parent_node.borrow_layout_data_unchecked())
|
||||
};
|
||||
match parent_layout_data {
|
||||
&Some(ref parent_layout_data_ref) => {
|
||||
// Check parent style.
|
||||
let parent_style = parent_layout_data_ref.shared_data.style.as_ref().unwrap();
|
||||
if !arc_ptr_eq(parent_style, &candidate.parent_style) {
|
||||
return None
|
||||
}
|
||||
|
||||
// Check tag names, classes, etc.
|
||||
if !candidate.can_share_style_with(&self.as_element()) {
|
||||
return None
|
||||
}
|
||||
|
||||
return Some(candidate.style.clone())
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
impl<'ln> MatchMethods for LayoutNode<'ln> {
|
||||
fn match_node(&self,
|
||||
stylist: &Stylist,
|
||||
applicable_declarations: &mut ApplicableDeclarations,
|
||||
shareable: &mut bool) {
|
||||
let style_attribute = self.as_element().style_attribute().as_ref();
|
||||
|
||||
applicable_declarations.normal_shareable =
|
||||
stylist.push_applicable_declarations(self,
|
||||
style_attribute,
|
||||
None,
|
||||
&mut applicable_declarations.normal);
|
||||
stylist.push_applicable_declarations(self,
|
||||
None,
|
||||
Some(Before),
|
||||
&mut applicable_declarations.before);
|
||||
stylist.push_applicable_declarations(self,
|
||||
None,
|
||||
Some(After),
|
||||
&mut applicable_declarations.after);
|
||||
|
||||
*shareable = applicable_declarations.normal_shareable
|
||||
}
|
||||
|
||||
unsafe fn share_style_if_possible(&self,
|
||||
style_sharing_candidate_cache:
|
||||
&mut StyleSharingCandidateCache,
|
||||
parent: Option<LayoutNode>)
|
||||
-> StyleSharingResult {
|
||||
if !self.is_element() {
|
||||
return CannotShare(false)
|
||||
}
|
||||
let ok = {
|
||||
let element = self.as_element();
|
||||
element.style_attribute().is_none() && element.get_attr(&Null, "id").is_none()
|
||||
};
|
||||
if !ok {
|
||||
return CannotShare(false)
|
||||
}
|
||||
|
||||
for (i, &(ref candidate, ())) in style_sharing_candidate_cache.iter().enumerate() {
|
||||
match self.share_style_with_candidate_if_possible(parent.clone(), candidate) {
|
||||
Some(shared_style) => {
|
||||
// Yay, cache hit. Share the style.
|
||||
let mut layout_data_ref = self.mutate_layout_data();
|
||||
layout_data_ref.get_mut_ref().shared_data.style = Some(shared_style);
|
||||
return StyleWasShared(i)
|
||||
}
|
||||
None => {}
|
||||
}
|
||||
}
|
||||
|
||||
CannotShare(true)
|
||||
}
|
||||
|
||||
fn recalc_style_for_subtree(&self,
|
||||
stylist: &Stylist,
|
||||
layout_context: &LayoutContext,
|
||||
applicable_declarations: &mut ApplicableDeclarations,
|
||||
parent: Option<LayoutNode>) {
|
||||
self.initialize_layout_data(layout_context.shared.layout_chan.clone());
|
||||
|
||||
// First, check to see whether we can share a style with someone.
|
||||
let sharing_result = unsafe {
|
||||
self.share_style_if_possible(layout_context.style_sharing_candidate_cache(), parent.clone())
|
||||
};
|
||||
|
||||
// Otherwise, match and cascade selectors.
|
||||
match sharing_result {
|
||||
CannotShare(mut shareable) => {
|
||||
if self.is_element() {
|
||||
self.match_node(stylist, applicable_declarations, &mut shareable)
|
||||
}
|
||||
|
||||
unsafe {
|
||||
self.cascade_node(parent,
|
||||
applicable_declarations,
|
||||
layout_context.applicable_declarations_cache())
|
||||
}
|
||||
|
||||
applicable_declarations.clear();
|
||||
|
||||
// Add ourselves to the LRU cache.
|
||||
if shareable {
|
||||
layout_context.style_sharing_candidate_cache().insert_if_possible(self)
|
||||
}
|
||||
}
|
||||
StyleWasShared(index) => layout_context.style_sharing_candidate_cache().touch(index),
|
||||
}
|
||||
|
||||
for kid in self.children() {
|
||||
kid.recalc_style_for_subtree(stylist,
|
||||
layout_context,
|
||||
applicable_declarations,
|
||||
Some(self.clone()))
|
||||
}
|
||||
|
||||
// Construct flows.
|
||||
let layout_node = ThreadSafeLayoutNode::new(self);
|
||||
let mut flow_constructor = FlowConstructor::new(layout_context);
|
||||
flow_constructor.process(&layout_node);
|
||||
}
|
||||
|
||||
unsafe fn cascade_node(&self,
|
||||
parent: Option<LayoutNode>,
|
||||
applicable_declarations: &ApplicableDeclarations,
|
||||
applicable_declarations_cache: &mut ApplicableDeclarationsCache) {
|
||||
// Get our parent's style. This must be unsafe so that we don't touch the parent's
|
||||
// borrow flags.
|
||||
//
|
||||
// FIXME(pcwalton): Isolate this unsafety into the `wrapper` module to allow
|
||||
// enforced safe, race-free access to the parent style.
|
||||
let parent_style = match parent {
|
||||
None => None,
|
||||
Some(parent_node) => {
|
||||
let parent_layout_data = parent_node.borrow_layout_data_unchecked();
|
||||
match *parent_layout_data {
|
||||
None => fail!("no parent data?!"),
|
||||
Some(ref parent_layout_data) => {
|
||||
match parent_layout_data.shared_data.style {
|
||||
None => fail!("parent hasn't been styled yet?!"),
|
||||
Some(ref style) => Some(style),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
let mut layout_data_ref = self.mutate_layout_data();
|
||||
match &mut *layout_data_ref {
|
||||
&None => fail!("no layout data"),
|
||||
&Some(ref mut layout_data) => {
|
||||
self.cascade_node_pseudo_element(parent_style,
|
||||
applicable_declarations.normal.as_slice(),
|
||||
&mut layout_data.shared_data.style,
|
||||
applicable_declarations_cache,
|
||||
applicable_declarations.normal_shareable);
|
||||
if applicable_declarations.before.len() > 0 {
|
||||
self.cascade_node_pseudo_element(Some(layout_data.shared_data.style.get_ref()),
|
||||
applicable_declarations.before.as_slice(),
|
||||
&mut layout_data.data.before_style,
|
||||
applicable_declarations_cache,
|
||||
false);
|
||||
}
|
||||
if applicable_declarations.after.len() > 0 {
|
||||
self.cascade_node_pseudo_element(Some(layout_data.shared_data.style.get_ref()),
|
||||
applicable_declarations.after.as_slice(),
|
||||
&mut layout_data.data.after_style,
|
||||
applicable_declarations_cache,
|
||||
false);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
30
components/layout/css/node_style.rs
Normal file
30
components/layout/css/node_style.rs
Normal file
|
@ -0,0 +1,30 @@
|
|||
/* 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/. */
|
||||
|
||||
// Style retrieval from DOM elements.
|
||||
|
||||
use css::node_util::NodeUtil;
|
||||
use incremental::RestyleDamage;
|
||||
use wrapper::ThreadSafeLayoutNode;
|
||||
|
||||
use style::ComputedValues;
|
||||
use sync::Arc;
|
||||
|
||||
/// Node mixin providing `style` method that returns a `NodeStyle`
|
||||
pub trait StyledNode {
|
||||
fn style<'a>(&'a self) -> &'a Arc<ComputedValues>;
|
||||
fn restyle_damage(&self) -> RestyleDamage;
|
||||
}
|
||||
|
||||
impl<'ln> StyledNode for ThreadSafeLayoutNode<'ln> {
|
||||
#[inline]
|
||||
fn style<'a>(&'a self) -> &'a Arc<ComputedValues> {
|
||||
self.get_css_select_results()
|
||||
}
|
||||
|
||||
fn restyle_damage(&self) -> RestyleDamage {
|
||||
self.get_restyle_damage()
|
||||
}
|
||||
}
|
||||
|
90
components/layout/css/node_util.rs
Normal file
90
components/layout/css/node_util.rs
Normal file
|
@ -0,0 +1,90 @@
|
|||
/* 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/. */
|
||||
|
||||
use incremental::RestyleDamage;
|
||||
use util::LayoutDataAccess;
|
||||
use wrapper::{TLayoutNode, ThreadSafeLayoutNode};
|
||||
use wrapper::{After, AfterBlock, Before, BeforeBlock, Normal};
|
||||
use std::mem;
|
||||
use style::ComputedValues;
|
||||
use sync::Arc;
|
||||
|
||||
pub trait NodeUtil {
|
||||
fn get_css_select_results<'a>(&'a self) -> &'a Arc<ComputedValues>;
|
||||
fn have_css_select_results(&self) -> bool;
|
||||
|
||||
fn get_restyle_damage(&self) -> RestyleDamage;
|
||||
fn set_restyle_damage(&self, damage: RestyleDamage);
|
||||
}
|
||||
|
||||
impl<'ln> NodeUtil for ThreadSafeLayoutNode<'ln> {
|
||||
/// Returns the style results for the given node. If CSS selector
|
||||
/// matching has not yet been performed, fails.
|
||||
#[inline]
|
||||
fn get_css_select_results<'a>(&'a self) -> &'a Arc<ComputedValues> {
|
||||
unsafe {
|
||||
let layout_data_ref = self.borrow_layout_data();
|
||||
match self.get_pseudo_element_type() {
|
||||
Before | BeforeBlock => {
|
||||
mem::transmute(layout_data_ref.as_ref()
|
||||
.unwrap()
|
||||
.data
|
||||
.before_style
|
||||
.as_ref()
|
||||
.unwrap())
|
||||
}
|
||||
After | AfterBlock => {
|
||||
mem::transmute(layout_data_ref.as_ref()
|
||||
.unwrap()
|
||||
.data
|
||||
.after_style
|
||||
.as_ref()
|
||||
.unwrap())
|
||||
}
|
||||
Normal => {
|
||||
mem::transmute(layout_data_ref.as_ref()
|
||||
.unwrap()
|
||||
.shared_data
|
||||
.style
|
||||
.as_ref()
|
||||
.unwrap())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Does this node have a computed style yet?
|
||||
fn have_css_select_results(&self) -> bool {
|
||||
let layout_data_ref = self.borrow_layout_data();
|
||||
layout_data_ref.get_ref().shared_data.style.is_some()
|
||||
}
|
||||
|
||||
/// Get the description of how to account for recent style changes.
|
||||
/// This is a simple bitfield and fine to copy by value.
|
||||
fn get_restyle_damage(&self) -> RestyleDamage {
|
||||
// For DOM elements, if we haven't computed damage yet, assume the worst.
|
||||
// Other nodes don't have styles.
|
||||
let default = if self.node_is_element() {
|
||||
RestyleDamage::all()
|
||||
} else {
|
||||
RestyleDamage::empty()
|
||||
};
|
||||
|
||||
let layout_data_ref = self.borrow_layout_data();
|
||||
layout_data_ref
|
||||
.get_ref()
|
||||
.data
|
||||
.restyle_damage
|
||||
.unwrap_or(default)
|
||||
}
|
||||
|
||||
/// Set the restyle damage field.
|
||||
fn set_restyle_damage(&self, damage: RestyleDamage) {
|
||||
let mut layout_data_ref = self.mutate_layout_data();
|
||||
match &mut *layout_data_ref {
|
||||
&Some(ref mut layout_data) => layout_data.data.restyle_damage = Some(damage),
|
||||
_ => fail!("no layout data for this node"),
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue