Separate style+layout and layout-specific wrapper functionality.

This patch does a number of things, unfortunately all at once:
* Hoists a large subset of the layout wrapper functionality into the style system.
* Merges TElementAttributes into the newly-created TElement.
* Reorganizes LayoutData by style vs layout, and removes LayoutDataShared.
* Simplifies the API for borrowing style/layout data.

There's still more to do to make the style system usable standalone, but
this is a good start.
This commit is contained in:
Bobby Holley 2015-12-17 16:21:29 -08:00
parent 89ab368258
commit 47059d2d26
20 changed files with 657 additions and 706 deletions

View file

@ -22,7 +22,6 @@ use euclid::approxeq::ApproxEq;
use euclid::num::Zero; use euclid::num::Zero;
use euclid::{Matrix2D, Matrix4, Point2D, Rect, SideOffsets2D, Size2D}; use euclid::{Matrix2D, Matrix4, Point2D, Rect, SideOffsets2D, Size2D};
use gfx_traits::{color, LayerId, LayerKind, ScrollPolicy}; use gfx_traits::{color, LayerId, LayerKind, ScrollPolicy};
use libc::uintptr_t;
use msg::constellation_msg::PipelineId; use msg::constellation_msg::PipelineId;
use net_traits::image::base::Image; use net_traits::image::base::Image;
use paint_context::PaintContext; use paint_context::PaintContext;
@ -49,6 +48,8 @@ use util::opts;
use util::print_tree::PrintTree; use util::print_tree::PrintTree;
use util::range::Range; use util::range::Range;
pub use style::dom::OpaqueNode;
// It seems cleaner to have layout code not mention Azure directly, so let's just reexport this for // It seems cleaner to have layout code not mention Azure directly, so let's just reexport this for
// layout to use. // layout to use.
pub use azure::azure_hl::GradientStop; pub use azure::azure_hl::GradientStop;
@ -59,24 +60,6 @@ pub mod optimizer;
/// items that involve a blur. This ensures that the display item boundaries include all the ink. /// items that involve a blur. This ensures that the display item boundaries include all the ink.
pub static BLUR_INFLATION_FACTOR: i32 = 3; pub static BLUR_INFLATION_FACTOR: i32 = 3;
/// An opaque handle to a node. The only safe operation that can be performed on this node is to
/// compare it to another opaque handle or to another node.
///
/// Because the script task's GC does not trace layout, node data cannot be safely stored in layout
/// data structures. Also, layout code tends to be faster when the DOM is not being accessed, for
/// locality reasons. Using `OpaqueNode` enforces this invariant.
#[derive(Clone, PartialEq, Copy, Debug, HeapSizeOf, Hash, Eq, Deserialize, Serialize)]
pub struct OpaqueNode(pub uintptr_t);
impl OpaqueNode {
/// Returns the address of this node, for debugging purposes.
#[inline]
pub fn id(&self) -> uintptr_t {
let OpaqueNode(pointer) = *self;
pointer
}
}
/// LayerInfo is used to store PaintLayer metadata during DisplayList construction. /// LayerInfo is used to store PaintLayer metadata during DisplayList construction.
/// It is also used for tracking LayerIds when creating layers to preserve ordering when /// It is also used for tracking LayerIds when creating layers to preserve ordering when
/// layered DisplayItems should render underneath unlayered DisplayItems. /// layered DisplayItems should render underneath unlayered DisplayItems.

View file

@ -15,7 +15,7 @@
use block::BlockFlow; use block::BlockFlow;
use context::LayoutContext; use context::LayoutContext;
use data::{HAS_NEWLY_CONSTRUCTED_FLOW, LayoutDataWrapper}; use data::{HAS_NEWLY_CONSTRUCTED_FLOW, PrivateLayoutData};
use flex::FlexFlow; use flex::FlexFlow;
use floats::FloatKind; use floats::FloatKind;
use flow::{MutableFlowUtils, MutableOwnedFlowUtils}; use flow::{MutableFlowUtils, MutableOwnedFlowUtils};
@ -58,7 +58,7 @@ use traversal::PostorderNodeMutTraversal;
use url::Url; use url::Url;
use util::linked_list; use util::linked_list;
use util::opts; use util::opts;
use wrapper::{PseudoElementType, TextContent, ThreadSafeLayoutElement, ThreadSafeLayoutNode}; use wrapper::{LayoutNode, PseudoElementType, TextContent, ThreadSafeLayoutElement, ThreadSafeLayoutNode};
/// The results of flow construction for a DOM node. /// The results of flow construction for a DOM node.
#[derive(Clone)] #[derive(Clone)]
@ -1326,10 +1326,9 @@ impl<'a, 'ln, ConcreteThreadSafeLayoutNode: ThreadSafeLayoutNode<'ln>>
let mut style = node.style().clone(); let mut style = node.style().clone();
let mut layout_data_ref = node.mutate_layout_data(); let mut data = node.mutate_layout_data().unwrap();
let layout_data = layout_data_ref.as_mut().expect("no layout data"); let damage = data.restyle_damage;
let damage = layout_data.data.restyle_damage; match *node.construction_result_mut(&mut *data) {
match *node.construction_result_mut(layout_data) {
ConstructionResult::None => true, ConstructionResult::None => true,
ConstructionResult::Flow(ref mut flow, _) => { ConstructionResult::Flow(ref mut flow, _) => {
// The node's flow is of the same type and has the same set of children and can // The node's flow is of the same type and has the same set of children and can
@ -1580,7 +1579,7 @@ trait NodeUtils {
/// Returns true if this node doesn't render its kids and false otherwise. /// Returns true if this node doesn't render its kids and false otherwise.
fn is_replaced_content(&self) -> bool; fn is_replaced_content(&self) -> bool;
fn construction_result_mut(self, layout_data: &mut LayoutDataWrapper) -> &mut ConstructionResult; fn construction_result_mut(self, layout_data: &mut PrivateLayoutData) -> &mut ConstructionResult;
/// Sets the construction result of a flow. /// Sets the construction result of a flow.
fn set_flow_construction_result(self, result: ConstructionResult); fn set_flow_construction_result(self, result: ConstructionResult);
@ -1611,30 +1610,26 @@ impl<'ln, ConcreteThreadSafeLayoutNode> NodeUtils for ConcreteThreadSafeLayoutNo
} }
} }
fn construction_result_mut(self, layout_data: &mut LayoutDataWrapper) -> &mut ConstructionResult { fn construction_result_mut(self, data: &mut PrivateLayoutData) -> &mut ConstructionResult {
match self.get_pseudo_element_type() { match self.get_pseudo_element_type() {
PseudoElementType::Before(_) => &mut layout_data.data.before_flow_construction_result, PseudoElementType::Before(_) => &mut data.before_flow_construction_result,
PseudoElementType::After (_) => &mut layout_data.data.after_flow_construction_result, PseudoElementType::After (_) => &mut data.after_flow_construction_result,
PseudoElementType::Normal => &mut layout_data.data.flow_construction_result, PseudoElementType::Normal => &mut data.flow_construction_result,
} }
} }
#[inline(always)] #[inline(always)]
fn set_flow_construction_result(self, result: ConstructionResult) { fn set_flow_construction_result(self, result: ConstructionResult) {
let mut layout_data_ref = self.mutate_layout_data(); let mut layout_data = self.mutate_layout_data().unwrap();
let layout_data = layout_data_ref.as_mut().expect("no layout data"); let dst = self.construction_result_mut(&mut *layout_data);
let dst = self.construction_result_mut(layout_data);
*dst = result; *dst = result;
} }
#[inline(always)] #[inline(always)]
fn swap_out_construction_result(self) -> ConstructionResult { fn swap_out_construction_result(self) -> ConstructionResult {
let mut layout_data_ref = self.mutate_layout_data(); let mut layout_data = self.mutate_layout_data().unwrap();
let layout_data = layout_data_ref.as_mut().expect("no layout data"); self.construction_result_mut(&mut *layout_data).swap_out()
self.construction_result_mut(layout_data).swap_out()
} }
} }

View file

@ -8,7 +8,7 @@
use animation; use animation;
use context::SharedLayoutContext; use context::SharedLayoutContext;
use data::LayoutDataWrapper; use data::PrivateLayoutData;
use incremental::{self, RestyleDamage}; use incremental::{self, RestyleDamage};
use msg::ParseErrorReporter; use msg::ParseErrorReporter;
use script::layout_interface::Animation; use script::layout_interface::Animation;
@ -20,18 +20,19 @@ use selectors::{Element};
use smallvec::SmallVec; use smallvec::SmallVec;
use std::borrow::ToOwned; use std::borrow::ToOwned;
use std::hash::{Hash, Hasher}; use std::hash::{Hash, Hasher};
use std::mem::transmute;
use std::slice::Iter; use std::slice::Iter;
use std::sync::mpsc::Sender; use std::sync::mpsc::Sender;
use std::sync::{Arc, Mutex}; use std::sync::{Arc, Mutex};
use string_cache::{Atom, Namespace}; use string_cache::{Atom, Namespace};
use style::node::TElementAttributes; use style::data::PrivateStyleData;
use style::dom::{TElement, TNode};
use style::properties::{ComputedValues, PropertyDeclaration, cascade}; use style::properties::{ComputedValues, PropertyDeclaration, cascade};
use style::selector_matching::{DeclarationBlock, Stylist}; use style::selector_matching::{DeclarationBlock, Stylist};
use util::arc_ptr_eq; use util::arc_ptr_eq;
use util::cache::{LRUCache, SimpleHashCache}; use util::cache::{LRUCache, SimpleHashCache};
use util::opts; use util::opts;
use util::vec::ForgetfulSink; use util::vec::ForgetfulSink;
use wrapper::{LayoutElement, LayoutNode};
pub struct ApplicableDeclarations { pub struct ApplicableDeclarations {
pub normal: SmallVec<[DeclarationBlock; 16]>, pub normal: SmallVec<[DeclarationBlock; 16]>,
@ -160,7 +161,7 @@ pub struct StyleSharingCandidateCache {
cache: LRUCache<StyleSharingCandidate, ()>, cache: LRUCache<StyleSharingCandidate, ()>,
} }
fn create_common_style_affecting_attributes_from_element<'le, E: LayoutElement<'le>>(element: &E) fn create_common_style_affecting_attributes_from_element<'le, E: TElement<'le>>(element: &E)
-> CommonStyleAffectingAttributes { -> CommonStyleAffectingAttributes {
let mut flags = CommonStyleAffectingAttributes::empty(); let mut flags = CommonStyleAffectingAttributes::empty();
for attribute_info in &common_style_affecting_attributes() { for attribute_info in &common_style_affecting_attributes() {
@ -211,17 +212,17 @@ impl StyleSharingCandidate {
/// Attempts to create a style sharing candidate from this node. Returns /// Attempts to create a style sharing candidate from this node. Returns
/// the style sharing candidate or `None` if this node is ineligible for /// the style sharing candidate or `None` if this node is ineligible for
/// style sharing. /// style sharing.
fn new<'le, E: LayoutElement<'le>>(element: &E) -> Option<StyleSharingCandidate> { fn new<'le, E: TElement<'le>>(element: &E) -> Option<StyleSharingCandidate> {
let parent_element = match element.parent_element() { let parent_element = match element.parent_element() {
None => return None, None => return None,
Some(parent_element) => parent_element, Some(parent_element) => parent_element,
}; };
let style = unsafe { let style = unsafe {
match *element.as_node().borrow_layout_data_unchecked() { match element.as_node().borrow_data_unchecked() {
None => return None, None => return None,
Some(ref layout_data_ref) => { Some(data_ref) => {
match layout_data_ref.shared_data.style { match (*data_ref).style {
None => return None, None => return None,
Some(ref data) => (*data).clone(), Some(ref data) => (*data).clone(),
} }
@ -229,10 +230,10 @@ impl StyleSharingCandidate {
} }
}; };
let parent_style = unsafe { let parent_style = unsafe {
match *parent_element.as_node().borrow_layout_data_unchecked() { match parent_element.as_node().borrow_data_unchecked() {
None => return None, None => return None,
Some(ref parent_layout_data_ref) => { Some(parent_data_ref) => {
match parent_layout_data_ref.shared_data.style { match (*parent_data_ref).style {
None => return None, None => return None,
Some(ref data) => (*data).clone(), Some(ref data) => (*data).clone(),
} }
@ -257,7 +258,7 @@ impl StyleSharingCandidate {
}) })
} }
fn can_share_style_with<'a, E: LayoutElement<'a>>(&self, element: &E) -> bool { fn can_share_style_with<'a, E: TElement<'a>>(&self, element: &E) -> bool {
if *element.get_local_name() != self.local_name { if *element.get_local_name() != self.local_name {
return false return false
} }
@ -342,7 +343,7 @@ impl StyleSharingCandidateCache {
self.cache.iter() self.cache.iter()
} }
pub fn insert_if_possible<'le, E: LayoutElement<'le>>(&mut self, element: &E) { pub fn insert_if_possible<'le, E: TElement<'le>>(&mut self, element: &E) {
match StyleSharingCandidate::new(element) { match StyleSharingCandidate::new(element) {
None => {} None => {}
Some(candidate) => self.cache.insert(candidate, ()) Some(candidate) => self.cache.insert(candidate, ())
@ -363,7 +364,7 @@ pub enum StyleSharingResult {
StyleWasShared(usize, RestyleDamage), StyleWasShared(usize, RestyleDamage),
} }
pub trait ElementMatchMethods<'le, ConcreteLayoutElement: LayoutElement<'le>> { pub trait ElementMatchMethods<'le, ConcreteElement: TElement<'le>> {
fn match_element(&self, fn match_element(&self,
stylist: &Stylist, stylist: &Stylist,
parent_bf: Option<&BloomFilter>, parent_bf: Option<&BloomFilter>,
@ -376,11 +377,11 @@ pub trait ElementMatchMethods<'le, ConcreteLayoutElement: LayoutElement<'le>> {
unsafe fn share_style_if_possible(&self, unsafe fn share_style_if_possible(&self,
style_sharing_candidate_cache: style_sharing_candidate_cache:
&mut StyleSharingCandidateCache, &mut StyleSharingCandidateCache,
parent: Option<ConcreteLayoutElement::ConcreteLayoutNode>) parent: Option<ConcreteElement::ConcreteNode>)
-> StyleSharingResult; -> StyleSharingResult;
} }
pub trait MatchMethods<'ln, ConcreteLayoutNode: LayoutNode<'ln>> { pub trait MatchMethods<'ln, ConcreteNode: TNode<'ln>> {
/// Inserts and removes the matching `Descendant` selectors from a bloom /// Inserts and removes the matching `Descendant` selectors from a bloom
/// filter. This is used to speed up CSS selector matching to remove /// filter. This is used to speed up CSS selector matching to remove
/// unnecessary tree climbs for `Descendant` queries. /// unnecessary tree climbs for `Descendant` queries.
@ -396,7 +397,7 @@ pub trait MatchMethods<'ln, ConcreteLayoutNode: LayoutNode<'ln>> {
unsafe fn cascade_node(&self, unsafe fn cascade_node(&self,
layout_context: &SharedLayoutContext, layout_context: &SharedLayoutContext,
parent: Option<ConcreteLayoutNode>, parent: Option<ConcreteNode>,
applicable_declarations: &ApplicableDeclarations, applicable_declarations: &ApplicableDeclarations,
applicable_declarations_cache: &mut ApplicableDeclarationsCache, applicable_declarations_cache: &mut ApplicableDeclarationsCache,
new_animations_sender: &Mutex<Sender<Animation>>); new_animations_sender: &Mutex<Sender<Animation>>);
@ -420,15 +421,15 @@ trait PrivateMatchMethods {
-> bool; -> bool;
} }
trait PrivateElementMatchMethods<'le, ConcreteLayoutElement: LayoutElement<'le>> { trait PrivateElementMatchMethods<'le, ConcreteElement: TElement<'le>> {
fn share_style_with_candidate_if_possible(&self, fn share_style_with_candidate_if_possible(&self,
parent_node: Option<ConcreteLayoutElement::ConcreteLayoutNode>, parent_node: Option<ConcreteElement::ConcreteNode>,
candidate: &StyleSharingCandidate) candidate: &StyleSharingCandidate)
-> Option<Arc<ComputedValues>>; -> Option<Arc<ComputedValues>>;
} }
impl<'ln, ConcreteLayoutNode> PrivateMatchMethods for ConcreteLayoutNode impl<'ln, ConcreteNode> PrivateMatchMethods for ConcreteNode
where ConcreteLayoutNode: LayoutNode<'ln> { where ConcreteNode: TNode<'ln> {
fn cascade_node_pseudo_element(&self, fn cascade_node_pseudo_element(&self,
layout_context: &SharedLayoutContext, layout_context: &SharedLayoutContext,
parent_style: Option<&Arc<ComputedValues>>, parent_style: Option<&Arc<ComputedValues>>,
@ -547,11 +548,11 @@ impl<'ln, ConcreteLayoutNode> PrivateMatchMethods for ConcreteLayoutNode
} }
} }
impl<'le, ConcreteLayoutElement> PrivateElementMatchMethods<'le, ConcreteLayoutElement> impl<'le, ConcreteElement> PrivateElementMatchMethods<'le, ConcreteElement>
for ConcreteLayoutElement for ConcreteElement
where ConcreteLayoutElement: LayoutElement<'le> { where ConcreteElement: TElement<'le> {
fn share_style_with_candidate_if_possible(&self, fn share_style_with_candidate_if_possible(&self,
parent_node: Option<ConcreteLayoutElement::ConcreteLayoutNode>, parent_node: Option<ConcreteElement::ConcreteNode>,
candidate: &StyleSharingCandidate) candidate: &StyleSharingCandidate)
-> Option<Arc<ComputedValues>> { -> Option<Arc<ComputedValues>> {
let parent_node = match parent_node { let parent_node = match parent_node {
@ -559,13 +560,13 @@ impl<'le, ConcreteLayoutElement> PrivateElementMatchMethods<'le, ConcreteLayoutE
Some(_) | None => return None, Some(_) | None => return None,
}; };
let parent_layout_data: &Option<LayoutDataWrapper> = unsafe { let parent_data: Option<&PrivateStyleData> = unsafe {
&*parent_node.borrow_layout_data_unchecked() parent_node.borrow_data_unchecked().map(|d| &*d)
}; };
match *parent_layout_data { match parent_data {
Some(ref parent_layout_data_ref) => { Some(parent_data_ref) => {
// Check parent style. // Check parent style.
let parent_style = parent_layout_data_ref.shared_data.style.as_ref().unwrap(); let parent_style = (*parent_data_ref).style.as_ref().unwrap();
if !arc_ptr_eq(parent_style, &candidate.parent_style) { if !arc_ptr_eq(parent_style, &candidate.parent_style) {
return None return None
} }
@ -584,9 +585,9 @@ impl<'le, ConcreteLayoutElement> PrivateElementMatchMethods<'le, ConcreteLayoutE
} }
} }
impl<'le, ConcreteLayoutElement> ElementMatchMethods<'le, ConcreteLayoutElement> impl<'le, ConcreteElement> ElementMatchMethods<'le, ConcreteElement>
for ConcreteLayoutElement for ConcreteElement
where ConcreteLayoutElement: LayoutElement<'le> { where ConcreteElement: TElement<'le> {
fn match_element(&self, fn match_element(&self,
stylist: &Stylist, stylist: &Stylist,
parent_bf: Option<&BloomFilter>, parent_bf: Option<&BloomFilter>,
@ -619,7 +620,7 @@ impl<'le, ConcreteLayoutElement> ElementMatchMethods<'le, ConcreteLayoutElement>
unsafe fn share_style_if_possible(&self, unsafe fn share_style_if_possible(&self,
style_sharing_candidate_cache: style_sharing_candidate_cache:
&mut StyleSharingCandidateCache, &mut StyleSharingCandidateCache,
parent: Option<ConcreteLayoutElement::ConcreteLayoutNode>) parent: Option<ConcreteElement::ConcreteNode>)
-> StyleSharingResult { -> StyleSharingResult {
if opts::get().disable_share_style_cache { if opts::get().disable_share_style_cache {
return StyleSharingResult::CannotShare return StyleSharingResult::CannotShare
@ -637,9 +638,7 @@ impl<'le, ConcreteLayoutElement> ElementMatchMethods<'le, ConcreteLayoutElement>
Some(shared_style) => { Some(shared_style) => {
// Yay, cache hit. Share the style. // Yay, cache hit. Share the style.
let node = self.as_node(); let node = self.as_node();
let mut layout_data_ref = node.mutate_layout_data(); let style = &mut node.mutate_data().unwrap().style;
let shared_data = &mut layout_data_ref.as_mut().unwrap().shared_data;
let style = &mut shared_data.style;
let damage = incremental::compute_damage(style, &*shared_style); let damage = incremental::compute_damage(style, &*shared_style);
*style = Some(shared_style); *style = Some(shared_style);
return StyleSharingResult::StyleWasShared(i, damage) return StyleSharingResult::StyleWasShared(i, damage)
@ -652,9 +651,9 @@ impl<'le, ConcreteLayoutElement> ElementMatchMethods<'le, ConcreteLayoutElement>
} }
} }
impl<'ln, ConcreteLayoutNode> MatchMethods<'ln, ConcreteLayoutNode> impl<'ln, ConcreteNode> MatchMethods<'ln, ConcreteNode>
for ConcreteLayoutNode for ConcreteNode
where ConcreteLayoutNode: LayoutNode<'ln> { where ConcreteNode: TNode<'ln> {
// The below two functions are copy+paste because I can't figure out how to // The below two functions are copy+paste because I can't figure out how to
// write a function which takes a generic function. I don't think it can // write a function which takes a generic function. I don't think it can
// be done. // be done.
@ -696,7 +695,7 @@ impl<'ln, ConcreteLayoutNode> MatchMethods<'ln, ConcreteLayoutNode>
unsafe fn cascade_node(&self, unsafe fn cascade_node(&self,
layout_context: &SharedLayoutContext, layout_context: &SharedLayoutContext,
parent: Option<ConcreteLayoutNode>, parent: Option<ConcreteNode>,
applicable_declarations: &ApplicableDeclarations, applicable_declarations: &ApplicableDeclarations,
applicable_declarations_cache: &mut ApplicableDeclarationsCache, applicable_declarations_cache: &mut ApplicableDeclarationsCache,
new_animations_sender: &Mutex<Sender<Animation>>) { new_animations_sender: &Mutex<Sender<Animation>>) {
@ -708,63 +707,57 @@ impl<'ln, ConcreteLayoutNode> MatchMethods<'ln, ConcreteLayoutNode>
let parent_style = match parent { let parent_style = match parent {
None => None, None => None,
Some(parent_node) => { Some(parent_node) => {
let parent_layout_data_ref = parent_node.borrow_layout_data_unchecked(); let parent_style = (*parent_node.borrow_data_unchecked().unwrap()).style.as_ref().unwrap();
let parent_layout_data = (&*parent_layout_data_ref).as_ref()
.expect("no parent data!?");
let parent_style = parent_layout_data.shared_data
.style
.as_ref()
.expect("parent hasn't been styled yet!");
Some(parent_style) Some(parent_style)
} }
}; };
let mut layout_data_ref = self.mutate_layout_data(); let mut data_ref = self.mutate_data().unwrap();
match *layout_data_ref { let mut data = &mut *data_ref;
None => panic!("no layout data"), if self.is_text_node() {
Some(ref mut layout_data) => { // Text nodes get a copy of the parent style. This ensures
if self.is_text_node() { // that during fragment construction any non-inherited
// Text nodes get a copy of the parent style. This ensures // CSS properties (such as vertical-align) are correctly
// that during fragment construction any non-inherited // set on the fragment(s).
// CSS properties (such as vertical-align) are correctly let cloned_parent_style = parent_style.unwrap().clone();
// set on the fragment(s). data.style = Some(cloned_parent_style);
let cloned_parent_style = parent_style.unwrap().clone(); } else {
layout_data.shared_data.style = Some(cloned_parent_style); let mut damage = self.cascade_node_pseudo_element(
} else { layout_context,
let mut damage = self.cascade_node_pseudo_element( parent_style,
layout_context, &applicable_declarations.normal,
parent_style, &mut data.style,
&applicable_declarations.normal, applicable_declarations_cache,
&mut layout_data.shared_data.style, new_animations_sender,
applicable_declarations_cache, applicable_declarations.normal_shareable,
new_animations_sender, true);
applicable_declarations.normal_shareable, if !applicable_declarations.before.is_empty() {
true); damage = damage | self.cascade_node_pseudo_element(
if !applicable_declarations.before.is_empty() { layout_context,
damage = damage | self.cascade_node_pseudo_element( Some(data.style.as_ref().unwrap()),
layout_context, &*applicable_declarations.before,
Some(layout_data.shared_data.style.as_ref().unwrap()), &mut data.before_style,
&*applicable_declarations.before, applicable_declarations_cache,
&mut layout_data.data.before_style, new_animations_sender,
applicable_declarations_cache, false,
new_animations_sender, false);
false,
false);
}
if !applicable_declarations.after.is_empty() {
damage = damage | self.cascade_node_pseudo_element(
layout_context,
Some(layout_data.shared_data.style.as_ref().unwrap()),
&*applicable_declarations.after,
&mut layout_data.data.after_style,
applicable_declarations_cache,
new_animations_sender,
false,
false);
}
layout_data.data.restyle_damage = damage;
}
} }
if !applicable_declarations.after.is_empty() {
damage = damage | self.cascade_node_pseudo_element(
layout_context,
Some(data.style.as_ref().unwrap()),
&*applicable_declarations.after,
&mut data.after_style,
applicable_declarations_cache,
new_animations_sender,
false,
false);
}
// FIXME(bholley): This is the only dependency in this file on non-style
// stuff.
let layout_data: &mut PrivateLayoutData = transmute(data);
layout_data.restyle_damage = damage;
} }
} }
} }

View file

@ -4,18 +4,15 @@
use construct::ConstructionResult; use construct::ConstructionResult;
use incremental::RestyleDamage; use incremental::RestyleDamage;
use parallel::DomParallelInfo; use style::data::PrivateStyleData;
use script::dom::node::SharedLayoutData;
use std::sync::Arc;
use style::properties::ComputedValues;
/// Data that layout associates with a node. /// Data that layout associates with a node.
pub struct PrivateLayoutData { pub struct PrivateLayoutData {
/// The results of CSS styling for this node's `before` pseudo-element, if any. /// Data that the style system associates with a node. When the
pub before_style: Option<Arc<ComputedValues>>, /// style system is being used standalone, this is all that hangs
/// off the node. This must be first to permit the various
/// The results of CSS styling for this node's `after` pseudo-element, if any. /// transmuations between PrivateStyleData PrivateLayoutData.
pub after_style: Option<Arc<ComputedValues>>, pub style_data: PrivateStyleData,
/// Description of how to account for recent style changes. /// Description of how to account for recent style changes.
pub restyle_damage: RestyleDamage, pub restyle_damage: RestyleDamage,
@ -28,9 +25,6 @@ pub struct PrivateLayoutData {
pub after_flow_construction_result: ConstructionResult, pub after_flow_construction_result: ConstructionResult,
/// Information needed during parallel traversals.
pub parallel: DomParallelInfo,
/// Various flags. /// Various flags.
pub flags: LayoutDataFlags, pub flags: LayoutDataFlags,
} }
@ -39,13 +33,11 @@ impl PrivateLayoutData {
/// Creates new layout data. /// Creates new layout data.
pub fn new() -> PrivateLayoutData { pub fn new() -> PrivateLayoutData {
PrivateLayoutData { PrivateLayoutData {
before_style: None, style_data: PrivateStyleData::new(),
after_style: None,
restyle_damage: RestyleDamage::empty(), restyle_damage: RestyleDamage::empty(),
flow_construction_result: ConstructionResult::None, flow_construction_result: ConstructionResult::None,
before_flow_construction_result: ConstructionResult::None, before_flow_construction_result: ConstructionResult::None,
after_flow_construction_result: ConstructionResult::None, after_flow_construction_result: ConstructionResult::None,
parallel: DomParallelInfo::new(),
flags: LayoutDataFlags::empty(), flags: LayoutDataFlags::empty(),
} }
} }
@ -57,16 +49,3 @@ bitflags! {
const HAS_NEWLY_CONSTRUCTED_FLOW = 0x01 const HAS_NEWLY_CONSTRUCTED_FLOW = 0x01
} }
} }
pub struct LayoutDataWrapper {
pub shared_data: SharedLayoutData,
pub data: Box<PrivateLayoutData>,
}
#[allow(dead_code, unsafe_code)]
fn static_assertion(x: Option<LayoutDataWrapper>) {
unsafe {
let _: Option<::script::dom::node::LayoutData> =
::std::intrinsics::transmute(x);
}
}

View file

@ -47,6 +47,7 @@ bitflags! {
} }
} }
impl RestyleDamage { impl RestyleDamage {
/// Supposing a flow has the given `position` property and this damage, returns the damage that /// Supposing a flow has the given `position` property and this damage, returns the damage that
/// we should add to the *parent* of this flow. /// we should add to the *parent* of this flow.

View file

@ -13,7 +13,6 @@ use azure::azure::AzColor;
use canvas_traits::CanvasMsg; use canvas_traits::CanvasMsg;
use construct::ConstructionResult; use construct::ConstructionResult;
use context::{SharedLayoutContext, StylistWrapper, heap_size_of_local_context}; use context::{SharedLayoutContext, StylistWrapper, heap_size_of_local_context};
use data::LayoutDataWrapper;
use display_list_builder::ToGfxColor; use display_list_builder::ToGfxColor;
use euclid::Matrix4; use euclid::Matrix4;
use euclid::point::Point2D; use euclid::point::Point2D;
@ -45,7 +44,7 @@ use profile_traits::time::{TimerMetadataFrameType, TimerMetadataReflowType};
use profile_traits::time::{self, TimerMetadata, profile}; use profile_traits::time::{self, TimerMetadata, profile};
use query::{LayoutRPCImpl, process_content_box_request, process_content_boxes_request}; use query::{LayoutRPCImpl, process_content_box_request, process_content_boxes_request};
use query::{process_node_geometry_request, process_offset_parent_query, process_resolved_style_request}; use query::{process_node_geometry_request, process_offset_parent_query, process_resolved_style_request};
use script::dom::node::LayoutData; use script::dom::node::OpaqueStyleAndLayoutData;
use script::layout_interface::Animation; use script::layout_interface::Animation;
use script::layout_interface::{LayoutRPC, OffsetParentResponse}; use script::layout_interface::{LayoutRPC, OffsetParentResponse};
use script::layout_interface::{Msg, NewLayoutTaskInfo, Reflow, ReflowGoal, ReflowQueryType}; use script::layout_interface::{Msg, NewLayoutTaskInfo, Reflow, ReflowGoal, ReflowQueryType};
@ -65,6 +64,7 @@ use std::sync::atomic::{AtomicUsize, Ordering};
use std::sync::mpsc::{channel, Sender, Receiver}; use std::sync::mpsc::{channel, Sender, Receiver};
use std::sync::{Arc, Mutex, MutexGuard, RwLock}; use std::sync::{Arc, Mutex, MutexGuard, RwLock};
use style::computed_values::{filter, mix_blend_mode}; use style::computed_values::{filter, mix_blend_mode};
use style::dom::{TDocument, TElement, TNode};
use style::media_queries::{Device, MediaType}; use style::media_queries::{Device, MediaType};
use style::selector_matching::{Stylist, USER_OR_USER_AGENT_STYLESHEETS}; use style::selector_matching::{Stylist, USER_OR_USER_AGENT_STYLESHEETS};
use style::stylesheets::{CSSRuleIteratorExt, Stylesheet}; use style::stylesheets::{CSSRuleIteratorExt, Stylesheet};
@ -77,8 +77,7 @@ use util::opts;
use util::task; use util::task;
use util::task_state; use util::task_state;
use util::workqueue::WorkQueue; use util::workqueue::WorkQueue;
use wrapper::{LayoutDocument, LayoutElement, LayoutNode}; use wrapper::{LayoutNode, NonOpaqueStyleAndLayoutData, ServoLayoutNode, ThreadSafeLayoutNode};
use wrapper::{ServoLayoutNode, ThreadSafeLayoutNode};
/// The number of screens of data we're allowed to generate display lists for in each direction. /// The number of screens of data we're allowed to generate display lists for in each direction.
pub const DISPLAY_PORT_SIZE_FACTOR: i32 = 8; pub const DISPLAY_PORT_SIZE_FACTOR: i32 = 8;
@ -607,9 +606,9 @@ impl LayoutTask {
Msg::SetVisibleRects(new_visible_rects) => { Msg::SetVisibleRects(new_visible_rects) => {
self.set_visible_rects(new_visible_rects, possibly_locked_rw_data); self.set_visible_rects(new_visible_rects, possibly_locked_rw_data);
} }
Msg::ReapLayoutData(dead_layout_data) => { Msg::ReapStyleAndLayoutData(dead_data) => {
unsafe { unsafe {
self.handle_reap_layout_data(dead_layout_data) self.handle_reap_style_and_layout_data(dead_data)
} }
} }
Msg::CollectReports(reports_chan) => { Msg::CollectReports(reports_chan) => {
@ -707,9 +706,9 @@ impl LayoutTask {
response_chan.send(()).unwrap(); response_chan.send(()).unwrap();
loop { loop {
match self.port.recv().unwrap() { match self.port.recv().unwrap() {
Msg::ReapLayoutData(dead_layout_data) => { Msg::ReapStyleAndLayoutData(dead_data) => {
unsafe { unsafe {
self.handle_reap_layout_data(dead_layout_data) self.handle_reap_style_and_layout_data(dead_data)
} }
} }
Msg::ExitNow => { Msg::ExitNow => {
@ -765,14 +764,11 @@ impl LayoutTask {
} }
fn try_get_layout_root<'ln, N: LayoutNode<'ln>>(&self, node: N) -> Option<FlowRef> { fn try_get_layout_root<'ln, N: LayoutNode<'ln>>(&self, node: N) -> Option<FlowRef> {
let mut layout_data_ref = node.mutate_layout_data(); let mut data = match node.mutate_layout_data() {
let layout_data = Some(x) => x,
match layout_data_ref.as_mut() { None => return None,
None => return None, };
Some(layout_data) => layout_data, let result = data.flow_construction_result.swap_out();
};
let result = layout_data.data.flow_construction_result.swap_out();
let mut flow = match result { let mut flow = match result {
ConstructionResult::Flow(mut flow, abs_descendants) => { ConstructionResult::Flow(mut flow, abs_descendants) => {
@ -1312,8 +1308,9 @@ impl LayoutTask {
/// Handles a message to destroy layout data. Layout data must be destroyed on *this* task /// Handles a message to destroy layout data. Layout data must be destroyed on *this* task
/// because the struct type is transmuted to a different type on the script side. /// because the struct type is transmuted to a different type on the script side.
unsafe fn handle_reap_layout_data(&self, layout_data: LayoutData) { unsafe fn handle_reap_style_and_layout_data(&self, data: OpaqueStyleAndLayoutData) {
let _: LayoutDataWrapper = transmute(layout_data); let non_opaque: NonOpaqueStyleAndLayoutData = transmute(data.ptr);
let _ = Box::from_raw(non_opaque);
} }
/// Returns profiling information which is passed to the time profiler. /// Returns profiling information which is passed to the time profiler.

View file

@ -2,11 +2,13 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this * 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/. */ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#![feature(as_unsafe_cell)]
#![feature(box_syntax)] #![feature(box_syntax)]
#![feature(cell_extras)] #![feature(cell_extras)]
#![feature(custom_derive)] #![feature(custom_derive)]
#![feature(hashmap_hasher)] #![feature(hashmap_hasher)]
#![feature(mpsc_select)] #![feature(mpsc_select)]
#![feature(nonzero)]
#![feature(plugin)] #![feature(plugin)]
#![feature(raw)] #![feature(raw)]
#![feature(step_by)] #![feature(step_by)]
@ -22,6 +24,7 @@ extern crate azure;
#[macro_use] #[macro_use]
extern crate bitflags; extern crate bitflags;
extern crate canvas_traits; extern crate canvas_traits;
extern crate core;
extern crate cssparser; extern crate cssparser;
extern crate encoding; extern crate encoding;
extern crate euclid; extern crate euclid;

View file

@ -15,6 +15,7 @@ use gfx::display_list::OpaqueNode;
use profile_traits::time::{self, TimerMetadata, profile}; use profile_traits::time::{self, TimerMetadata, profile};
use std::mem; use std::mem;
use std::sync::atomic::{AtomicIsize, Ordering}; use std::sync::atomic::{AtomicIsize, Ordering};
use style::dom::UnsafeNode;
use traversal::PostorderNodeMutTraversal; use traversal::PostorderNodeMutTraversal;
use traversal::{AssignBSizesAndStoreOverflow, AssignISizes, BubbleISizes}; use traversal::{AssignBSizesAndStoreOverflow, AssignISizes, BubbleISizes};
use traversal::{BuildDisplayList, ComputeAbsolutePositions}; use traversal::{BuildDisplayList, ComputeAbsolutePositions};
@ -22,17 +23,17 @@ use traversal::{ConstructFlows, RecalcStyleForNode};
use traversal::{PostorderDomTraversal, PreorderDomTraversal}; use traversal::{PostorderDomTraversal, PreorderDomTraversal};
use util::opts; use util::opts;
use util::workqueue::{WorkQueue, WorkUnit, WorkerProxy}; use util::workqueue::{WorkQueue, WorkUnit, WorkerProxy};
use wrapper::{LayoutNode, UnsafeLayoutNode}; use wrapper::LayoutNode;
const CHUNK_SIZE: usize = 64; const CHUNK_SIZE: usize = 64;
pub struct WorkQueueData(usize, usize); pub struct WorkQueueData(usize, usize);
#[allow(dead_code)] #[allow(dead_code)]
fn static_assertion(node: UnsafeLayoutNode) { fn static_assertion(node: UnsafeNode) {
unsafe { unsafe {
let _: UnsafeFlow = ::std::intrinsics::transmute(node); let _: UnsafeFlow = ::std::intrinsics::transmute(node);
let _: UnsafeLayoutNodeList = ::std::intrinsics::transmute(node); let _: UnsafeNodeList = ::std::intrinsics::transmute(node);
} }
} }
@ -55,31 +56,17 @@ pub fn borrowed_flow_to_unsafe_flow(flow: &Flow) -> UnsafeFlow {
} }
} }
/// Information that we need stored in each DOM node. pub type UnsafeNodeList = (Box<Vec<UnsafeNode>>, OpaqueNode);
pub struct DomParallelInfo {
/// The number of children that still need work done.
pub children_count: AtomicIsize,
}
impl DomParallelInfo { pub type UnsafeFlowList = (Box<Vec<UnsafeNode>>, usize);
pub fn new() -> DomParallelInfo {
DomParallelInfo {
children_count: AtomicIsize::new(0),
}
}
}
pub type UnsafeLayoutNodeList = (Box<Vec<UnsafeLayoutNode>>, OpaqueNode);
pub type UnsafeFlowList = (Box<Vec<UnsafeLayoutNode>>, usize);
pub type ChunkedDomTraversalFunction = pub type ChunkedDomTraversalFunction =
extern "Rust" fn(UnsafeLayoutNodeList, extern "Rust" fn(UnsafeNodeList,
&mut WorkerProxy<SharedLayoutContext, UnsafeLayoutNodeList>); &mut WorkerProxy<SharedLayoutContext, UnsafeNodeList>);
pub type DomTraversalFunction = pub type DomTraversalFunction =
extern "Rust" fn(OpaqueNode, UnsafeLayoutNode, extern "Rust" fn(OpaqueNode, UnsafeNode,
&mut WorkerProxy<SharedLayoutContext, UnsafeLayoutNodeList>); &mut WorkerProxy<SharedLayoutContext, UnsafeNodeList>);
pub type ChunkedFlowTraversalFunction = pub type ChunkedFlowTraversalFunction =
extern "Rust" fn(UnsafeFlowList, &mut WorkerProxy<SharedLayoutContext, UnsafeFlowList>); extern "Rust" fn(UnsafeFlowList, &mut WorkerProxy<SharedLayoutContext, UnsafeFlowList>);
@ -91,14 +78,14 @@ pub trait ParallelPreorderDomTraversal<'ln, ConcreteLayoutNode>
: PreorderDomTraversal<'ln, ConcreteLayoutNode> : PreorderDomTraversal<'ln, ConcreteLayoutNode>
where ConcreteLayoutNode: LayoutNode<'ln> { where ConcreteLayoutNode: LayoutNode<'ln> {
fn run_parallel(&self, fn run_parallel(&self,
nodes: UnsafeLayoutNodeList, nodes: UnsafeNodeList,
proxy: &mut WorkerProxy<SharedLayoutContext, UnsafeLayoutNodeList>); proxy: &mut WorkerProxy<SharedLayoutContext, UnsafeNodeList>);
#[inline(always)] #[inline(always)]
fn run_parallel_helper( fn run_parallel_helper(
&self, &self,
unsafe_nodes: UnsafeLayoutNodeList, unsafe_nodes: UnsafeNodeList,
proxy: &mut WorkerProxy<SharedLayoutContext, UnsafeLayoutNodeList>, proxy: &mut WorkerProxy<SharedLayoutContext, UnsafeNodeList>,
top_down_func: ChunkedDomTraversalFunction, top_down_func: ChunkedDomTraversalFunction,
bottom_up_func: DomTraversalFunction) { bottom_up_func: DomTraversalFunction) {
let mut discovered_child_nodes = Vec::new(); let mut discovered_child_nodes = Vec::new();
@ -113,10 +100,9 @@ pub trait ParallelPreorderDomTraversal<'ln, ConcreteLayoutNode>
// Reset the count of children. // Reset the count of children.
{ {
let mut layout_data_ref = node.mutate_layout_data(); let data = node.mutate_data().unwrap();
let layout_data = layout_data_ref.as_mut().expect("no layout data"); data.parallel.children_count.store(child_count as isize,
layout_data.data.parallel.children_count.store(child_count as isize, Ordering::Relaxed);
Ordering::Relaxed);
} }
// Possibly enqueue the children. // Possibly enqueue the children.
@ -156,7 +142,7 @@ trait ParallelPostorderDomTraversal<'ln, ConcreteLayoutNode>
/// ///
/// The only communication between siblings is that they both /// The only communication between siblings is that they both
/// fetch-and-subtract the parent's children count. /// fetch-and-subtract the parent's children count.
fn run_parallel(&self, unsafe_node: UnsafeLayoutNode) { fn run_parallel(&self, unsafe_node: UnsafeNode) {
// Get a real layout node. // Get a real layout node.
let mut node = unsafe { ConcreteLayoutNode::from_unsafe(&unsafe_node) }; let mut node = unsafe { ConcreteLayoutNode::from_unsafe(&unsafe_node) };
loop { loop {
@ -168,13 +154,11 @@ trait ParallelPostorderDomTraversal<'ln, ConcreteLayoutNode>
Some(parent) => parent, Some(parent) => parent,
}; };
let parent_layout_data = unsafe { let parent_data = unsafe {
&*parent.borrow_layout_data_unchecked() &*parent.borrow_data_unchecked().unwrap()
}; };
let parent_layout_data = parent_layout_data.as_ref().expect("no layout data");
if parent_layout_data if parent_data
.data
.parallel .parallel
.children_count .children_count
.fetch_sub(1, Ordering::Relaxed) != 1 { .fetch_sub(1, Ordering::Relaxed) != 1 {
@ -360,8 +344,8 @@ impl<'a, 'ln, ConcreteLayoutNode> ParallelPreorderDomTraversal<'ln, ConcreteLayo
for RecalcStyleForNode<'a> for RecalcStyleForNode<'a>
where ConcreteLayoutNode: LayoutNode<'ln> { where ConcreteLayoutNode: LayoutNode<'ln> {
fn run_parallel(&self, fn run_parallel(&self,
unsafe_nodes: UnsafeLayoutNodeList, unsafe_nodes: UnsafeNodeList,
proxy: &mut WorkerProxy<SharedLayoutContext, UnsafeLayoutNodeList>) { proxy: &mut WorkerProxy<SharedLayoutContext, UnsafeNodeList>) {
// Not exactly sure why we need UFCS here, but we seem to. // Not exactly sure why we need UFCS here, but we seem to.
<RecalcStyleForNode<'a> as ParallelPreorderDomTraversal<'ln, ConcreteLayoutNode>> <RecalcStyleForNode<'a> as ParallelPreorderDomTraversal<'ln, ConcreteLayoutNode>>
::run_parallel_helper(self, unsafe_nodes, proxy, ::run_parallel_helper(self, unsafe_nodes, proxy,
@ -370,8 +354,8 @@ impl<'a, 'ln, ConcreteLayoutNode> ParallelPreorderDomTraversal<'ln, ConcreteLayo
} }
} }
fn recalc_style<'ln, ConcreteLayoutNode>(unsafe_nodes: UnsafeLayoutNodeList, fn recalc_style<'ln, ConcreteLayoutNode>(unsafe_nodes: UnsafeNodeList,
proxy: &mut WorkerProxy<SharedLayoutContext, UnsafeLayoutNodeList>) proxy: &mut WorkerProxy<SharedLayoutContext, UnsafeNodeList>)
where ConcreteLayoutNode: LayoutNode<'ln> { where ConcreteLayoutNode: LayoutNode<'ln> {
let shared_layout_context = proxy.user_data(); let shared_layout_context = proxy.user_data();
let layout_context = LayoutContext::new(shared_layout_context); let layout_context = LayoutContext::new(shared_layout_context);
@ -388,8 +372,8 @@ fn recalc_style<'ln, ConcreteLayoutNode>(unsafe_nodes: UnsafeLayoutNodeList,
fn construct_flows<'ln, ConcreteLayoutNode: LayoutNode<'ln>>( fn construct_flows<'ln, ConcreteLayoutNode: LayoutNode<'ln>>(
root: OpaqueNode, root: OpaqueNode,
unsafe_node: UnsafeLayoutNode, unsafe_node: UnsafeNode,
proxy: &mut WorkerProxy<SharedLayoutContext, UnsafeLayoutNodeList>) { proxy: &mut WorkerProxy<SharedLayoutContext, UnsafeNodeList>) {
let shared_layout_context = proxy.user_data(); let shared_layout_context = proxy.user_data();
let layout_context = LayoutContext::new(shared_layout_context); let layout_context = LayoutContext::new(shared_layout_context);
let construct_flows_traversal = ConstructFlows { let construct_flows_traversal = ConstructFlows {

View file

@ -479,9 +479,9 @@ pub fn process_resolved_style_request<'ln, N: LayoutNode<'ln>>(
layout_root: &mut FlowRef, layout_root: &mut FlowRef,
requested_node: N, requested_node: N,
property: &Atom) -> Option<String> { property: &Atom) -> Option<String> {
let layout_data = layout_node.borrow_layout_data(); let maybe_data = layout_node.borrow_layout_data();
let position = layout_data.as_ref().map(|layout_data| { let position = maybe_data.map(|data| {
match layout_data.data.flow_construction_result { match (*data).flow_construction_result {
ConstructionResult::Flow(ref flow_ref, _) => ConstructionResult::Flow(ref flow_ref, _) =>
flow::base(flow_ref.deref()).stacking_relative_position, flow::base(flow_ref.deref()).stacking_relative_position,
// TODO(dzbarsky) search parents until we find node with a flow ref. // TODO(dzbarsky) search parents until we find node with a flow ref.

View file

@ -15,10 +15,10 @@ use script::layout_interface::ReflowGoal;
use selectors::bloom::BloomFilter; use selectors::bloom::BloomFilter;
use std::cell::RefCell; use std::cell::RefCell;
use std::mem; use std::mem;
use style::dom::UnsafeNode;
use util::opts; use util::opts;
use util::tid::tid; use util::tid::tid;
use wrapper::{LayoutNode, UnsafeLayoutNode}; use wrapper::{LayoutNode, ThreadSafeLayoutNode};
use wrapper::{ThreadSafeLayoutNode};
/// Every time we do another layout, the old bloom filters are invalid. This is /// Every time we do another layout, the old bloom filters are invalid. This is
/// detected by ticking a generation number every layout. /// detected by ticking a generation number every layout.
@ -45,7 +45,7 @@ type Generation = u32;
/// will no longer be the for the parent of the node we're currently on. When /// will no longer be the for the parent of the node we're currently on. When
/// this happens, the task local bloom filter will be thrown away and rebuilt. /// this happens, the task local bloom filter will be thrown away and rebuilt.
thread_local!( thread_local!(
static STYLE_BLOOM: RefCell<Option<(Box<BloomFilter>, UnsafeLayoutNode, Generation)>> = RefCell::new(None)); static STYLE_BLOOM: RefCell<Option<(Box<BloomFilter>, UnsafeNode, Generation)>> = RefCell::new(None));
/// Returns the task local bloom filter. /// Returns the task local bloom filter.
/// ///
@ -88,7 +88,7 @@ fn take_task_local_bloom_filter<'ln, N>(parent_node: Option<N>,
} }
fn put_task_local_bloom_filter(bf: Box<BloomFilter>, fn put_task_local_bloom_filter(bf: Box<BloomFilter>,
unsafe_node: &UnsafeLayoutNode, unsafe_node: &UnsafeNode,
layout_context: &LayoutContext) { layout_context: &LayoutContext) {
STYLE_BLOOM.with(move |style_bloom| { STYLE_BLOOM.with(move |style_bloom| {
assert!(style_bloom.borrow().is_none(), assert!(style_bloom.borrow().is_none(),
@ -153,7 +153,7 @@ impl<'a, 'ln, ConcreteLayoutNode> PreorderDomTraversal<'ln, ConcreteLayoutNode>
// //
// FIXME(pcwalton): Stop allocating here. Ideally this should just be done by the HTML // FIXME(pcwalton): Stop allocating here. Ideally this should just be done by the HTML
// parser. // parser.
node.initialize_layout_data(); node.initialize_data();
// Get the parent node. // Get the parent node.
let parent_opt = node.layout_parent_node(self.root); let parent_opt = node.layout_parent_node(self.root);

View file

@ -30,7 +30,8 @@
#![allow(unsafe_code)] #![allow(unsafe_code)]
use data::{LayoutDataFlags, LayoutDataWrapper, PrivateLayoutData}; use core::nonzero::NonZero;
use data::{LayoutDataFlags, PrivateLayoutData};
use gfx::display_list::OpaqueNode; use gfx::display_list::OpaqueNode;
use gfx::text::glyph::CharIndex; use gfx::text::glyph::CharIndex;
use incremental::RestyleDamage; use incremental::RestyleDamage;
@ -49,7 +50,7 @@ use script::dom::htmlimageelement::LayoutHTMLImageElementHelpers;
use script::dom::htmlinputelement::{HTMLInputElement, LayoutHTMLInputElementHelpers}; use script::dom::htmlinputelement::{HTMLInputElement, LayoutHTMLInputElementHelpers};
use script::dom::htmltextareaelement::{HTMLTextAreaElement, LayoutHTMLTextAreaElementHelpers}; use script::dom::htmltextareaelement::{HTMLTextAreaElement, LayoutHTMLTextAreaElementHelpers};
use script::dom::node::{HAS_CHANGED, HAS_DIRTY_DESCENDANTS, IS_DIRTY}; use script::dom::node::{HAS_CHANGED, HAS_DIRTY_DESCENDANTS, IS_DIRTY};
use script::dom::node::{LayoutNodeHelpers, Node, SharedLayoutData}; use script::dom::node::{LayoutNodeHelpers, Node, OpaqueStyleAndLayoutData};
use script::dom::text::Text; use script::dom::text::Text;
use script::layout_interface::TrustedNodeAddress; use script::layout_interface::TrustedNodeAddress;
use selectors::matching::DeclarationBlock; use selectors::matching::DeclarationBlock;
@ -57,204 +58,38 @@ use selectors::parser::{AttrSelector, NamespaceConstraint};
use selectors::states::*; use selectors::states::*;
use smallvec::VecLike; use smallvec::VecLike;
use std::borrow::ToOwned; use std::borrow::ToOwned;
use std::cell::{Ref, RefMut}; use std::cell::{Ref, RefCell, RefMut};
use std::marker::PhantomData; use std::marker::PhantomData;
use std::mem; use std::mem::{transmute, transmute_copy};
use std::sync::Arc; use std::sync::Arc;
use string_cache::{Atom, Namespace}; use string_cache::{Atom, Namespace};
use style::computed_values::content::ContentItem; use style::computed_values::content::ContentItem;
use style::computed_values::{content, display}; use style::computed_values::{content, display};
use style::node::TElementAttributes; use style::data::PrivateStyleData;
use style::dom::{TDocument, TElement, TNode, UnsafeNode};
use style::properties::ComputedValues; use style::properties::ComputedValues;
use style::properties::{PropertyDeclaration, PropertyDeclarationBlock}; use style::properties::{PropertyDeclaration, PropertyDeclarationBlock};
use style::restyle_hints::{ElementSnapshot, RESTYLE_DESCENDANTS, RESTYLE_LATER_SIBLINGS, RESTYLE_SELF, RestyleHint}; use style::restyle_hints::ElementSnapshot;
use url::Url; use url::Url;
use util::str::{is_whitespace, search_index}; use util::str::{is_whitespace, search_index};
/// Opaque type stored in type-unsafe work queues for parallel layout. pub type NonOpaqueStyleAndLayoutData = *mut RefCell<PrivateLayoutData>;
/// Must be transmutable to and from LayoutNode.
pub type UnsafeLayoutNode = (usize, usize);
/// A wrapper so that layout can access only the methods that it should have access to. Layout must /// A wrapper so that layout can access only the methods that it should have access to. Layout must
/// only ever see these and must never see instances of `LayoutJS`. /// only ever see these and must never see instances of `LayoutJS`.
pub trait LayoutNode<'ln> : Sized + Copy + Clone { pub trait LayoutNode<'ln> : TNode<'ln> {
type ConcreteThreadSafeLayoutNode: ThreadSafeLayoutNode<'ln>; type ConcreteThreadSafeLayoutNode: ThreadSafeLayoutNode<'ln>;
type ConcreteLayoutElement: LayoutElement<'ln, ConcreteLayoutNode = Self,
ConcreteLayoutDocument = Self::ConcreteLayoutDocument>;
type ConcreteLayoutDocument: LayoutDocument<'ln, ConcreteLayoutNode = Self,
ConcreteLayoutElement = Self::ConcreteLayoutElement>;
fn to_unsafe(&self) -> UnsafeLayoutNode;
unsafe fn from_unsafe(&UnsafeLayoutNode) -> Self;
fn to_threadsafe(&self) -> Self::ConcreteThreadSafeLayoutNode; fn to_threadsafe(&self) -> Self::ConcreteThreadSafeLayoutNode;
/// Returns the type ID of this node. /// Returns the type ID of this node.
fn type_id(&self) -> NodeTypeId; fn type_id(&self) -> NodeTypeId;
/// Returns whether this is a text node. It turns out that this is all the style system cares /// Similar to borrow_data*, but returns the full PrivateLayoutData rather
/// about, and thus obviates the need to compute the full type id, which would be expensive in /// than only the PrivateStyleData.
/// Gecko. unsafe fn borrow_layout_data_unchecked(&self) -> Option<*const PrivateLayoutData>;
fn is_text_node(&self) -> bool; fn borrow_layout_data(&self) -> Option<Ref<PrivateLayoutData>>;
fn mutate_layout_data(&self) -> Option<RefMut<PrivateLayoutData>>;
fn is_element(&self) -> bool;
fn dump(self);
fn traverse_preorder(self) -> LayoutTreeIterator<'ln, Self> {
LayoutTreeIterator::new(self)
}
/// Returns an iterator over this node's children.
fn children(self) -> LayoutNodeChildrenIterator<'ln, Self> {
LayoutNodeChildrenIterator {
current: self.first_child(),
phantom: PhantomData,
}
}
fn rev_children(self) -> LayoutNodeReverseChildrenIterator<'ln, Self> {
LayoutNodeReverseChildrenIterator {
current: self.last_child(),
phantom: PhantomData,
}
}
/// Converts self into an `OpaqueNode`.
fn opaque(&self) -> OpaqueNode;
/// Resets layout data and styles for the node.
///
/// FIXME(pcwalton): Do this as part of fragment building instead of in a traversal.
fn initialize_layout_data(self);
/// While doing a reflow, the node at the root has no parent, as far as we're
/// concerned. This method returns `None` at the reflow root.
fn layout_parent_node(self, reflow_root: OpaqueNode) -> Option<Self>;
fn debug_id(self) -> usize;
fn as_element(&self) -> Option<Self::ConcreteLayoutElement>;
fn as_document(&self) -> Option<Self::ConcreteLayoutDocument>;
fn children_count(&self) -> u32;
fn has_changed(&self) -> bool;
unsafe fn set_changed(&self, value: bool);
fn is_dirty(&self) -> bool;
unsafe fn set_dirty(&self, value: bool);
fn has_dirty_descendants(&self) -> bool;
unsafe fn set_dirty_descendants(&self, value: bool);
fn dirty_self(&self) {
unsafe {
self.set_dirty(true);
self.set_dirty_descendants(true);
}
}
fn dirty_descendants(&self) {
for ref child in self.children() {
child.dirty_self();
child.dirty_descendants();
}
}
/// Borrows the layout data without checks.
#[inline(always)]
unsafe fn borrow_layout_data_unchecked(&self) -> *const Option<LayoutDataWrapper>;
/// Borrows the layout data immutably. Fails on a conflicting borrow.
#[inline(always)]
fn borrow_layout_data(&self) -> Ref<Option<LayoutDataWrapper>>;
/// Borrows the layout data mutably. Fails on a conflicting borrow.
#[inline(always)]
fn mutate_layout_data(&self) -> RefMut<Option<LayoutDataWrapper>>;
fn parent_node(&self) -> Option<Self>;
fn first_child(&self) -> Option<Self>;
fn last_child(&self) -> Option<Self>;
fn prev_sibling(&self) -> Option<Self>;
fn next_sibling(&self) -> Option<Self>;
}
pub trait LayoutDocument<'ld> : Sized + Copy + Clone {
type ConcreteLayoutNode: LayoutNode<'ld, ConcreteLayoutElement = Self::ConcreteLayoutElement,
ConcreteLayoutDocument = Self>;
type ConcreteLayoutElement: LayoutElement<'ld, ConcreteLayoutNode = Self::ConcreteLayoutNode,
ConcreteLayoutDocument = Self>;
fn as_node(&self) -> Self::ConcreteLayoutNode;
fn root_node(&self) -> Option<Self::ConcreteLayoutNode>;
fn drain_modified_elements(&self) -> Vec<(Self::ConcreteLayoutElement, ElementSnapshot)>;
}
pub trait LayoutElement<'le> : Sized + Copy + Clone + ::selectors::Element + TElementAttributes {
type ConcreteLayoutNode: LayoutNode<'le, ConcreteLayoutElement = Self,
ConcreteLayoutDocument = Self::ConcreteLayoutDocument>;
type ConcreteLayoutDocument: LayoutDocument<'le, ConcreteLayoutNode = Self::ConcreteLayoutNode,
ConcreteLayoutElement = Self>;
fn as_node(&self) -> Self::ConcreteLayoutNode;
fn style_attribute(&self) -> &'le Option<PropertyDeclarationBlock>;
fn get_state(&self) -> ElementState;
/// Properly marks nodes as dirty in response to restyle hints.
fn note_restyle_hint(&self, mut hint: RestyleHint) {
// Bail early if there's no restyling to do.
if hint.is_empty() {
return;
}
// If the restyle hint is non-empty, we need to restyle either this element
// or one of its siblings. Mark our ancestor chain as having dirty descendants.
let node = self.as_node();
let mut curr = node;
while let Some(parent) = curr.parent_node() {
if parent.has_dirty_descendants() { break }
unsafe { parent.set_dirty_descendants(true); }
curr = parent;
}
// Process hints.
if hint.contains(RESTYLE_SELF) {
node.dirty_self();
// FIXME(bholley, #8438): We currently need to RESTYLE_DESCENDANTS in the
// RESTYLE_SELF case in order to make sure "inherit" style structs propagate
// properly. See the explanation in the github issue.
hint.insert(RESTYLE_DESCENDANTS);
}
if hint.contains(RESTYLE_DESCENDANTS) {
unsafe { node.set_dirty_descendants(true); }
node.dirty_descendants();
}
if hint.contains(RESTYLE_LATER_SIBLINGS) {
let mut next = ::selectors::Element::next_sibling_element(self);
while let Some(sib) = next {
let sib_node = sib.as_node();
sib_node.dirty_self();
sib_node.dirty_descendants();
next = ::selectors::Element::next_sibling_element(&sib);
}
}
}
} }
#[derive(Copy, Clone)] #[derive(Copy, Clone)]
@ -294,31 +129,20 @@ impl<'ln> ServoLayoutNode<'ln> {
} }
} }
impl<'ln> LayoutNode<'ln> for ServoLayoutNode<'ln> { impl<'ln> TNode<'ln> for ServoLayoutNode<'ln> {
type ConcreteThreadSafeLayoutNode = ServoThreadSafeLayoutNode<'ln>; type ConcreteElement = ServoLayoutElement<'ln>;
type ConcreteLayoutElement = ServoLayoutElement<'ln>; type ConcreteDocument = ServoLayoutDocument<'ln>;
type ConcreteLayoutDocument = ServoLayoutDocument<'ln>;
fn to_unsafe(&self) -> UnsafeLayoutNode { fn to_unsafe(&self) -> UnsafeNode {
unsafe { unsafe {
let ptr: usize = mem::transmute_copy(self); let ptr: usize = transmute_copy(self);
(ptr, 0) (ptr, 0)
} }
} }
unsafe fn from_unsafe(n: &UnsafeLayoutNode) -> Self { unsafe fn from_unsafe(n: &UnsafeNode) -> Self {
let (node, _) = *n; let (node, _) = *n;
mem::transmute(node) transmute(node)
}
fn to_threadsafe(&self) -> Self::ConcreteThreadSafeLayoutNode {
ServoThreadSafeLayoutNode::new(self)
}
fn type_id(&self) -> NodeTypeId {
unsafe {
self.node.type_id_for_layout()
}
} }
fn is_text_node(&self) -> bool { fn is_text_node(&self) -> bool {
@ -339,16 +163,17 @@ impl<'ln> LayoutNode<'ln> for ServoLayoutNode<'ln> {
OpaqueNodeMethods::from_jsmanaged(unsafe { self.get_jsmanaged() }) OpaqueNodeMethods::from_jsmanaged(unsafe { self.get_jsmanaged() })
} }
fn initialize_layout_data(self) { fn initialize_data(self) {
let mut layout_data_ref = self.mutate_layout_data(); let has_data = unsafe { self.borrow_data_unchecked().is_some() };
match *layout_data_ref { if !has_data {
None => { let ptr: NonOpaqueStyleAndLayoutData =
*layout_data_ref = Some(LayoutDataWrapper { Box::into_raw(box RefCell::new(PrivateLayoutData::new()));
shared_data: SharedLayoutData { style: None }, let opaque = OpaqueStyleAndLayoutData {
data: box PrivateLayoutData::new(), ptr: unsafe { NonZero::new(ptr as *mut ()) }
}); };
unsafe {
self.node.init_style_and_layout_data(opaque);
} }
Some(_) => {}
} }
} }
@ -400,20 +225,16 @@ impl<'ln> LayoutNode<'ln> for ServoLayoutNode<'ln> {
self.node.set_flag(HAS_DIRTY_DESCENDANTS, value) self.node.set_flag(HAS_DIRTY_DESCENDANTS, value)
} }
unsafe fn borrow_layout_data_unchecked(&self) -> *const Option<LayoutDataWrapper> { unsafe fn borrow_data_unchecked(&self) -> Option<*const PrivateStyleData> {
mem::transmute(self.get_jsmanaged().layout_data_unchecked()) self.borrow_layout_data_unchecked().map(|d| &(*d).style_data as *const PrivateStyleData)
} }
fn borrow_layout_data(&self) -> Ref<Option<LayoutDataWrapper>> { fn borrow_data(&self) -> Option<Ref<PrivateStyleData>> {
unsafe { unsafe { self.borrow_layout_data().map(|d| transmute(d)) }
mem::transmute(self.get_jsmanaged().layout_data())
}
} }
fn mutate_layout_data(&self) -> RefMut<Option<LayoutDataWrapper>> { fn mutate_data(&self) -> Option<RefMut<PrivateStyleData>> {
unsafe { unsafe { self.mutate_layout_data().map(|d| transmute(d)) }
mem::transmute(self.get_jsmanaged().layout_data_mut())
}
} }
fn parent_node(&self) -> Option<ServoLayoutNode<'ln>> { fn parent_node(&self) -> Option<ServoLayoutNode<'ln>> {
@ -447,6 +268,46 @@ impl<'ln> LayoutNode<'ln> for ServoLayoutNode<'ln> {
} }
} }
impl<'ln> LayoutNode<'ln> for ServoLayoutNode<'ln> {
type ConcreteThreadSafeLayoutNode = ServoThreadSafeLayoutNode<'ln>;
fn to_threadsafe(&self) -> Self::ConcreteThreadSafeLayoutNode {
ServoThreadSafeLayoutNode::new(self)
}
fn type_id(&self) -> NodeTypeId {
unsafe {
self.node.type_id_for_layout()
}
}
unsafe fn borrow_layout_data_unchecked(&self) -> Option<*const PrivateLayoutData> {
self.get_jsmanaged().get_style_and_layout_data().map(|opaque| {
let container: NonOpaqueStyleAndLayoutData = transmute(opaque.ptr);
&(*(*container).as_unsafe_cell().get()) as *const PrivateLayoutData
})
}
fn borrow_layout_data(&self) -> Option<Ref<PrivateLayoutData>> {
unsafe {
self.get_jsmanaged().get_style_and_layout_data().map(|opaque| {
let container: NonOpaqueStyleAndLayoutData = transmute(opaque.ptr);
(*container).borrow()
})
}
}
fn mutate_layout_data(&self) -> Option<RefMut<PrivateLayoutData>> {
unsafe {
self.get_jsmanaged().get_style_and_layout_data().map(|opaque| {
let container: NonOpaqueStyleAndLayoutData = transmute(opaque.ptr);
(*container).borrow_mut()
})
}
}
}
impl<'ln> ServoLayoutNode<'ln> { impl<'ln> ServoLayoutNode<'ln> {
fn dump_indent(self, indent: u32) { fn dump_indent(self, indent: u32) {
let mut s = String::new(); let mut s = String::new();
@ -468,11 +329,7 @@ impl<'ln> ServoLayoutNode<'ln> {
} }
pub fn flow_debug_id(self) -> usize { pub fn flow_debug_id(self) -> usize {
let layout_data_ref = self.borrow_layout_data(); self.borrow_layout_data().map_or(0, |d| d.flow_construction_result.debug_id())
match *layout_data_ref {
None => 0,
Some(ref layout_data) => layout_data.data.flow_construction_result.debug_id()
}
} }
/// Returns the interior of this node as a `LayoutJS`. This is highly unsafe for layout to /// Returns the interior of this node as a `LayoutJS`. This is highly unsafe for layout to
@ -482,65 +339,6 @@ impl<'ln> ServoLayoutNode<'ln> {
} }
} }
pub struct LayoutNodeChildrenIterator<'a, ConcreteLayoutNode> where ConcreteLayoutNode: LayoutNode<'a> {
current: Option<ConcreteLayoutNode>,
// Satisfy the compiler about the unused lifetime.
phantom: PhantomData<&'a ()>,
}
impl<'a, ConcreteLayoutNode> Iterator for LayoutNodeChildrenIterator<'a, ConcreteLayoutNode>
where ConcreteLayoutNode: LayoutNode<'a> {
type Item = ConcreteLayoutNode;
fn next(&mut self) -> Option<ConcreteLayoutNode> {
let node = self.current;
self.current = node.and_then(|node| node.next_sibling());
node
}
}
pub struct LayoutNodeReverseChildrenIterator<'a, ConcreteLayoutNode> where ConcreteLayoutNode: LayoutNode<'a> {
current: Option<ConcreteLayoutNode>,
// Satisfy the compiler about the unused lifetime.
phantom: PhantomData<&'a ()>,
}
impl<'a, ConcreteLayoutNode> Iterator for LayoutNodeReverseChildrenIterator<'a, ConcreteLayoutNode>
where ConcreteLayoutNode: LayoutNode<'a> {
type Item = ConcreteLayoutNode;
fn next(&mut self) -> Option<ConcreteLayoutNode> {
let node = self.current;
self.current = node.and_then(|node| node.prev_sibling());
node
}
}
pub struct LayoutTreeIterator<'a, ConcreteLayoutNode> where ConcreteLayoutNode: LayoutNode<'a> {
stack: Vec<ConcreteLayoutNode>,
// Satisfy the compiler about the unused lifetime.
phantom: PhantomData<&'a ()>,
}
impl<'a, ConcreteLayoutNode> LayoutTreeIterator<'a, ConcreteLayoutNode> where ConcreteLayoutNode: LayoutNode<'a> {
fn new(root: ConcreteLayoutNode) -> LayoutTreeIterator<'a, ConcreteLayoutNode> {
let mut stack = vec!();
stack.push(root);
LayoutTreeIterator {
stack: stack,
phantom: PhantomData,
}
}
}
impl<'a, ConcreteLayoutNode> Iterator for LayoutTreeIterator<'a, ConcreteLayoutNode>
where ConcreteLayoutNode: LayoutNode<'a> {
type Item = ConcreteLayoutNode;
fn next(&mut self) -> Option<ConcreteLayoutNode> {
let ret = self.stack.pop();
ret.map(|node| self.stack.extend(node.rev_children()));
ret
}
}
// A wrapper around documents that ensures ayout can only ever access safe properties. // A wrapper around documents that ensures ayout can only ever access safe properties.
#[derive(Copy, Clone)] #[derive(Copy, Clone)]
pub struct ServoLayoutDocument<'ld> { pub struct ServoLayoutDocument<'ld> {
@ -548,9 +346,9 @@ pub struct ServoLayoutDocument<'ld> {
chain: PhantomData<&'ld ()>, chain: PhantomData<&'ld ()>,
} }
impl<'ld> LayoutDocument<'ld> for ServoLayoutDocument<'ld> { impl<'ld> TDocument<'ld> for ServoLayoutDocument<'ld> {
type ConcreteLayoutNode = ServoLayoutNode<'ld>; type ConcreteNode = ServoLayoutNode<'ld>;
type ConcreteLayoutElement = ServoLayoutElement<'ld>; type ConcreteElement = ServoLayoutElement<'ld>;
fn as_node(&self) -> ServoLayoutNode<'ld> { fn as_node(&self) -> ServoLayoutNode<'ld> {
ServoLayoutNode::from_layout_js(self.document.upcast()) ServoLayoutNode::from_layout_js(self.document.upcast())
@ -582,9 +380,9 @@ pub struct ServoLayoutElement<'le> {
chain: PhantomData<&'le ()>, chain: PhantomData<&'le ()>,
} }
impl<'le> LayoutElement<'le> for ServoLayoutElement<'le> { impl<'le> TElement<'le> for ServoLayoutElement<'le> {
type ConcreteLayoutNode = ServoLayoutNode<'le>; type ConcreteNode = ServoLayoutNode<'le>;
type ConcreteLayoutDocument = ServoLayoutDocument<'le>; type ConcreteDocument = ServoLayoutDocument<'le>;
fn as_node(&self) -> ServoLayoutNode<'le> { fn as_node(&self) -> ServoLayoutNode<'le> {
ServoLayoutNode::from_layout_js(self.element.upcast()) ServoLayoutNode::from_layout_js(self.element.upcast())
@ -599,6 +397,28 @@ impl<'le> LayoutElement<'le> for ServoLayoutElement<'le> {
fn get_state(&self) -> ElementState { fn get_state(&self) -> ElementState {
self.element.get_state_for_layout() self.element.get_state_for_layout()
} }
fn synthesize_presentational_hints_for_legacy_attributes<V>(&self, hints: &mut V)
where V: VecLike<DeclarationBlock<Vec<PropertyDeclaration>>>
{
unsafe {
self.element.synthesize_presentational_hints_for_legacy_attributes(hints);
}
}
#[inline]
fn get_attr<'a>(&'a self, namespace: &Namespace, name: &Atom) -> Option<&'a str> {
unsafe {
(*self.element.unsafe_get()).get_attr_val_for_layout(namespace, name)
}
}
#[inline]
fn get_attrs<'a>(&'a self, name: &Atom) -> Vec<&'a str> {
unsafe {
(*self.element.unsafe_get()).get_attr_vals_for_layout(name)
}
}
} }
@ -783,30 +603,6 @@ impl<'le> ::selectors::Element for ServoLayoutElement<'le> {
} }
} }
impl<'le> TElementAttributes for ServoLayoutElement<'le> {
fn synthesize_presentational_hints_for_legacy_attributes<V>(&self, hints: &mut V)
where V: VecLike<DeclarationBlock<Vec<PropertyDeclaration>>>
{
unsafe {
self.element.synthesize_presentational_hints_for_legacy_attributes(hints);
}
}
#[inline]
fn get_attr<'a>(&'a self, namespace: &Namespace, name: &Atom) -> Option<&'a str> {
unsafe {
(*self.element.unsafe_get()).get_attr_val_for_layout(namespace, name)
}
}
#[inline]
fn get_attrs<'a>(&'a self, name: &Atom) -> Vec<&'a str> {
unsafe {
(*self.element.unsafe_get()).get_attr_vals_for_layout(name)
}
}
}
#[derive(Copy, PartialEq, Clone)] #[derive(Copy, PartialEq, Clone)]
pub enum PseudoElementType<T> { pub enum PseudoElementType<T> {
Normal, Normal,
@ -865,18 +661,14 @@ pub trait ThreadSafeLayoutNode<'ln> : Clone + Copy + Sized {
#[inline] #[inline]
fn get_before_pseudo(&self) -> Option<Self> { fn get_before_pseudo(&self) -> Option<Self> {
let layout_data_ref = self.borrow_layout_data(); self.borrow_layout_data().unwrap().style_data.before_style.as_ref().map(|style| {
let node_layout_data_wrapper = layout_data_ref.as_ref().unwrap();
node_layout_data_wrapper.data.before_style.as_ref().map(|style| {
self.with_pseudo(PseudoElementType::Before(style.get_box().display)) self.with_pseudo(PseudoElementType::Before(style.get_box().display))
}) })
} }
#[inline] #[inline]
fn get_after_pseudo(&self) -> Option<Self> { fn get_after_pseudo(&self) -> Option<Self> {
let layout_data_ref = self.borrow_layout_data(); self.borrow_layout_data().unwrap().style_data.after_style.as_ref().map(|style| {
let node_layout_data_wrapper = layout_data_ref.as_ref().unwrap();
node_layout_data_wrapper.data.after_style.as_ref().map(|style| {
self.with_pseudo(PseudoElementType::After(style.get_box().display)) self.with_pseudo(PseudoElementType::After(style.get_box().display))
}) })
} }
@ -885,24 +677,23 @@ pub trait ThreadSafeLayoutNode<'ln> : Clone + Copy + Sized {
/// ///
/// TODO(pcwalton): Make this private. It will let us avoid borrow flag checks in some cases. /// TODO(pcwalton): Make this private. It will let us avoid borrow flag checks in some cases.
#[inline(always)] #[inline(always)]
fn borrow_layout_data(&self) -> Ref<Option<LayoutDataWrapper>>; fn borrow_layout_data(&self) -> Option<Ref<PrivateLayoutData>>;
/// Borrows the layout data mutably. Fails on a conflicting borrow. /// Borrows the layout data mutably. Fails on a conflicting borrow.
/// ///
/// TODO(pcwalton): Make this private. It will let us avoid borrow flag checks in some cases. /// TODO(pcwalton): Make this private. It will let us avoid borrow flag checks in some cases.
#[inline(always)] #[inline(always)]
fn mutate_layout_data(&self) -> RefMut<Option<LayoutDataWrapper>>; fn mutate_layout_data(&self) -> Option<RefMut<PrivateLayoutData>>;
/// Returns the style results for the given node. If CSS selector matching /// Returns the style results for the given node. If CSS selector matching
/// has not yet been performed, fails. /// has not yet been performed, fails.
#[inline] #[inline]
fn style(&self) -> Ref<Arc<ComputedValues>> { fn style(&self) -> Ref<Arc<ComputedValues>> {
Ref::map(self.borrow_layout_data(), |layout_data_ref| { Ref::map(self.borrow_layout_data().unwrap(), |data| {
let layout_data = layout_data_ref.as_ref().expect("no layout data");
let style = match self.get_pseudo_element_type() { let style = match self.get_pseudo_element_type() {
PseudoElementType::Before(_) => &layout_data.data.before_style, PseudoElementType::Before(_) => &data.style_data.before_style,
PseudoElementType::After(_) => &layout_data.data.after_style, PseudoElementType::After(_) => &data.style_data.after_style,
PseudoElementType::Normal => &layout_data.shared_data.style, PseudoElementType::Normal => &data.style_data.style,
}; };
style.as_ref().unwrap() style.as_ref().unwrap()
}) })
@ -910,14 +701,12 @@ pub trait ThreadSafeLayoutNode<'ln> : Clone + Copy + Sized {
/// Removes the style from this node. /// Removes the style from this node.
fn unstyle(self) { fn unstyle(self) {
let mut layout_data_ref = self.mutate_layout_data(); let mut data = self.mutate_layout_data().unwrap();
let layout_data = layout_data_ref.as_mut().expect("no layout data");
let style = let style =
match self.get_pseudo_element_type() { match self.get_pseudo_element_type() {
PseudoElementType::Before(_) => &mut layout_data.data.before_style, PseudoElementType::Before(_) => &mut data.style_data.before_style,
PseudoElementType::After (_) => &mut layout_data.data.after_style, PseudoElementType::After (_) => &mut data.style_data.after_style,
PseudoElementType::Normal => &mut layout_data.shared_data.style, PseudoElementType::Normal => &mut data.style_data.style,
}; };
*style = None; *style = None;
@ -928,17 +717,12 @@ pub trait ThreadSafeLayoutNode<'ln> : Clone + Copy + Sized {
/// Get the description of how to account for recent style changes. /// Get the description of how to account for recent style changes.
/// This is a simple bitfield and fine to copy by value. /// This is a simple bitfield and fine to copy by value.
fn restyle_damage(self) -> RestyleDamage { fn restyle_damage(self) -> RestyleDamage {
let layout_data_ref = self.borrow_layout_data(); self.borrow_layout_data().unwrap().restyle_damage
layout_data_ref.as_ref().unwrap().data.restyle_damage
} }
/// Set the restyle damage field. /// Set the restyle damage field.
fn set_restyle_damage(self, damage: RestyleDamage) { fn set_restyle_damage(self, damage: RestyleDamage) {
let mut layout_data_ref = self.mutate_layout_data(); self.mutate_layout_data().unwrap().restyle_damage = damage;
match *layout_data_ref {
Some(ref mut layout_data) => layout_data.data.restyle_damage = damage,
_ => panic!("no layout data for this node"),
}
} }
/// Returns the layout data flags for this node. /// Returns the layout data flags for this node.
@ -946,20 +730,12 @@ pub trait ThreadSafeLayoutNode<'ln> : Clone + Copy + Sized {
/// Adds the given flags to this node. /// Adds the given flags to this node.
fn insert_flags(self, new_flags: LayoutDataFlags) { fn insert_flags(self, new_flags: LayoutDataFlags) {
let mut layout_data_ref = self.mutate_layout_data(); self.mutate_layout_data().unwrap().flags.insert(new_flags);
match *layout_data_ref {
Some(ref mut layout_data) => layout_data.data.flags.insert(new_flags),
_ => panic!("no layout data for this node"),
}
} }
/// Removes the given flags from this node. /// Removes the given flags from this node.
fn remove_flags(self, flags: LayoutDataFlags) { fn remove_flags(self, flags: LayoutDataFlags) {
let mut layout_data_ref = self.mutate_layout_data(); self.mutate_layout_data().unwrap().flags.remove(flags);
match *layout_data_ref {
Some(ref mut layout_data) => layout_data.data.flags.remove(flags),
_ => panic!("no layout data for this node"),
}
} }
/// Returns true if this node contributes content. This is used in the implementation of /// Returns true if this node contributes content. This is used in the implementation of
@ -1049,14 +825,6 @@ impl<'ln> ServoThreadSafeLayoutNode<'ln> {
unsafe fn get_jsmanaged(&self) -> &LayoutJS<Node> { unsafe fn get_jsmanaged(&self) -> &LayoutJS<Node> {
self.node.get_jsmanaged() self.node.get_jsmanaged()
} }
/// Borrows the layout data without checking.
#[inline(always)]
fn borrow_layout_data_unchecked(&self) -> *const Option<LayoutDataWrapper> {
unsafe {
self.node.borrow_layout_data_unchecked()
}
}
} }
impl<'ln> ThreadSafeLayoutNode<'ln> for ServoThreadSafeLayoutNode<'ln> { impl<'ln> ThreadSafeLayoutNode<'ln> for ServoThreadSafeLayoutNode<'ln> {
@ -1112,11 +880,11 @@ impl<'ln> ThreadSafeLayoutNode<'ln> for ServoThreadSafeLayoutNode<'ln> {
self.pseudo self.pseudo
} }
fn borrow_layout_data(&self) -> Ref<Option<LayoutDataWrapper>> { fn borrow_layout_data(&self) -> Option<Ref<PrivateLayoutData>> {
self.node.borrow_layout_data() self.node.borrow_layout_data()
} }
fn mutate_layout_data(&self) -> RefMut<Option<LayoutDataWrapper>> { fn mutate_layout_data(&self) -> Option<RefMut<PrivateLayoutData>> {
self.node.mutate_layout_data() self.node.mutate_layout_data()
} }
@ -1143,17 +911,13 @@ impl<'ln> ThreadSafeLayoutNode<'ln> for ServoThreadSafeLayoutNode<'ln> {
fn flags(self) -> LayoutDataFlags { fn flags(self) -> LayoutDataFlags {
unsafe { unsafe {
match *self.borrow_layout_data_unchecked() { (*self.node.borrow_layout_data_unchecked().unwrap()).flags
None => panic!(),
Some(ref layout_data) => layout_data.data.flags,
}
} }
} }
fn text_content(&self) -> TextContent { fn text_content(&self) -> TextContent {
if self.pseudo != PseudoElementType::Normal { if self.pseudo != PseudoElementType::Normal {
let layout_data_ref = self.borrow_layout_data(); let data = &self.borrow_layout_data().unwrap().style_data;
let data = &layout_data_ref.as_ref().unwrap().data;
let style = if self.pseudo.is_before() { let style = if self.pseudo.is_before() {
&data.before_style &data.before_style

View file

@ -57,14 +57,12 @@ use selectors::matching::matches;
use selectors::parser::Selector; use selectors::parser::Selector;
use selectors::parser::parse_author_origin_selector_list_from_str; use selectors::parser::parse_author_origin_selector_list_from_str;
use std::borrow::ToOwned; use std::borrow::ToOwned;
use std::cell::{Cell, Ref, RefCell, RefMut}; use std::cell::Cell;
use std::cmp::max; use std::cmp::max;
use std::default::Default; use std::default::Default;
use std::iter::{self, FilterMap, Peekable}; use std::iter::{self, FilterMap, Peekable};
use std::mem; use std::mem;
use std::sync::Arc;
use string_cache::{Atom, Namespace, QualName}; use string_cache::{Atom, Namespace, QualName};
use style::properties::ComputedValues;
use util::str::DOMString; use util::str::DOMString;
use util::task_state; use util::task_state;
use uuid::Uuid; use uuid::Uuid;
@ -115,11 +113,11 @@ pub struct Node {
/// are this node. /// are this node.
ranges: WeakRangeVec, ranges: WeakRangeVec,
/// Layout information. Only the layout task may touch this data. /// Style+Layout information. Only the layout task may touch this data.
/// ///
/// Must be sent back to the layout task to be destroyed when this /// Must be sent back to the layout task to be destroyed when this
/// node is finalized. /// node is finalized.
layout_data: LayoutDataRef, style_and_layout_data: Cell<Option<OpaqueStyleAndLayoutData>>,
unique_id: DOMRefCell<Option<Box<Uuid>>>, unique_id: DOMRefCell<Option<Box<Uuid>>>,
} }
@ -164,7 +162,7 @@ impl NodeFlags {
impl Drop for Node { impl Drop for Node {
#[allow(unsafe_code)] #[allow(unsafe_code)]
fn drop(&mut self) { fn drop(&mut self) {
self.layout_data.dispose(self); self.style_and_layout_data.get().map(|d| d.dispose(self));
} }
} }
@ -177,74 +175,27 @@ enum SuppressObserver {
Unsuppressed Unsuppressed
} }
/// Layout data that is shared between the script and layout tasks. #[derive(Copy, Clone, HeapSizeOf)]
#[derive(HeapSizeOf)] pub struct OpaqueStyleAndLayoutData {
pub struct SharedLayoutData { #[ignore_heap_size_of = "TODO(#6910) Box value that should be counted but \
/// The results of CSS styling for this node. the type lives in layout"]
pub style: Option<Arc<ComputedValues>>, pub ptr: NonZero<*mut ()>
}
/// Encapsulates the abstract layout data.
#[derive(HeapSizeOf)]
pub struct LayoutData {
_shared_data: SharedLayoutData,
#[ignore_heap_size_of = "TODO(#6910) Box value that should be counted but the type lives in layout"]
_data: NonZero<*const ()>,
} }
#[allow(unsafe_code)] #[allow(unsafe_code)]
unsafe impl Send for LayoutData {} unsafe impl Send for OpaqueStyleAndLayoutData {}
#[derive(HeapSizeOf)] no_jsmanaged_fields!(OpaqueStyleAndLayoutData);
pub struct LayoutDataRef {
data_cell: RefCell<Option<LayoutData>>,
}
no_jsmanaged_fields!(LayoutDataRef);
impl LayoutDataRef { impl OpaqueStyleAndLayoutData {
pub fn new() -> LayoutDataRef { /// Sends the style and layout data, if any, back to the layout task to be destroyed.
LayoutDataRef { pub fn dispose(self, node: &Node) {
data_cell: RefCell::new(None),
}
}
/// Sends layout data, if any, back to the layout task to be destroyed.
pub fn dispose(&self, node: &Node) {
debug_assert!(task_state::get().is_script()); debug_assert!(task_state::get().is_script());
if let Some(layout_data) = mem::replace(&mut *self.data_cell.borrow_mut(), None) { let win = window_from_node(node);
let win = window_from_node(node); let LayoutChan(chan) = win.layout_chan();
let LayoutChan(chan) = win.layout_chan(); node.style_and_layout_data.set(None);
chan.send(Msg::ReapLayoutData(layout_data)).unwrap() chan.send(Msg::ReapStyleAndLayoutData(self)).unwrap();
}
}
/// Borrows the layout data immutably, *assuming that there are no mutators*. Bad things will
/// happen if you try to mutate the layout data while this is held. This is the only thread-
/// safe layout data accessor.
#[inline]
#[allow(unsafe_code)]
pub unsafe fn borrow_unchecked(&self) -> *const Option<LayoutData> {
debug_assert!(task_state::get().is_layout());
self.data_cell.as_unsafe_cell().get() as *const _
}
/// Borrows the layout data immutably. This function is *not* thread-safe.
#[inline]
pub fn borrow(&self) -> Ref<Option<LayoutData>> {
debug_assert!(task_state::get().is_layout());
self.data_cell.borrow()
}
/// Borrows the layout data mutably. This function is *not* thread-safe.
///
/// FIXME(pcwalton): We should really put this behind a `MutLayoutView` phantom type, to
/// prevent CSS selector matching from mutably accessing nodes it's not supposed to and racing
/// on it. This has already resulted in one bug!
#[inline]
pub fn borrow_mut(&self) -> RefMut<Option<LayoutData>> {
debug_assert!(task_state::get().is_layout());
self.data_cell.borrow_mut()
} }
} }
@ -334,7 +285,7 @@ impl Node {
for node in child.traverse_preorder() { for node in child.traverse_preorder() {
node.set_flag(IS_IN_DOC, false); node.set_flag(IS_IN_DOC, false);
vtable_for(&&*node).unbind_from_tree(&context); vtable_for(&&*node).unbind_from_tree(&context);
node.layout_data.dispose(&node); node.style_and_layout_data.get().map(|d| d.dispose(&node));
} }
self.owner_doc().content_and_heritage_changed(self, NodeDamage::OtherNodeDamage); self.owner_doc().content_and_heritage_changed(self, NodeDamage::OtherNodeDamage);
@ -378,7 +329,7 @@ impl<'a> Iterator for QuerySelectorIterator {
impl Node { impl Node {
pub fn teardown(&self) { pub fn teardown(&self) {
self.layout_data.dispose(self); self.style_and_layout_data.get().map(|d| d.dispose(self));
for kid in self.children() { for kid in self.children() {
kid.teardown(); kid.teardown();
} }
@ -966,9 +917,8 @@ pub trait LayoutNodeHelpers {
unsafe fn children_count(&self) -> u32; unsafe fn children_count(&self) -> u32;
unsafe fn layout_data(&self) -> Ref<Option<LayoutData>>; unsafe fn get_style_and_layout_data(&self) -> Option<OpaqueStyleAndLayoutData>;
unsafe fn layout_data_mut(&self) -> RefMut<Option<LayoutData>>; unsafe fn init_style_and_layout_data(&self, OpaqueStyleAndLayoutData);
unsafe fn layout_data_unchecked(&self) -> *const Option<LayoutData>;
} }
impl LayoutNodeHelpers for LayoutJS<Node> { impl LayoutNodeHelpers for LayoutJS<Node> {
@ -1049,20 +999,15 @@ impl LayoutNodeHelpers for LayoutJS<Node> {
#[inline] #[inline]
#[allow(unsafe_code)] #[allow(unsafe_code)]
unsafe fn layout_data(&self) -> Ref<Option<LayoutData>> { unsafe fn get_style_and_layout_data(&self) -> Option<OpaqueStyleAndLayoutData> {
(*self.unsafe_get()).layout_data.borrow() (*self.unsafe_get()).style_and_layout_data.get()
} }
#[inline] #[inline]
#[allow(unsafe_code)] #[allow(unsafe_code)]
unsafe fn layout_data_mut(&self) -> RefMut<Option<LayoutData>> { unsafe fn init_style_and_layout_data(&self, val: OpaqueStyleAndLayoutData) {
(*self.unsafe_get()).layout_data.borrow_mut() debug_assert!((*self.unsafe_get()).style_and_layout_data.get().is_none());
} (*self.unsafe_get()).style_and_layout_data.set(Some(val));
#[inline]
#[allow(unsafe_code)]
unsafe fn layout_data_unchecked(&self) -> *const Option<LayoutData> {
(*self.unsafe_get()).layout_data.borrow_unchecked()
} }
} }
@ -1322,7 +1267,7 @@ impl Node {
inclusive_descendants_version: Cell::new(0), inclusive_descendants_version: Cell::new(0),
ranges: WeakRangeVec::new(), ranges: WeakRangeVec::new(),
layout_data: LayoutDataRef::new(), style_and_layout_data: Cell::new(None),
unique_id: DOMRefCell::new(None), unique_id: DOMRefCell::new(None),
} }

View file

@ -7,7 +7,7 @@
//! the DOM to be placed in a separate crate from layout. //! the DOM to be placed in a separate crate from layout.
use app_units::Au; use app_units::Au;
use dom::node::LayoutData; use dom::node::OpaqueStyleAndLayoutData;
use euclid::point::Point2D; use euclid::point::Point2D;
use euclid::rect::Rect; use euclid::rect::Rect;
use gfx_traits::LayerId; use gfx_traits::LayerId;
@ -59,7 +59,7 @@ pub enum Msg {
/// Destroys layout data associated with a DOM node. /// Destroys layout data associated with a DOM node.
/// ///
/// TODO(pcwalton): Maybe think about batching to avoid message traffic. /// TODO(pcwalton): Maybe think about batching to avoid message traffic.
ReapLayoutData(LayoutData), ReapStyleAndLayoutData(OpaqueStyleAndLayoutData),
/// Requests that the layout task measure its memory usage. The resulting reports are sent back /// Requests that the layout task measure its memory usage. The resulting reports are sent back
/// via the supplied channel. /// via the supplied channel.

48
components/style/data.rs Normal file
View file

@ -0,0 +1,48 @@
/* 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 properties::ComputedValues;
use std::sync::Arc;
use std::sync::atomic::AtomicIsize;
pub struct PrivateStyleData {
/// The results of CSS styling for this node.
pub style: Option<Arc<ComputedValues>>,
/// The results of CSS styling for this node's `before` pseudo-element, if any.
pub before_style: Option<Arc<ComputedValues>>,
/// The results of CSS styling for this node's `after` pseudo-element, if any.
pub after_style: Option<Arc<ComputedValues>>,
/// Information needed during parallel traversals.
pub parallel: DomParallelInfo,
}
impl PrivateStyleData {
pub fn new() -> PrivateStyleData {
PrivateStyleData {
style: None,
before_style: None,
after_style: None,
parallel: DomParallelInfo::new(),
}
}
}
/// Information that we need stored in each DOM node.
#[derive(HeapSizeOf)]
pub struct DomParallelInfo {
/// The number of children that still need work done.
pub children_count: AtomicIsize,
}
impl DomParallelInfo {
pub fn new() -> DomParallelInfo {
DomParallelInfo {
children_count: AtomicIsize::new(0),
}
}
}

274
components/style/dom.rs Normal file
View file

@ -0,0 +1,274 @@
/* 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)]
use data::PrivateStyleData;
use properties::{PropertyDeclaration, PropertyDeclarationBlock};
use restyle_hints::{ElementSnapshot, RESTYLE_DESCENDANTS, RESTYLE_LATER_SIBLINGS, RESTYLE_SELF, RestyleHint};
use selectors::matching::DeclarationBlock;
use selectors::states::ElementState;
use smallvec::VecLike;
use std::cell::{Ref, RefMut};
use std::marker::PhantomData;
use string_cache::{Atom, Namespace};
/// Opaque type stored in type-unsafe work queues for parallel layout.
/// Must be transmutable to and from TNode.
pub type UnsafeNode = (usize, usize);
/// An opaque handle to a node, which, unlike UnsafeNode, cannot be transformed
/// back into a non-opaque representation. The only safe operation that can be
/// performed on this node is to compare it to another opaque handle or to another
/// OpaqueNode.
///
/// Layout and Graphics use this to safely represent nodes for comparison purposes.
/// Because the script task's GC does not trace layout, node data cannot be safely stored in layout
/// data structures. Also, layout code tends to be faster when the DOM is not being accessed, for
/// locality reasons. Using `OpaqueNode` enforces this invariant.
#[derive(Clone, PartialEq, Copy, Debug, HeapSizeOf, Hash, Eq, Deserialize, Serialize)]
pub struct OpaqueNode(pub usize);
impl OpaqueNode {
/// Returns the address of this node, for debugging purposes.
#[inline]
pub fn id(&self) -> usize {
let OpaqueNode(pointer) = *self;
pointer
}
}
pub trait TNode<'ln> : Sized + Copy + Clone {
type ConcreteElement: TElement<'ln, ConcreteNode = Self, ConcreteDocument = Self::ConcreteDocument>;
type ConcreteDocument: TDocument<'ln, ConcreteNode = Self, ConcreteElement = Self::ConcreteElement>;
fn to_unsafe(&self) -> UnsafeNode;
unsafe fn from_unsafe(n: &UnsafeNode) -> Self;
/// Returns whether this is a text node. It turns out that this is all the style system cares
/// about, and thus obviates the need to compute the full type id, which would be expensive in
/// Gecko.
fn is_text_node(&self) -> bool;
fn is_element(&self) -> bool;
fn dump(self);
fn traverse_preorder(self) -> TreeIterator<'ln, Self> {
TreeIterator::new(self)
}
/// Returns an iterator over this node's children.
fn children(self) -> ChildrenIterator<'ln, Self> {
ChildrenIterator {
current: self.first_child(),
phantom: PhantomData,
}
}
fn rev_children(self) -> ReverseChildrenIterator<'ln, Self> {
ReverseChildrenIterator {
current: self.last_child(),
phantom: PhantomData,
}
}
/// Converts self into an `OpaqueNode`.
fn opaque(&self) -> OpaqueNode;
/// Initializes style and layout data for the node. No-op if the data is already
/// initialized.
///
/// FIXME(pcwalton): Do this as part of fragment building instead of in a traversal.
fn initialize_data(self);
/// While doing a reflow, the node at the root has no parent, as far as we're
/// concerned. This method returns `None` at the reflow root.
fn layout_parent_node(self, reflow_root: OpaqueNode) -> Option<Self>;
fn debug_id(self) -> usize;
fn as_element(&self) -> Option<Self::ConcreteElement>;
fn as_document(&self) -> Option<Self::ConcreteDocument>;
fn children_count(&self) -> u32;
fn has_changed(&self) -> bool;
unsafe fn set_changed(&self, value: bool);
fn is_dirty(&self) -> bool;
unsafe fn set_dirty(&self, value: bool);
fn has_dirty_descendants(&self) -> bool;
unsafe fn set_dirty_descendants(&self, value: bool);
fn dirty_self(&self) {
unsafe {
self.set_dirty(true);
self.set_dirty_descendants(true);
}
}
fn dirty_descendants(&self) {
for ref child in self.children() {
child.dirty_self();
child.dirty_descendants();
}
}
/// Borrows the PrivateStyleData without checks.
#[inline(always)]
unsafe fn borrow_data_unchecked(&self) -> Option<*const PrivateStyleData>;
/// Borrows the PrivateStyleData immutably. Fails on a conflicting borrow.
#[inline(always)]
fn borrow_data(&self) -> Option<Ref<PrivateStyleData>>;
/// Borrows the PrivateStyleData mutably. Fails on a conflicting borrow.
#[inline(always)]
fn mutate_data(&self) -> Option<RefMut<PrivateStyleData>>;
fn parent_node(&self) -> Option<Self>;
fn first_child(&self) -> Option<Self>;
fn last_child(&self) -> Option<Self>;
fn prev_sibling(&self) -> Option<Self>;
fn next_sibling(&self) -> Option<Self>;
}
pub trait TDocument<'ld> : Sized + Copy + Clone {
type ConcreteNode: TNode<'ld, ConcreteElement = Self::ConcreteElement, ConcreteDocument = Self>;
type ConcreteElement: TElement<'ld, ConcreteNode = Self::ConcreteNode, ConcreteDocument = Self>;
fn as_node(&self) -> Self::ConcreteNode;
fn root_node(&self) -> Option<Self::ConcreteNode>;
fn drain_modified_elements(&self) -> Vec<(Self::ConcreteElement, ElementSnapshot)>;
}
pub trait TElement<'le> : Sized + Copy + Clone + ::selectors::Element {
type ConcreteNode: TNode<'le, ConcreteElement = Self, ConcreteDocument = Self::ConcreteDocument>;
type ConcreteDocument: TDocument<'le, ConcreteNode = Self::ConcreteNode, ConcreteElement = Self>;
fn as_node(&self) -> Self::ConcreteNode;
fn style_attribute(&self) -> &'le Option<PropertyDeclarationBlock>;
fn get_state(&self) -> ElementState;
fn synthesize_presentational_hints_for_legacy_attributes<V>(&self, &mut V)
where V: VecLike<DeclarationBlock<Vec<PropertyDeclaration>>>;
fn get_attr<'a>(&'a self, namespace: &Namespace, attr: &Atom) -> Option<&'a str>;
fn get_attrs<'a>(&'a self, attr: &Atom) -> Vec<&'a str>;
/// Properly marks nodes as dirty in response to restyle hints.
fn note_restyle_hint(&self, mut hint: RestyleHint) {
// Bail early if there's no restyling to do.
if hint.is_empty() {
return;
}
// If the restyle hint is non-empty, we need to restyle either this element
// or one of its siblings. Mark our ancestor chain as having dirty descendants.
let node = self.as_node();
let mut curr = node;
while let Some(parent) = curr.parent_node() {
if parent.has_dirty_descendants() { break }
unsafe { parent.set_dirty_descendants(true); }
curr = parent;
}
// Process hints.
if hint.contains(RESTYLE_SELF) {
node.dirty_self();
// FIXME(bholley, #8438): We currently need to RESTYLE_DESCENDANTS in the
// RESTYLE_SELF case in order to make sure "inherit" style structs propagate
// properly. See the explanation in the github issue.
hint.insert(RESTYLE_DESCENDANTS);
}
if hint.contains(RESTYLE_DESCENDANTS) {
unsafe { node.set_dirty_descendants(true); }
node.dirty_descendants();
}
if hint.contains(RESTYLE_LATER_SIBLINGS) {
let mut next = ::selectors::Element::next_sibling_element(self);
while let Some(sib) = next {
let sib_node = sib.as_node();
sib_node.dirty_self();
sib_node.dirty_descendants();
next = ::selectors::Element::next_sibling_element(&sib);
}
}
}
}
pub struct TreeIterator<'a, ConcreteNode> where ConcreteNode: TNode<'a> {
stack: Vec<ConcreteNode>,
// Satisfy the compiler about the unused lifetime.
phantom: PhantomData<&'a ()>,
}
impl<'a, ConcreteNode> TreeIterator<'a, ConcreteNode> where ConcreteNode: TNode<'a> {
fn new(root: ConcreteNode) -> TreeIterator<'a, ConcreteNode> {
let mut stack = vec!();
stack.push(root);
TreeIterator {
stack: stack,
phantom: PhantomData,
}
}
}
impl<'a, ConcreteNode> Iterator for TreeIterator<'a, ConcreteNode>
where ConcreteNode: TNode<'a> {
type Item = ConcreteNode;
fn next(&mut self) -> Option<ConcreteNode> {
let ret = self.stack.pop();
ret.map(|node| self.stack.extend(node.rev_children()));
ret
}
}
pub struct ChildrenIterator<'a, ConcreteNode> where ConcreteNode: TNode<'a> {
current: Option<ConcreteNode>,
// Satisfy the compiler about the unused lifetime.
phantom: PhantomData<&'a ()>,
}
impl<'a, ConcreteNode> Iterator for ChildrenIterator<'a, ConcreteNode>
where ConcreteNode: TNode<'a> {
type Item = ConcreteNode;
fn next(&mut self) -> Option<ConcreteNode> {
let node = self.current;
self.current = node.and_then(|node| node.next_sibling());
node
}
}
pub struct ReverseChildrenIterator<'a, ConcreteNode> where ConcreteNode: TNode<'a> {
current: Option<ConcreteNode>,
// Satisfy the compiler about the unused lifetime.
phantom: PhantomData<&'a ()>,
}
impl<'a, ConcreteNode> Iterator for ReverseChildrenIterator<'a, ConcreteNode>
where ConcreteNode: TNode<'a> {
type Item = ConcreteNode;
fn next(&mut self) -> Option<ConcreteNode> {
let node = self.current;
self.current = node.and_then(|node| node.prev_sibling());
node
}
}

View file

@ -17,6 +17,7 @@
extern crate app_units; extern crate app_units;
#[macro_use] #[macro_use]
extern crate bitflags; extern crate bitflags;
extern crate core;
#[macro_use] #[macro_use]
extern crate cssparser; extern crate cssparser;
extern crate encoding; extern crate encoding;
@ -43,9 +44,10 @@ extern crate util;
pub mod animation; pub mod animation;
pub mod attr; pub mod attr;
mod custom_properties; mod custom_properties;
pub mod data;
pub mod dom;
pub mod font_face; pub mod font_face;
pub mod media_queries; pub mod media_queries;
pub mod node;
pub mod parser; pub mod parser;
pub mod restyle_hints; pub mod restyle_hints;
pub mod selector_matching; pub mod selector_matching;

View file

@ -1,19 +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/. */
//! Traits that nodes must implement. Breaks the otherwise-cyclic dependency between layout and
//! style.
use properties::PropertyDeclaration;
use selectors::matching::DeclarationBlock;
use smallvec::VecLike;
use string_cache::{Atom, Namespace};
pub trait TElementAttributes {
fn synthesize_presentational_hints_for_legacy_attributes<V>(&self, &mut V)
where V: VecLike<DeclarationBlock<Vec<PropertyDeclaration>>>;
fn get_attr<'a>(&'a self, namespace: &Namespace, attr: &Atom) -> Option<&'a str>;
fn get_attrs<'a>(&'a self, attr: &Atom) -> Vec<&'a str>;
}

View file

@ -3,11 +3,11 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
use cssparser::{Parser, SourcePosition}; use cssparser::{Parser, SourcePosition};
use dom::TElement;
use log; use log;
use media_queries::{Device, MediaType}; use media_queries::{Device, MediaType};
use msg::ParseErrorReporter; use msg::ParseErrorReporter;
use msg::constellation_msg::PipelineId; use msg::constellation_msg::PipelineId;
use node::TElementAttributes;
use properties::{PropertyDeclaration, PropertyDeclarationBlock}; use properties::{PropertyDeclaration, PropertyDeclarationBlock};
use restyle_hints::{ElementSnapshot, RestyleHint, DependencySet}; use restyle_hints::{ElementSnapshot, RestyleHint, DependencySet};
use selectors::Element; use selectors::Element;
@ -270,7 +270,7 @@ impl Stylist {
/// The returned boolean indicates whether the style is *shareable*; that is, whether the /// The returned boolean indicates whether the style is *shareable*; that is, whether the
/// matched selectors are simple enough to allow the matching logic to be reduced to the logic /// 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`. /// in `css::matching::PrivateMatchMethods::candidate_element_allows_for_style_sharing`.
pub fn push_applicable_declarations<E, V>( pub fn push_applicable_declarations<'le, E, V>(
&self, &self,
element: &E, element: &E,
parent_bf: Option<&BloomFilter>, parent_bf: Option<&BloomFilter>,
@ -278,7 +278,7 @@ impl Stylist {
pseudo_element: Option<PseudoElement>, pseudo_element: Option<PseudoElement>,
applicable_declarations: &mut V) applicable_declarations: &mut V)
-> bool -> bool
where E: Element + TElementAttributes, where E: Element + TElement<'le>,
V: VecLike<DeclarationBlock> { V: VecLike<DeclarationBlock> {
assert!(!self.is_device_dirty); assert!(!self.is_device_dirty);
assert!(style_attribute.is_none() || pseudo_element.is_none(), assert!(style_attribute.is_none() || pseudo_element.is_none(),

View file

@ -35,6 +35,7 @@ use std::mem::{size_of, transmute};
use std::rc::Rc; use std::rc::Rc;
use std::result::Result; use std::result::Result;
use std::sync::Arc; use std::sync::Arc;
use std::sync::atomic::{AtomicIsize, AtomicUsize};
use str::{DOMString, LengthOrPercentageOrAuto}; use str::{DOMString, LengthOrPercentageOrAuto};
use string_cache::atom::Atom; use string_cache::atom::Atom;
use string_cache::namespace::{QualName, Namespace}; use string_cache::namespace::{QualName, Namespace};
@ -418,6 +419,7 @@ impl HeapSizeOf for Value {
known_heap_size!(0, u8, u16, u32, u64, usize); known_heap_size!(0, u8, u16, u32, u64, usize);
known_heap_size!(0, i8, i16, i32, i64, isize); known_heap_size!(0, i8, i16, i32, i64, isize);
known_heap_size!(0, bool, f32, f64); known_heap_size!(0, bool, f32, f64);
known_heap_size!(0, AtomicIsize, AtomicUsize);
known_heap_size!(0, Rect<T>, Point2D<T>, Size2D<T>, Matrix2D<T>, SideOffsets2D<T>, Range<T>); known_heap_size!(0, Rect<T>, Point2D<T>, Size2D<T>, Matrix2D<T>, SideOffsets2D<T>, Range<T>);
known_heap_size!(0, Length<T, U>, ScaleFactor<T, U, V>); known_heap_size!(0, Length<T, U>, ScaleFactor<T, U, V>);

View file

@ -38,10 +38,10 @@ macro_rules! sizeof_checker (
// Update the sizes here // Update the sizes here
sizeof_checker!(size_event_target, EventTarget, 40); sizeof_checker!(size_event_target, EventTarget, 40);
sizeof_checker!(size_node, Node, 184); sizeof_checker!(size_node, Node, 168);
sizeof_checker!(size_element, Element, 328); sizeof_checker!(size_element, Element, 312);
sizeof_checker!(size_htmlelement, HTMLElement, 344); sizeof_checker!(size_htmlelement, HTMLElement, 328);
sizeof_checker!(size_div, HTMLDivElement, 344); sizeof_checker!(size_div, HTMLDivElement, 328);
sizeof_checker!(size_span, HTMLSpanElement, 344); sizeof_checker!(size_span, HTMLSpanElement, 328);
sizeof_checker!(size_text, Text, 216); sizeof_checker!(size_text, Text, 200);
sizeof_checker!(size_characterdata, CharacterData, 216); sizeof_checker!(size_characterdata, CharacterData, 200);