aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--components/layout/lib.rs1
-rw-r--r--components/layout/traversal.rs35
-rw-r--r--components/layout/wrapper.rs38
-rw-r--r--components/layout_thread/Cargo.toml1
-rw-r--r--components/layout_thread/lib.rs17
-rw-r--r--components/script/layout_wrapper.rs183
-rw-r--r--components/script_layout_interface/wrapper_traits.rs11
-rw-r--r--components/servo/Cargo.lock1
-rw-r--r--components/style/dom.rs155
-rw-r--r--components/style/gecko/traversal.rs15
-rw-r--r--components/style/gecko/wrapper.rs180
-rw-r--r--components/style/matching.rs14
-rw-r--r--components/style/parallel.rs18
-rw-r--r--components/style/sequential.rs7
-rw-r--r--components/style/traversal.rs30
-rw-r--r--ports/cef/Cargo.lock1
-rw-r--r--ports/geckolib/glue.rs39
17 files changed, 391 insertions, 355 deletions
diff --git a/components/layout/lib.rs b/components/layout/lib.rs
index b272ad503de..bff6eeca1ac 100644
--- a/components/layout/lib.rs
+++ b/components/layout/lib.rs
@@ -46,7 +46,6 @@ extern crate range;
extern crate rustc_serialize;
extern crate script_layout_interface;
extern crate script_traits;
-extern crate selectors;
extern crate smallvec;
#[macro_use(atom, ns)] extern crate string_cache;
extern crate style;
diff --git a/components/layout/traversal.rs b/components/layout/traversal.rs
index 2f6c49b8ea8..54bf5da3b44 100644
--- a/components/layout/traversal.rs
+++ b/components/layout/traversal.rs
@@ -11,13 +11,12 @@ use flow::{self, PreorderFlowTraversal};
use flow::{CAN_BE_FRAGMENTED, Flow, ImmutableFlowUtils, PostorderFlowTraversal};
use gfx::display_list::OpaqueNode;
use script_layout_interface::restyle_damage::{BUBBLE_ISIZES, REFLOW, REFLOW_OUT_OF_FLOW, REPAINT, RestyleDamage};
-use script_layout_interface::wrapper_traits::{LayoutNode, ThreadSafeLayoutNode};
+use script_layout_interface::wrapper_traits::{LayoutElement, LayoutNode, ThreadSafeLayoutNode};
use std::mem;
use style::atomic_refcell::AtomicRefCell;
use style::context::{LocalStyleContext, SharedStyleContext, StyleContext};
use style::data::NodeData;
-use style::dom::TNode;
-use style::selector_impl::ServoSelectorImpl;
+use style::dom::{StylingMode, TElement, TNode};
use style::traversal::{DomTraversalContext, put_thread_local_bloom_filter};
use style::traversal::{recalc_style_at, remove_from_bloom_filter};
use style::traversal::RestyleResult;
@@ -32,7 +31,7 @@ pub struct RecalcStyleAndConstructFlows<'lc> {
impl<'lc, N> DomTraversalContext<N> for RecalcStyleAndConstructFlows<'lc>
where N: LayoutNode + TNode,
- N::ConcreteElement: ::selectors::Element<Impl=ServoSelectorImpl>
+ N::ConcreteElement: LayoutElement
{
type SharedContext = SharedLayoutContext;
@@ -114,9 +113,27 @@ impl<'lc, N> DomTraversalContext<N> for RecalcStyleAndConstructFlows<'lc>
construct_flows_at(&self.context, self.root, node);
}
- fn ensure_node_data(node: &N) -> &AtomicRefCell<NodeData> {
- node.initialize_data();
- node.get_style_data().unwrap()
+ fn should_traverse_child(parent: N::ConcreteElement, child: N) -> bool {
+ // If this node has been marked as damaged in some way, we need to
+ // traverse it unconditionally for layout.
+ if child.has_changed() {
+ return true;
+ }
+
+ match child.as_element() {
+ Some(el) => el.styling_mode() != StylingMode::Stop,
+ // Aside from the has_changed case above, we want to traverse non-element children
+ // in two additional cases:
+ // (1) They child doesn't yet have layout data (preorder traversal initializes it).
+ // (2) The parent element has restyle damage (so the text flow also needs fixup).
+ None => child.get_raw_data().is_none() ||
+ parent.as_node().to_threadsafe().restyle_damage() != RestyleDamage::empty(),
+ }
+ }
+
+ fn ensure_element_data(element: &N::ConcreteElement) -> &AtomicRefCell<NodeData> {
+ element.as_node().initialize_data();
+ element.get_style_data().unwrap()
}
fn local_context(&self) -> &LocalStyleContext {
@@ -140,8 +157,8 @@ fn construct_flows_at<'a, N: LayoutNode>(context: &'a LayoutContext<'a>, root: O
// Always reconstruct if incremental layout is turned off.
let nonincremental_layout = opts::get().nonincremental_layout;
- if nonincremental_layout || node.has_dirty_descendants() ||
- tnode.restyle_damage() != RestyleDamage::empty() {
+ if nonincremental_layout || tnode.restyle_damage() != RestyleDamage::empty() ||
+ node.as_element().map_or(false, |el| el.has_dirty_descendants()) {
let mut flow_constructor = FlowConstructor::new(context);
if nonincremental_layout || !flow_constructor.repair_if_possible(&tnode) {
flow_constructor.process(&tnode);
diff --git a/components/layout/wrapper.rs b/components/layout/wrapper.rs
index c37499a12af..6d1b9ce4379 100644
--- a/components/layout/wrapper.rs
+++ b/components/layout/wrapper.rs
@@ -33,12 +33,12 @@
use core::nonzero::NonZero;
use data::{LayoutDataFlags, PersistentLayoutData};
use script_layout_interface::{OpaqueStyleAndLayoutData, PartialPersistentLayoutData};
-use script_layout_interface::wrapper_traits::{GetLayoutData, LayoutNode};
use script_layout_interface::wrapper_traits::{ThreadSafeLayoutElement, ThreadSafeLayoutNode};
+use script_layout_interface::wrapper_traits::GetLayoutData;
use style::atomic_refcell::{AtomicRef, AtomicRefCell, AtomicRefMut};
use style::computed_values::content::{self, ContentItem};
-pub type NonOpaqueStyleAndLayoutData = *mut AtomicRefCell<PersistentLayoutData>;
+pub type NonOpaqueStyleAndLayoutData = AtomicRefCell<PersistentLayoutData>;
pub trait LayoutNodeLayoutData {
/// Similar to borrow_data*, but returns the full PersistentLayoutData rather
@@ -50,21 +50,11 @@ pub trait LayoutNodeLayoutData {
impl<T: GetLayoutData> LayoutNodeLayoutData for T {
fn borrow_layout_data(&self) -> Option<AtomicRef<PersistentLayoutData>> {
- unsafe {
- self.get_style_and_layout_data().map(|opaque| {
- let container = *opaque.ptr as NonOpaqueStyleAndLayoutData;
- (*container).borrow()
- })
- }
+ self.get_raw_data().map(|d| d.borrow())
}
fn mutate_layout_data(&self) -> Option<AtomicRefMut<PersistentLayoutData>> {
- unsafe {
- self.get_style_and_layout_data().map(|opaque| {
- let container = *opaque.ptr as NonOpaqueStyleAndLayoutData;
- (*container).borrow_mut()
- })
- }
+ self.get_raw_data().map(|d| d.borrow_mut())
}
fn flow_debug_id(self) -> usize {
@@ -73,19 +63,27 @@ impl<T: GetLayoutData> LayoutNodeLayoutData for T {
}
pub trait LayoutNodeHelpers {
- fn initialize_data(self);
+ fn initialize_data(&self);
+ fn get_raw_data(&self) -> Option<&NonOpaqueStyleAndLayoutData>;
}
-impl<T: LayoutNode> LayoutNodeHelpers for T {
- fn initialize_data(self) {
- if self.borrow_layout_data().is_none() {
- let ptr: NonOpaqueStyleAndLayoutData =
+impl<T: GetLayoutData> LayoutNodeHelpers for T {
+ fn initialize_data(&self) {
+ if self.get_raw_data().is_none() {
+ let ptr: *mut NonOpaqueStyleAndLayoutData =
Box::into_raw(box AtomicRefCell::new(PersistentLayoutData::new()));
let opaque = OpaqueStyleAndLayoutData {
ptr: unsafe { NonZero::new(ptr as *mut AtomicRefCell<PartialPersistentLayoutData>) }
};
self.init_style_and_layout_data(opaque);
- }
+ };
+ }
+
+ fn get_raw_data(&self) -> Option<&NonOpaqueStyleAndLayoutData> {
+ self.get_style_and_layout_data().map(|opaque| {
+ let container = *opaque.ptr as *mut NonOpaqueStyleAndLayoutData;
+ unsafe { &*container }
+ })
}
}
diff --git a/components/layout_thread/Cargo.toml b/components/layout_thread/Cargo.toml
index e41b6d3b090..37998d1b48b 100644
--- a/components/layout_thread/Cargo.toml
+++ b/components/layout_thread/Cargo.toml
@@ -30,6 +30,7 @@ profile_traits = {path = "../profile_traits"}
script = {path = "../script"}
script_layout_interface = {path = "../script_layout_interface"}
script_traits = {path = "../script_traits"}
+selectors = "0.14"
serde_derive = "0.8"
serde_json = "0.8"
style = {path = "../style"}
diff --git a/components/layout_thread/lib.rs b/components/layout_thread/lib.rs
index 51ec52cb0d0..a2ad05025a6 100644
--- a/components/layout_thread/lib.rs
+++ b/components/layout_thread/lib.rs
@@ -37,6 +37,7 @@ extern crate profile_traits;
extern crate script;
extern crate script_layout_interface;
extern crate script_traits;
+extern crate selectors;
extern crate serde_json;
extern crate style;
extern crate url;
@@ -94,6 +95,7 @@ use script_layout_interface::rpc::{LayoutRPC, MarginStyleResponse, NodeOverflowR
use script_layout_interface::wrapper_traits::LayoutNode;
use script_traits::{ConstellationControlMsg, LayoutControlMsg, LayoutMsg as ConstellationMsg};
use script_traits::{StackingContextScrollState, UntrustedNodeAddress};
+use selectors::Element;
use std::borrow::ToOwned;
use std::collections::HashMap;
use std::hash::BuildHasherDefault;
@@ -1109,11 +1111,11 @@ impl LayoutThread {
// NB: The dirty bit is propagated down the tree.
unsafe { node.set_dirty(); }
- let mut current = node.parent_node();
- while let Some(node) = current {
- if node.has_dirty_descendants() { break; }
- unsafe { node.set_dirty_descendants(); }
- current = node.parent_node();
+ let mut current = node.parent_node().and_then(|n| n.as_element());
+ while let Some(el) = current {
+ if el.has_dirty_descendants() { break; }
+ unsafe { el.set_dirty_descendants(); }
+ current = el.parent_element();
}
next = iter.next_skipping_children();
@@ -1155,7 +1157,8 @@ impl LayoutThread {
viewport_size_changed,
data.reflow_info.goal);
- if node.is_dirty() || node.has_dirty_descendants() {
+ let el = node.as_element();
+ if el.is_some() && (el.unwrap().deprecated_dirty_bit_is_set() || el.unwrap().has_dirty_descendants()) {
// Recalculate CSS styles and rebuild flows and fragments.
profile(time::ProfilerCategory::LayoutStyleRecalc,
self.profiler_metadata(),
@@ -1485,7 +1488,7 @@ impl LayoutThread {
/// because the struct type is transmuted to a different type on the script side.
unsafe fn handle_reap_style_and_layout_data(&self, data: OpaqueStyleAndLayoutData) {
let ptr: *mut AtomicRefCell<PartialPersistentLayoutData> = *data.ptr;
- let non_opaque: NonOpaqueStyleAndLayoutData = ptr as *mut _;
+ let non_opaque: *mut NonOpaqueStyleAndLayoutData = ptr as *mut _;
let _ = Box::from_raw(non_opaque);
}
diff --git a/components/script/layout_wrapper.rs b/components/script/layout_wrapper.rs
index 73d06eec76a..34fa3e10a3a 100644
--- a/components/script/layout_wrapper.rs
+++ b/components/script/layout_wrapper.rs
@@ -46,7 +46,7 @@ use range::Range;
use script_layout_interface::{HTMLCanvasData, LayoutNodeType, SVGSVGData, TrustedNodeAddress};
use script_layout_interface::{OpaqueStyleAndLayoutData, PartialPersistentLayoutData};
use script_layout_interface::restyle_damage::RestyleDamage;
-use script_layout_interface::wrapper_traits::{DangerousThreadSafeLayoutNode, GetLayoutData, LayoutNode};
+use script_layout_interface::wrapper_traits::{DangerousThreadSafeLayoutNode, GetLayoutData, LayoutElement, LayoutNode};
use script_layout_interface::wrapper_traits::{PseudoElementType, ThreadSafeLayoutElement, ThreadSafeLayoutNode};
use selectors::matching::ElementFlags;
use selectors::parser::{AttrSelector, NamespaceConstraint};
@@ -107,10 +107,6 @@ impl<'ln> ServoLayoutNode<'ln> {
}
}
- pub fn mutate_data(&self) -> Option<AtomicRefMut<NodeData>> {
- self.get_style_data().map(|d| d.borrow_mut())
- }
-
fn script_type_id(&self) -> NodeTypeId {
unsafe {
self.node.type_id_for_layout()
@@ -165,11 +161,11 @@ impl<'ln> TNode for ServoLayoutNode<'ln> {
unsafe { self.get_jsmanaged().opaque() }
}
- fn layout_parent_node(self, reflow_root: OpaqueNode) -> Option<ServoLayoutNode<'ln>> {
+ fn layout_parent_element(self, reflow_root: OpaqueNode) -> Option<ServoLayoutElement<'ln>> {
if self.opaque() == reflow_root {
None
} else {
- self.parent_node()
+ self.parent_node().and_then(|x| x.as_element())
}
}
@@ -185,18 +181,6 @@ impl<'ln> TNode for ServoLayoutNode<'ln> {
self.node.downcast().map(ServoLayoutDocument::from_layout_js)
}
- fn deprecated_dirty_bit_is_set(&self) -> bool {
- unsafe { self.node.get_flag(IS_DIRTY) }
- }
-
- fn has_dirty_descendants(&self) -> bool {
- unsafe { self.node.get_flag(HAS_DIRTY_DESCENDANTS) }
- }
-
- unsafe fn set_dirty_descendants(&self) {
- self.node.set_flag(HAS_DIRTY_DESCENDANTS, true)
- }
-
fn needs_dirty_on_viewport_size_changed(&self) -> bool {
unsafe { self.node.get_flag(DIRTY_ON_VIEWPORT_SIZE_CHANGE) }
}
@@ -213,34 +197,6 @@ impl<'ln> TNode for ServoLayoutNode<'ln> {
self.node.set_flag(CAN_BE_FRAGMENTED, value)
}
- fn store_children_to_process(&self, n: isize) {
- let data = self.get_partial_layout_data().unwrap().borrow();
- data.parallel.children_to_process.store(n, Ordering::Relaxed);
- }
-
- fn did_process_child(&self) -> isize {
- let data = self.get_partial_layout_data().unwrap().borrow();
- let old_value = data.parallel.children_to_process.fetch_sub(1, Ordering::Relaxed);
- debug_assert!(old_value >= 1);
- old_value - 1
- }
-
- fn begin_styling(&self) -> AtomicRefMut<NodeData> {
- let mut data = self.mutate_data().unwrap();
- data.gather_previous_styles(|| None);
- data
- }
-
- fn style_text_node(&self, style: Arc<ComputedValues>) {
- debug_assert!(self.is_text_node());
- let mut data = self.get_partial_layout_data().unwrap().borrow_mut();
- data.style_data.style_text_node(style);
- }
-
- fn borrow_data(&self) -> Option<AtomicRef<NodeData>> {
- self.get_style_data().map(|d| d.borrow())
- }
-
fn parent_node(&self) -> Option<ServoLayoutNode<'ln>> {
unsafe {
self.node.parent_node_ref().map(|node| self.new_with_this_lifetime(&node))
@@ -305,16 +261,12 @@ impl<'ln> LayoutNode for ServoLayoutNode<'ln> {
self.node.set_flag(IS_DIRTY, false);
self.node.set_flag(HAS_DIRTY_DESCENDANTS, false);
}
+}
- // NB: This duplicates the get_style_data on ThreadSafeLayoutElement, but
- // will go away soon.
- fn get_style_data(&self) -> Option<&AtomicRefCell<NodeData>> {
+impl<'ln> GetLayoutData for ServoLayoutNode<'ln> {
+ fn get_style_and_layout_data(&self) -> Option<OpaqueStyleAndLayoutData> {
unsafe {
- self.get_jsmanaged().get_style_and_layout_data().map(|d| {
- let ppld: &AtomicRefCell<PartialPersistentLayoutData> = &**d.ptr;
- let psd: &AtomicRefCell<NodeData> = transmute(ppld);
- psd
- })
+ self.get_jsmanaged().get_style_and_layout_data()
}
}
@@ -325,30 +277,34 @@ impl<'ln> LayoutNode for ServoLayoutNode<'ln> {
}
}
-impl<'ln> GetLayoutData for ServoLayoutNode<'ln> {
- fn get_style_and_layout_data(&self) -> Option<OpaqueStyleAndLayoutData> {
- unsafe {
- self.get_jsmanaged().get_style_and_layout_data()
- }
- }
-}
-
impl<'le> GetLayoutData for ServoLayoutElement<'le> {
fn get_style_and_layout_data(&self) -> Option<OpaqueStyleAndLayoutData> {
self.as_node().get_style_and_layout_data()
}
+
+ fn init_style_and_layout_data(&self, data: OpaqueStyleAndLayoutData) {
+ self.as_node().init_style_and_layout_data(data)
+ }
}
impl<'ln> GetLayoutData for ServoThreadSafeLayoutNode<'ln> {
fn get_style_and_layout_data(&self) -> Option<OpaqueStyleAndLayoutData> {
self.node.get_style_and_layout_data()
}
+
+ fn init_style_and_layout_data(&self, data: OpaqueStyleAndLayoutData) {
+ self.node.init_style_and_layout_data(data)
+ }
}
impl<'le> GetLayoutData for ServoThreadSafeLayoutElement<'le> {
fn get_style_and_layout_data(&self) -> Option<OpaqueStyleAndLayoutData> {
self.element.as_node().get_style_and_layout_data()
}
+
+ fn init_style_and_layout_data(&self, data: OpaqueStyleAndLayoutData) {
+ self.element.as_node().init_style_and_layout_data(data)
+ }
}
impl<'ln> ServoLayoutNode<'ln> {
@@ -360,14 +316,6 @@ impl<'ln> ServoLayoutNode<'ln> {
self.node.set_flag(IS_DIRTY, true)
}
- fn get_partial_layout_data(&self) -> Option<&AtomicRefCell<PartialPersistentLayoutData>> {
- unsafe {
- self.get_jsmanaged().get_style_and_layout_data().map(|d| {
- &**d.ptr
- })
- }
- }
-
fn dump_indent(self, indent: u32) {
let mut s = String::new();
for _ in 0..indent {
@@ -400,12 +348,17 @@ impl<'ln> ServoLayoutNode<'ln> {
fn debug_str(self) -> String {
format!("{:?}: changed={} dirty={} dirty_descendants={}",
self.script_type_id(), self.has_changed(),
- self.deprecated_dirty_bit_is_set(),
- self.has_dirty_descendants())
+ self.as_element().map_or(false, |el| el.deprecated_dirty_bit_is_set()),
+ self.as_element().map_or(false, |el| el.has_dirty_descendants()))
}
fn debug_style_str(self) -> String {
- if let Some(data) = self.borrow_data() {
+ let maybe_element = self.as_element();
+ let maybe_data = match maybe_element {
+ Some(ref el) => el.borrow_data(),
+ None => None,
+ };
+ if let Some(data) = maybe_data {
format!("{:?}: {:?}", self.script_type_id(), &*data)
} else {
format!("{:?}: style_data=None", self.script_type_id())
@@ -518,8 +471,7 @@ impl<'le> TElement for ServoLayoutElement<'le> {
}
fn set_restyle_damage(self, damage: RestyleDamage) {
- let node = self.as_node();
- node.get_partial_layout_data().unwrap().borrow_mut().restyle_damage = damage;
+ self.get_partial_layout_data().unwrap().borrow_mut().restyle_damage = damage;
}
#[inline]
@@ -529,6 +481,53 @@ impl<'le> TElement for ServoLayoutElement<'le> {
-> Option<&'a Arc<ComputedValues>> {
current_cv
}
+
+ fn deprecated_dirty_bit_is_set(&self) -> bool {
+ unsafe { self.as_node().node.get_flag(IS_DIRTY) }
+ }
+
+ fn has_dirty_descendants(&self) -> bool {
+ unsafe { self.as_node().node.get_flag(HAS_DIRTY_DESCENDANTS) }
+ }
+
+ unsafe fn set_dirty_descendants(&self) {
+ self.as_node().node.set_flag(HAS_DIRTY_DESCENDANTS, true)
+ }
+
+ fn store_children_to_process(&self, n: isize) {
+ let data = self.get_partial_layout_data().unwrap().borrow();
+ data.parallel.children_to_process.store(n, Ordering::Relaxed);
+ }
+
+ fn did_process_child(&self) -> isize {
+ let data = self.get_partial_layout_data().unwrap().borrow();
+ let old_value = data.parallel.children_to_process.fetch_sub(1, Ordering::Relaxed);
+ debug_assert!(old_value >= 1);
+ old_value - 1
+ }
+
+ fn begin_styling(&self) -> AtomicRefMut<NodeData> {
+ let mut data = self.mutate_data().unwrap();
+ data.gather_previous_styles(|| None);
+ data
+ }
+
+ fn borrow_data(&self) -> Option<AtomicRef<NodeData>> {
+ self.get_style_data().map(|d| d.borrow())
+ }
+
+}
+
+impl<'le> LayoutElement for ServoLayoutElement<'le> {
+ fn get_style_data(&self) -> Option<&AtomicRefCell<NodeData>> {
+ unsafe {
+ self.get_style_and_layout_data().map(|d| {
+ let ppld: &AtomicRefCell<PartialPersistentLayoutData> = &**d.ptr;
+ let psd: &AtomicRefCell<NodeData> = transmute(ppld);
+ psd
+ })
+ }
+ }
}
impl<'le> PartialEq for ServoLayoutElement<'le> {
@@ -551,6 +550,18 @@ impl<'le> ServoLayoutElement<'le> {
(*self.element.unsafe_get()).get_attr_val_for_layout(namespace, name)
}
}
+
+ fn mutate_data(&self) -> Option<AtomicRefMut<NodeData>> {
+ self.get_style_data().map(|d| d.borrow_mut())
+ }
+
+ fn get_partial_layout_data(&self) -> Option<&AtomicRefCell<PartialPersistentLayoutData>> {
+ unsafe {
+ self.get_style_and_layout_data().map(|d| {
+ &**d.ptr
+ })
+ }
+ }
}
fn as_element<'le>(node: LayoutJS<Node>) -> Option<ServoLayoutElement<'le>> {
@@ -826,7 +837,7 @@ impl<'ln> ThreadSafeLayoutNode for ServoThreadSafeLayoutNode<'ln> {
// works, but would be difficult to change. (Text node style is
// also not visible to script.)
debug_assert!(self.is_text_node());
- let parent = self.node.parent_node().unwrap();
+ let parent = self.node.parent_node().unwrap().as_element().unwrap();
let parent_data = parent.get_style_data().unwrap().borrow();
parent_data.current_styles().primary.clone()
}
@@ -875,17 +886,19 @@ impl<'ln> ThreadSafeLayoutNode for ServoThreadSafeLayoutNode<'ln> {
if self.node.has_changed() {
RestyleDamage::rebuild_and_reflow()
} else if self.is_text_node() {
- let parent = self.node.parent_node().unwrap();
+ let parent = self.node.parent_node().unwrap().as_element().unwrap();
let parent_data = parent.get_partial_layout_data().unwrap().borrow();
parent_data.restyle_damage
} else {
- self.node.get_partial_layout_data().unwrap().borrow().restyle_damage
+ let el = self.as_element().unwrap().element;
+ let damage = el.get_partial_layout_data().unwrap().borrow().restyle_damage.clone();
+ damage
}
}
fn clear_restyle_damage(self) {
- if self.is_element() {
- let mut data = self.node.get_partial_layout_data().unwrap().borrow_mut();
+ if let Some(el) = self.as_element() {
+ let mut data = el.element.get_partial_layout_data().unwrap().borrow_mut();
data.restyle_damage = RestyleDamage::empty();
}
}
@@ -1078,13 +1091,7 @@ impl<'le> ThreadSafeLayoutElement for ServoThreadSafeLayoutElement<'le> {
}
fn get_style_data(&self) -> Option<&AtomicRefCell<NodeData>> {
- unsafe {
- self.element.as_node().get_style_and_layout_data().map(|d| {
- let ppld: &AtomicRefCell<PartialPersistentLayoutData> = &**d.ptr;
- let psd: &AtomicRefCell<NodeData> = transmute(ppld);
- psd
- })
- }
+ self.element.get_style_data()
}
}
diff --git a/components/script_layout_interface/wrapper_traits.rs b/components/script_layout_interface/wrapper_traits.rs
index 669a3e331be..416d04d9522 100644
--- a/components/script_layout_interface/wrapper_traits.rs
+++ b/components/script_layout_interface/wrapper_traits.rs
@@ -19,7 +19,7 @@ use style::atomic_refcell::AtomicRefCell;
use style::computed_values::display;
use style::context::SharedStyleContext;
use style::data::NodeData;
-use style::dom::{LayoutIterator, NodeInfo, PresentationalHintsSynthetizer, TNode};
+use style::dom::{LayoutIterator, NodeInfo, PresentationalHintsSynthetizer, TElement, TNode};
use style::dom::OpaqueNode;
use style::properties::ServoComputedValues;
use style::selector_impl::{PseudoElement, PseudoElementCascadeType, ServoSelectorImpl};
@@ -73,6 +73,7 @@ impl<T> PseudoElementType<T> {
/// Trait to abstract access to layout data across various data structures.
pub trait GetLayoutData {
fn get_style_and_layout_data(&self) -> Option<OpaqueStyleAndLayoutData>;
+ fn init_style_and_layout_data(&self, data: OpaqueStyleAndLayoutData);
}
/// A wrapper so that layout can access only the methods that it should have access to. Layout must
@@ -88,10 +89,6 @@ pub trait LayoutNode: GetLayoutData + TNode {
unsafe fn clear_dirty_bits(&self);
- fn get_style_data(&self) -> Option<&AtomicRefCell<NodeData>>;
-
- fn init_style_and_layout_data(&self, data: OpaqueStyleAndLayoutData);
-
fn rev_children(self) -> LayoutIterator<ReverseChildrenIterator<Self>> {
LayoutIterator(ReverseChildrenIterator {
current: self.last_child(),
@@ -276,6 +273,10 @@ pub trait DangerousThreadSafeLayoutNode: ThreadSafeLayoutNode {
unsafe fn dangerous_next_sibling(&self) -> Option<Self>;
}
+pub trait LayoutElement: Clone + Copy + Sized + Debug + GetLayoutData + TElement {
+ fn get_style_data(&self) -> Option<&AtomicRefCell<NodeData>>;
+}
+
pub trait ThreadSafeLayoutElement: Clone + Copy + Sized + Debug +
::selectors::Element<Impl=ServoSelectorImpl> +
GetLayoutData +
diff --git a/components/servo/Cargo.lock b/components/servo/Cargo.lock
index 80c03276756..0aece035e9e 100644
--- a/components/servo/Cargo.lock
+++ b/components/servo/Cargo.lock
@@ -1201,6 +1201,7 @@ dependencies = [
"script 0.0.1",
"script_layout_interface 0.0.1",
"script_traits 0.0.1",
+ "selectors 0.14.0 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_derive 0.8.12 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_json 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)",
"style 0.0.1",
diff --git a/components/style/dom.rs b/components/style/dom.rs
index 7ead2605416..03eee395f7b 100644
--- a/components/style/dom.rs
+++ b/components/style/dom.rs
@@ -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,6 +131,70 @@ pub trait TNode : Sized + Copy + Clone + NodeInfo {
fn as_document(&self) -> Option<Self::ConcreteDocument>;
+ fn needs_dirty_on_viewport_size_changed(&self) -> bool;
+
+ unsafe fn set_dirty_on_viewport_size_changed(&self);
+
+ fn can_be_fragmented(&self) -> bool;
+
+ unsafe fn set_can_be_fragmented(&self, value: bool);
+
+ 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 : Sized + Copy + Clone {
+ type ConcreteNode: TNode<ConcreteElement = Self::ConcreteElement, ConcreteDocument = Self>;
+ type ConcreteElement: TElement<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,
+ <Self::ConcreteElement as ElementExt>::Snapshot)>;
+
+ fn needs_paint_from_layout(&self);
+ fn will_paint(&self);
+}
+
+pub trait PresentationalHintsSynthetizer {
+ fn synthesize_presentational_hints_for_legacy_attributes<V>(&self, hints: &mut V)
+ where V: Push<ApplicableDeclarationBlock>;
+}
+
+pub trait TElement : PartialEq + Debug + Sized + Copy + Clone + ElementExt + PresentationalHintsSynthetizer {
+ type ConcreteNode: TNode<ConcreteElement = Self, ConcreteDocument = Self::ConcreteDocument>;
+ type ConcreteDocument: TDocument<ConcreteNode = Self::ConcreteNode, ConcreteElement = Self>;
+ type ConcreteRestyleDamage: TRestyleDamage;
+
+ fn as_node(&self) -> Self::ConcreteNode;
+
+ fn style_attribute(&self) -> Option<&Arc<RwLock<PropertyDeclarationBlock>>>;
+
+ fn get_state(&self) -> ElementState;
+
+ fn has_attr(&self, namespace: &Namespace, attr: &Atom) -> bool;
+ fn attr_equals(&self, namespace: &Namespace, attr: &Atom, value: &Atom) -> bool;
+
+ /// Set the restyle damage field.
+ fn set_restyle_damage(self, damage: Self::ConcreteRestyleDamage);
+
+ /// XXX: It's a bit unfortunate we need to pass the current computed values
+ /// as an argument here, but otherwise Servo would crash due to double
+ /// borrows to return it.
+ 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>;
+
/// 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
@@ -141,14 +205,6 @@ pub trait TNode : Sized + Copy + Clone + NodeInfo {
unsafe fn set_dirty_descendants(&self);
- fn needs_dirty_on_viewport_size_changed(&self) -> bool;
-
- unsafe fn set_dirty_on_viewport_size_changed(&self);
-
- fn can_be_fragmented(&self) -> bool;
-
- 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);
@@ -157,6 +213,7 @@ pub trait TNode : Sized + Copy + Clone + NodeInfo {
/// 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 }
@@ -207,69 +264,9 @@ pub trait TNode : Sized + Copy + Clone + NodeInfo {
/// 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>;
-
- fn last_child(&self) -> Option<Self>;
-
- fn prev_sibling(&self) -> Option<Self>;
-
- fn next_sibling(&self) -> Option<Self>;
-}
-
-pub trait TDocument : Sized + Copy + Clone {
- type ConcreteNode: TNode<ConcreteElement = Self::ConcreteElement, ConcreteDocument = Self>;
- type ConcreteElement: TElement<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,
- <Self::ConcreteElement as ElementExt>::Snapshot)>;
-
- fn needs_paint_from_layout(&self);
- fn will_paint(&self);
-}
-
-pub trait PresentationalHintsSynthetizer {
- fn synthesize_presentational_hints_for_legacy_attributes<V>(&self, hints: &mut V)
- where V: Push<ApplicableDeclarationBlock>;
-}
-
-pub trait TElement : PartialEq + Debug + Sized + Copy + Clone + ElementExt + PresentationalHintsSynthetizer {
- type ConcreteNode: TNode<ConcreteElement = Self, ConcreteDocument = Self::ConcreteDocument>;
- type ConcreteDocument: TDocument<ConcreteNode = Self::ConcreteNode, ConcreteElement = Self>;
- type ConcreteRestyleDamage: TRestyleDamage;
-
- fn as_node(&self) -> Self::ConcreteNode;
-
- fn style_attribute(&self) -> Option<&Arc<RwLock<PropertyDeclarationBlock>>>;
-
- fn get_state(&self) -> ElementState;
-
- fn has_attr(&self, namespace: &Namespace, attr: &Atom) -> bool;
- fn attr_equals(&self, namespace: &Namespace, attr: &Atom, value: &Atom) -> bool;
-
- /// Set the restyle damage field.
- fn set_restyle_damage(self, damage: Self::ConcreteRestyleDamage);
-
- /// XXX: It's a bit unfortunate we need to pass the current computed values
- /// as an argument here, but otherwise Servo would crash due to double
- /// borrows to return it.
- 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>;
-
/// Properly marks nodes as dirty in response to restyle hints.
fn note_restyle_hint<C: DomTraversalContext<Self::ConcreteNode>>(&self, hint: RestyleHint) {
// Bail early if there's no restyling to do.
@@ -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);
}
}
diff --git a/components/style/gecko/traversal.rs b/components/style/gecko/traversal.rs
index c9ddca69d73..e827911006e 100644
--- a/components/style/gecko/traversal.rs
+++ b/components/style/gecko/traversal.rs
@@ -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 {
diff --git a/components/style/gecko/wrapper.rs b/components/style/gecko/wrapper.rs
index e1ca9ab6723..a4fa5d552e1 100644
--- a/components/style/gecko/wrapper.rs
+++ b/components/style/gecko/wrapper.rs
@@ -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> {
diff --git a/components/style/matching.rs b/components/style/matching.rs
index 794e18e2c7b..07add314809 100644
--- a/components/style/matching.rs
+++ b/components/style/matching.rs
@@ -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 =
diff --git a/components/style/parallel.rs b/components/style/parallel.rs
index ad83d3ac475..c525e0f7680 100644
--- a/components/style/parallel.rs
+++ b/components/style/parallel.rs
@@ -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();
}
}
diff --git a/components/style/sequential.rs b/components/style/sequential.rs
index 87925b4d5f7..2b3f2553798 100644
--- a/components/style/sequential.rs
+++ b/components/style/sequential.rs
@@ -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);
diff --git a/components/style/traversal.rs b/components/style/traversal.rs
index 48b598ba93a..80f5cc43dc1 100644
--- a/components/style/traversal.rs
+++ b/components/style/traversal.rs
@@ -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();
diff --git a/ports/cef/Cargo.lock b/ports/cef/Cargo.lock
index 8f929d5f616..f5e817e527e 100644
--- a/ports/cef/Cargo.lock
+++ b/ports/cef/Cargo.lock
@@ -1101,6 +1101,7 @@ dependencies = [
"script 0.0.1",
"script_layout_interface 0.0.1",
"script_traits 0.0.1",
+ "selectors 0.14.0 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_derive 0.8.12 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_json 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)",
"style 0.0.1",
diff --git a/ports/geckolib/glue.rs b/ports/geckolib/glue.rs
index 07ea507b533..4584cf7ab58 100644
--- a/ports/geckolib/glue.rs
+++ b/ports/geckolib/glue.rs
@@ -73,9 +73,7 @@ pub extern "C" fn Servo_Shutdown() -> () {
unsafe { ComputedValues::shutdown(); }
}
-fn restyle_subtree(node: GeckoNode, raw_data: RawServoStyleSetBorrowed) {
- debug_assert!(node.is_element() || node.is_text_node());
-
+fn restyle_subtree(element: GeckoElement, raw_data: RawServoStyleSetBorrowed) {
// Force the creation of our lazily-constructed initial computed values on
// the main thread, since it's not safe to call elsewhere.
//
@@ -106,16 +104,16 @@ fn restyle_subtree(node: GeckoNode, raw_data: RawServoStyleSetBorrowed) {
timer: Timer::new(),
};
- if node.styling_mode() == StylingMode::Stop {
+ if element.styling_mode() == StylingMode::Stop {
error!("Unnecessary call to restyle_subtree");
return;
}
if per_doc_data.num_threads == 1 || per_doc_data.work_queue.is_none() {
- sequential::traverse_dom::<GeckoNode, RecalcStyleOnly>(node, &shared_style_context);
+ sequential::traverse_dom::<_, RecalcStyleOnly>(element.as_node(), &shared_style_context);
} else {
- parallel::traverse_dom::<GeckoNode, RecalcStyleOnly>(node, &shared_style_context,
- per_doc_data.work_queue.as_mut().unwrap());
+ parallel::traverse_dom::<_, RecalcStyleOnly>(element.as_node(), &shared_style_context,
+ per_doc_data.work_queue.as_mut().unwrap());
}
}
@@ -123,7 +121,9 @@ fn restyle_subtree(node: GeckoNode, raw_data: RawServoStyleSetBorrowed) {
pub extern "C" fn Servo_RestyleSubtree(node: RawGeckoNodeBorrowed,
raw_data: RawServoStyleSetBorrowed) -> () {
let node = GeckoNode(node);
- restyle_subtree(node, raw_data);
+ if let Some(element) = node.as_element() {
+ restyle_subtree(element, raw_data);
+ }
}
#[no_mangle]
@@ -158,8 +158,9 @@ pub extern "C" fn Servo_StyleWorkerThreadCount() -> u32 {
#[no_mangle]
pub extern "C" fn Servo_Node_ClearNodeData(node: RawGeckoNodeBorrowed) -> () {
- let node = GeckoNode(node);
- node.clear_data();
+ if let Some(element) = GeckoNode(node).as_element() {
+ element.clear_data();
+ }
}
#[no_mangle]
@@ -253,7 +254,20 @@ pub extern "C" fn Servo_StyleSheet_Release(sheet: RawServoStyleSheetBorrowed) ->
pub extern "C" fn Servo_ComputedValues_Get(node: RawGeckoNodeBorrowed)
-> ServoComputedValuesStrong {
let node = GeckoNode(node);
- let data = node.borrow_data();
+
+ // Gecko erroneously calls this function from ServoRestyleManager::RecreateStyleContexts.
+ // We plan to fix that, but just support it for now until that code gets rewritten.
+ if node.is_text_node() {
+ error!("Don't call Servo_ComputedValue_Get() for text nodes");
+ let parent = node.parent_node().unwrap().as_element().unwrap();
+ let parent_cv = parent.borrow_data().map_or(Arc::new(ComputedValues::initial_values().clone()),
+ |x| x.get_current_styles().unwrap()
+ .primary.clone());
+ return ComputedValues::inherit_from(&parent_cv).into_strong();
+ }
+
+ let element = node.as_element().unwrap();
+ let data = element.borrow_data();
let arc_cv = match data.as_ref().and_then(|x| x.get_current_styles()) {
Some(styles) => styles.primary.clone(),
None => {
@@ -315,8 +329,7 @@ pub extern "C" fn Servo_ComputedValues_GetForPseudoElement(parent_style: ServoCo
match GeckoSelectorImpl::pseudo_element_cascade_type(&pseudo) {
PseudoElementCascadeType::Eager => {
- let node = element.as_node();
- let maybe_computed = node.get_pseudo_style(&pseudo);
+ let maybe_computed = element.get_pseudo_style(&pseudo);
maybe_computed.map_or_else(parent_or_null, FFIArcHelpers::into_strong)
}
PseudoElementCascadeType::Lazy => {