зеркало из https://github.com/mozilla/gecko-dev.git
servo: Merge #9051 - Split layout wrappers into style+layout and layout-only functionality (from bholley:split_style_and_layout_wrappers); r=SimonSapin
This is a step towards removing the dependency of stylo on layout/. This PR depends on #9004. Source-Repo: https://github.com/servo/servo Source-Revision: 0f5c614609fd8867a9e7c27b8a398ea7d877c714
This commit is contained in:
Родитель
70ca13cc30
Коммит
a5868c1c28
|
@ -22,7 +22,6 @@ use euclid::approxeq::ApproxEq;
|
|||
use euclid::num::Zero;
|
||||
use euclid::{Matrix2D, Matrix4, Point2D, Rect, SideOffsets2D, Size2D};
|
||||
use gfx_traits::{color, LayerId, LayerKind, ScrollPolicy};
|
||||
use libc::uintptr_t;
|
||||
use msg::constellation_msg::PipelineId;
|
||||
use net_traits::image::base::Image;
|
||||
use paint_context::PaintContext;
|
||||
|
@ -49,6 +48,8 @@ use util::opts;
|
|||
use util::print_tree::PrintTree;
|
||||
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
|
||||
// layout to use.
|
||||
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.
|
||||
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.
|
||||
/// It is also used for tracking LayerIds when creating layers to preserve ordering when
|
||||
/// layered DisplayItems should render underneath unlayered DisplayItems.
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
|
||||
use block::BlockFlow;
|
||||
use context::LayoutContext;
|
||||
use data::{HAS_NEWLY_CONSTRUCTED_FLOW, LayoutDataWrapper};
|
||||
use data::{HAS_NEWLY_CONSTRUCTED_FLOW, PrivateLayoutData};
|
||||
use flex::FlexFlow;
|
||||
use floats::FloatKind;
|
||||
use flow::{MutableFlowUtils, MutableOwnedFlowUtils};
|
||||
|
@ -58,7 +58,7 @@ use traversal::PostorderNodeMutTraversal;
|
|||
use url::Url;
|
||||
use util::linked_list;
|
||||
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.
|
||||
#[derive(Clone)]
|
||||
|
@ -1326,10 +1326,9 @@ impl<'a, 'ln, ConcreteThreadSafeLayoutNode: ThreadSafeLayoutNode<'ln>>
|
|||
|
||||
|
||||
let mut style = node.style().clone();
|
||||
let mut layout_data_ref = node.mutate_layout_data();
|
||||
let layout_data = layout_data_ref.as_mut().expect("no layout data");
|
||||
let damage = layout_data.data.restyle_damage;
|
||||
match *node.construction_result_mut(layout_data) {
|
||||
let mut data = node.mutate_layout_data().unwrap();
|
||||
let damage = data.restyle_damage;
|
||||
match *node.construction_result_mut(&mut *data) {
|
||||
ConstructionResult::None => true,
|
||||
ConstructionResult::Flow(ref mut flow, _) => {
|
||||
// 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.
|
||||
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.
|
||||
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() {
|
||||
PseudoElementType::Before(_) => &mut layout_data.data.before_flow_construction_result,
|
||||
PseudoElementType::After (_) => &mut layout_data.data.after_flow_construction_result,
|
||||
PseudoElementType::Normal => &mut layout_data.data.flow_construction_result,
|
||||
PseudoElementType::Before(_) => &mut data.before_flow_construction_result,
|
||||
PseudoElementType::After (_) => &mut data.after_flow_construction_result,
|
||||
PseudoElementType::Normal => &mut data.flow_construction_result,
|
||||
}
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn set_flow_construction_result(self, result: ConstructionResult) {
|
||||
let mut layout_data_ref = self.mutate_layout_data();
|
||||
let layout_data = layout_data_ref.as_mut().expect("no layout data");
|
||||
|
||||
let dst = self.construction_result_mut(layout_data);
|
||||
let mut layout_data = self.mutate_layout_data().unwrap();
|
||||
let dst = self.construction_result_mut(&mut *layout_data);
|
||||
|
||||
*dst = result;
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn swap_out_construction_result(self) -> ConstructionResult {
|
||||
let mut layout_data_ref = self.mutate_layout_data();
|
||||
let layout_data = layout_data_ref.as_mut().expect("no layout data");
|
||||
|
||||
self.construction_result_mut(layout_data).swap_out()
|
||||
let mut layout_data = self.mutate_layout_data().unwrap();
|
||||
self.construction_result_mut(&mut *layout_data).swap_out()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
|
||||
use animation;
|
||||
use context::SharedLayoutContext;
|
||||
use data::LayoutDataWrapper;
|
||||
use data::PrivateLayoutData;
|
||||
use incremental::{self, RestyleDamage};
|
||||
use msg::ParseErrorReporter;
|
||||
use script::layout_interface::Animation;
|
||||
|
@ -20,18 +20,19 @@ use selectors::{Element};
|
|||
use smallvec::SmallVec;
|
||||
use std::borrow::ToOwned;
|
||||
use std::hash::{Hash, Hasher};
|
||||
use std::mem::transmute;
|
||||
use std::slice::Iter;
|
||||
use std::sync::mpsc::Sender;
|
||||
use std::sync::{Arc, Mutex};
|
||||
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::selector_matching::{DeclarationBlock, Stylist};
|
||||
use util::arc_ptr_eq;
|
||||
use util::cache::{LRUCache, SimpleHashCache};
|
||||
use util::opts;
|
||||
use util::vec::ForgetfulSink;
|
||||
use wrapper::{LayoutElement, LayoutNode};
|
||||
|
||||
pub struct ApplicableDeclarations {
|
||||
pub normal: SmallVec<[DeclarationBlock; 16]>,
|
||||
|
@ -160,7 +161,7 @@ pub struct StyleSharingCandidateCache {
|
|||
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 {
|
||||
let mut flags = CommonStyleAffectingAttributes::empty();
|
||||
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
|
||||
/// the style sharing candidate or `None` if this node is ineligible for
|
||||
/// 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() {
|
||||
None => return None,
|
||||
Some(parent_element) => parent_element,
|
||||
};
|
||||
|
||||
let style = unsafe {
|
||||
match *element.as_node().borrow_layout_data_unchecked() {
|
||||
match element.as_node().borrow_data_unchecked() {
|
||||
None => return None,
|
||||
Some(ref layout_data_ref) => {
|
||||
match layout_data_ref.shared_data.style {
|
||||
Some(data_ref) => {
|
||||
match (*data_ref).style {
|
||||
None => return None,
|
||||
Some(ref data) => (*data).clone(),
|
||||
}
|
||||
|
@ -229,10 +230,10 @@ impl StyleSharingCandidate {
|
|||
}
|
||||
};
|
||||
let parent_style = unsafe {
|
||||
match *parent_element.as_node().borrow_layout_data_unchecked() {
|
||||
match parent_element.as_node().borrow_data_unchecked() {
|
||||
None => return None,
|
||||
Some(ref parent_layout_data_ref) => {
|
||||
match parent_layout_data_ref.shared_data.style {
|
||||
Some(parent_data_ref) => {
|
||||
match (*parent_data_ref).style {
|
||||
None => return None,
|
||||
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 {
|
||||
return false
|
||||
}
|
||||
|
@ -342,7 +343,7 @@ impl StyleSharingCandidateCache {
|
|||
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) {
|
||||
None => {}
|
||||
Some(candidate) => self.cache.insert(candidate, ())
|
||||
|
@ -363,7 +364,7 @@ pub enum StyleSharingResult {
|
|||
StyleWasShared(usize, RestyleDamage),
|
||||
}
|
||||
|
||||
pub trait ElementMatchMethods<'le, ConcreteLayoutElement: LayoutElement<'le>> {
|
||||
pub trait ElementMatchMethods<'le, ConcreteElement: TElement<'le>> {
|
||||
fn match_element(&self,
|
||||
stylist: &Stylist,
|
||||
parent_bf: Option<&BloomFilter>,
|
||||
|
@ -376,11 +377,11 @@ pub trait ElementMatchMethods<'le, ConcreteLayoutElement: LayoutElement<'le>> {
|
|||
unsafe fn share_style_if_possible(&self,
|
||||
style_sharing_candidate_cache:
|
||||
&mut StyleSharingCandidateCache,
|
||||
parent: Option<ConcreteLayoutElement::ConcreteLayoutNode>)
|
||||
parent: Option<ConcreteElement::ConcreteNode>)
|
||||
-> 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
|
||||
/// filter. This is used to speed up CSS selector matching to remove
|
||||
/// unnecessary tree climbs for `Descendant` queries.
|
||||
|
@ -396,7 +397,7 @@ pub trait MatchMethods<'ln, ConcreteLayoutNode: LayoutNode<'ln>> {
|
|||
|
||||
unsafe fn cascade_node(&self,
|
||||
layout_context: &SharedLayoutContext,
|
||||
parent: Option<ConcreteLayoutNode>,
|
||||
parent: Option<ConcreteNode>,
|
||||
applicable_declarations: &ApplicableDeclarations,
|
||||
applicable_declarations_cache: &mut ApplicableDeclarationsCache,
|
||||
new_animations_sender: &Mutex<Sender<Animation>>);
|
||||
|
@ -420,15 +421,15 @@ trait PrivateMatchMethods {
|
|||
-> bool;
|
||||
}
|
||||
|
||||
trait PrivateElementMatchMethods<'le, ConcreteLayoutElement: LayoutElement<'le>> {
|
||||
trait PrivateElementMatchMethods<'le, ConcreteElement: TElement<'le>> {
|
||||
fn share_style_with_candidate_if_possible(&self,
|
||||
parent_node: Option<ConcreteLayoutElement::ConcreteLayoutNode>,
|
||||
parent_node: Option<ConcreteElement::ConcreteNode>,
|
||||
candidate: &StyleSharingCandidate)
|
||||
-> Option<Arc<ComputedValues>>;
|
||||
}
|
||||
|
||||
impl<'ln, ConcreteLayoutNode> PrivateMatchMethods for ConcreteLayoutNode
|
||||
where ConcreteLayoutNode: LayoutNode<'ln> {
|
||||
impl<'ln, ConcreteNode> PrivateMatchMethods for ConcreteNode
|
||||
where ConcreteNode: TNode<'ln> {
|
||||
fn cascade_node_pseudo_element(&self,
|
||||
layout_context: &SharedLayoutContext,
|
||||
parent_style: Option<&Arc<ComputedValues>>,
|
||||
|
@ -547,11 +548,11 @@ impl<'ln, ConcreteLayoutNode> PrivateMatchMethods for ConcreteLayoutNode
|
|||
}
|
||||
}
|
||||
|
||||
impl<'le, ConcreteLayoutElement> PrivateElementMatchMethods<'le, ConcreteLayoutElement>
|
||||
for ConcreteLayoutElement
|
||||
where ConcreteLayoutElement: LayoutElement<'le> {
|
||||
impl<'le, ConcreteElement> PrivateElementMatchMethods<'le, ConcreteElement>
|
||||
for ConcreteElement
|
||||
where ConcreteElement: TElement<'le> {
|
||||
fn share_style_with_candidate_if_possible(&self,
|
||||
parent_node: Option<ConcreteLayoutElement::ConcreteLayoutNode>,
|
||||
parent_node: Option<ConcreteElement::ConcreteNode>,
|
||||
candidate: &StyleSharingCandidate)
|
||||
-> Option<Arc<ComputedValues>> {
|
||||
let parent_node = match parent_node {
|
||||
|
@ -559,13 +560,13 @@ impl<'le, ConcreteLayoutElement> PrivateElementMatchMethods<'le, ConcreteLayoutE
|
|||
Some(_) | None => return None,
|
||||
};
|
||||
|
||||
let parent_layout_data: &Option<LayoutDataWrapper> = unsafe {
|
||||
&*parent_node.borrow_layout_data_unchecked()
|
||||
let parent_data: Option<&PrivateStyleData> = unsafe {
|
||||
parent_node.borrow_data_unchecked().map(|d| &*d)
|
||||
};
|
||||
match *parent_layout_data {
|
||||
Some(ref parent_layout_data_ref) => {
|
||||
match parent_data {
|
||||
Some(parent_data_ref) => {
|
||||
// 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) {
|
||||
return None
|
||||
}
|
||||
|
@ -584,9 +585,9 @@ impl<'le, ConcreteLayoutElement> PrivateElementMatchMethods<'le, ConcreteLayoutE
|
|||
}
|
||||
}
|
||||
|
||||
impl<'le, ConcreteLayoutElement> ElementMatchMethods<'le, ConcreteLayoutElement>
|
||||
for ConcreteLayoutElement
|
||||
where ConcreteLayoutElement: LayoutElement<'le> {
|
||||
impl<'le, ConcreteElement> ElementMatchMethods<'le, ConcreteElement>
|
||||
for ConcreteElement
|
||||
where ConcreteElement: TElement<'le> {
|
||||
fn match_element(&self,
|
||||
stylist: &Stylist,
|
||||
parent_bf: Option<&BloomFilter>,
|
||||
|
@ -619,7 +620,7 @@ impl<'le, ConcreteLayoutElement> ElementMatchMethods<'le, ConcreteLayoutElement>
|
|||
unsafe fn share_style_if_possible(&self,
|
||||
style_sharing_candidate_cache:
|
||||
&mut StyleSharingCandidateCache,
|
||||
parent: Option<ConcreteLayoutElement::ConcreteLayoutNode>)
|
||||
parent: Option<ConcreteElement::ConcreteNode>)
|
||||
-> StyleSharingResult {
|
||||
if opts::get().disable_share_style_cache {
|
||||
return StyleSharingResult::CannotShare
|
||||
|
@ -637,9 +638,7 @@ impl<'le, ConcreteLayoutElement> ElementMatchMethods<'le, ConcreteLayoutElement>
|
|||
Some(shared_style) => {
|
||||
// Yay, cache hit. Share the style.
|
||||
let node = self.as_node();
|
||||
let mut layout_data_ref = node.mutate_layout_data();
|
||||
let shared_data = &mut layout_data_ref.as_mut().unwrap().shared_data;
|
||||
let style = &mut shared_data.style;
|
||||
let style = &mut node.mutate_data().unwrap().style;
|
||||
let damage = incremental::compute_damage(style, &*shared_style);
|
||||
*style = Some(shared_style);
|
||||
return StyleSharingResult::StyleWasShared(i, damage)
|
||||
|
@ -652,9 +651,9 @@ impl<'le, ConcreteLayoutElement> ElementMatchMethods<'le, ConcreteLayoutElement>
|
|||
}
|
||||
}
|
||||
|
||||
impl<'ln, ConcreteLayoutNode> MatchMethods<'ln, ConcreteLayoutNode>
|
||||
for ConcreteLayoutNode
|
||||
where ConcreteLayoutNode: LayoutNode<'ln> {
|
||||
impl<'ln, ConcreteNode> MatchMethods<'ln, ConcreteNode>
|
||||
for ConcreteNode
|
||||
where ConcreteNode: TNode<'ln> {
|
||||
// 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
|
||||
// be done.
|
||||
|
@ -696,7 +695,7 @@ impl<'ln, ConcreteLayoutNode> MatchMethods<'ln, ConcreteLayoutNode>
|
|||
|
||||
unsafe fn cascade_node(&self,
|
||||
layout_context: &SharedLayoutContext,
|
||||
parent: Option<ConcreteLayoutNode>,
|
||||
parent: Option<ConcreteNode>,
|
||||
applicable_declarations: &ApplicableDeclarations,
|
||||
applicable_declarations_cache: &mut ApplicableDeclarationsCache,
|
||||
new_animations_sender: &Mutex<Sender<Animation>>) {
|
||||
|
@ -708,63 +707,57 @@ impl<'ln, ConcreteLayoutNode> MatchMethods<'ln, ConcreteLayoutNode>
|
|||
let parent_style = match parent {
|
||||
None => None,
|
||||
Some(parent_node) => {
|
||||
let parent_layout_data_ref = parent_node.borrow_layout_data_unchecked();
|
||||
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!");
|
||||
let parent_style = (*parent_node.borrow_data_unchecked().unwrap()).style.as_ref().unwrap();
|
||||
Some(parent_style)
|
||||
}
|
||||
};
|
||||
|
||||
let mut layout_data_ref = self.mutate_layout_data();
|
||||
match *layout_data_ref {
|
||||
None => panic!("no layout data"),
|
||||
Some(ref mut layout_data) => {
|
||||
if self.is_text_node() {
|
||||
// Text nodes get a copy of the parent style. This ensures
|
||||
// that during fragment construction any non-inherited
|
||||
// CSS properties (such as vertical-align) are correctly
|
||||
// set on the fragment(s).
|
||||
let cloned_parent_style = parent_style.unwrap().clone();
|
||||
layout_data.shared_data.style = Some(cloned_parent_style);
|
||||
} else {
|
||||
let mut damage = self.cascade_node_pseudo_element(
|
||||
layout_context,
|
||||
parent_style,
|
||||
&applicable_declarations.normal,
|
||||
&mut layout_data.shared_data.style,
|
||||
applicable_declarations_cache,
|
||||
new_animations_sender,
|
||||
applicable_declarations.normal_shareable,
|
||||
true);
|
||||
if !applicable_declarations.before.is_empty() {
|
||||
damage = damage | self.cascade_node_pseudo_element(
|
||||
layout_context,
|
||||
Some(layout_data.shared_data.style.as_ref().unwrap()),
|
||||
&*applicable_declarations.before,
|
||||
&mut layout_data.data.before_style,
|
||||
applicable_declarations_cache,
|
||||
new_animations_sender,
|
||||
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;
|
||||
}
|
||||
let mut data_ref = self.mutate_data().unwrap();
|
||||
let mut data = &mut *data_ref;
|
||||
if self.is_text_node() {
|
||||
// Text nodes get a copy of the parent style. This ensures
|
||||
// that during fragment construction any non-inherited
|
||||
// CSS properties (such as vertical-align) are correctly
|
||||
// set on the fragment(s).
|
||||
let cloned_parent_style = parent_style.unwrap().clone();
|
||||
data.style = Some(cloned_parent_style);
|
||||
} else {
|
||||
let mut damage = self.cascade_node_pseudo_element(
|
||||
layout_context,
|
||||
parent_style,
|
||||
&applicable_declarations.normal,
|
||||
&mut data.style,
|
||||
applicable_declarations_cache,
|
||||
new_animations_sender,
|
||||
applicable_declarations.normal_shareable,
|
||||
true);
|
||||
if !applicable_declarations.before.is_empty() {
|
||||
damage = damage | self.cascade_node_pseudo_element(
|
||||
layout_context,
|
||||
Some(data.style.as_ref().unwrap()),
|
||||
&*applicable_declarations.before,
|
||||
&mut data.before_style,
|
||||
applicable_declarations_cache,
|
||||
new_animations_sender,
|
||||
false,
|
||||
false);
|
||||
}
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,18 +4,15 @@
|
|||
|
||||
use construct::ConstructionResult;
|
||||
use incremental::RestyleDamage;
|
||||
use parallel::DomParallelInfo;
|
||||
use script::dom::node::SharedLayoutData;
|
||||
use std::sync::Arc;
|
||||
use style::properties::ComputedValues;
|
||||
use style::data::PrivateStyleData;
|
||||
|
||||
/// Data that layout associates with a node.
|
||||
pub struct PrivateLayoutData {
|
||||
/// 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>>,
|
||||
/// Data that the style system associates with a node. When the
|
||||
/// style system is being used standalone, this is all that hangs
|
||||
/// off the node. This must be first to permit the various
|
||||
/// transmuations between PrivateStyleData PrivateLayoutData.
|
||||
pub style_data: PrivateStyleData,
|
||||
|
||||
/// Description of how to account for recent style changes.
|
||||
pub restyle_damage: RestyleDamage,
|
||||
|
@ -28,9 +25,6 @@ pub struct PrivateLayoutData {
|
|||
|
||||
pub after_flow_construction_result: ConstructionResult,
|
||||
|
||||
/// Information needed during parallel traversals.
|
||||
pub parallel: DomParallelInfo,
|
||||
|
||||
/// Various flags.
|
||||
pub flags: LayoutDataFlags,
|
||||
}
|
||||
|
@ -39,13 +33,11 @@ impl PrivateLayoutData {
|
|||
/// Creates new layout data.
|
||||
pub fn new() -> PrivateLayoutData {
|
||||
PrivateLayoutData {
|
||||
before_style: None,
|
||||
after_style: None,
|
||||
style_data: PrivateStyleData::new(),
|
||||
restyle_damage: RestyleDamage::empty(),
|
||||
flow_construction_result: ConstructionResult::None,
|
||||
before_flow_construction_result: ConstructionResult::None,
|
||||
after_flow_construction_result: ConstructionResult::None,
|
||||
parallel: DomParallelInfo::new(),
|
||||
flags: LayoutDataFlags::empty(),
|
||||
}
|
||||
}
|
||||
|
@ -57,16 +49,3 @@ bitflags! {
|
|||
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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -47,6 +47,7 @@ bitflags! {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
impl RestyleDamage {
|
||||
/// Supposing a flow has the given `position` property and this damage, returns the damage that
|
||||
/// we should add to the *parent* of this flow.
|
||||
|
|
|
@ -13,7 +13,6 @@ use azure::azure::AzColor;
|
|||
use canvas_traits::CanvasMsg;
|
||||
use construct::ConstructionResult;
|
||||
use context::{SharedLayoutContext, StylistWrapper, heap_size_of_local_context};
|
||||
use data::LayoutDataWrapper;
|
||||
use display_list_builder::ToGfxColor;
|
||||
use euclid::Matrix4;
|
||||
use euclid::point::Point2D;
|
||||
|
@ -45,7 +44,7 @@ use profile_traits::time::{TimerMetadataFrameType, TimerMetadataReflowType};
|
|||
use profile_traits::time::{self, TimerMetadata, profile};
|
||||
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 script::dom::node::LayoutData;
|
||||
use script::dom::node::OpaqueStyleAndLayoutData;
|
||||
use script::layout_interface::Animation;
|
||||
use script::layout_interface::{LayoutRPC, OffsetParentResponse};
|
||||
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::{Arc, Mutex, MutexGuard, RwLock};
|
||||
use style::computed_values::{filter, mix_blend_mode};
|
||||
use style::dom::{TDocument, TElement, TNode};
|
||||
use style::media_queries::{Device, MediaType};
|
||||
use style::selector_matching::{Stylist, USER_OR_USER_AGENT_STYLESHEETS};
|
||||
use style::stylesheets::{CSSRuleIteratorExt, Stylesheet};
|
||||
|
@ -77,8 +77,7 @@ use util::opts;
|
|||
use util::task;
|
||||
use util::task_state;
|
||||
use util::workqueue::WorkQueue;
|
||||
use wrapper::{LayoutDocument, LayoutElement, LayoutNode};
|
||||
use wrapper::{ServoLayoutNode, ThreadSafeLayoutNode};
|
||||
use wrapper::{LayoutNode, NonOpaqueStyleAndLayoutData, ServoLayoutNode, ThreadSafeLayoutNode};
|
||||
|
||||
/// 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;
|
||||
|
@ -607,9 +606,9 @@ impl LayoutTask {
|
|||
Msg::SetVisibleRects(new_visible_rects) => {
|
||||
self.set_visible_rects(new_visible_rects, possibly_locked_rw_data);
|
||||
}
|
||||
Msg::ReapLayoutData(dead_layout_data) => {
|
||||
Msg::ReapStyleAndLayoutData(dead_data) => {
|
||||
unsafe {
|
||||
self.handle_reap_layout_data(dead_layout_data)
|
||||
self.handle_reap_style_and_layout_data(dead_data)
|
||||
}
|
||||
}
|
||||
Msg::CollectReports(reports_chan) => {
|
||||
|
@ -707,9 +706,9 @@ impl LayoutTask {
|
|||
response_chan.send(()).unwrap();
|
||||
loop {
|
||||
match self.port.recv().unwrap() {
|
||||
Msg::ReapLayoutData(dead_layout_data) => {
|
||||
Msg::ReapStyleAndLayoutData(dead_data) => {
|
||||
unsafe {
|
||||
self.handle_reap_layout_data(dead_layout_data)
|
||||
self.handle_reap_style_and_layout_data(dead_data)
|
||||
}
|
||||
}
|
||||
Msg::ExitNow => {
|
||||
|
@ -765,14 +764,11 @@ impl LayoutTask {
|
|||
}
|
||||
|
||||
fn try_get_layout_root<'ln, N: LayoutNode<'ln>>(&self, node: N) -> Option<FlowRef> {
|
||||
let mut layout_data_ref = node.mutate_layout_data();
|
||||
let layout_data =
|
||||
match layout_data_ref.as_mut() {
|
||||
None => return None,
|
||||
Some(layout_data) => layout_data,
|
||||
};
|
||||
|
||||
let result = layout_data.data.flow_construction_result.swap_out();
|
||||
let mut data = match node.mutate_layout_data() {
|
||||
Some(x) => x,
|
||||
None => return None,
|
||||
};
|
||||
let result = data.flow_construction_result.swap_out();
|
||||
|
||||
let mut flow = match result {
|
||||
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
|
||||
/// because the struct type is transmuted to a different type on the script side.
|
||||
unsafe fn handle_reap_layout_data(&self, layout_data: LayoutData) {
|
||||
let _: LayoutDataWrapper = transmute(layout_data);
|
||||
unsafe fn handle_reap_style_and_layout_data(&self, data: OpaqueStyleAndLayoutData) {
|
||||
let non_opaque: NonOpaqueStyleAndLayoutData = transmute(data.ptr);
|
||||
let _ = Box::from_raw(non_opaque);
|
||||
}
|
||||
|
||||
/// Returns profiling information which is passed to the time profiler.
|
||||
|
|
|
@ -2,11 +2,13 @@
|
|||
* 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/. */
|
||||
|
||||
#![feature(as_unsafe_cell)]
|
||||
#![feature(box_syntax)]
|
||||
#![feature(cell_extras)]
|
||||
#![feature(custom_derive)]
|
||||
#![feature(hashmap_hasher)]
|
||||
#![feature(mpsc_select)]
|
||||
#![feature(nonzero)]
|
||||
#![feature(plugin)]
|
||||
#![feature(raw)]
|
||||
#![feature(step_by)]
|
||||
|
@ -22,6 +24,7 @@ extern crate azure;
|
|||
#[macro_use]
|
||||
extern crate bitflags;
|
||||
extern crate canvas_traits;
|
||||
extern crate core;
|
||||
extern crate cssparser;
|
||||
extern crate encoding;
|
||||
extern crate euclid;
|
||||
|
|
|
@ -15,6 +15,7 @@ use gfx::display_list::OpaqueNode;
|
|||
use profile_traits::time::{self, TimerMetadata, profile};
|
||||
use std::mem;
|
||||
use std::sync::atomic::{AtomicIsize, Ordering};
|
||||
use style::dom::UnsafeNode;
|
||||
use traversal::PostorderNodeMutTraversal;
|
||||
use traversal::{AssignBSizesAndStoreOverflow, AssignISizes, BubbleISizes};
|
||||
use traversal::{BuildDisplayList, ComputeAbsolutePositions};
|
||||
|
@ -22,17 +23,17 @@ use traversal::{ConstructFlows, RecalcStyleForNode};
|
|||
use traversal::{PostorderDomTraversal, PreorderDomTraversal};
|
||||
use util::opts;
|
||||
use util::workqueue::{WorkQueue, WorkUnit, WorkerProxy};
|
||||
use wrapper::{LayoutNode, UnsafeLayoutNode};
|
||||
use wrapper::LayoutNode;
|
||||
|
||||
const CHUNK_SIZE: usize = 64;
|
||||
|
||||
pub struct WorkQueueData(usize, usize);
|
||||
|
||||
#[allow(dead_code)]
|
||||
fn static_assertion(node: UnsafeLayoutNode) {
|
||||
fn static_assertion(node: UnsafeNode) {
|
||||
unsafe {
|
||||
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 struct DomParallelInfo {
|
||||
/// The number of children that still need work done.
|
||||
pub children_count: AtomicIsize,
|
||||
}
|
||||
pub type UnsafeNodeList = (Box<Vec<UnsafeNode>>, OpaqueNode);
|
||||
|
||||
impl DomParallelInfo {
|
||||
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 UnsafeFlowList = (Box<Vec<UnsafeNode>>, usize);
|
||||
|
||||
pub type ChunkedDomTraversalFunction =
|
||||
extern "Rust" fn(UnsafeLayoutNodeList,
|
||||
&mut WorkerProxy<SharedLayoutContext, UnsafeLayoutNodeList>);
|
||||
extern "Rust" fn(UnsafeNodeList,
|
||||
&mut WorkerProxy<SharedLayoutContext, UnsafeNodeList>);
|
||||
|
||||
pub type DomTraversalFunction =
|
||||
extern "Rust" fn(OpaqueNode, UnsafeLayoutNode,
|
||||
&mut WorkerProxy<SharedLayoutContext, UnsafeLayoutNodeList>);
|
||||
extern "Rust" fn(OpaqueNode, UnsafeNode,
|
||||
&mut WorkerProxy<SharedLayoutContext, UnsafeNodeList>);
|
||||
|
||||
pub type ChunkedFlowTraversalFunction =
|
||||
extern "Rust" fn(UnsafeFlowList, &mut WorkerProxy<SharedLayoutContext, UnsafeFlowList>);
|
||||
|
@ -91,14 +78,14 @@ pub trait ParallelPreorderDomTraversal<'ln, ConcreteLayoutNode>
|
|||
: PreorderDomTraversal<'ln, ConcreteLayoutNode>
|
||||
where ConcreteLayoutNode: LayoutNode<'ln> {
|
||||
fn run_parallel(&self,
|
||||
nodes: UnsafeLayoutNodeList,
|
||||
proxy: &mut WorkerProxy<SharedLayoutContext, UnsafeLayoutNodeList>);
|
||||
nodes: UnsafeNodeList,
|
||||
proxy: &mut WorkerProxy<SharedLayoutContext, UnsafeNodeList>);
|
||||
|
||||
#[inline(always)]
|
||||
fn run_parallel_helper(
|
||||
&self,
|
||||
unsafe_nodes: UnsafeLayoutNodeList,
|
||||
proxy: &mut WorkerProxy<SharedLayoutContext, UnsafeLayoutNodeList>,
|
||||
unsafe_nodes: UnsafeNodeList,
|
||||
proxy: &mut WorkerProxy<SharedLayoutContext, UnsafeNodeList>,
|
||||
top_down_func: ChunkedDomTraversalFunction,
|
||||
bottom_up_func: DomTraversalFunction) {
|
||||
let mut discovered_child_nodes = Vec::new();
|
||||
|
@ -113,10 +100,9 @@ pub trait ParallelPreorderDomTraversal<'ln, ConcreteLayoutNode>
|
|||
|
||||
// Reset the count of children.
|
||||
{
|
||||
let mut layout_data_ref = node.mutate_layout_data();
|
||||
let layout_data = layout_data_ref.as_mut().expect("no layout data");
|
||||
layout_data.data.parallel.children_count.store(child_count as isize,
|
||||
Ordering::Relaxed);
|
||||
let data = node.mutate_data().unwrap();
|
||||
data.parallel.children_count.store(child_count as isize,
|
||||
Ordering::Relaxed);
|
||||
}
|
||||
|
||||
// Possibly enqueue the children.
|
||||
|
@ -156,7 +142,7 @@ trait ParallelPostorderDomTraversal<'ln, ConcreteLayoutNode>
|
|||
///
|
||||
/// The only communication between siblings is that they both
|
||||
/// 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.
|
||||
let mut node = unsafe { ConcreteLayoutNode::from_unsafe(&unsafe_node) };
|
||||
loop {
|
||||
|
@ -168,13 +154,11 @@ trait ParallelPostorderDomTraversal<'ln, ConcreteLayoutNode>
|
|||
Some(parent) => parent,
|
||||
};
|
||||
|
||||
let parent_layout_data = unsafe {
|
||||
&*parent.borrow_layout_data_unchecked()
|
||||
let parent_data = unsafe {
|
||||
&*parent.borrow_data_unchecked().unwrap()
|
||||
};
|
||||
let parent_layout_data = parent_layout_data.as_ref().expect("no layout data");
|
||||
|
||||
if parent_layout_data
|
||||
.data
|
||||
if parent_data
|
||||
.parallel
|
||||
.children_count
|
||||
.fetch_sub(1, Ordering::Relaxed) != 1 {
|
||||
|
@ -360,8 +344,8 @@ impl<'a, 'ln, ConcreteLayoutNode> ParallelPreorderDomTraversal<'ln, ConcreteLayo
|
|||
for RecalcStyleForNode<'a>
|
||||
where ConcreteLayoutNode: LayoutNode<'ln> {
|
||||
fn run_parallel(&self,
|
||||
unsafe_nodes: UnsafeLayoutNodeList,
|
||||
proxy: &mut WorkerProxy<SharedLayoutContext, UnsafeLayoutNodeList>) {
|
||||
unsafe_nodes: UnsafeNodeList,
|
||||
proxy: &mut WorkerProxy<SharedLayoutContext, UnsafeNodeList>) {
|
||||
// Not exactly sure why we need UFCS here, but we seem to.
|
||||
<RecalcStyleForNode<'a> as ParallelPreorderDomTraversal<'ln, ConcreteLayoutNode>>
|
||||
::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,
|
||||
proxy: &mut WorkerProxy<SharedLayoutContext, UnsafeLayoutNodeList>)
|
||||
fn recalc_style<'ln, ConcreteLayoutNode>(unsafe_nodes: UnsafeNodeList,
|
||||
proxy: &mut WorkerProxy<SharedLayoutContext, UnsafeNodeList>)
|
||||
where ConcreteLayoutNode: LayoutNode<'ln> {
|
||||
let shared_layout_context = proxy.user_data();
|
||||
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>>(
|
||||
root: OpaqueNode,
|
||||
unsafe_node: UnsafeLayoutNode,
|
||||
proxy: &mut WorkerProxy<SharedLayoutContext, UnsafeLayoutNodeList>) {
|
||||
unsafe_node: UnsafeNode,
|
||||
proxy: &mut WorkerProxy<SharedLayoutContext, UnsafeNodeList>) {
|
||||
let shared_layout_context = proxy.user_data();
|
||||
let layout_context = LayoutContext::new(shared_layout_context);
|
||||
let construct_flows_traversal = ConstructFlows {
|
||||
|
|
|
@ -479,9 +479,9 @@ pub fn process_resolved_style_request<'ln, N: LayoutNode<'ln>>(
|
|||
layout_root: &mut FlowRef,
|
||||
requested_node: N,
|
||||
property: &Atom) -> Option<String> {
|
||||
let layout_data = layout_node.borrow_layout_data();
|
||||
let position = layout_data.as_ref().map(|layout_data| {
|
||||
match layout_data.data.flow_construction_result {
|
||||
let maybe_data = layout_node.borrow_layout_data();
|
||||
let position = maybe_data.map(|data| {
|
||||
match (*data).flow_construction_result {
|
||||
ConstructionResult::Flow(ref flow_ref, _) =>
|
||||
flow::base(flow_ref.deref()).stacking_relative_position,
|
||||
// TODO(dzbarsky) search parents until we find node with a flow ref.
|
||||
|
|
|
@ -15,10 +15,10 @@ use script::layout_interface::ReflowGoal;
|
|||
use selectors::bloom::BloomFilter;
|
||||
use std::cell::RefCell;
|
||||
use std::mem;
|
||||
use style::dom::UnsafeNode;
|
||||
use util::opts;
|
||||
use util::tid::tid;
|
||||
use wrapper::{LayoutNode, UnsafeLayoutNode};
|
||||
use wrapper::{ThreadSafeLayoutNode};
|
||||
use wrapper::{LayoutNode, ThreadSafeLayoutNode};
|
||||
|
||||
/// Every time we do another layout, the old bloom filters are invalid. This is
|
||||
/// 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
|
||||
/// this happens, the task local bloom filter will be thrown away and rebuilt.
|
||||
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.
|
||||
///
|
||||
|
@ -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>,
|
||||
unsafe_node: &UnsafeLayoutNode,
|
||||
unsafe_node: &UnsafeNode,
|
||||
layout_context: &LayoutContext) {
|
||||
STYLE_BLOOM.with(move |style_bloom| {
|
||||
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
|
||||
// parser.
|
||||
node.initialize_layout_data();
|
||||
node.initialize_data();
|
||||
|
||||
// Get the parent node.
|
||||
let parent_opt = node.layout_parent_node(self.root);
|
||||
|
|
|
@ -30,7 +30,8 @@
|
|||
|
||||
#![allow(unsafe_code)]
|
||||
|
||||
use data::{LayoutDataFlags, LayoutDataWrapper, PrivateLayoutData};
|
||||
use core::nonzero::NonZero;
|
||||
use data::{LayoutDataFlags, PrivateLayoutData};
|
||||
use gfx::display_list::OpaqueNode;
|
||||
use gfx::text::glyph::CharIndex;
|
||||
use incremental::RestyleDamage;
|
||||
|
@ -49,7 +50,7 @@ use script::dom::htmlimageelement::LayoutHTMLImageElementHelpers;
|
|||
use script::dom::htmlinputelement::{HTMLInputElement, LayoutHTMLInputElementHelpers};
|
||||
use script::dom::htmltextareaelement::{HTMLTextAreaElement, LayoutHTMLTextAreaElementHelpers};
|
||||
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::layout_interface::TrustedNodeAddress;
|
||||
use selectors::matching::DeclarationBlock;
|
||||
|
@ -57,204 +58,38 @@ use selectors::parser::{AttrSelector, NamespaceConstraint};
|
|||
use selectors::states::*;
|
||||
use smallvec::VecLike;
|
||||
use std::borrow::ToOwned;
|
||||
use std::cell::{Ref, RefMut};
|
||||
use std::cell::{Ref, RefCell, RefMut};
|
||||
use std::marker::PhantomData;
|
||||
use std::mem;
|
||||
use std::mem::{transmute, transmute_copy};
|
||||
use std::sync::Arc;
|
||||
use string_cache::{Atom, Namespace};
|
||||
use style::computed_values::content::ContentItem;
|
||||
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::{PropertyDeclaration, PropertyDeclarationBlock};
|
||||
use style::restyle_hints::{ElementSnapshot, RESTYLE_DESCENDANTS, RESTYLE_LATER_SIBLINGS, RESTYLE_SELF, RestyleHint};
|
||||
use style::restyle_hints::ElementSnapshot;
|
||||
use url::Url;
|
||||
use util::str::{is_whitespace, search_index};
|
||||
|
||||
/// Opaque type stored in type-unsafe work queues for parallel layout.
|
||||
/// Must be transmutable to and from LayoutNode.
|
||||
pub type UnsafeLayoutNode = (usize, usize);
|
||||
pub type NonOpaqueStyleAndLayoutData = *mut RefCell<PrivateLayoutData>;
|
||||
|
||||
/// 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`.
|
||||
|
||||
pub trait LayoutNode<'ln> : Sized + Copy + Clone {
|
||||
pub trait LayoutNode<'ln> : TNode<'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;
|
||||
|
||||
/// Returns the type ID of this node.
|
||||
fn type_id(&self) -> NodeTypeId;
|
||||
|
||||
/// 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) -> 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
/// Similar to borrow_data*, but returns the full PrivateLayoutData rather
|
||||
/// than only the PrivateStyleData.
|
||||
unsafe fn borrow_layout_data_unchecked(&self) -> Option<*const PrivateLayoutData>;
|
||||
fn borrow_layout_data(&self) -> Option<Ref<PrivateLayoutData>>;
|
||||
fn mutate_layout_data(&self) -> Option<RefMut<PrivateLayoutData>>;
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
|
@ -294,31 +129,20 @@ impl<'ln> ServoLayoutNode<'ln> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'ln> LayoutNode<'ln> for ServoLayoutNode<'ln> {
|
||||
type ConcreteThreadSafeLayoutNode = ServoThreadSafeLayoutNode<'ln>;
|
||||
type ConcreteLayoutElement = ServoLayoutElement<'ln>;
|
||||
type ConcreteLayoutDocument = ServoLayoutDocument<'ln>;
|
||||
impl<'ln> TNode<'ln> for ServoLayoutNode<'ln> {
|
||||
type ConcreteElement = ServoLayoutElement<'ln>;
|
||||
type ConcreteDocument = ServoLayoutDocument<'ln>;
|
||||
|
||||
fn to_unsafe(&self) -> UnsafeLayoutNode {
|
||||
fn to_unsafe(&self) -> UnsafeNode {
|
||||
unsafe {
|
||||
let ptr: usize = mem::transmute_copy(self);
|
||||
let ptr: usize = transmute_copy(self);
|
||||
(ptr, 0)
|
||||
}
|
||||
}
|
||||
|
||||
unsafe fn from_unsafe(n: &UnsafeLayoutNode) -> Self {
|
||||
unsafe fn from_unsafe(n: &UnsafeNode) -> Self {
|
||||
let (node, _) = *n;
|
||||
mem::transmute(node)
|
||||
}
|
||||
|
||||
fn to_threadsafe(&self) -> Self::ConcreteThreadSafeLayoutNode {
|
||||
ServoThreadSafeLayoutNode::new(self)
|
||||
}
|
||||
|
||||
fn type_id(&self) -> NodeTypeId {
|
||||
unsafe {
|
||||
self.node.type_id_for_layout()
|
||||
}
|
||||
transmute(node)
|
||||
}
|
||||
|
||||
fn is_text_node(&self) -> bool {
|
||||
|
@ -339,16 +163,17 @@ impl<'ln> LayoutNode<'ln> for ServoLayoutNode<'ln> {
|
|||
OpaqueNodeMethods::from_jsmanaged(unsafe { self.get_jsmanaged() })
|
||||
}
|
||||
|
||||
fn initialize_layout_data(self) {
|
||||
let mut layout_data_ref = self.mutate_layout_data();
|
||||
match *layout_data_ref {
|
||||
None => {
|
||||
*layout_data_ref = Some(LayoutDataWrapper {
|
||||
shared_data: SharedLayoutData { style: None },
|
||||
data: box PrivateLayoutData::new(),
|
||||
});
|
||||
fn initialize_data(self) {
|
||||
let has_data = unsafe { self.borrow_data_unchecked().is_some() };
|
||||
if !has_data {
|
||||
let ptr: NonOpaqueStyleAndLayoutData =
|
||||
Box::into_raw(box RefCell::new(PrivateLayoutData::new()));
|
||||
let opaque = OpaqueStyleAndLayoutData {
|
||||
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)
|
||||
}
|
||||
|
||||
unsafe fn borrow_layout_data_unchecked(&self) -> *const Option<LayoutDataWrapper> {
|
||||
mem::transmute(self.get_jsmanaged().layout_data_unchecked())
|
||||
unsafe fn borrow_data_unchecked(&self) -> Option<*const PrivateStyleData> {
|
||||
self.borrow_layout_data_unchecked().map(|d| &(*d).style_data as *const PrivateStyleData)
|
||||
}
|
||||
|
||||
fn borrow_layout_data(&self) -> Ref<Option<LayoutDataWrapper>> {
|
||||
unsafe {
|
||||
mem::transmute(self.get_jsmanaged().layout_data())
|
||||
}
|
||||
fn borrow_data(&self) -> Option<Ref<PrivateStyleData>> {
|
||||
unsafe { self.borrow_layout_data().map(|d| transmute(d)) }
|
||||
}
|
||||
|
||||
fn mutate_layout_data(&self) -> RefMut<Option<LayoutDataWrapper>> {
|
||||
unsafe {
|
||||
mem::transmute(self.get_jsmanaged().layout_data_mut())
|
||||
}
|
||||
fn mutate_data(&self) -> Option<RefMut<PrivateStyleData>> {
|
||||
unsafe { self.mutate_layout_data().map(|d| transmute(d)) }
|
||||
}
|
||||
|
||||
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> {
|
||||
fn dump_indent(self, indent: u32) {
|
||||
let mut s = String::new();
|
||||
|
@ -468,11 +329,7 @@ impl<'ln> ServoLayoutNode<'ln> {
|
|||
}
|
||||
|
||||
pub fn flow_debug_id(self) -> usize {
|
||||
let layout_data_ref = self.borrow_layout_data();
|
||||
match *layout_data_ref {
|
||||
None => 0,
|
||||
Some(ref layout_data) => layout_data.data.flow_construction_result.debug_id()
|
||||
}
|
||||
self.borrow_layout_data().map_or(0, |d| d.flow_construction_result.debug_id())
|
||||
}
|
||||
|
||||
/// 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.
|
||||
#[derive(Copy, Clone)]
|
||||
pub struct ServoLayoutDocument<'ld> {
|
||||
|
@ -548,9 +346,9 @@ pub struct ServoLayoutDocument<'ld> {
|
|||
chain: PhantomData<&'ld ()>,
|
||||
}
|
||||
|
||||
impl<'ld> LayoutDocument<'ld> for ServoLayoutDocument<'ld> {
|
||||
type ConcreteLayoutNode = ServoLayoutNode<'ld>;
|
||||
type ConcreteLayoutElement = ServoLayoutElement<'ld>;
|
||||
impl<'ld> TDocument<'ld> for ServoLayoutDocument<'ld> {
|
||||
type ConcreteNode = ServoLayoutNode<'ld>;
|
||||
type ConcreteElement = ServoLayoutElement<'ld>;
|
||||
|
||||
fn as_node(&self) -> ServoLayoutNode<'ld> {
|
||||
ServoLayoutNode::from_layout_js(self.document.upcast())
|
||||
|
@ -582,9 +380,9 @@ pub struct ServoLayoutElement<'le> {
|
|||
chain: PhantomData<&'le ()>,
|
||||
}
|
||||
|
||||
impl<'le> LayoutElement<'le> for ServoLayoutElement<'le> {
|
||||
type ConcreteLayoutNode = ServoLayoutNode<'le>;
|
||||
type ConcreteLayoutDocument = ServoLayoutDocument<'le>;
|
||||
impl<'le> TElement<'le> for ServoLayoutElement<'le> {
|
||||
type ConcreteNode = ServoLayoutNode<'le>;
|
||||
type ConcreteDocument = ServoLayoutDocument<'le>;
|
||||
|
||||
fn as_node(&self) -> ServoLayoutNode<'le> {
|
||||
ServoLayoutNode::from_layout_js(self.element.upcast())
|
||||
|
@ -599,6 +397,28 @@ impl<'le> LayoutElement<'le> for ServoLayoutElement<'le> {
|
|||
fn get_state(&self) -> ElementState {
|
||||
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)]
|
||||
pub enum PseudoElementType<T> {
|
||||
Normal,
|
||||
|
@ -865,18 +661,14 @@ pub trait ThreadSafeLayoutNode<'ln> : Clone + Copy + Sized {
|
|||
|
||||
#[inline]
|
||||
fn get_before_pseudo(&self) -> Option<Self> {
|
||||
let layout_data_ref = self.borrow_layout_data();
|
||||
let node_layout_data_wrapper = layout_data_ref.as_ref().unwrap();
|
||||
node_layout_data_wrapper.data.before_style.as_ref().map(|style| {
|
||||
self.borrow_layout_data().unwrap().style_data.before_style.as_ref().map(|style| {
|
||||
self.with_pseudo(PseudoElementType::Before(style.get_box().display))
|
||||
})
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn get_after_pseudo(&self) -> Option<Self> {
|
||||
let layout_data_ref = self.borrow_layout_data();
|
||||
let node_layout_data_wrapper = layout_data_ref.as_ref().unwrap();
|
||||
node_layout_data_wrapper.data.after_style.as_ref().map(|style| {
|
||||
self.borrow_layout_data().unwrap().style_data.after_style.as_ref().map(|style| {
|
||||
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.
|
||||
#[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.
|
||||
///
|
||||
/// TODO(pcwalton): Make this private. It will let us avoid borrow flag checks in some cases.
|
||||
#[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
|
||||
/// has not yet been performed, fails.
|
||||
#[inline]
|
||||
fn style(&self) -> Ref<Arc<ComputedValues>> {
|
||||
Ref::map(self.borrow_layout_data(), |layout_data_ref| {
|
||||
let layout_data = layout_data_ref.as_ref().expect("no layout data");
|
||||
Ref::map(self.borrow_layout_data().unwrap(), |data| {
|
||||
let style = match self.get_pseudo_element_type() {
|
||||
PseudoElementType::Before(_) => &layout_data.data.before_style,
|
||||
PseudoElementType::After(_) => &layout_data.data.after_style,
|
||||
PseudoElementType::Normal => &layout_data.shared_data.style,
|
||||
PseudoElementType::Before(_) => &data.style_data.before_style,
|
||||
PseudoElementType::After(_) => &data.style_data.after_style,
|
||||
PseudoElementType::Normal => &data.style_data.style,
|
||||
};
|
||||
style.as_ref().unwrap()
|
||||
})
|
||||
|
@ -910,14 +701,12 @@ pub trait ThreadSafeLayoutNode<'ln> : Clone + Copy + Sized {
|
|||
|
||||
/// Removes the style from this node.
|
||||
fn unstyle(self) {
|
||||
let mut layout_data_ref = self.mutate_layout_data();
|
||||
let layout_data = layout_data_ref.as_mut().expect("no layout data");
|
||||
|
||||
let mut data = self.mutate_layout_data().unwrap();
|
||||
let style =
|
||||
match self.get_pseudo_element_type() {
|
||||
PseudoElementType::Before(_) => &mut layout_data.data.before_style,
|
||||
PseudoElementType::After (_) => &mut layout_data.data.after_style,
|
||||
PseudoElementType::Normal => &mut layout_data.shared_data.style,
|
||||
PseudoElementType::Before(_) => &mut data.style_data.before_style,
|
||||
PseudoElementType::After (_) => &mut data.style_data.after_style,
|
||||
PseudoElementType::Normal => &mut data.style_data.style,
|
||||
};
|
||||
|
||||
*style = None;
|
||||
|
@ -928,17 +717,12 @@ pub trait ThreadSafeLayoutNode<'ln> : Clone + Copy + Sized {
|
|||
/// Get the description of how to account for recent style changes.
|
||||
/// This is a simple bitfield and fine to copy by value.
|
||||
fn restyle_damage(self) -> RestyleDamage {
|
||||
let layout_data_ref = self.borrow_layout_data();
|
||||
layout_data_ref.as_ref().unwrap().data.restyle_damage
|
||||
self.borrow_layout_data().unwrap().restyle_damage
|
||||
}
|
||||
|
||||
/// Set the restyle damage field.
|
||||
fn set_restyle_damage(self, damage: RestyleDamage) {
|
||||
let mut layout_data_ref = self.mutate_layout_data();
|
||||
match *layout_data_ref {
|
||||
Some(ref mut layout_data) => layout_data.data.restyle_damage = damage,
|
||||
_ => panic!("no layout data for this node"),
|
||||
}
|
||||
self.mutate_layout_data().unwrap().restyle_damage = damage;
|
||||
}
|
||||
|
||||
/// 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.
|
||||
fn insert_flags(self, new_flags: LayoutDataFlags) {
|
||||
let mut layout_data_ref = self.mutate_layout_data();
|
||||
match *layout_data_ref {
|
||||
Some(ref mut layout_data) => layout_data.data.flags.insert(new_flags),
|
||||
_ => panic!("no layout data for this node"),
|
||||
}
|
||||
self.mutate_layout_data().unwrap().flags.insert(new_flags);
|
||||
}
|
||||
|
||||
/// Removes the given flags from this node.
|
||||
fn remove_flags(self, flags: LayoutDataFlags) {
|
||||
let mut layout_data_ref = self.mutate_layout_data();
|
||||
match *layout_data_ref {
|
||||
Some(ref mut layout_data) => layout_data.data.flags.remove(flags),
|
||||
_ => panic!("no layout data for this node"),
|
||||
}
|
||||
self.mutate_layout_data().unwrap().flags.remove(flags);
|
||||
}
|
||||
|
||||
/// 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> {
|
||||
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> {
|
||||
|
@ -1112,11 +880,11 @@ impl<'ln> ThreadSafeLayoutNode<'ln> for ServoThreadSafeLayoutNode<'ln> {
|
|||
self.pseudo
|
||||
}
|
||||
|
||||
fn borrow_layout_data(&self) -> Ref<Option<LayoutDataWrapper>> {
|
||||
fn borrow_layout_data(&self) -> Option<Ref<PrivateLayoutData>> {
|
||||
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()
|
||||
}
|
||||
|
||||
|
@ -1143,17 +911,13 @@ impl<'ln> ThreadSafeLayoutNode<'ln> for ServoThreadSafeLayoutNode<'ln> {
|
|||
|
||||
fn flags(self) -> LayoutDataFlags {
|
||||
unsafe {
|
||||
match *self.borrow_layout_data_unchecked() {
|
||||
None => panic!(),
|
||||
Some(ref layout_data) => layout_data.data.flags,
|
||||
}
|
||||
(*self.node.borrow_layout_data_unchecked().unwrap()).flags
|
||||
}
|
||||
}
|
||||
|
||||
fn text_content(&self) -> TextContent {
|
||||
if self.pseudo != PseudoElementType::Normal {
|
||||
let layout_data_ref = self.borrow_layout_data();
|
||||
let data = &layout_data_ref.as_ref().unwrap().data;
|
||||
let data = &self.borrow_layout_data().unwrap().style_data;
|
||||
|
||||
let style = if self.pseudo.is_before() {
|
||||
&data.before_style
|
||||
|
|
|
@ -57,14 +57,12 @@ use selectors::matching::matches;
|
|||
use selectors::parser::Selector;
|
||||
use selectors::parser::parse_author_origin_selector_list_from_str;
|
||||
use std::borrow::ToOwned;
|
||||
use std::cell::{Cell, Ref, RefCell, RefMut};
|
||||
use std::cell::Cell;
|
||||
use std::cmp::max;
|
||||
use std::default::Default;
|
||||
use std::iter::{self, FilterMap, Peekable};
|
||||
use std::mem;
|
||||
use std::sync::Arc;
|
||||
use string_cache::{Atom, Namespace, QualName};
|
||||
use style::properties::ComputedValues;
|
||||
use util::str::DOMString;
|
||||
use util::task_state;
|
||||
use uuid::Uuid;
|
||||
|
@ -115,11 +113,11 @@ pub struct Node {
|
|||
/// are this node.
|
||||
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
|
||||
/// node is finalized.
|
||||
layout_data: LayoutDataRef,
|
||||
style_and_layout_data: Cell<Option<OpaqueStyleAndLayoutData>>,
|
||||
|
||||
unique_id: DOMRefCell<Option<Box<Uuid>>>,
|
||||
}
|
||||
|
@ -164,7 +162,7 @@ impl NodeFlags {
|
|||
impl Drop for Node {
|
||||
#[allow(unsafe_code)]
|
||||
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
|
||||
}
|
||||
|
||||
/// Layout data that is shared between the script and layout tasks.
|
||||
#[derive(HeapSizeOf)]
|
||||
pub struct SharedLayoutData {
|
||||
/// The results of CSS styling for this node.
|
||||
pub style: Option<Arc<ComputedValues>>,
|
||||
}
|
||||
|
||||
/// 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 ()>,
|
||||
#[derive(Copy, Clone, HeapSizeOf)]
|
||||
pub struct OpaqueStyleAndLayoutData {
|
||||
#[ignore_heap_size_of = "TODO(#6910) Box value that should be counted but \
|
||||
the type lives in layout"]
|
||||
pub ptr: NonZero<*mut ()>
|
||||
}
|
||||
|
||||
#[allow(unsafe_code)]
|
||||
unsafe impl Send for LayoutData {}
|
||||
unsafe impl Send for OpaqueStyleAndLayoutData {}
|
||||
|
||||
#[derive(HeapSizeOf)]
|
||||
pub struct LayoutDataRef {
|
||||
data_cell: RefCell<Option<LayoutData>>,
|
||||
}
|
||||
no_jsmanaged_fields!(OpaqueStyleAndLayoutData);
|
||||
|
||||
no_jsmanaged_fields!(LayoutDataRef);
|
||||
|
||||
impl LayoutDataRef {
|
||||
pub fn new() -> LayoutDataRef {
|
||||
LayoutDataRef {
|
||||
data_cell: RefCell::new(None),
|
||||
}
|
||||
}
|
||||
|
||||
/// Sends layout data, if any, back to the layout task to be destroyed.
|
||||
pub fn dispose(&self, node: &Node) {
|
||||
impl OpaqueStyleAndLayoutData {
|
||||
/// Sends the style and 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());
|
||||
if let Some(layout_data) = mem::replace(&mut *self.data_cell.borrow_mut(), None) {
|
||||
let win = window_from_node(node);
|
||||
let LayoutChan(chan) = win.layout_chan();
|
||||
chan.send(Msg::ReapLayoutData(layout_data)).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()
|
||||
let win = window_from_node(node);
|
||||
let LayoutChan(chan) = win.layout_chan();
|
||||
node.style_and_layout_data.set(None);
|
||||
chan.send(Msg::ReapStyleAndLayoutData(self)).unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -334,7 +285,7 @@ impl Node {
|
|||
for node in child.traverse_preorder() {
|
||||
node.set_flag(IS_IN_DOC, false);
|
||||
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);
|
||||
|
@ -378,7 +329,7 @@ impl<'a> Iterator for QuerySelectorIterator {
|
|||
|
||||
impl Node {
|
||||
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() {
|
||||
kid.teardown();
|
||||
}
|
||||
|
@ -966,9 +917,8 @@ pub trait LayoutNodeHelpers {
|
|||
|
||||
unsafe fn children_count(&self) -> u32;
|
||||
|
||||
unsafe fn layout_data(&self) -> Ref<Option<LayoutData>>;
|
||||
unsafe fn layout_data_mut(&self) -> RefMut<Option<LayoutData>>;
|
||||
unsafe fn layout_data_unchecked(&self) -> *const Option<LayoutData>;
|
||||
unsafe fn get_style_and_layout_data(&self) -> Option<OpaqueStyleAndLayoutData>;
|
||||
unsafe fn init_style_and_layout_data(&self, OpaqueStyleAndLayoutData);
|
||||
}
|
||||
|
||||
impl LayoutNodeHelpers for LayoutJS<Node> {
|
||||
|
@ -1049,20 +999,15 @@ impl LayoutNodeHelpers for LayoutJS<Node> {
|
|||
|
||||
#[inline]
|
||||
#[allow(unsafe_code)]
|
||||
unsafe fn layout_data(&self) -> Ref<Option<LayoutData>> {
|
||||
(*self.unsafe_get()).layout_data.borrow()
|
||||
unsafe fn get_style_and_layout_data(&self) -> Option<OpaqueStyleAndLayoutData> {
|
||||
(*self.unsafe_get()).style_and_layout_data.get()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
#[allow(unsafe_code)]
|
||||
unsafe fn layout_data_mut(&self) -> RefMut<Option<LayoutData>> {
|
||||
(*self.unsafe_get()).layout_data.borrow_mut()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
#[allow(unsafe_code)]
|
||||
unsafe fn layout_data_unchecked(&self) -> *const Option<LayoutData> {
|
||||
(*self.unsafe_get()).layout_data.borrow_unchecked()
|
||||
unsafe fn init_style_and_layout_data(&self, val: OpaqueStyleAndLayoutData) {
|
||||
debug_assert!((*self.unsafe_get()).style_and_layout_data.get().is_none());
|
||||
(*self.unsafe_get()).style_and_layout_data.set(Some(val));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1322,7 +1267,7 @@ impl Node {
|
|||
inclusive_descendants_version: Cell::new(0),
|
||||
ranges: WeakRangeVec::new(),
|
||||
|
||||
layout_data: LayoutDataRef::new(),
|
||||
style_and_layout_data: Cell::new(None),
|
||||
|
||||
unique_id: DOMRefCell::new(None),
|
||||
}
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
//! the DOM to be placed in a separate crate from layout.
|
||||
|
||||
use app_units::Au;
|
||||
use dom::node::LayoutData;
|
||||
use dom::node::OpaqueStyleAndLayoutData;
|
||||
use euclid::point::Point2D;
|
||||
use euclid::rect::Rect;
|
||||
use gfx_traits::LayerId;
|
||||
|
@ -59,7 +59,7 @@ pub enum Msg {
|
|||
/// Destroys layout data associated with a DOM node.
|
||||
///
|
||||
/// 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
|
||||
/// via the supplied channel.
|
||||
|
|
|
@ -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),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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
|
||||
}
|
||||
}
|
|
@ -17,6 +17,7 @@
|
|||
extern crate app_units;
|
||||
#[macro_use]
|
||||
extern crate bitflags;
|
||||
extern crate core;
|
||||
#[macro_use]
|
||||
extern crate cssparser;
|
||||
extern crate encoding;
|
||||
|
@ -43,9 +44,10 @@ extern crate util;
|
|||
pub mod animation;
|
||||
pub mod attr;
|
||||
mod custom_properties;
|
||||
pub mod data;
|
||||
pub mod dom;
|
||||
pub mod font_face;
|
||||
pub mod media_queries;
|
||||
pub mod node;
|
||||
pub mod parser;
|
||||
pub mod restyle_hints;
|
||||
pub mod selector_matching;
|
||||
|
|
|
@ -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>;
|
||||
}
|
|
@ -3,11 +3,11 @@
|
|||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
use cssparser::{Parser, SourcePosition};
|
||||
use dom::TElement;
|
||||
use log;
|
||||
use media_queries::{Device, MediaType};
|
||||
use msg::ParseErrorReporter;
|
||||
use msg::constellation_msg::PipelineId;
|
||||
use node::TElementAttributes;
|
||||
use properties::{PropertyDeclaration, PropertyDeclarationBlock};
|
||||
use restyle_hints::{ElementSnapshot, RestyleHint, DependencySet};
|
||||
use selectors::Element;
|
||||
|
@ -270,7 +270,7 @@ impl Stylist {
|
|||
/// 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
|
||||
/// 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,
|
||||
element: &E,
|
||||
parent_bf: Option<&BloomFilter>,
|
||||
|
@ -278,7 +278,7 @@ impl Stylist {
|
|||
pseudo_element: Option<PseudoElement>,
|
||||
applicable_declarations: &mut V)
|
||||
-> bool
|
||||
where E: Element + TElementAttributes,
|
||||
where E: Element + TElement<'le>,
|
||||
V: VecLike<DeclarationBlock> {
|
||||
assert!(!self.is_device_dirty);
|
||||
assert!(style_attribute.is_none() || pseudo_element.is_none(),
|
||||
|
|
|
@ -35,6 +35,7 @@ use std::mem::{size_of, transmute};
|
|||
use std::rc::Rc;
|
||||
use std::result::Result;
|
||||
use std::sync::Arc;
|
||||
use std::sync::atomic::{AtomicIsize, AtomicUsize};
|
||||
use str::{DOMString, LengthOrPercentageOrAuto};
|
||||
use string_cache::atom::Atom;
|
||||
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, i8, i16, i32, i64, isize);
|
||||
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, Length<T, U>, ScaleFactor<T, U, V>);
|
||||
|
|
|
@ -38,10 +38,10 @@ macro_rules! sizeof_checker (
|
|||
|
||||
// Update the sizes here
|
||||
sizeof_checker!(size_event_target, EventTarget, 40);
|
||||
sizeof_checker!(size_node, Node, 184);
|
||||
sizeof_checker!(size_element, Element, 328);
|
||||
sizeof_checker!(size_htmlelement, HTMLElement, 344);
|
||||
sizeof_checker!(size_div, HTMLDivElement, 344);
|
||||
sizeof_checker!(size_span, HTMLSpanElement, 344);
|
||||
sizeof_checker!(size_text, Text, 216);
|
||||
sizeof_checker!(size_characterdata, CharacterData, 216);
|
||||
sizeof_checker!(size_node, Node, 168);
|
||||
sizeof_checker!(size_element, Element, 312);
|
||||
sizeof_checker!(size_htmlelement, HTMLElement, 328);
|
||||
sizeof_checker!(size_div, HTMLDivElement, 328);
|
||||
sizeof_checker!(size_span, HTMLSpanElement, 328);
|
||||
sizeof_checker!(size_text, Text, 200);
|
||||
sizeof_checker!(size_characterdata, CharacterData, 200);
|
||||
|
|
Загрузка…
Ссылка в новой задаче