Hoist most styling functionality from TNode to TElement.

MozReview-Commit-ID: DZ8ZrsZIiAU
This commit is contained in:
Bobby Holley 2016-10-26 22:56:59 -07:00
parent 47d29fd056
commit 5442fbec3f
17 changed files with 399 additions and 363 deletions

View file

@ -5,9 +5,9 @@
use atomic_refcell::AtomicRefCell;
use context::{LocalStyleContext, SharedStyleContext, StyleContext};
use data::NodeData;
use dom::{NodeInfo, OpaqueNode, TNode};
use dom::{NodeInfo, OpaqueNode, StylingMode, TElement, TNode};
use gecko::context::StandaloneStyleContext;
use gecko::wrapper::GeckoNode;
use gecko::wrapper::{GeckoElement, GeckoNode};
use std::mem;
use traversal::{DomTraversalContext, recalc_style_at};
use traversal::RestyleResult;
@ -48,8 +48,15 @@ impl<'lc, 'ln> DomTraversalContext<GeckoNode<'ln>> for RecalcStyleOnly<'lc> {
/// We don't use the post-order traversal for anything.
fn needs_postorder_traversal(&self) -> bool { false }
fn ensure_node_data<'a>(node: &'a GeckoNode<'ln>) -> &'a AtomicRefCell<NodeData> {
node.ensure_data()
fn should_traverse_child(_parent: GeckoElement<'ln>, child: GeckoNode<'ln>) -> bool {
match child.as_element() {
Some(el) => el.styling_mode() != StylingMode::Stop,
None => false, // Gecko restyle doesn't need to traverse text nodes.
}
}
fn ensure_element_data<'a>(element: &'a GeckoElement<'ln>) -> &'a AtomicRefCell<NodeData> {
element.ensure_data()
}
fn local_context(&self) -> &LocalStyleContext {

View file

@ -64,51 +64,6 @@ impl<'ln> GeckoNode<'ln> {
debug_assert!(!self.0.mNodeInfo.mRawPtr.is_null());
unsafe { &*self.0.mNodeInfo.mRawPtr }
}
fn flags(&self) -> u32 {
(self.0)._base._base_1.mFlags
}
// FIXME: We can implement this without OOL calls, but we can't easily given
// GeckoNode is a raw reference.
//
// We can use a Cell<T>, but that's a bit of a pain.
fn set_flags(&self, flags: u32) {
unsafe { Gecko_SetNodeFlags(self.0, flags) }
}
pub fn clear_data(&self) {
let ptr = self.0.mServoData.get();
if !ptr.is_null() {
let data = unsafe { Box::from_raw(self.0.mServoData.get()) };
self.0.mServoData.set(ptr::null_mut());
// Perform a mutable borrow of the data in debug builds. This
// serves as an assertion that there are no outstanding borrows
// when we destroy the data.
debug_assert!({ let _ = data.borrow_mut(); true });
}
}
pub fn get_pseudo_style(&self, pseudo: &PseudoElement) -> Option<Arc<ComputedValues>> {
self.borrow_data().and_then(|data| data.current_styles().pseudos
.get(pseudo).map(|c| c.clone()))
}
fn get_node_data(&self) -> Option<&AtomicRefCell<NodeData>> {
unsafe { self.0.mServoData.get().as_ref() }
}
pub fn ensure_data(&self) -> &AtomicRefCell<NodeData> {
match self.get_node_data() {
Some(x) => x,
None => {
let ptr = Box::into_raw(Box::new(AtomicRefCell::new(NodeData::new())));
self.0.mServoData.set(ptr);
unsafe { &* ptr }
},
}
}
}
#[derive(Clone, Copy, Debug, PartialEq)]
@ -192,11 +147,11 @@ impl<'ln> TNode for GeckoNode<'ln> {
OpaqueNode(ptr)
}
fn layout_parent_node(self, reflow_root: OpaqueNode) -> Option<GeckoNode<'ln>> {
fn layout_parent_element(self, reflow_root: OpaqueNode) -> Option<GeckoElement<'ln>> {
if self.opaque() == reflow_root {
None
} else {
self.parent_node()
self.parent_node().and_then(|x| x.as_element())
}
}
@ -216,23 +171,6 @@ impl<'ln> TNode for GeckoNode<'ln> {
unimplemented!()
}
fn deprecated_dirty_bit_is_set(&self) -> bool {
self.flags() & (NODE_IS_DIRTY_FOR_SERVO as u32) != 0
}
fn has_dirty_descendants(&self) -> bool {
// Return true unconditionally if we're not yet styled. This is a hack
// and should go away soon.
if self.get_node_data().is_none() {
return true;
}
self.flags() & (NODE_HAS_DIRTY_DESCENDANTS_FOR_SERVO as u32) != 0
}
unsafe fn set_dirty_descendants(&self) {
self.set_flags(NODE_HAS_DIRTY_DESCENDANTS_FOR_SERVO as u32)
}
fn can_be_fragmented(&self) -> bool {
// FIXME(SimonSapin): Servo uses this to implement CSS multicol / fragmentation
// Maybe this isnt useful for Gecko?
@ -244,34 +182,6 @@ impl<'ln> TNode for GeckoNode<'ln> {
// Maybe this isnt useful for Gecko?
}
fn store_children_to_process(&self, _: isize) {
// This is only used for bottom-up traversal, and is thus a no-op for Gecko.
}
fn did_process_child(&self) -> isize {
panic!("Atomic child count not implemented in Gecko");
}
fn begin_styling(&self) -> AtomicRefMut<NodeData> {
let mut data = self.ensure_data().borrow_mut();
data.gather_previous_styles(|| self.get_styles_from_frame());
data
}
fn style_text_node(&self, style: Arc<ComputedValues>) {
debug_assert!(self.is_text_node());
// FIXME(bholley): Gecko currently relies on the dirty bit being set to
// drive the post-traversal. This will go away soon.
unsafe { self.set_flags(NODE_IS_DIRTY_FOR_SERVO as u32); }
self.ensure_data().borrow_mut().style_text_node(style);
}
fn borrow_data(&self) -> Option<AtomicRef<NodeData>> {
self.get_node_data().map(|x| x.borrow())
}
fn parent_node(&self) -> Option<GeckoNode<'ln>> {
unsafe { self.0.mParent.as_ref().map(GeckoNode) }
}
@ -387,6 +297,55 @@ impl<'le> GeckoElement<'le> {
let extra_data = ParserContextExtraData::default();
parse_style_attribute(value, &base_url, Box::new(StdoutErrorReporter), extra_data)
}
fn flags(&self) -> u32 {
self.raw_node()._base._base_1.mFlags
}
fn raw_node(&self) -> &RawGeckoNode {
&(self.0)._base._base._base
}
// FIXME: We can implement this without OOL calls, but we can't easily given
// GeckoNode is a raw reference.
//
// We can use a Cell<T>, but that's a bit of a pain.
fn set_flags(&self, flags: u32) {
unsafe { Gecko_SetNodeFlags(self.as_node().0, flags) }
}
pub fn clear_data(&self) {
let ptr = self.raw_node().mServoData.get();
if !ptr.is_null() {
let data = unsafe { Box::from_raw(self.raw_node().mServoData.get()) };
self.raw_node().mServoData.set(ptr::null_mut());
// Perform a mutable borrow of the data in debug builds. This
// serves as an assertion that there are no outstanding borrows
// when we destroy the data.
debug_assert!({ let _ = data.borrow_mut(); true });
}
}
pub fn get_pseudo_style(&self, pseudo: &PseudoElement) -> Option<Arc<ComputedValues>> {
self.borrow_data().and_then(|data| data.current_styles().pseudos
.get(pseudo).map(|c| c.clone()))
}
fn get_node_data(&self) -> Option<&AtomicRefCell<NodeData>> {
unsafe { self.raw_node().mServoData.get().as_ref() }
}
pub fn ensure_data(&self) -> &AtomicRefCell<NodeData> {
match self.get_node_data() {
Some(x) => x,
None => {
let ptr = Box::into_raw(Box::new(AtomicRefCell::new(NodeData::new())));
self.raw_node().mServoData.set(ptr);
unsafe { &* ptr }
},
}
}
}
lazy_static! {
@ -438,7 +397,7 @@ impl<'le> TElement for GeckoElement<'le> {
fn set_restyle_damage(self, damage: GeckoRestyleDamage) {
// FIXME(bholley): Gecko currently relies on the dirty bit being set to
// drive the post-traversal. This will go away soon.
unsafe { self.as_node().set_flags(NODE_IS_DIRTY_FOR_SERVO as u32) }
unsafe { self.set_flags(NODE_IS_DIRTY_FOR_SERVO as u32) }
unsafe { Gecko_StoreStyleDifference(self.as_node().0, damage.0) }
}
@ -459,6 +418,41 @@ impl<'le> TElement for GeckoElement<'le> {
context_ptr.as_ref()
}
}
fn deprecated_dirty_bit_is_set(&self) -> bool {
self.flags() & (NODE_IS_DIRTY_FOR_SERVO as u32) != 0
}
fn has_dirty_descendants(&self) -> bool {
// Return true unconditionally if we're not yet styled. This is a hack
// and should go away soon.
if self.get_node_data().is_none() {
return true;
}
self.flags() & (NODE_HAS_DIRTY_DESCENDANTS_FOR_SERVO as u32) != 0
}
unsafe fn set_dirty_descendants(&self) {
self.set_flags(NODE_HAS_DIRTY_DESCENDANTS_FOR_SERVO as u32)
}
fn store_children_to_process(&self, _: isize) {
// This is only used for bottom-up traversal, and is thus a no-op for Gecko.
}
fn did_process_child(&self) -> isize {
panic!("Atomic child count not implemented in Gecko");
}
fn begin_styling(&self) -> AtomicRefMut<NodeData> {
let mut data = self.ensure_data().borrow_mut();
data.gather_previous_styles(|| self.get_styles_from_frame());
data
}
fn borrow_data(&self) -> Option<AtomicRef<NodeData>> {
self.get_node_data().map(|x| x.borrow())
}
}
impl<'le> PartialEq for GeckoElement<'le> {