mirror of
https://github.com/servo/servo.git
synced 2025-08-06 22:15:33 +01:00
Auto merge of #13956 - bholley:more_telement, r=emilio
incremental restyle: Hoist most styling functionality from TNode to TElement This is a continuation of the work in #13951. I'm separating it out into a separate PR since the aforementioned patch has a green try run and this one doesn't yet. <!-- Reviewable:start --> --- This change is [<img src="https://reviewable.io/review_button.svg" height="34" align="absmiddle" alt="Reviewable"/>](https://reviewable.io/reviews/servo/servo/13956) <!-- Reviewable:end -->
This commit is contained in:
commit
b611e5c3b2
22 changed files with 449 additions and 415 deletions
|
@ -46,7 +46,6 @@ extern crate range;
|
||||||
extern crate rustc_serialize;
|
extern crate rustc_serialize;
|
||||||
extern crate script_layout_interface;
|
extern crate script_layout_interface;
|
||||||
extern crate script_traits;
|
extern crate script_traits;
|
||||||
extern crate selectors;
|
|
||||||
extern crate smallvec;
|
extern crate smallvec;
|
||||||
#[macro_use(atom, ns)] extern crate string_cache;
|
#[macro_use(atom, ns)] extern crate string_cache;
|
||||||
extern crate style;
|
extern crate style;
|
||||||
|
|
|
@ -11,13 +11,12 @@ use flow::{self, PreorderFlowTraversal};
|
||||||
use flow::{CAN_BE_FRAGMENTED, Flow, ImmutableFlowUtils, PostorderFlowTraversal};
|
use flow::{CAN_BE_FRAGMENTED, Flow, ImmutableFlowUtils, PostorderFlowTraversal};
|
||||||
use gfx::display_list::OpaqueNode;
|
use gfx::display_list::OpaqueNode;
|
||||||
use script_layout_interface::restyle_damage::{BUBBLE_ISIZES, REFLOW, REFLOW_OUT_OF_FLOW, REPAINT, RestyleDamage};
|
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 std::mem;
|
||||||
use style::atomic_refcell::AtomicRefCell;
|
use style::atomic_refcell::AtomicRefCell;
|
||||||
use style::context::{LocalStyleContext, SharedStyleContext, StyleContext};
|
use style::context::{LocalStyleContext, SharedStyleContext, StyleContext};
|
||||||
use style::data::NodeData;
|
use style::data::ElementData;
|
||||||
use style::dom::TNode;
|
use style::dom::{StylingMode, TElement, TNode};
|
||||||
use style::selector_impl::ServoSelectorImpl;
|
|
||||||
use style::traversal::{DomTraversalContext, put_thread_local_bloom_filter};
|
use style::traversal::{DomTraversalContext, put_thread_local_bloom_filter};
|
||||||
use style::traversal::{recalc_style_at, remove_from_bloom_filter};
|
use style::traversal::{recalc_style_at, remove_from_bloom_filter};
|
||||||
use style::traversal::RestyleResult;
|
use style::traversal::RestyleResult;
|
||||||
|
@ -32,7 +31,7 @@ pub struct RecalcStyleAndConstructFlows<'lc> {
|
||||||
|
|
||||||
impl<'lc, N> DomTraversalContext<N> for RecalcStyleAndConstructFlows<'lc>
|
impl<'lc, N> DomTraversalContext<N> for RecalcStyleAndConstructFlows<'lc>
|
||||||
where N: LayoutNode + TNode,
|
where N: LayoutNode + TNode,
|
||||||
N::ConcreteElement: ::selectors::Element<Impl=ServoSelectorImpl>
|
N::ConcreteElement: LayoutElement
|
||||||
|
|
||||||
{
|
{
|
||||||
type SharedContext = SharedLayoutContext;
|
type SharedContext = SharedLayoutContext;
|
||||||
|
@ -114,9 +113,27 @@ impl<'lc, N> DomTraversalContext<N> for RecalcStyleAndConstructFlows<'lc>
|
||||||
construct_flows_at(&self.context, self.root, node);
|
construct_flows_at(&self.context, self.root, node);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn ensure_node_data(node: &N) -> &AtomicRefCell<NodeData> {
|
fn should_traverse_child(parent: N::ConcreteElement, child: N) -> bool {
|
||||||
node.initialize_data();
|
// If this node has been marked as damaged in some way, we need to
|
||||||
node.get_style_data().unwrap()
|
// 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<ElementData> {
|
||||||
|
element.as_node().initialize_data();
|
||||||
|
element.get_style_data().unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn local_context(&self) -> &LocalStyleContext {
|
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.
|
// Always reconstruct if incremental layout is turned off.
|
||||||
let nonincremental_layout = opts::get().nonincremental_layout;
|
let nonincremental_layout = opts::get().nonincremental_layout;
|
||||||
if nonincremental_layout || node.has_dirty_descendants() ||
|
if nonincremental_layout || tnode.restyle_damage() != RestyleDamage::empty() ||
|
||||||
tnode.restyle_damage() != RestyleDamage::empty() {
|
node.as_element().map_or(false, |el| el.has_dirty_descendants()) {
|
||||||
let mut flow_constructor = FlowConstructor::new(context);
|
let mut flow_constructor = FlowConstructor::new(context);
|
||||||
if nonincremental_layout || !flow_constructor.repair_if_possible(&tnode) {
|
if nonincremental_layout || !flow_constructor.repair_if_possible(&tnode) {
|
||||||
flow_constructor.process(&tnode);
|
flow_constructor.process(&tnode);
|
||||||
|
|
|
@ -33,16 +33,16 @@
|
||||||
use core::nonzero::NonZero;
|
use core::nonzero::NonZero;
|
||||||
use data::{LayoutDataFlags, PersistentLayoutData};
|
use data::{LayoutDataFlags, PersistentLayoutData};
|
||||||
use script_layout_interface::{OpaqueStyleAndLayoutData, PartialPersistentLayoutData};
|
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::{ThreadSafeLayoutElement, ThreadSafeLayoutNode};
|
||||||
|
use script_layout_interface::wrapper_traits::GetLayoutData;
|
||||||
use style::atomic_refcell::{AtomicRef, AtomicRefCell, AtomicRefMut};
|
use style::atomic_refcell::{AtomicRef, AtomicRefCell, AtomicRefMut};
|
||||||
use style::computed_values::content::{self, ContentItem};
|
use style::computed_values::content::{self, ContentItem};
|
||||||
|
|
||||||
pub type NonOpaqueStyleAndLayoutData = *mut AtomicRefCell<PersistentLayoutData>;
|
pub type NonOpaqueStyleAndLayoutData = AtomicRefCell<PersistentLayoutData>;
|
||||||
|
|
||||||
pub trait LayoutNodeLayoutData {
|
pub trait LayoutNodeLayoutData {
|
||||||
/// Similar to borrow_data*, but returns the full PersistentLayoutData rather
|
/// Similar to borrow_data*, but returns the full PersistentLayoutData rather
|
||||||
/// than only the style::data::NodeData.
|
/// than only the style::data::ElementData.
|
||||||
fn borrow_layout_data(&self) -> Option<AtomicRef<PersistentLayoutData>>;
|
fn borrow_layout_data(&self) -> Option<AtomicRef<PersistentLayoutData>>;
|
||||||
fn mutate_layout_data(&self) -> Option<AtomicRefMut<PersistentLayoutData>>;
|
fn mutate_layout_data(&self) -> Option<AtomicRefMut<PersistentLayoutData>>;
|
||||||
fn flow_debug_id(self) -> usize;
|
fn flow_debug_id(self) -> usize;
|
||||||
|
@ -50,21 +50,11 @@ pub trait LayoutNodeLayoutData {
|
||||||
|
|
||||||
impl<T: GetLayoutData> LayoutNodeLayoutData for T {
|
impl<T: GetLayoutData> LayoutNodeLayoutData for T {
|
||||||
fn borrow_layout_data(&self) -> Option<AtomicRef<PersistentLayoutData>> {
|
fn borrow_layout_data(&self) -> Option<AtomicRef<PersistentLayoutData>> {
|
||||||
unsafe {
|
self.get_raw_data().map(|d| d.borrow())
|
||||||
self.get_style_and_layout_data().map(|opaque| {
|
|
||||||
let container = *opaque.ptr as NonOpaqueStyleAndLayoutData;
|
|
||||||
(*container).borrow()
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn mutate_layout_data(&self) -> Option<AtomicRefMut<PersistentLayoutData>> {
|
fn mutate_layout_data(&self) -> Option<AtomicRefMut<PersistentLayoutData>> {
|
||||||
unsafe {
|
self.get_raw_data().map(|d| d.borrow_mut())
|
||||||
self.get_style_and_layout_data().map(|opaque| {
|
|
||||||
let container = *opaque.ptr as NonOpaqueStyleAndLayoutData;
|
|
||||||
(*container).borrow_mut()
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn flow_debug_id(self) -> usize {
|
fn flow_debug_id(self) -> usize {
|
||||||
|
@ -73,19 +63,27 @@ impl<T: GetLayoutData> LayoutNodeLayoutData for T {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait LayoutNodeHelpers {
|
pub trait LayoutNodeHelpers {
|
||||||
fn initialize_data(self);
|
fn initialize_data(&self);
|
||||||
|
fn get_raw_data(&self) -> Option<&NonOpaqueStyleAndLayoutData>;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: LayoutNode> LayoutNodeHelpers for T {
|
impl<T: GetLayoutData> LayoutNodeHelpers for T {
|
||||||
fn initialize_data(self) {
|
fn initialize_data(&self) {
|
||||||
if self.borrow_layout_data().is_none() {
|
if self.get_raw_data().is_none() {
|
||||||
let ptr: NonOpaqueStyleAndLayoutData =
|
let ptr: *mut NonOpaqueStyleAndLayoutData =
|
||||||
Box::into_raw(box AtomicRefCell::new(PersistentLayoutData::new()));
|
Box::into_raw(box AtomicRefCell::new(PersistentLayoutData::new()));
|
||||||
let opaque = OpaqueStyleAndLayoutData {
|
let opaque = OpaqueStyleAndLayoutData {
|
||||||
ptr: unsafe { NonZero::new(ptr as *mut AtomicRefCell<PartialPersistentLayoutData>) }
|
ptr: unsafe { NonZero::new(ptr as *mut AtomicRefCell<PartialPersistentLayoutData>) }
|
||||||
};
|
};
|
||||||
self.init_style_and_layout_data(opaque);
|
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 }
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -30,6 +30,7 @@ profile_traits = {path = "../profile_traits"}
|
||||||
script = {path = "../script"}
|
script = {path = "../script"}
|
||||||
script_layout_interface = {path = "../script_layout_interface"}
|
script_layout_interface = {path = "../script_layout_interface"}
|
||||||
script_traits = {path = "../script_traits"}
|
script_traits = {path = "../script_traits"}
|
||||||
|
selectors = "0.14"
|
||||||
serde_derive = "0.8"
|
serde_derive = "0.8"
|
||||||
serde_json = "0.8"
|
serde_json = "0.8"
|
||||||
style = {path = "../style"}
|
style = {path = "../style"}
|
||||||
|
|
|
@ -37,6 +37,7 @@ extern crate profile_traits;
|
||||||
extern crate script;
|
extern crate script;
|
||||||
extern crate script_layout_interface;
|
extern crate script_layout_interface;
|
||||||
extern crate script_traits;
|
extern crate script_traits;
|
||||||
|
extern crate selectors;
|
||||||
extern crate serde_json;
|
extern crate serde_json;
|
||||||
extern crate style;
|
extern crate style;
|
||||||
extern crate url;
|
extern crate url;
|
||||||
|
@ -94,6 +95,7 @@ use script_layout_interface::rpc::{LayoutRPC, MarginStyleResponse, NodeOverflowR
|
||||||
use script_layout_interface::wrapper_traits::LayoutNode;
|
use script_layout_interface::wrapper_traits::LayoutNode;
|
||||||
use script_traits::{ConstellationControlMsg, LayoutControlMsg, LayoutMsg as ConstellationMsg};
|
use script_traits::{ConstellationControlMsg, LayoutControlMsg, LayoutMsg as ConstellationMsg};
|
||||||
use script_traits::{StackingContextScrollState, UntrustedNodeAddress};
|
use script_traits::{StackingContextScrollState, UntrustedNodeAddress};
|
||||||
|
use selectors::Element;
|
||||||
use std::borrow::ToOwned;
|
use std::borrow::ToOwned;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::hash::BuildHasherDefault;
|
use std::hash::BuildHasherDefault;
|
||||||
|
@ -1109,11 +1111,11 @@ impl LayoutThread {
|
||||||
// NB: The dirty bit is propagated down the tree.
|
// NB: The dirty bit is propagated down the tree.
|
||||||
unsafe { node.set_dirty(); }
|
unsafe { node.set_dirty(); }
|
||||||
|
|
||||||
let mut current = node.parent_node();
|
let mut current = node.parent_node().and_then(|n| n.as_element());
|
||||||
while let Some(node) = current {
|
while let Some(el) = current {
|
||||||
if node.has_dirty_descendants() { break; }
|
if el.has_dirty_descendants() { break; }
|
||||||
unsafe { node.set_dirty_descendants(); }
|
unsafe { el.set_dirty_descendants(); }
|
||||||
current = node.parent_node();
|
current = el.parent_element();
|
||||||
}
|
}
|
||||||
|
|
||||||
next = iter.next_skipping_children();
|
next = iter.next_skipping_children();
|
||||||
|
@ -1155,7 +1157,8 @@ impl LayoutThread {
|
||||||
viewport_size_changed,
|
viewport_size_changed,
|
||||||
data.reflow_info.goal);
|
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.
|
// Recalculate CSS styles and rebuild flows and fragments.
|
||||||
profile(time::ProfilerCategory::LayoutStyleRecalc,
|
profile(time::ProfilerCategory::LayoutStyleRecalc,
|
||||||
self.profiler_metadata(),
|
self.profiler_metadata(),
|
||||||
|
@ -1485,7 +1488,7 @@ impl LayoutThread {
|
||||||
/// because the struct type is transmuted to a different type on the script side.
|
/// because the struct type is transmuted to a different type on the script side.
|
||||||
unsafe fn handle_reap_style_and_layout_data(&self, data: OpaqueStyleAndLayoutData) {
|
unsafe fn handle_reap_style_and_layout_data(&self, data: OpaqueStyleAndLayoutData) {
|
||||||
let ptr: *mut AtomicRefCell<PartialPersistentLayoutData> = *data.ptr;
|
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);
|
let _ = Box::from_raw(non_opaque);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -46,7 +46,7 @@ use range::Range;
|
||||||
use script_layout_interface::{HTMLCanvasData, LayoutNodeType, SVGSVGData, TrustedNodeAddress};
|
use script_layout_interface::{HTMLCanvasData, LayoutNodeType, SVGSVGData, TrustedNodeAddress};
|
||||||
use script_layout_interface::{OpaqueStyleAndLayoutData, PartialPersistentLayoutData};
|
use script_layout_interface::{OpaqueStyleAndLayoutData, PartialPersistentLayoutData};
|
||||||
use script_layout_interface::restyle_damage::RestyleDamage;
|
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 script_layout_interface::wrapper_traits::{PseudoElementType, ThreadSafeLayoutElement, ThreadSafeLayoutNode};
|
||||||
use selectors::matching::ElementFlags;
|
use selectors::matching::ElementFlags;
|
||||||
use selectors::parser::{AttrSelector, NamespaceConstraint};
|
use selectors::parser::{AttrSelector, NamespaceConstraint};
|
||||||
|
@ -60,7 +60,7 @@ use style::atomic_refcell::{AtomicRef, AtomicRefCell, AtomicRefMut};
|
||||||
use style::attr::AttrValue;
|
use style::attr::AttrValue;
|
||||||
use style::computed_values::display;
|
use style::computed_values::display;
|
||||||
use style::context::SharedStyleContext;
|
use style::context::SharedStyleContext;
|
||||||
use style::data::NodeData;
|
use style::data::ElementData;
|
||||||
use style::dom::{LayoutIterator, NodeInfo, OpaqueNode, PresentationalHintsSynthetizer, TDocument, TElement, TNode};
|
use style::dom::{LayoutIterator, NodeInfo, OpaqueNode, PresentationalHintsSynthetizer, TDocument, TElement, TNode};
|
||||||
use style::dom::{TRestyleDamage, UnsafeNode};
|
use style::dom::{TRestyleDamage, UnsafeNode};
|
||||||
use style::element_state::*;
|
use style::element_state::*;
|
||||||
|
@ -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 {
|
fn script_type_id(&self) -> NodeTypeId {
|
||||||
unsafe {
|
unsafe {
|
||||||
self.node.type_id_for_layout()
|
self.node.type_id_for_layout()
|
||||||
|
@ -165,11 +161,11 @@ impl<'ln> TNode for ServoLayoutNode<'ln> {
|
||||||
unsafe { self.get_jsmanaged().opaque() }
|
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 {
|
if self.opaque() == reflow_root {
|
||||||
None
|
None
|
||||||
} else {
|
} 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)
|
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 {
|
fn needs_dirty_on_viewport_size_changed(&self) -> bool {
|
||||||
unsafe { self.node.get_flag(DIRTY_ON_VIEWPORT_SIZE_CHANGE) }
|
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)
|
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>> {
|
fn parent_node(&self) -> Option<ServoLayoutNode<'ln>> {
|
||||||
unsafe {
|
unsafe {
|
||||||
self.node.parent_node_ref().map(|node| self.new_with_this_lifetime(&node))
|
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(IS_DIRTY, false);
|
||||||
self.node.set_flag(HAS_DIRTY_DESCENDANTS, false);
|
self.node.set_flag(HAS_DIRTY_DESCENDANTS, false);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// NB: This duplicates the get_style_data on ThreadSafeLayoutElement, but
|
impl<'ln> GetLayoutData for ServoLayoutNode<'ln> {
|
||||||
// will go away soon.
|
fn get_style_and_layout_data(&self) -> Option<OpaqueStyleAndLayoutData> {
|
||||||
fn get_style_data(&self) -> Option<&AtomicRefCell<NodeData>> {
|
|
||||||
unsafe {
|
unsafe {
|
||||||
self.get_jsmanaged().get_style_and_layout_data().map(|d| {
|
self.get_jsmanaged().get_style_and_layout_data()
|
||||||
let ppld: &AtomicRefCell<PartialPersistentLayoutData> = &**d.ptr;
|
|
||||||
let psd: &AtomicRefCell<NodeData> = transmute(ppld);
|
|
||||||
psd
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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> {
|
impl<'le> GetLayoutData for ServoLayoutElement<'le> {
|
||||||
fn get_style_and_layout_data(&self) -> Option<OpaqueStyleAndLayoutData> {
|
fn get_style_and_layout_data(&self) -> Option<OpaqueStyleAndLayoutData> {
|
||||||
self.as_node().get_style_and_layout_data()
|
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> {
|
impl<'ln> GetLayoutData for ServoThreadSafeLayoutNode<'ln> {
|
||||||
fn get_style_and_layout_data(&self) -> Option<OpaqueStyleAndLayoutData> {
|
fn get_style_and_layout_data(&self) -> Option<OpaqueStyleAndLayoutData> {
|
||||||
self.node.get_style_and_layout_data()
|
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> {
|
impl<'le> GetLayoutData for ServoThreadSafeLayoutElement<'le> {
|
||||||
fn get_style_and_layout_data(&self) -> Option<OpaqueStyleAndLayoutData> {
|
fn get_style_and_layout_data(&self) -> Option<OpaqueStyleAndLayoutData> {
|
||||||
self.element.as_node().get_style_and_layout_data()
|
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> {
|
impl<'ln> ServoLayoutNode<'ln> {
|
||||||
|
@ -360,14 +316,6 @@ impl<'ln> ServoLayoutNode<'ln> {
|
||||||
self.node.set_flag(IS_DIRTY, true)
|
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) {
|
fn dump_indent(self, indent: u32) {
|
||||||
let mut s = String::new();
|
let mut s = String::new();
|
||||||
for _ in 0..indent {
|
for _ in 0..indent {
|
||||||
|
@ -400,12 +348,17 @@ impl<'ln> ServoLayoutNode<'ln> {
|
||||||
fn debug_str(self) -> String {
|
fn debug_str(self) -> String {
|
||||||
format!("{:?}: changed={} dirty={} dirty_descendants={}",
|
format!("{:?}: changed={} dirty={} dirty_descendants={}",
|
||||||
self.script_type_id(), self.has_changed(),
|
self.script_type_id(), self.has_changed(),
|
||||||
self.deprecated_dirty_bit_is_set(),
|
self.as_element().map_or(false, |el| el.deprecated_dirty_bit_is_set()),
|
||||||
self.has_dirty_descendants())
|
self.as_element().map_or(false, |el| el.has_dirty_descendants()))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn debug_style_str(self) -> String {
|
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)
|
format!("{:?}: {:?}", self.script_type_id(), &*data)
|
||||||
} else {
|
} else {
|
||||||
format!("{:?}: style_data=None", self.script_type_id())
|
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) {
|
fn set_restyle_damage(self, damage: RestyleDamage) {
|
||||||
let node = self.as_node();
|
self.get_partial_layout_data().unwrap().borrow_mut().restyle_damage = damage;
|
||||||
node.get_partial_layout_data().unwrap().borrow_mut().restyle_damage = damage;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
|
@ -529,6 +481,53 @@ impl<'le> TElement for ServoLayoutElement<'le> {
|
||||||
-> Option<&'a Arc<ComputedValues>> {
|
-> Option<&'a Arc<ComputedValues>> {
|
||||||
current_cv
|
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<ElementData> {
|
||||||
|
let mut data = self.mutate_data().unwrap();
|
||||||
|
data.gather_previous_styles(|| None);
|
||||||
|
data
|
||||||
|
}
|
||||||
|
|
||||||
|
fn borrow_data(&self) -> Option<AtomicRef<ElementData>> {
|
||||||
|
self.get_style_data().map(|d| d.borrow())
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'le> LayoutElement for ServoLayoutElement<'le> {
|
||||||
|
fn get_style_data(&self) -> Option<&AtomicRefCell<ElementData>> {
|
||||||
|
unsafe {
|
||||||
|
self.get_style_and_layout_data().map(|d| {
|
||||||
|
let ppld: &AtomicRefCell<PartialPersistentLayoutData> = &**d.ptr;
|
||||||
|
let psd: &AtomicRefCell<ElementData> = transmute(ppld);
|
||||||
|
psd
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'le> PartialEq for ServoLayoutElement<'le> {
|
impl<'le> PartialEq for ServoLayoutElement<'le> {
|
||||||
|
@ -551,6 +550,16 @@ impl<'le> ServoLayoutElement<'le> {
|
||||||
(*self.element.unsafe_get()).get_attr_val_for_layout(namespace, name)
|
(*self.element.unsafe_get()).get_attr_val_for_layout(namespace, name)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn mutate_data(&self) -> Option<AtomicRefMut<ElementData>> {
|
||||||
|
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>> {
|
fn as_element<'le>(node: LayoutJS<Node>) -> Option<ServoLayoutElement<'le>> {
|
||||||
|
@ -826,7 +835,7 @@ impl<'ln> ThreadSafeLayoutNode for ServoThreadSafeLayoutNode<'ln> {
|
||||||
// works, but would be difficult to change. (Text node style is
|
// works, but would be difficult to change. (Text node style is
|
||||||
// also not visible to script.)
|
// also not visible to script.)
|
||||||
debug_assert!(self.is_text_node());
|
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();
|
let parent_data = parent.get_style_data().unwrap().borrow();
|
||||||
parent_data.current_styles().primary.clone()
|
parent_data.current_styles().primary.clone()
|
||||||
}
|
}
|
||||||
|
@ -875,17 +884,19 @@ impl<'ln> ThreadSafeLayoutNode for ServoThreadSafeLayoutNode<'ln> {
|
||||||
if self.node.has_changed() {
|
if self.node.has_changed() {
|
||||||
RestyleDamage::rebuild_and_reflow()
|
RestyleDamage::rebuild_and_reflow()
|
||||||
} else if self.is_text_node() {
|
} 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();
|
let parent_data = parent.get_partial_layout_data().unwrap().borrow();
|
||||||
parent_data.restyle_damage
|
parent_data.restyle_damage
|
||||||
} else {
|
} 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) {
|
fn clear_restyle_damage(self) {
|
||||||
if self.is_element() {
|
if let Some(el) = self.as_element() {
|
||||||
let mut data = self.node.get_partial_layout_data().unwrap().borrow_mut();
|
let mut data = el.element.get_partial_layout_data().unwrap().borrow_mut();
|
||||||
data.restyle_damage = RestyleDamage::empty();
|
data.restyle_damage = RestyleDamage::empty();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1077,14 +1088,8 @@ impl<'le> ThreadSafeLayoutElement for ServoThreadSafeLayoutElement<'le> {
|
||||||
self.element.get_attr(namespace, name)
|
self.element.get_attr(namespace, name)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_style_data(&self) -> Option<&AtomicRefCell<NodeData>> {
|
fn get_style_data(&self) -> Option<&AtomicRefCell<ElementData>> {
|
||||||
unsafe {
|
self.element.get_style_data()
|
||||||
self.element.as_node().get_style_and_layout_data().map(|d| {
|
|
||||||
let ppld: &AtomicRefCell<PartialPersistentLayoutData> = &**d.ptr;
|
|
||||||
let psd: &AtomicRefCell<NodeData> = transmute(ppld);
|
|
||||||
psd
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -53,14 +53,14 @@ use libc::c_void;
|
||||||
use restyle_damage::RestyleDamage;
|
use restyle_damage::RestyleDamage;
|
||||||
use std::sync::atomic::AtomicIsize;
|
use std::sync::atomic::AtomicIsize;
|
||||||
use style::atomic_refcell::AtomicRefCell;
|
use style::atomic_refcell::AtomicRefCell;
|
||||||
use style::data::NodeData;
|
use style::data::ElementData;
|
||||||
|
|
||||||
pub struct PartialPersistentLayoutData {
|
pub struct PartialPersistentLayoutData {
|
||||||
/// Data that the style system associates with a node. When the
|
/// Data that the style system associates with a node. When the
|
||||||
/// style system is being used standalone, this is all that hangs
|
/// style system is being used standalone, this is all that hangs
|
||||||
/// off the node. This must be first to permit the various
|
/// off the node. This must be first to permit the various
|
||||||
/// transmutations between NodeData and PersistentLayoutData.
|
/// transmutations between ElementData and PersistentLayoutData.
|
||||||
pub style_data: NodeData,
|
pub style_data: ElementData,
|
||||||
|
|
||||||
/// Description of how to account for recent style changes.
|
/// Description of how to account for recent style changes.
|
||||||
pub restyle_damage: RestyleDamage,
|
pub restyle_damage: RestyleDamage,
|
||||||
|
@ -72,7 +72,7 @@ pub struct PartialPersistentLayoutData {
|
||||||
impl PartialPersistentLayoutData {
|
impl PartialPersistentLayoutData {
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
PartialPersistentLayoutData {
|
PartialPersistentLayoutData {
|
||||||
style_data: NodeData::new(),
|
style_data: ElementData::new(),
|
||||||
restyle_damage: RestyleDamage::empty(),
|
restyle_damage: RestyleDamage::empty(),
|
||||||
parallel: DomParallelInfo::new(),
|
parallel: DomParallelInfo::new(),
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,8 +18,8 @@ use string_cache::{Atom, Namespace};
|
||||||
use style::atomic_refcell::AtomicRefCell;
|
use style::atomic_refcell::AtomicRefCell;
|
||||||
use style::computed_values::display;
|
use style::computed_values::display;
|
||||||
use style::context::SharedStyleContext;
|
use style::context::SharedStyleContext;
|
||||||
use style::data::NodeData;
|
use style::data::ElementData;
|
||||||
use style::dom::{LayoutIterator, NodeInfo, PresentationalHintsSynthetizer, TNode};
|
use style::dom::{LayoutIterator, NodeInfo, PresentationalHintsSynthetizer, TElement, TNode};
|
||||||
use style::dom::OpaqueNode;
|
use style::dom::OpaqueNode;
|
||||||
use style::properties::ServoComputedValues;
|
use style::properties::ServoComputedValues;
|
||||||
use style::selector_impl::{PseudoElement, PseudoElementCascadeType, ServoSelectorImpl};
|
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.
|
/// Trait to abstract access to layout data across various data structures.
|
||||||
pub trait GetLayoutData {
|
pub trait GetLayoutData {
|
||||||
fn get_style_and_layout_data(&self) -> Option<OpaqueStyleAndLayoutData>;
|
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
|
/// 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);
|
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>> {
|
fn rev_children(self) -> LayoutIterator<ReverseChildrenIterator<Self>> {
|
||||||
LayoutIterator(ReverseChildrenIterator {
|
LayoutIterator(ReverseChildrenIterator {
|
||||||
current: self.last_child(),
|
current: self.last_child(),
|
||||||
|
@ -276,6 +273,10 @@ pub trait DangerousThreadSafeLayoutNode: ThreadSafeLayoutNode {
|
||||||
unsafe fn dangerous_next_sibling(&self) -> Option<Self>;
|
unsafe fn dangerous_next_sibling(&self) -> Option<Self>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub trait LayoutElement: Clone + Copy + Sized + Debug + GetLayoutData + TElement {
|
||||||
|
fn get_style_data(&self) -> Option<&AtomicRefCell<ElementData>>;
|
||||||
|
}
|
||||||
|
|
||||||
pub trait ThreadSafeLayoutElement: Clone + Copy + Sized + Debug +
|
pub trait ThreadSafeLayoutElement: Clone + Copy + Sized + Debug +
|
||||||
::selectors::Element<Impl=ServoSelectorImpl> +
|
::selectors::Element<Impl=ServoSelectorImpl> +
|
||||||
GetLayoutData +
|
GetLayoutData +
|
||||||
|
@ -295,7 +296,7 @@ pub trait ThreadSafeLayoutElement: Clone + Copy + Sized + Debug +
|
||||||
#[inline]
|
#[inline]
|
||||||
fn get_attr(&self, namespace: &Namespace, name: &Atom) -> Option<&str>;
|
fn get_attr(&self, namespace: &Namespace, name: &Atom) -> Option<&str>;
|
||||||
|
|
||||||
fn get_style_data(&self) -> Option<&AtomicRefCell<NodeData>>;
|
fn get_style_data(&self) -> Option<&AtomicRefCell<ElementData>>;
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn get_pseudo_element_type(&self) -> PseudoElementType<Option<display::T>>;
|
fn get_pseudo_element_type(&self) -> PseudoElementType<Option<display::T>>;
|
||||||
|
|
1
components/servo/Cargo.lock
generated
1
components/servo/Cargo.lock
generated
|
@ -1201,6 +1201,7 @@ dependencies = [
|
||||||
"script 0.0.1",
|
"script 0.0.1",
|
||||||
"script_layout_interface 0.0.1",
|
"script_layout_interface 0.0.1",
|
||||||
"script_traits 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_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)",
|
"serde_json 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"style 0.0.1",
|
"style 0.0.1",
|
||||||
|
|
|
@ -67,7 +67,7 @@ COMPILATION_TARGETS = {
|
||||||
},
|
},
|
||||||
"raw_lines": [
|
"raw_lines": [
|
||||||
"use atomic_refcell::AtomicRefCell;",
|
"use atomic_refcell::AtomicRefCell;",
|
||||||
"use data::NodeData;",
|
"use data::ElementData;",
|
||||||
"pub use nsstring::nsStringRepr as nsString;"
|
"pub use nsstring::nsStringRepr as nsString;"
|
||||||
],
|
],
|
||||||
"blacklist_types": ["nsString"],
|
"blacklist_types": ["nsString"],
|
||||||
|
@ -226,7 +226,7 @@ COMPILATION_TARGETS = {
|
||||||
}, {
|
}, {
|
||||||
"generic": False,
|
"generic": False,
|
||||||
"gecko": "ServoNodeData",
|
"gecko": "ServoNodeData",
|
||||||
"servo": "AtomicRefCell<NodeData>",
|
"servo": "AtomicRefCell<ElementData>",
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
|
|
@ -35,7 +35,7 @@ impl DerefMut for PseudoStyles {
|
||||||
/// The styles associated with a node, including the styles for any
|
/// The styles associated with a node, including the styles for any
|
||||||
/// pseudo-elements.
|
/// pseudo-elements.
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct NodeStyles {
|
pub struct ElementStyles {
|
||||||
/// The results of CSS styling for this node.
|
/// The results of CSS styling for this node.
|
||||||
pub primary: Arc<ComputedValues>,
|
pub primary: Arc<ComputedValues>,
|
||||||
|
|
||||||
|
@ -43,9 +43,9 @@ pub struct NodeStyles {
|
||||||
pub pseudos: PseudoStyles,
|
pub pseudos: PseudoStyles,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl NodeStyles {
|
impl ElementStyles {
|
||||||
pub fn new(primary: Arc<ComputedValues>) -> Self {
|
pub fn new(primary: Arc<ComputedValues>) -> Self {
|
||||||
NodeStyles {
|
ElementStyles {
|
||||||
primary: primary,
|
primary: primary,
|
||||||
pseudos: PseudoStyles::empty(),
|
pseudos: PseudoStyles::empty(),
|
||||||
}
|
}
|
||||||
|
@ -53,7 +53,7 @@ impl NodeStyles {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
enum NodeDataStyles {
|
enum ElementDataStyles {
|
||||||
/// The field has not been initialized.
|
/// The field has not been initialized.
|
||||||
Uninitialized,
|
Uninitialized,
|
||||||
|
|
||||||
|
@ -64,19 +64,19 @@ enum NodeDataStyles {
|
||||||
/// immutable, but for now we need to mutate it a bit before styling to
|
/// immutable, but for now we need to mutate it a bit before styling to
|
||||||
/// handle animations.
|
/// handle animations.
|
||||||
///
|
///
|
||||||
/// Note that since NodeStyles contains an Arc, the null pointer
|
/// Note that since ElementStyles contains an Arc, the null pointer
|
||||||
/// optimization prevents the Option<> here from consuming an extra word.
|
/// optimization prevents the Option<> here from consuming an extra word.
|
||||||
Previous(Option<NodeStyles>),
|
Previous(Option<ElementStyles>),
|
||||||
|
|
||||||
/// The field holds the current, up-to-date style.
|
/// The field holds the current, up-to-date style.
|
||||||
///
|
///
|
||||||
/// This is the output of the styling algorithm.
|
/// This is the output of the styling algorithm.
|
||||||
Current(NodeStyles),
|
Current(ElementStyles),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl NodeDataStyles {
|
impl ElementDataStyles {
|
||||||
fn is_previous(&self) -> bool {
|
fn is_previous(&self) -> bool {
|
||||||
use self::NodeDataStyles::*;
|
use self::ElementDataStyles::*;
|
||||||
match *self {
|
match *self {
|
||||||
Previous(_) => true,
|
Previous(_) => true,
|
||||||
_ => false,
|
_ => false,
|
||||||
|
@ -113,34 +113,34 @@ impl RestyleData {
|
||||||
/// In both cases, it is wrapped inside an AtomicRefCell to ensure thread
|
/// In both cases, it is wrapped inside an AtomicRefCell to ensure thread
|
||||||
/// safety.
|
/// safety.
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct NodeData {
|
pub struct ElementData {
|
||||||
styles: NodeDataStyles,
|
styles: ElementDataStyles,
|
||||||
pub restyle_data: Option<RestyleData>,
|
pub restyle_data: Option<RestyleData>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl NodeData {
|
impl ElementData {
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
NodeData {
|
ElementData {
|
||||||
styles: NodeDataStyles::Uninitialized,
|
styles: ElementDataStyles::Uninitialized,
|
||||||
restyle_data: None,
|
restyle_data: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn has_current_styles(&self) -> bool {
|
pub fn has_current_styles(&self) -> bool {
|
||||||
match self.styles {
|
match self.styles {
|
||||||
NodeDataStyles::Current(_) => true,
|
ElementDataStyles::Current(_) => true,
|
||||||
_ => false,
|
_ => false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_current_styles(&self) -> Option<&NodeStyles> {
|
pub fn get_current_styles(&self) -> Option<&ElementStyles> {
|
||||||
match self.styles {
|
match self.styles {
|
||||||
NodeDataStyles::Current(ref s) => Some(s),
|
ElementDataStyles::Current(ref s) => Some(s),
|
||||||
_ => None,
|
_ => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn current_styles(&self) -> &NodeStyles {
|
pub fn current_styles(&self) -> &ElementStyles {
|
||||||
self.get_current_styles().expect("Calling current_styles before or during styling")
|
self.get_current_styles().expect("Calling current_styles before or during styling")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -149,29 +149,29 @@ impl NodeData {
|
||||||
#[cfg(not(feature = "gecko"))]
|
#[cfg(not(feature = "gecko"))]
|
||||||
pub fn current_pseudos_mut(&mut self) -> &mut PseudoStyles {
|
pub fn current_pseudos_mut(&mut self) -> &mut PseudoStyles {
|
||||||
match self.styles {
|
match self.styles {
|
||||||
NodeDataStyles::Current(ref mut s) => &mut s.pseudos,
|
ElementDataStyles::Current(ref mut s) => &mut s.pseudos,
|
||||||
_ => panic!("Calling current_pseudos_mut before or during styling"),
|
_ => panic!("Calling current_pseudos_mut before or during styling"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn previous_styles(&self) -> Option<&NodeStyles> {
|
pub fn previous_styles(&self) -> Option<&ElementStyles> {
|
||||||
match self.styles {
|
match self.styles {
|
||||||
NodeDataStyles::Previous(ref s) => s.as_ref(),
|
ElementDataStyles::Previous(ref s) => s.as_ref(),
|
||||||
_ => panic!("Calling previous_styles without having gathered it"),
|
_ => panic!("Calling previous_styles without having gathered it"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn previous_styles_mut(&mut self) -> Option<&mut NodeStyles> {
|
pub fn previous_styles_mut(&mut self) -> Option<&mut ElementStyles> {
|
||||||
match self.styles {
|
match self.styles {
|
||||||
NodeDataStyles::Previous(ref mut s) => s.as_mut(),
|
ElementDataStyles::Previous(ref mut s) => s.as_mut(),
|
||||||
_ => panic!("Calling previous_styles without having gathered it"),
|
_ => panic!("Calling previous_styles without having gathered it"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn gather_previous_styles<F>(&mut self, f: F)
|
pub fn gather_previous_styles<F>(&mut self, f: F)
|
||||||
where F: FnOnce() -> Option<NodeStyles>
|
where F: FnOnce() -> Option<ElementStyles>
|
||||||
{
|
{
|
||||||
use self::NodeDataStyles::*;
|
use self::ElementDataStyles::*;
|
||||||
self.styles = match mem::replace(&mut self.styles, Uninitialized) {
|
self.styles = match mem::replace(&mut self.styles, Uninitialized) {
|
||||||
Uninitialized => Previous(f()),
|
Uninitialized => Previous(f()),
|
||||||
Current(x) => Previous(Some(x)),
|
Current(x) => Previous(Some(x)),
|
||||||
|
@ -186,13 +186,13 @@ impl NodeData {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn style_text_node(&mut self, style: Arc<ComputedValues>) {
|
pub fn style_text_node(&mut self, style: Arc<ComputedValues>) {
|
||||||
self.styles = NodeDataStyles::Current(NodeStyles::new(style));
|
self.styles = ElementDataStyles::Current(ElementStyles::new(style));
|
||||||
self.restyle_data = None;
|
self.restyle_data = None;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn finish_styling(&mut self, styles: NodeStyles) {
|
pub fn finish_styling(&mut self, styles: ElementStyles) {
|
||||||
debug_assert!(self.styles.is_previous());
|
debug_assert!(self.styles.is_previous());
|
||||||
self.styles = NodeDataStyles::Current(styles);
|
self.styles = ElementDataStyles::Current(styles);
|
||||||
self.restyle_data = None;
|
self.restyle_data = None;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
#![allow(unsafe_code)]
|
#![allow(unsafe_code)]
|
||||||
|
|
||||||
use atomic_refcell::{AtomicRef, AtomicRefMut};
|
use atomic_refcell::{AtomicRef, AtomicRefMut};
|
||||||
use data::{NodeStyles, NodeData};
|
use data::{ElementStyles, ElementData};
|
||||||
use element_state::ElementState;
|
use element_state::ElementState;
|
||||||
use parking_lot::RwLock;
|
use parking_lot::RwLock;
|
||||||
use properties::{ComputedValues, PropertyDeclarationBlock};
|
use properties::{ComputedValues, PropertyDeclarationBlock};
|
||||||
|
@ -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
|
/// 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.
|
/// 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;
|
fn debug_id(self) -> usize;
|
||||||
|
|
||||||
|
@ -131,16 +131,6 @@ pub trait TNode : Sized + Copy + Clone + NodeInfo {
|
||||||
|
|
||||||
fn as_document(&self) -> Option<Self::ConcreteDocument>;
|
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;
|
fn needs_dirty_on_viewport_size_changed(&self) -> bool;
|
||||||
|
|
||||||
unsafe fn set_dirty_on_viewport_size_changed(&self);
|
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);
|
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 parent_node(&self) -> Option<Self>;
|
||||||
|
|
||||||
fn first_child(&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,
|
fn existing_style_for_restyle_damage<'a>(&'a self,
|
||||||
current_computed_values: Option<&'a Arc<ComputedValues>>,
|
current_computed_values: Option<&'a Arc<ComputedValues>>,
|
||||||
pseudo: Option<&PseudoElement>)
|
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 ElementData 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<ElementStyles> { 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<ElementData>;
|
||||||
|
|
||||||
|
/// Immutable borrows the ElementData.
|
||||||
|
fn borrow_data(&self) -> Option<AtomicRef<ElementData>>;
|
||||||
|
|
||||||
/// Properly marks nodes as dirty in response to restyle hints.
|
/// Properly marks nodes as dirty in response to restyle hints.
|
||||||
fn note_restyle_hint<C: DomTraversalContext<Self::ConcreteNode>>(&self, hint: RestyleHint) {
|
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
|
// 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.
|
// or one of its siblings. Mark our ancestor chain as having dirty descendants.
|
||||||
let node = self.as_node();
|
let mut curr = *self;
|
||||||
let mut curr = node;
|
while let Some(parent) = curr.parent_element() {
|
||||||
while let Some(parent) = curr.parent_node() {
|
|
||||||
if parent.has_dirty_descendants() { break }
|
if parent.has_dirty_descendants() { break }
|
||||||
unsafe { parent.set_dirty_descendants(); }
|
unsafe { parent.set_dirty_descendants(); }
|
||||||
curr = parent;
|
curr = parent;
|
||||||
|
@ -289,22 +285,21 @@ pub trait TElement : PartialEq + Debug + Sized + Copy + Clone + ElementExt + Pre
|
||||||
|
|
||||||
// Process hints.
|
// Process hints.
|
||||||
if hint.contains(RESTYLE_SELF) {
|
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.
|
// XXX(emilio): For now, dirty implies dirty descendants if found.
|
||||||
} else if hint.contains(RESTYLE_DESCENDANTS) {
|
} else if hint.contains(RESTYLE_DESCENDANTS) {
|
||||||
unsafe { node.set_dirty_descendants(); }
|
unsafe { self.set_dirty_descendants(); }
|
||||||
let mut current = node.first_child();
|
let mut current = self.first_child_element();
|
||||||
while let Some(node) = current {
|
while let Some(el) = current {
|
||||||
unsafe { C::ensure_node_data(&node).borrow_mut().ensure_restyle_data(); }
|
unsafe { C::ensure_element_data(&el).borrow_mut().ensure_restyle_data(); }
|
||||||
current = node.next_sibling();
|
current = el.next_sibling_element();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if hint.contains(RESTYLE_LATER_SIBLINGS) {
|
if hint.contains(RESTYLE_LATER_SIBLINGS) {
|
||||||
let mut next = ::selectors::Element::next_sibling_element(self);
|
let mut next = ::selectors::Element::next_sibling_element(self);
|
||||||
while let Some(sib) = next {
|
while let Some(sib) = next {
|
||||||
let sib_node = sib.as_node();
|
unsafe { C::ensure_element_data(&sib).borrow_mut().ensure_restyle_data() };
|
||||||
unsafe { C::ensure_node_data(&sib_node).borrow_mut().ensure_restyle_data() };
|
|
||||||
next = ::selectors::Element::next_sibling_element(&sib);
|
next = ::selectors::Element::next_sibling_element(&sib);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,10 +4,10 @@
|
||||||
|
|
||||||
use atomic_refcell::AtomicRefCell;
|
use atomic_refcell::AtomicRefCell;
|
||||||
use context::{LocalStyleContext, SharedStyleContext, StyleContext};
|
use context::{LocalStyleContext, SharedStyleContext, StyleContext};
|
||||||
use data::NodeData;
|
use data::ElementData;
|
||||||
use dom::{NodeInfo, OpaqueNode, TNode};
|
use dom::{NodeInfo, OpaqueNode, StylingMode, TElement, TNode};
|
||||||
use gecko::context::StandaloneStyleContext;
|
use gecko::context::StandaloneStyleContext;
|
||||||
use gecko::wrapper::GeckoNode;
|
use gecko::wrapper::{GeckoElement, GeckoNode};
|
||||||
use std::mem;
|
use std::mem;
|
||||||
use traversal::{DomTraversalContext, recalc_style_at};
|
use traversal::{DomTraversalContext, recalc_style_at};
|
||||||
use traversal::RestyleResult;
|
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.
|
/// We don't use the post-order traversal for anything.
|
||||||
fn needs_postorder_traversal(&self) -> bool { false }
|
fn needs_postorder_traversal(&self) -> bool { false }
|
||||||
|
|
||||||
fn ensure_node_data<'a>(node: &'a GeckoNode<'ln>) -> &'a AtomicRefCell<NodeData> {
|
fn should_traverse_child(_parent: GeckoElement<'ln>, child: GeckoNode<'ln>) -> bool {
|
||||||
node.ensure_data()
|
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<ElementData> {
|
||||||
|
element.ensure_data()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn local_context(&self) -> &LocalStyleContext {
|
fn local_context(&self) -> &LocalStyleContext {
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
|
|
||||||
|
|
||||||
use atomic_refcell::{AtomicRef, AtomicRefCell, AtomicRefMut};
|
use atomic_refcell::{AtomicRef, AtomicRefCell, AtomicRefMut};
|
||||||
use data::NodeData;
|
use data::ElementData;
|
||||||
use dom::{LayoutIterator, NodeInfo, TDocument, TElement, TNode, TRestyleDamage, UnsafeNode};
|
use dom::{LayoutIterator, NodeInfo, TDocument, TElement, TNode, TRestyleDamage, UnsafeNode};
|
||||||
use dom::{OpaqueNode, PresentationalHintsSynthetizer};
|
use dom::{OpaqueNode, PresentationalHintsSynthetizer};
|
||||||
use element_state::ElementState;
|
use element_state::ElementState;
|
||||||
|
@ -64,51 +64,6 @@ impl<'ln> GeckoNode<'ln> {
|
||||||
debug_assert!(!self.0.mNodeInfo.mRawPtr.is_null());
|
debug_assert!(!self.0.mNodeInfo.mRawPtr.is_null());
|
||||||
unsafe { &*self.0.mNodeInfo.mRawPtr }
|
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)]
|
#[derive(Clone, Copy, Debug, PartialEq)]
|
||||||
|
@ -192,11 +147,11 @@ impl<'ln> TNode for GeckoNode<'ln> {
|
||||||
OpaqueNode(ptr)
|
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 {
|
if self.opaque() == reflow_root {
|
||||||
None
|
None
|
||||||
} else {
|
} else {
|
||||||
self.parent_node()
|
self.parent_node().and_then(|x| x.as_element())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -216,23 +171,6 @@ impl<'ln> TNode for GeckoNode<'ln> {
|
||||||
unimplemented!()
|
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 {
|
fn can_be_fragmented(&self) -> bool {
|
||||||
// FIXME(SimonSapin): Servo uses this to implement CSS multicol / fragmentation
|
// FIXME(SimonSapin): Servo uses this to implement CSS multicol / fragmentation
|
||||||
// Maybe this isn’t useful for Gecko?
|
// Maybe this isn’t useful for Gecko?
|
||||||
|
@ -244,34 +182,6 @@ impl<'ln> TNode for GeckoNode<'ln> {
|
||||||
// Maybe this isn’t useful for Gecko?
|
// 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>> {
|
fn parent_node(&self) -> Option<GeckoNode<'ln>> {
|
||||||
unsafe { self.0.mParent.as_ref().map(GeckoNode) }
|
unsafe { self.0.mParent.as_ref().map(GeckoNode) }
|
||||||
}
|
}
|
||||||
|
@ -387,6 +297,55 @@ impl<'le> GeckoElement<'le> {
|
||||||
let extra_data = ParserContextExtraData::default();
|
let extra_data = ParserContextExtraData::default();
|
||||||
parse_style_attribute(value, &base_url, Box::new(StdoutErrorReporter), extra_data)
|
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<ElementData>> {
|
||||||
|
unsafe { self.raw_node().mServoData.get().as_ref() }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn ensure_data(&self) -> &AtomicRefCell<ElementData> {
|
||||||
|
match self.get_node_data() {
|
||||||
|
Some(x) => x,
|
||||||
|
None => {
|
||||||
|
let ptr = Box::into_raw(Box::new(AtomicRefCell::new(ElementData::new())));
|
||||||
|
self.raw_node().mServoData.set(ptr);
|
||||||
|
unsafe { &* ptr }
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
lazy_static! {
|
lazy_static! {
|
||||||
|
@ -438,7 +397,7 @@ impl<'le> TElement for GeckoElement<'le> {
|
||||||
fn set_restyle_damage(self, damage: GeckoRestyleDamage) {
|
fn set_restyle_damage(self, damage: GeckoRestyleDamage) {
|
||||||
// FIXME(bholley): Gecko currently relies on the dirty bit being set to
|
// FIXME(bholley): Gecko currently relies on the dirty bit being set to
|
||||||
// drive the post-traversal. This will go away soon.
|
// 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) }
|
unsafe { Gecko_StoreStyleDifference(self.as_node().0, damage.0) }
|
||||||
}
|
}
|
||||||
|
@ -459,6 +418,41 @@ impl<'le> TElement for GeckoElement<'le> {
|
||||||
context_ptr.as_ref()
|
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<ElementData> {
|
||||||
|
let mut data = self.ensure_data().borrow_mut();
|
||||||
|
data.gather_previous_styles(|| self.get_styles_from_frame());
|
||||||
|
data
|
||||||
|
}
|
||||||
|
|
||||||
|
fn borrow_data(&self) -> Option<AtomicRef<ElementData>> {
|
||||||
|
self.get_node_data().map(|x| x.borrow())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'le> PartialEq for GeckoElement<'le> {
|
impl<'le> PartialEq for GeckoElement<'le> {
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
/* automatically generated by rust-bindgen */
|
/* automatically generated by rust-bindgen */
|
||||||
|
|
||||||
use atomic_refcell::AtomicRefCell;
|
use atomic_refcell::AtomicRefCell;
|
||||||
use data::NodeData;
|
use data::ElementData;
|
||||||
pub use nsstring::nsStringRepr as nsString;
|
pub use nsstring::nsStringRepr as nsString;
|
||||||
pub type ServoUnsafeCell<T> = ::std::cell::UnsafeCell<T>;
|
pub type ServoUnsafeCell<T> = ::std::cell::UnsafeCell<T>;
|
||||||
pub type ServoCell<T> = ::std::cell::Cell<T>;
|
pub type ServoCell<T> = ::std::cell::Cell<T>;
|
||||||
pub type ServoNodeData = AtomicRefCell<NodeData>;
|
pub type ServoNodeData = AtomicRefCell<ElementData>;
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
/* automatically generated by rust-bindgen */
|
/* automatically generated by rust-bindgen */
|
||||||
|
|
||||||
use atomic_refcell::AtomicRefCell;
|
use atomic_refcell::AtomicRefCell;
|
||||||
use data::NodeData;
|
use data::ElementData;
|
||||||
pub use nsstring::nsStringRepr as nsString;
|
pub use nsstring::nsStringRepr as nsString;
|
||||||
pub type ServoUnsafeCell<T> = ::std::cell::UnsafeCell<T>;
|
pub type ServoUnsafeCell<T> = ::std::cell::UnsafeCell<T>;
|
||||||
pub type ServoCell<T> = ::std::cell::Cell<T>;
|
pub type ServoCell<T> = ::std::cell::Cell<T>;
|
||||||
pub type ServoNodeData = AtomicRefCell<NodeData>;
|
pub type ServoNodeData = AtomicRefCell<ElementData>;
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
|
|
|
@ -11,7 +11,7 @@ use arc_ptr_eq;
|
||||||
use cache::{LRUCache, SimpleHashCache};
|
use cache::{LRUCache, SimpleHashCache};
|
||||||
use cascade_info::CascadeInfo;
|
use cascade_info::CascadeInfo;
|
||||||
use context::{SharedStyleContext, StyleContext};
|
use context::{SharedStyleContext, StyleContext};
|
||||||
use data::{NodeStyles, PseudoStyles};
|
use data::{ElementStyles, PseudoStyles};
|
||||||
use dom::{TElement, TNode, TRestyleDamage, UnsafeNode};
|
use dom::{TElement, TNode, TRestyleDamage, UnsafeNode};
|
||||||
use properties::{CascadeFlags, ComputedValues, SHAREABLE, cascade};
|
use properties::{CascadeFlags, ComputedValues, SHAREABLE, cascade};
|
||||||
use properties::longhands::display::computed_value as display;
|
use properties::longhands::display::computed_value as display;
|
||||||
|
@ -441,8 +441,7 @@ impl StyleSharingCandidateCache {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
let node = element.as_node();
|
let data = element.borrow_data().unwrap();
|
||||||
let data = node.borrow_data().unwrap();
|
|
||||||
let style = &data.current_styles().primary;
|
let style = &data.current_styles().primary;
|
||||||
|
|
||||||
let box_style = style.get_box();
|
let box_style = style.get_box();
|
||||||
|
@ -460,7 +459,7 @@ impl StyleSharingCandidateCache {
|
||||||
element.as_node().to_unsafe(), parent.as_node().to_unsafe());
|
element.as_node().to_unsafe(), parent.as_node().to_unsafe());
|
||||||
|
|
||||||
self.cache.insert(StyleSharingCandidate {
|
self.cache.insert(StyleSharingCandidate {
|
||||||
node: node.to_unsafe(),
|
node: element.as_node().to_unsafe(),
|
||||||
style: style.clone(),
|
style: style.clone(),
|
||||||
common_style_affecting_attributes: None,
|
common_style_affecting_attributes: None,
|
||||||
class_attributes: None,
|
class_attributes: None,
|
||||||
|
@ -716,8 +715,7 @@ pub trait MatchMethods : TElement {
|
||||||
match sharing_result {
|
match sharing_result {
|
||||||
Ok(shared_style) => {
|
Ok(shared_style) => {
|
||||||
// Yay, cache hit. Share the style.
|
// Yay, cache hit. Share the style.
|
||||||
let node = self.as_node();
|
let mut data = self.begin_styling();
|
||||||
let mut data = node.begin_styling();
|
|
||||||
|
|
||||||
// TODO: add the display: none optimisation here too! Even
|
// TODO: add the display: none optimisation here too! Even
|
||||||
// better, factor it out/make it a bit more generic so Gecko
|
// better, factor it out/make it a bit more generic so Gecko
|
||||||
|
@ -739,7 +737,7 @@ pub trait MatchMethods : TElement {
|
||||||
RestyleResult::Continue
|
RestyleResult::Continue
|
||||||
};
|
};
|
||||||
|
|
||||||
data.finish_styling(NodeStyles::new(shared_style));
|
data.finish_styling(ElementStyles::new(shared_style));
|
||||||
|
|
||||||
return StyleSharingResult::StyleWasShared(i, damage, restyle_result)
|
return StyleSharingResult::StyleWasShared(i, damage, restyle_result)
|
||||||
}
|
}
|
||||||
|
@ -863,12 +861,10 @@ pub trait MatchMethods : TElement {
|
||||||
where Ctx: StyleContext<'a>
|
where Ctx: StyleContext<'a>
|
||||||
{
|
{
|
||||||
// Get our parent's style.
|
// Get our parent's style.
|
||||||
let parent_as_node = parent.map(|x| x.as_node());
|
let parent_data = parent.as_ref().map(|x| x.borrow_data().unwrap());
|
||||||
let parent_data = parent_as_node.as_ref().map(|x| x.borrow_data().unwrap());
|
|
||||||
let parent_style = parent_data.as_ref().map(|x| &x.current_styles().primary);
|
let parent_style = parent_data.as_ref().map(|x| &x.current_styles().primary);
|
||||||
|
|
||||||
let node = self.as_node();
|
let mut data = self.begin_styling();
|
||||||
let mut data = node.begin_styling();
|
|
||||||
let mut new_styles;
|
let mut new_styles;
|
||||||
|
|
||||||
let mut applicable_declarations_cache =
|
let mut applicable_declarations_cache =
|
||||||
|
@ -886,7 +882,7 @@ pub trait MatchMethods : TElement {
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
new_styles = NodeStyles::new(
|
new_styles = ElementStyles::new(
|
||||||
self.cascade_node_pseudo_element(context,
|
self.cascade_node_pseudo_element(context,
|
||||||
parent_style.clone(),
|
parent_style.clone(),
|
||||||
old_primary,
|
old_primary,
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
|
|
||||||
#![allow(unsafe_code)]
|
#![allow(unsafe_code)]
|
||||||
|
|
||||||
use dom::{OpaqueNode, StylingMode, TNode, UnsafeNode};
|
use dom::{OpaqueNode, StylingMode, TElement, TNode, UnsafeNode};
|
||||||
use std::mem;
|
use std::mem;
|
||||||
use std::sync::atomic::Ordering;
|
use std::sync::atomic::Ordering;
|
||||||
use traversal::{RestyleResult, DomTraversalContext};
|
use traversal::{RestyleResult, DomTraversalContext};
|
||||||
|
@ -47,7 +47,7 @@ pub fn traverse_dom<N, C>(root: N,
|
||||||
where N: TNode,
|
where N: TNode,
|
||||||
C: DomTraversalContext<N>
|
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 {
|
if opts::get().style_sharing_stats {
|
||||||
STYLE_SHARING_CACHE_HITS.store(0, Ordering::SeqCst);
|
STYLE_SHARING_CACHE_HITS.store(0, Ordering::SeqCst);
|
||||||
STYLE_SHARING_CACHE_MISSES.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.
|
// Perform the appropriate traversal.
|
||||||
let mut children_to_process = 0isize;
|
let mut children_to_process = 0isize;
|
||||||
if let RestyleResult::Continue = context.process_preorder(node) {
|
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;
|
children_to_process += 1;
|
||||||
discovered_child_nodes.push(kid.to_unsafe())
|
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
|
// Reset the count of children if we need to do a bottom-up traversal
|
||||||
// after the top up.
|
// after the top up.
|
||||||
if context.needs_postorder_traversal() {
|
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 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)
|
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.
|
// Perform the appropriate operation.
|
||||||
context.process_postorder(node);
|
context.process_postorder(node);
|
||||||
|
|
||||||
let parent = match node.layout_parent_node(root) {
|
let parent = match node.layout_parent_element(root) {
|
||||||
None => break,
|
None => break,
|
||||||
Some(parent) => parent,
|
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.
|
// 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.
|
//! Implements sequential traversal over the DOM tree.
|
||||||
|
|
||||||
use dom::{StylingMode, TNode};
|
use dom::{StylingMode, TElement, TNode};
|
||||||
use traversal::{RestyleResult, DomTraversalContext};
|
use traversal::{RestyleResult, DomTraversalContext};
|
||||||
|
|
||||||
pub fn traverse_dom<N, C>(root: N,
|
pub fn traverse_dom<N, C>(root: N,
|
||||||
|
@ -17,7 +17,8 @@ pub fn traverse_dom<N, C>(root: N,
|
||||||
C: DomTraversalContext<N>
|
C: DomTraversalContext<N>
|
||||||
{
|
{
|
||||||
if let RestyleResult::Continue = context.process_preorder(node) {
|
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() {
|
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());
|
let context = C::new(shared, root.opaque());
|
||||||
doit::<N, C>(&context, root);
|
doit::<N, C>(&context, root);
|
||||||
|
|
||||||
|
|
|
@ -6,8 +6,8 @@
|
||||||
|
|
||||||
use atomic_refcell::AtomicRefCell;
|
use atomic_refcell::AtomicRefCell;
|
||||||
use context::{LocalStyleContext, SharedStyleContext, StyleContext};
|
use context::{LocalStyleContext, SharedStyleContext, StyleContext};
|
||||||
use data::NodeData;
|
use data::ElementData;
|
||||||
use dom::{NodeInfo, OpaqueNode, StylingMode, TElement, TNode, UnsafeNode};
|
use dom::{OpaqueNode, StylingMode, TElement, TNode, UnsafeNode};
|
||||||
use matching::{ApplicableDeclarations, MatchMethods, StyleSharingResult};
|
use matching::{ApplicableDeclarations, MatchMethods, StyleSharingResult};
|
||||||
use selectors::bloom::BloomFilter;
|
use selectors::bloom::BloomFilter;
|
||||||
use selectors::matching::StyleRelations;
|
use selectors::matching::StyleRelations;
|
||||||
|
@ -118,7 +118,7 @@ fn insert_ancestors_into_bloom_filter<E>(bf: &mut Box<BloomFilter>,
|
||||||
ancestors += 1;
|
ancestors += 1;
|
||||||
|
|
||||||
el.insert_into_bloom_filter(&mut **bf);
|
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,
|
None => break,
|
||||||
Some(p) => p,
|
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_node, unsafe_layout_node);
|
||||||
assert_eq!(old_generation, context.shared_context().generation);
|
assert_eq!(old_generation, context.shared_context().generation);
|
||||||
|
|
||||||
match node.layout_parent_node(root) {
|
match node.layout_parent_element(root) {
|
||||||
None => {
|
None => {
|
||||||
debug!("[{}] - {:X}, and deleting BF.", tid(), unsafe_layout_node.0);
|
debug!("[{}] - {:X}, and deleting BF.", tid(), unsafe_layout_node.0);
|
||||||
// If this is the reflow root, eat the thread-local bloom filter.
|
// 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) => {
|
Some(parent) => {
|
||||||
// Otherwise, put it back, but remove this node.
|
// Otherwise, put it back, but remove this node.
|
||||||
node.as_element().map(|x| x.remove_from_bloom_filter(&mut *bf));
|
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());
|
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.
|
/// If it's false, then process_postorder has no effect at all.
|
||||||
fn needs_postorder_traversal(&self) -> bool { true }
|
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
|
/// Helper for the traversal implementations to select the children that
|
||||||
/// should be enqueued for processing.
|
/// 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
|
// If we enqueue any children for traversal, we need to set the dirty
|
||||||
// descendants bit. Avoid doing it more than once.
|
// descendants bit. Avoid doing it more than once.
|
||||||
let mut marked_dirty_descendants = false;
|
let mut marked_dirty_descendants = false;
|
||||||
|
|
||||||
for kid in parent.children() {
|
for kid in parent.as_node().children() {
|
||||||
if kid.styling_mode() != StylingMode::Stop {
|
if Self::should_traverse_child(parent, kid) {
|
||||||
if !marked_dirty_descendants {
|
if !marked_dirty_descendants {
|
||||||
unsafe { parent.set_dirty_descendants(); }
|
unsafe { parent.set_dirty_descendants(); }
|
||||||
marked_dirty_descendants = true;
|
marked_dirty_descendants = true;
|
||||||
|
@ -194,10 +197,10 @@ pub trait DomTraversalContext<N: TNode> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Ensures the existence of the NodeData, and returns it. This can't live
|
/// Ensures the existence of the ElementData, and returns it. This can't live
|
||||||
/// on TNode because of the trait-based separation between Servo's script
|
/// on TNode because of the trait-based separation between Servo's script
|
||||||
/// and layout crates.
|
/// and layout crates.
|
||||||
fn ensure_node_data(node: &N) -> &AtomicRefCell<NodeData>;
|
fn ensure_element_data(element: &N::ConcreteElement) -> &AtomicRefCell<ElementData>;
|
||||||
|
|
||||||
fn local_context(&self) -> &LocalStyleContext;
|
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,
|
// We only need to mark whether we have display none, and forget about it,
|
||||||
// our style is up to date.
|
// our style is up to date.
|
||||||
let node = element.as_node();
|
if let Some(data) = element.borrow_data() {
|
||||||
if let Some(data) = node.borrow_data() {
|
|
||||||
if let Some(style) = data.get_current_styles().map(|x| &x.primary) {
|
if let Some(style) = data.get_current_styles().map(|x| &x.primary) {
|
||||||
if !*parents_had_display_none {
|
if !*parents_had_display_none {
|
||||||
*parents_had_display_none = style.get_box().clone_display() == display::T::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 bf = take_thread_local_bloom_filter(element.parent_element(), root, context.shared_context());
|
||||||
|
|
||||||
let mut restyle_result = RestyleResult::Continue;
|
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");
|
debug_assert!(mode != StylingMode::Stop, "Parent should not have enqueued us");
|
||||||
if mode != StylingMode::Traverse {
|
if mode != StylingMode::Traverse {
|
||||||
// Check to see whether we can share a style with someone.
|
// 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.
|
// fashion.
|
||||||
if mode == StylingMode::Restyle && restyle_result == RestyleResult::Continue {
|
if mode == StylingMode::Restyle && restyle_result == RestyleResult::Continue {
|
||||||
for kid in element.as_node().children() {
|
for kid in element.as_node().children() {
|
||||||
let mut data = D::ensure_node_data(&kid).borrow_mut();
|
if let Some(kid) = kid.as_element() {
|
||||||
if kid.is_text_node() {
|
let mut data = D::ensure_element_data(&kid).borrow_mut();
|
||||||
data.ensure_restyle_data();
|
|
||||||
} else {
|
|
||||||
data.gather_previous_styles(|| kid.get_styles_from_frame());
|
data.gather_previous_styles(|| kid.get_styles_from_frame());
|
||||||
if data.previous_styles().is_some() {
|
if data.previous_styles().is_some() {
|
||||||
data.ensure_restyle_data();
|
data.ensure_restyle_data();
|
||||||
|
|
1
ports/cef/Cargo.lock
generated
1
ports/cef/Cargo.lock
generated
|
@ -1101,6 +1101,7 @@ dependencies = [
|
||||||
"script 0.0.1",
|
"script 0.0.1",
|
||||||
"script_layout_interface 0.0.1",
|
"script_layout_interface 0.0.1",
|
||||||
"script_traits 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_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)",
|
"serde_json 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"style 0.0.1",
|
"style 0.0.1",
|
||||||
|
|
|
@ -73,9 +73,7 @@ pub extern "C" fn Servo_Shutdown() -> () {
|
||||||
unsafe { ComputedValues::shutdown(); }
|
unsafe { ComputedValues::shutdown(); }
|
||||||
}
|
}
|
||||||
|
|
||||||
fn restyle_subtree(node: GeckoNode, raw_data: RawServoStyleSetBorrowed) {
|
fn restyle_subtree(element: GeckoElement, raw_data: RawServoStyleSetBorrowed) {
|
||||||
debug_assert!(node.is_element() || node.is_text_node());
|
|
||||||
|
|
||||||
// Force the creation of our lazily-constructed initial computed values on
|
// Force the creation of our lazily-constructed initial computed values on
|
||||||
// the main thread, since it's not safe to call elsewhere.
|
// 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(),
|
timer: Timer::new(),
|
||||||
};
|
};
|
||||||
|
|
||||||
if node.styling_mode() == StylingMode::Stop {
|
if element.styling_mode() == StylingMode::Stop {
|
||||||
error!("Unnecessary call to restyle_subtree");
|
error!("Unnecessary call to restyle_subtree");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if per_doc_data.num_threads == 1 || per_doc_data.work_queue.is_none() {
|
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 {
|
} else {
|
||||||
parallel::traverse_dom::<GeckoNode, RecalcStyleOnly>(node, &shared_style_context,
|
parallel::traverse_dom::<_, RecalcStyleOnly>(element.as_node(), &shared_style_context,
|
||||||
per_doc_data.work_queue.as_mut().unwrap());
|
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,
|
pub extern "C" fn Servo_RestyleSubtree(node: RawGeckoNodeBorrowed,
|
||||||
raw_data: RawServoStyleSetBorrowed) -> () {
|
raw_data: RawServoStyleSetBorrowed) -> () {
|
||||||
let node = GeckoNode(node);
|
let node = GeckoNode(node);
|
||||||
restyle_subtree(node, raw_data);
|
if let Some(element) = node.as_element() {
|
||||||
|
restyle_subtree(element, raw_data);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
|
@ -158,8 +158,9 @@ pub extern "C" fn Servo_StyleWorkerThreadCount() -> u32 {
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub extern "C" fn Servo_Node_ClearNodeData(node: RawGeckoNodeBorrowed) -> () {
|
pub extern "C" fn Servo_Node_ClearNodeData(node: RawGeckoNodeBorrowed) -> () {
|
||||||
let node = GeckoNode(node);
|
if let Some(element) = GeckoNode(node).as_element() {
|
||||||
node.clear_data();
|
element.clear_data();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
|
@ -253,7 +254,20 @@ pub extern "C" fn Servo_StyleSheet_Release(sheet: RawServoStyleSheetBorrowed) ->
|
||||||
pub extern "C" fn Servo_ComputedValues_Get(node: RawGeckoNodeBorrowed)
|
pub extern "C" fn Servo_ComputedValues_Get(node: RawGeckoNodeBorrowed)
|
||||||
-> ServoComputedValuesStrong {
|
-> ServoComputedValuesStrong {
|
||||||
let node = GeckoNode(node);
|
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_else(|| 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()) {
|
let arc_cv = match data.as_ref().and_then(|x| x.get_current_styles()) {
|
||||||
Some(styles) => styles.primary.clone(),
|
Some(styles) => styles.primary.clone(),
|
||||||
None => {
|
None => {
|
||||||
|
@ -315,8 +329,7 @@ pub extern "C" fn Servo_ComputedValues_GetForPseudoElement(parent_style: ServoCo
|
||||||
|
|
||||||
match GeckoSelectorImpl::pseudo_element_cascade_type(&pseudo) {
|
match GeckoSelectorImpl::pseudo_element_cascade_type(&pseudo) {
|
||||||
PseudoElementCascadeType::Eager => {
|
PseudoElementCascadeType::Eager => {
|
||||||
let node = element.as_node();
|
let maybe_computed = element.get_pseudo_style(&pseudo);
|
||||||
let maybe_computed = node.get_pseudo_style(&pseudo);
|
|
||||||
maybe_computed.map_or_else(parent_or_null, FFIArcHelpers::into_strong)
|
maybe_computed.map_or_else(parent_or_null, FFIArcHelpers::into_strong)
|
||||||
}
|
}
|
||||||
PseudoElementCascadeType::Lazy => {
|
PseudoElementCascadeType::Lazy => {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue