mirror of
https://github.com/servo/servo.git
synced 2025-08-12 17:05:33 +01:00
Hoist most styling functionality from TNode to TElement.
MozReview-Commit-ID: DZ8ZrsZIiAU
This commit is contained in:
parent
47d29fd056
commit
5442fbec3f
17 changed files with 399 additions and 363 deletions
|
@ -123,7 +123,7 @@ pub trait TNode : Sized + Copy + Clone + NodeInfo {
|
|||
|
||||
/// 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 layout_parent_element(self, reflow_root: OpaqueNode) -> Option<Self::ConcreteElement>;
|
||||
|
||||
fn debug_id(self) -> usize;
|
||||
|
||||
|
@ -131,16 +131,6 @@ pub trait TNode : Sized + Copy + Clone + NodeInfo {
|
|||
|
||||
fn as_document(&self) -> Option<Self::ConcreteDocument>;
|
||||
|
||||
/// The concept of a dirty bit doesn't exist in our new restyle algorithm.
|
||||
/// Instead, we associate restyle and change hints with nodes. However, we
|
||||
/// continue to allow the dirty bit to trigger unconditional restyles while
|
||||
/// we transition both Servo and Stylo to the new architecture.
|
||||
fn deprecated_dirty_bit_is_set(&self) -> bool;
|
||||
|
||||
fn has_dirty_descendants(&self) -> bool;
|
||||
|
||||
unsafe fn set_dirty_descendants(&self);
|
||||
|
||||
fn needs_dirty_on_viewport_size_changed(&self) -> bool;
|
||||
|
||||
unsafe fn set_dirty_on_viewport_size_changed(&self);
|
||||
|
@ -149,71 +139,6 @@ pub trait TNode : Sized + Copy + Clone + NodeInfo {
|
|||
|
||||
unsafe fn set_can_be_fragmented(&self, value: bool);
|
||||
|
||||
/// Atomically stores the number of children of this node that we will
|
||||
/// need to process during bottom-up traversal.
|
||||
fn store_children_to_process(&self, n: isize);
|
||||
|
||||
/// Atomically notes that a child has been processed during bottom-up
|
||||
/// traversal. Returns the number of children left to process.
|
||||
fn did_process_child(&self) -> isize;
|
||||
|
||||
/// Returns true if this node has a styled layout frame that owns the style.
|
||||
fn frame_has_style(&self) -> bool { false }
|
||||
|
||||
/// Returns the styles from the layout frame that owns them, if any.
|
||||
///
|
||||
/// FIXME(bholley): Once we start dropping NodeData from nodes when
|
||||
/// creating frames, we'll want to teach this method to actually get
|
||||
/// style data from the frame.
|
||||
fn get_styles_from_frame(&self) -> Option<NodeStyles> { None }
|
||||
|
||||
/// Returns the styling mode for this node. This is only valid to call before
|
||||
/// and during restyling, before finish_styling is invoked.
|
||||
///
|
||||
/// See the comments around StylingMode.
|
||||
fn styling_mode(&self) -> StylingMode {
|
||||
use self::StylingMode::*;
|
||||
|
||||
// Non-incremental layout impersonates Initial.
|
||||
if opts::get().nonincremental_layout {
|
||||
return Initial;
|
||||
}
|
||||
|
||||
// Compute the default result if this node doesn't require processing.
|
||||
let mode_for_descendants = if self.has_dirty_descendants() {
|
||||
Traverse
|
||||
} else {
|
||||
Stop
|
||||
};
|
||||
|
||||
match self.borrow_data() {
|
||||
// No node data, no style on the frame.
|
||||
None if !self.frame_has_style() => Initial,
|
||||
// No node data, style on the frame.
|
||||
None => mode_for_descendants,
|
||||
Some(d) => {
|
||||
if d.restyle_data.is_some() || self.deprecated_dirty_bit_is_set() {
|
||||
Restyle
|
||||
} else {
|
||||
debug_assert!(!self.frame_has_style()); // display:none etc
|
||||
mode_for_descendants
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
/// Sets up the appropriate data structures to style a node, returing a
|
||||
/// mutable handle to the node data upon which further style calculations
|
||||
/// can be performed.
|
||||
fn begin_styling(&self) -> AtomicRefMut<NodeData>;
|
||||
|
||||
/// Set the style directly for a text node. This skips various unnecessary
|
||||
/// steps from begin_styling like computing the previous style.
|
||||
fn style_text_node(&self, style: Arc<ComputedValues>);
|
||||
|
||||
/// Immutable borrows the NodeData.
|
||||
fn borrow_data(&self) -> Option<AtomicRef<NodeData>>;
|
||||
|
||||
fn parent_node(&self) -> Option<Self>;
|
||||
|
||||
fn first_child(&self) -> Option<Self>;
|
||||
|
@ -268,7 +193,79 @@ pub trait TElement : PartialEq + Debug + Sized + Copy + Clone + ElementExt + Pre
|
|||
fn existing_style_for_restyle_damage<'a>(&'a self,
|
||||
current_computed_values: Option<&'a Arc<ComputedValues>>,
|
||||
pseudo: Option<&PseudoElement>)
|
||||
-> Option<&'a <Self::ConcreteRestyleDamage as TRestyleDamage> ::PreExistingComputedValues>;
|
||||
-> Option<&'a <Self::ConcreteRestyleDamage as TRestyleDamage>::PreExistingComputedValues>;
|
||||
|
||||
/// The concept of a dirty bit doesn't exist in our new restyle algorithm.
|
||||
/// Instead, we associate restyle and change hints with nodes. However, we
|
||||
/// continue to allow the dirty bit to trigger unconditional restyles while
|
||||
/// we transition both Servo and Stylo to the new architecture.
|
||||
fn deprecated_dirty_bit_is_set(&self) -> bool;
|
||||
|
||||
fn has_dirty_descendants(&self) -> bool;
|
||||
|
||||
unsafe fn set_dirty_descendants(&self);
|
||||
|
||||
/// Atomically stores the number of children of this node that we will
|
||||
/// need to process during bottom-up traversal.
|
||||
fn store_children_to_process(&self, n: isize);
|
||||
|
||||
/// Atomically notes that a child has been processed during bottom-up
|
||||
/// traversal. Returns the number of children left to process.
|
||||
fn did_process_child(&self) -> isize;
|
||||
|
||||
|
||||
/// Returns true if this node has a styled layout frame that owns the style.
|
||||
fn frame_has_style(&self) -> bool { false }
|
||||
|
||||
/// Returns the styles from the layout frame that owns them, if any.
|
||||
///
|
||||
/// FIXME(bholley): Once we start dropping NodeData from nodes when
|
||||
/// creating frames, we'll want to teach this method to actually get
|
||||
/// style data from the frame.
|
||||
fn get_styles_from_frame(&self) -> Option<NodeStyles> { None }
|
||||
|
||||
/// Returns the styling mode for this node. This is only valid to call before
|
||||
/// and during restyling, before finish_styling is invoked.
|
||||
///
|
||||
/// See the comments around StylingMode.
|
||||
fn styling_mode(&self) -> StylingMode {
|
||||
use self::StylingMode::*;
|
||||
|
||||
// Non-incremental layout impersonates Initial.
|
||||
if opts::get().nonincremental_layout {
|
||||
return Initial;
|
||||
}
|
||||
|
||||
// Compute the default result if this node doesn't require processing.
|
||||
let mode_for_descendants = if self.has_dirty_descendants() {
|
||||
Traverse
|
||||
} else {
|
||||
Stop
|
||||
};
|
||||
|
||||
match self.borrow_data() {
|
||||
// No node data, no style on the frame.
|
||||
None if !self.frame_has_style() => Initial,
|
||||
// No node data, style on the frame.
|
||||
None => mode_for_descendants,
|
||||
Some(d) => {
|
||||
if d.restyle_data.is_some() || self.deprecated_dirty_bit_is_set() {
|
||||
Restyle
|
||||
} else {
|
||||
debug_assert!(!self.frame_has_style()); // display:none etc
|
||||
mode_for_descendants
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
/// Sets up the appropriate data structures to style a node, returing a
|
||||
/// mutable handle to the node data upon which further style calculations
|
||||
/// can be performed.
|
||||
fn begin_styling(&self) -> AtomicRefMut<NodeData>;
|
||||
|
||||
/// Immutable borrows the NodeData.
|
||||
fn borrow_data(&self) -> Option<AtomicRef<NodeData>>;
|
||||
|
||||
/// Properly marks nodes as dirty in response to restyle hints.
|
||||
fn note_restyle_hint<C: DomTraversalContext<Self::ConcreteNode>>(&self, hint: RestyleHint) {
|
||||
|
@ -279,9 +276,8 @@ pub trait TElement : PartialEq + Debug + Sized + Copy + Clone + ElementExt + Pre
|
|||
|
||||
// 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() {
|
||||
let mut curr = *self;
|
||||
while let Some(parent) = curr.parent_element() {
|
||||
if parent.has_dirty_descendants() { break }
|
||||
unsafe { parent.set_dirty_descendants(); }
|
||||
curr = parent;
|
||||
|
@ -289,22 +285,21 @@ pub trait TElement : PartialEq + Debug + Sized + Copy + Clone + ElementExt + Pre
|
|||
|
||||
// Process hints.
|
||||
if hint.contains(RESTYLE_SELF) {
|
||||
unsafe { C::ensure_node_data(&node).borrow_mut().ensure_restyle_data(); }
|
||||
unsafe { C::ensure_element_data(self).borrow_mut().ensure_restyle_data(); }
|
||||
// XXX(emilio): For now, dirty implies dirty descendants if found.
|
||||
} else if hint.contains(RESTYLE_DESCENDANTS) {
|
||||
unsafe { node.set_dirty_descendants(); }
|
||||
let mut current = node.first_child();
|
||||
while let Some(node) = current {
|
||||
unsafe { C::ensure_node_data(&node).borrow_mut().ensure_restyle_data(); }
|
||||
current = node.next_sibling();
|
||||
unsafe { self.set_dirty_descendants(); }
|
||||
let mut current = self.first_child_element();
|
||||
while let Some(el) = current {
|
||||
unsafe { C::ensure_element_data(&el).borrow_mut().ensure_restyle_data(); }
|
||||
current = el.next_sibling_element();
|
||||
}
|
||||
}
|
||||
|
||||
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();
|
||||
unsafe { C::ensure_node_data(&sib_node).borrow_mut().ensure_restyle_data() };
|
||||
unsafe { C::ensure_element_data(&sib).borrow_mut().ensure_restyle_data() };
|
||||
next = ::selectors::Element::next_sibling_element(&sib);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,9 +5,9 @@
|
|||
use atomic_refcell::AtomicRefCell;
|
||||
use context::{LocalStyleContext, SharedStyleContext, StyleContext};
|
||||
use data::NodeData;
|
||||
use dom::{NodeInfo, OpaqueNode, TNode};
|
||||
use dom::{NodeInfo, OpaqueNode, StylingMode, TElement, TNode};
|
||||
use gecko::context::StandaloneStyleContext;
|
||||
use gecko::wrapper::GeckoNode;
|
||||
use gecko::wrapper::{GeckoElement, GeckoNode};
|
||||
use std::mem;
|
||||
use traversal::{DomTraversalContext, recalc_style_at};
|
||||
use traversal::RestyleResult;
|
||||
|
@ -48,8 +48,15 @@ impl<'lc, 'ln> DomTraversalContext<GeckoNode<'ln>> for RecalcStyleOnly<'lc> {
|
|||
/// We don't use the post-order traversal for anything.
|
||||
fn needs_postorder_traversal(&self) -> bool { false }
|
||||
|
||||
fn ensure_node_data<'a>(node: &'a GeckoNode<'ln>) -> &'a AtomicRefCell<NodeData> {
|
||||
node.ensure_data()
|
||||
fn should_traverse_child(_parent: GeckoElement<'ln>, child: GeckoNode<'ln>) -> bool {
|
||||
match child.as_element() {
|
||||
Some(el) => el.styling_mode() != StylingMode::Stop,
|
||||
None => false, // Gecko restyle doesn't need to traverse text nodes.
|
||||
}
|
||||
}
|
||||
|
||||
fn ensure_element_data<'a>(element: &'a GeckoElement<'ln>) -> &'a AtomicRefCell<NodeData> {
|
||||
element.ensure_data()
|
||||
}
|
||||
|
||||
fn local_context(&self) -> &LocalStyleContext {
|
||||
|
|
|
@ -64,51 +64,6 @@ impl<'ln> GeckoNode<'ln> {
|
|||
debug_assert!(!self.0.mNodeInfo.mRawPtr.is_null());
|
||||
unsafe { &*self.0.mNodeInfo.mRawPtr }
|
||||
}
|
||||
|
||||
fn flags(&self) -> u32 {
|
||||
(self.0)._base._base_1.mFlags
|
||||
}
|
||||
|
||||
// FIXME: We can implement this without OOL calls, but we can't easily given
|
||||
// GeckoNode is a raw reference.
|
||||
//
|
||||
// We can use a Cell<T>, but that's a bit of a pain.
|
||||
fn set_flags(&self, flags: u32) {
|
||||
unsafe { Gecko_SetNodeFlags(self.0, flags) }
|
||||
}
|
||||
|
||||
pub fn clear_data(&self) {
|
||||
let ptr = self.0.mServoData.get();
|
||||
if !ptr.is_null() {
|
||||
let data = unsafe { Box::from_raw(self.0.mServoData.get()) };
|
||||
self.0.mServoData.set(ptr::null_mut());
|
||||
|
||||
// Perform a mutable borrow of the data in debug builds. This
|
||||
// serves as an assertion that there are no outstanding borrows
|
||||
// when we destroy the data.
|
||||
debug_assert!({ let _ = data.borrow_mut(); true });
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_pseudo_style(&self, pseudo: &PseudoElement) -> Option<Arc<ComputedValues>> {
|
||||
self.borrow_data().and_then(|data| data.current_styles().pseudos
|
||||
.get(pseudo).map(|c| c.clone()))
|
||||
}
|
||||
|
||||
fn get_node_data(&self) -> Option<&AtomicRefCell<NodeData>> {
|
||||
unsafe { self.0.mServoData.get().as_ref() }
|
||||
}
|
||||
|
||||
pub fn ensure_data(&self) -> &AtomicRefCell<NodeData> {
|
||||
match self.get_node_data() {
|
||||
Some(x) => x,
|
||||
None => {
|
||||
let ptr = Box::into_raw(Box::new(AtomicRefCell::new(NodeData::new())));
|
||||
self.0.mServoData.set(ptr);
|
||||
unsafe { &* ptr }
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, PartialEq)]
|
||||
|
@ -192,11 +147,11 @@ impl<'ln> TNode for GeckoNode<'ln> {
|
|||
OpaqueNode(ptr)
|
||||
}
|
||||
|
||||
fn layout_parent_node(self, reflow_root: OpaqueNode) -> Option<GeckoNode<'ln>> {
|
||||
fn layout_parent_element(self, reflow_root: OpaqueNode) -> Option<GeckoElement<'ln>> {
|
||||
if self.opaque() == reflow_root {
|
||||
None
|
||||
} else {
|
||||
self.parent_node()
|
||||
self.parent_node().and_then(|x| x.as_element())
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -216,23 +171,6 @@ impl<'ln> TNode for GeckoNode<'ln> {
|
|||
unimplemented!()
|
||||
}
|
||||
|
||||
fn deprecated_dirty_bit_is_set(&self) -> bool {
|
||||
self.flags() & (NODE_IS_DIRTY_FOR_SERVO as u32) != 0
|
||||
}
|
||||
|
||||
fn has_dirty_descendants(&self) -> bool {
|
||||
// Return true unconditionally if we're not yet styled. This is a hack
|
||||
// and should go away soon.
|
||||
if self.get_node_data().is_none() {
|
||||
return true;
|
||||
}
|
||||
self.flags() & (NODE_HAS_DIRTY_DESCENDANTS_FOR_SERVO as u32) != 0
|
||||
}
|
||||
|
||||
unsafe fn set_dirty_descendants(&self) {
|
||||
self.set_flags(NODE_HAS_DIRTY_DESCENDANTS_FOR_SERVO as u32)
|
||||
}
|
||||
|
||||
fn can_be_fragmented(&self) -> bool {
|
||||
// FIXME(SimonSapin): Servo uses this to implement CSS multicol / fragmentation
|
||||
// Maybe this isn’t useful for Gecko?
|
||||
|
@ -244,34 +182,6 @@ impl<'ln> TNode for GeckoNode<'ln> {
|
|||
// Maybe this isn’t useful for Gecko?
|
||||
}
|
||||
|
||||
fn store_children_to_process(&self, _: isize) {
|
||||
// This is only used for bottom-up traversal, and is thus a no-op for Gecko.
|
||||
}
|
||||
|
||||
fn did_process_child(&self) -> isize {
|
||||
panic!("Atomic child count not implemented in Gecko");
|
||||
}
|
||||
|
||||
fn begin_styling(&self) -> AtomicRefMut<NodeData> {
|
||||
let mut data = self.ensure_data().borrow_mut();
|
||||
data.gather_previous_styles(|| self.get_styles_from_frame());
|
||||
data
|
||||
}
|
||||
|
||||
fn style_text_node(&self, style: Arc<ComputedValues>) {
|
||||
debug_assert!(self.is_text_node());
|
||||
|
||||
// FIXME(bholley): Gecko currently relies on the dirty bit being set to
|
||||
// drive the post-traversal. This will go away soon.
|
||||
unsafe { self.set_flags(NODE_IS_DIRTY_FOR_SERVO as u32); }
|
||||
|
||||
self.ensure_data().borrow_mut().style_text_node(style);
|
||||
}
|
||||
|
||||
fn borrow_data(&self) -> Option<AtomicRef<NodeData>> {
|
||||
self.get_node_data().map(|x| x.borrow())
|
||||
}
|
||||
|
||||
fn parent_node(&self) -> Option<GeckoNode<'ln>> {
|
||||
unsafe { self.0.mParent.as_ref().map(GeckoNode) }
|
||||
}
|
||||
|
@ -387,6 +297,55 @@ impl<'le> GeckoElement<'le> {
|
|||
let extra_data = ParserContextExtraData::default();
|
||||
parse_style_attribute(value, &base_url, Box::new(StdoutErrorReporter), extra_data)
|
||||
}
|
||||
|
||||
fn flags(&self) -> u32 {
|
||||
self.raw_node()._base._base_1.mFlags
|
||||
}
|
||||
|
||||
fn raw_node(&self) -> &RawGeckoNode {
|
||||
&(self.0)._base._base._base
|
||||
}
|
||||
|
||||
// FIXME: We can implement this without OOL calls, but we can't easily given
|
||||
// GeckoNode is a raw reference.
|
||||
//
|
||||
// We can use a Cell<T>, but that's a bit of a pain.
|
||||
fn set_flags(&self, flags: u32) {
|
||||
unsafe { Gecko_SetNodeFlags(self.as_node().0, flags) }
|
||||
}
|
||||
|
||||
pub fn clear_data(&self) {
|
||||
let ptr = self.raw_node().mServoData.get();
|
||||
if !ptr.is_null() {
|
||||
let data = unsafe { Box::from_raw(self.raw_node().mServoData.get()) };
|
||||
self.raw_node().mServoData.set(ptr::null_mut());
|
||||
|
||||
// Perform a mutable borrow of the data in debug builds. This
|
||||
// serves as an assertion that there are no outstanding borrows
|
||||
// when we destroy the data.
|
||||
debug_assert!({ let _ = data.borrow_mut(); true });
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_pseudo_style(&self, pseudo: &PseudoElement) -> Option<Arc<ComputedValues>> {
|
||||
self.borrow_data().and_then(|data| data.current_styles().pseudos
|
||||
.get(pseudo).map(|c| c.clone()))
|
||||
}
|
||||
|
||||
fn get_node_data(&self) -> Option<&AtomicRefCell<NodeData>> {
|
||||
unsafe { self.raw_node().mServoData.get().as_ref() }
|
||||
}
|
||||
|
||||
pub fn ensure_data(&self) -> &AtomicRefCell<NodeData> {
|
||||
match self.get_node_data() {
|
||||
Some(x) => x,
|
||||
None => {
|
||||
let ptr = Box::into_raw(Box::new(AtomicRefCell::new(NodeData::new())));
|
||||
self.raw_node().mServoData.set(ptr);
|
||||
unsafe { &* ptr }
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
lazy_static! {
|
||||
|
@ -438,7 +397,7 @@ impl<'le> TElement for GeckoElement<'le> {
|
|||
fn set_restyle_damage(self, damage: GeckoRestyleDamage) {
|
||||
// FIXME(bholley): Gecko currently relies on the dirty bit being set to
|
||||
// drive the post-traversal. This will go away soon.
|
||||
unsafe { self.as_node().set_flags(NODE_IS_DIRTY_FOR_SERVO as u32) }
|
||||
unsafe { self.set_flags(NODE_IS_DIRTY_FOR_SERVO as u32) }
|
||||
|
||||
unsafe { Gecko_StoreStyleDifference(self.as_node().0, damage.0) }
|
||||
}
|
||||
|
@ -459,6 +418,41 @@ impl<'le> TElement for GeckoElement<'le> {
|
|||
context_ptr.as_ref()
|
||||
}
|
||||
}
|
||||
|
||||
fn deprecated_dirty_bit_is_set(&self) -> bool {
|
||||
self.flags() & (NODE_IS_DIRTY_FOR_SERVO as u32) != 0
|
||||
}
|
||||
|
||||
fn has_dirty_descendants(&self) -> bool {
|
||||
// Return true unconditionally if we're not yet styled. This is a hack
|
||||
// and should go away soon.
|
||||
if self.get_node_data().is_none() {
|
||||
return true;
|
||||
}
|
||||
self.flags() & (NODE_HAS_DIRTY_DESCENDANTS_FOR_SERVO as u32) != 0
|
||||
}
|
||||
|
||||
unsafe fn set_dirty_descendants(&self) {
|
||||
self.set_flags(NODE_HAS_DIRTY_DESCENDANTS_FOR_SERVO as u32)
|
||||
}
|
||||
|
||||
fn store_children_to_process(&self, _: isize) {
|
||||
// This is only used for bottom-up traversal, and is thus a no-op for Gecko.
|
||||
}
|
||||
|
||||
fn did_process_child(&self) -> isize {
|
||||
panic!("Atomic child count not implemented in Gecko");
|
||||
}
|
||||
|
||||
fn begin_styling(&self) -> AtomicRefMut<NodeData> {
|
||||
let mut data = self.ensure_data().borrow_mut();
|
||||
data.gather_previous_styles(|| self.get_styles_from_frame());
|
||||
data
|
||||
}
|
||||
|
||||
fn borrow_data(&self) -> Option<AtomicRef<NodeData>> {
|
||||
self.get_node_data().map(|x| x.borrow())
|
||||
}
|
||||
}
|
||||
|
||||
impl<'le> PartialEq for GeckoElement<'le> {
|
||||
|
|
|
@ -441,8 +441,7 @@ impl StyleSharingCandidateCache {
|
|||
return;
|
||||
}
|
||||
|
||||
let node = element.as_node();
|
||||
let data = node.borrow_data().unwrap();
|
||||
let data = element.borrow_data().unwrap();
|
||||
let style = &data.current_styles().primary;
|
||||
|
||||
let box_style = style.get_box();
|
||||
|
@ -460,7 +459,7 @@ impl StyleSharingCandidateCache {
|
|||
element.as_node().to_unsafe(), parent.as_node().to_unsafe());
|
||||
|
||||
self.cache.insert(StyleSharingCandidate {
|
||||
node: node.to_unsafe(),
|
||||
node: element.as_node().to_unsafe(),
|
||||
style: style.clone(),
|
||||
common_style_affecting_attributes: None,
|
||||
class_attributes: None,
|
||||
|
@ -716,8 +715,7 @@ pub trait MatchMethods : TElement {
|
|||
match sharing_result {
|
||||
Ok(shared_style) => {
|
||||
// Yay, cache hit. Share the style.
|
||||
let node = self.as_node();
|
||||
let mut data = node.begin_styling();
|
||||
let mut data = self.begin_styling();
|
||||
|
||||
// TODO: add the display: none optimisation here too! Even
|
||||
// better, factor it out/make it a bit more generic so Gecko
|
||||
|
@ -863,12 +861,10 @@ pub trait MatchMethods : TElement {
|
|||
where Ctx: StyleContext<'a>
|
||||
{
|
||||
// Get our parent's style.
|
||||
let parent_as_node = parent.map(|x| x.as_node());
|
||||
let parent_data = parent_as_node.as_ref().map(|x| x.borrow_data().unwrap());
|
||||
let parent_data = parent.as_ref().map(|x| x.borrow_data().unwrap());
|
||||
let parent_style = parent_data.as_ref().map(|x| &x.current_styles().primary);
|
||||
|
||||
let node = self.as_node();
|
||||
let mut data = node.begin_styling();
|
||||
let mut data = self.begin_styling();
|
||||
let mut new_styles;
|
||||
|
||||
let mut applicable_declarations_cache =
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
|
||||
#![allow(unsafe_code)]
|
||||
|
||||
use dom::{OpaqueNode, StylingMode, TNode, UnsafeNode};
|
||||
use dom::{OpaqueNode, StylingMode, TElement, TNode, UnsafeNode};
|
||||
use std::mem;
|
||||
use std::sync::atomic::Ordering;
|
||||
use traversal::{RestyleResult, DomTraversalContext};
|
||||
|
@ -47,7 +47,7 @@ pub fn traverse_dom<N, C>(root: N,
|
|||
where N: TNode,
|
||||
C: DomTraversalContext<N>
|
||||
{
|
||||
debug_assert!(root.styling_mode() != StylingMode::Stop);
|
||||
debug_assert!(root.as_element().unwrap().styling_mode() != StylingMode::Stop);
|
||||
if opts::get().style_sharing_stats {
|
||||
STYLE_SHARING_CACHE_HITS.store(0, Ordering::SeqCst);
|
||||
STYLE_SHARING_CACHE_MISSES.store(0, Ordering::SeqCst);
|
||||
|
@ -84,7 +84,7 @@ fn top_down_dom<N, C>(unsafe_nodes: UnsafeNodeList,
|
|||
// Perform the appropriate traversal.
|
||||
let mut children_to_process = 0isize;
|
||||
if let RestyleResult::Continue = context.process_preorder(node) {
|
||||
C::traverse_children(node, |kid| {
|
||||
C::traverse_children(node.as_element().unwrap(), |kid| {
|
||||
children_to_process += 1;
|
||||
discovered_child_nodes.push(kid.to_unsafe())
|
||||
});
|
||||
|
@ -93,11 +93,13 @@ fn top_down_dom<N, C>(unsafe_nodes: UnsafeNodeList,
|
|||
// Reset the count of children if we need to do a bottom-up traversal
|
||||
// after the top up.
|
||||
if context.needs_postorder_traversal() {
|
||||
node.store_children_to_process(children_to_process);
|
||||
|
||||
// If there were no more children, start walking back up.
|
||||
if children_to_process == 0 {
|
||||
// If there were no more children, start walking back up.
|
||||
bottom_up_dom::<N, C>(unsafe_nodes.1, unsafe_node, proxy)
|
||||
} else {
|
||||
// Otherwise record the number of children to process when the
|
||||
// time comes.
|
||||
node.as_element().unwrap().store_children_to_process(children_to_process);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -139,7 +141,7 @@ fn bottom_up_dom<N, C>(root: OpaqueNode,
|
|||
// Perform the appropriate operation.
|
||||
context.process_postorder(node);
|
||||
|
||||
let parent = match node.layout_parent_node(root) {
|
||||
let parent = match node.layout_parent_element(root) {
|
||||
None => break,
|
||||
Some(parent) => parent,
|
||||
};
|
||||
|
@ -151,6 +153,6 @@ fn bottom_up_dom<N, C>(root: OpaqueNode,
|
|||
}
|
||||
|
||||
// We were the last child of our parent. Construct flows for our parent.
|
||||
node = parent;
|
||||
node = parent.as_node();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
|
||||
//! Implements sequential traversal over the DOM tree.
|
||||
|
||||
use dom::{StylingMode, TNode};
|
||||
use dom::{StylingMode, TElement, TNode};
|
||||
use traversal::{RestyleResult, DomTraversalContext};
|
||||
|
||||
pub fn traverse_dom<N, C>(root: N,
|
||||
|
@ -17,7 +17,8 @@ pub fn traverse_dom<N, C>(root: N,
|
|||
C: DomTraversalContext<N>
|
||||
{
|
||||
if let RestyleResult::Continue = context.process_preorder(node) {
|
||||
C::traverse_children(node, |kid| doit::<N, C>(context, kid));
|
||||
C::traverse_children(node.as_element().unwrap(),
|
||||
|kid| doit::<N, C>(context, kid));
|
||||
}
|
||||
|
||||
if context.needs_postorder_traversal() {
|
||||
|
@ -25,7 +26,7 @@ pub fn traverse_dom<N, C>(root: N,
|
|||
}
|
||||
}
|
||||
|
||||
debug_assert!(root.styling_mode() != StylingMode::Stop);
|
||||
debug_assert!(root.as_element().unwrap().styling_mode() != StylingMode::Stop);
|
||||
let context = C::new(shared, root.opaque());
|
||||
doit::<N, C>(&context, root);
|
||||
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
use atomic_refcell::AtomicRefCell;
|
||||
use context::{LocalStyleContext, SharedStyleContext, StyleContext};
|
||||
use data::NodeData;
|
||||
use dom::{NodeInfo, OpaqueNode, StylingMode, TElement, TNode, UnsafeNode};
|
||||
use dom::{OpaqueNode, StylingMode, TElement, TNode, UnsafeNode};
|
||||
use matching::{ApplicableDeclarations, MatchMethods, StyleSharingResult};
|
||||
use selectors::bloom::BloomFilter;
|
||||
use selectors::matching::StyleRelations;
|
||||
|
@ -118,7 +118,7 @@ fn insert_ancestors_into_bloom_filter<E>(bf: &mut Box<BloomFilter>,
|
|||
ancestors += 1;
|
||||
|
||||
el.insert_into_bloom_filter(&mut **bf);
|
||||
el = match el.as_node().layout_parent_node(root).and_then(|x| x.as_element()) {
|
||||
el = match el.as_node().layout_parent_element(root) {
|
||||
None => break,
|
||||
Some(p) => p,
|
||||
};
|
||||
|
@ -142,7 +142,7 @@ pub fn remove_from_bloom_filter<'a, N, C>(context: &C, root: OpaqueNode, node: N
|
|||
assert_eq!(old_node, unsafe_layout_node);
|
||||
assert_eq!(old_generation, context.shared_context().generation);
|
||||
|
||||
match node.layout_parent_node(root) {
|
||||
match node.layout_parent_element(root) {
|
||||
None => {
|
||||
debug!("[{}] - {:X}, and deleting BF.", tid(), unsafe_layout_node.0);
|
||||
// If this is the reflow root, eat the thread-local bloom filter.
|
||||
|
@ -150,7 +150,7 @@ pub fn remove_from_bloom_filter<'a, N, C>(context: &C, root: OpaqueNode, node: N
|
|||
Some(parent) => {
|
||||
// Otherwise, put it back, but remove this node.
|
||||
node.as_element().map(|x| x.remove_from_bloom_filter(&mut *bf));
|
||||
let unsafe_parent = parent.to_unsafe();
|
||||
let unsafe_parent = parent.as_node().to_unsafe();
|
||||
put_thread_local_bloom_filter(bf, &unsafe_parent, &context.shared_context());
|
||||
},
|
||||
};
|
||||
|
@ -175,16 +175,19 @@ pub trait DomTraversalContext<N: TNode> {
|
|||
/// If it's false, then process_postorder has no effect at all.
|
||||
fn needs_postorder_traversal(&self) -> bool { true }
|
||||
|
||||
/// Returns true if traversal should visit the given child.
|
||||
fn should_traverse_child(parent: N::ConcreteElement, child: N) -> bool;
|
||||
|
||||
/// Helper for the traversal implementations to select the children that
|
||||
/// should be enqueued for processing.
|
||||
fn traverse_children<F: FnMut(N)>(parent: N, mut f: F)
|
||||
fn traverse_children<F: FnMut(N)>(parent: N::ConcreteElement, mut f: F)
|
||||
{
|
||||
// If we enqueue any children for traversal, we need to set the dirty
|
||||
// descendants bit. Avoid doing it more than once.
|
||||
let mut marked_dirty_descendants = false;
|
||||
|
||||
for kid in parent.children() {
|
||||
if kid.styling_mode() != StylingMode::Stop {
|
||||
for kid in parent.as_node().children() {
|
||||
if Self::should_traverse_child(parent, kid) {
|
||||
if !marked_dirty_descendants {
|
||||
unsafe { parent.set_dirty_descendants(); }
|
||||
marked_dirty_descendants = true;
|
||||
|
@ -197,7 +200,7 @@ pub trait DomTraversalContext<N: TNode> {
|
|||
/// Ensures the existence of the NodeData, and returns it. This can't live
|
||||
/// on TNode because of the trait-based separation between Servo's script
|
||||
/// and layout crates.
|
||||
fn ensure_node_data(node: &N) -> &AtomicRefCell<NodeData>;
|
||||
fn ensure_element_data(element: &N::ConcreteElement) -> &AtomicRefCell<NodeData>;
|
||||
|
||||
fn local_context(&self) -> &LocalStyleContext;
|
||||
}
|
||||
|
@ -248,8 +251,7 @@ fn ensure_element_styled_internal<'a, E, C>(element: E,
|
|||
//
|
||||
// We only need to mark whether we have display none, and forget about it,
|
||||
// our style is up to date.
|
||||
let node = element.as_node();
|
||||
if let Some(data) = node.borrow_data() {
|
||||
if let Some(data) = element.borrow_data() {
|
||||
if let Some(style) = data.get_current_styles().map(|x| &x.primary) {
|
||||
if !*parents_had_display_none {
|
||||
*parents_had_display_none = style.get_box().clone_display() == display::T::none;
|
||||
|
@ -290,7 +292,7 @@ pub fn recalc_style_at<'a, E, C, D>(context: &'a C,
|
|||
let mut bf = take_thread_local_bloom_filter(element.parent_element(), root, context.shared_context());
|
||||
|
||||
let mut restyle_result = RestyleResult::Continue;
|
||||
let mode = element.as_node().styling_mode();
|
||||
let mode = element.styling_mode();
|
||||
debug_assert!(mode != StylingMode::Stop, "Parent should not have enqueued us");
|
||||
if mode != StylingMode::Traverse {
|
||||
// Check to see whether we can share a style with someone.
|
||||
|
@ -358,10 +360,8 @@ pub fn recalc_style_at<'a, E, C, D>(context: &'a C,
|
|||
// fashion.
|
||||
if mode == StylingMode::Restyle && restyle_result == RestyleResult::Continue {
|
||||
for kid in element.as_node().children() {
|
||||
let mut data = D::ensure_node_data(&kid).borrow_mut();
|
||||
if kid.is_text_node() {
|
||||
data.ensure_restyle_data();
|
||||
} else {
|
||||
if let Some(kid) = kid.as_element() {
|
||||
let mut data = D::ensure_element_data(&kid).borrow_mut();
|
||||
data.gather_previous_styles(|| kid.get_styles_from_frame());
|
||||
if data.previous_styles().is_some() {
|
||||
data.ensure_restyle_data();
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue