mirror of
https://github.com/servo/servo.git
synced 2025-07-23 15:23:42 +01:00
Hoist exported ThreadSafeLayoutFoo functionality into traits.
This commit is contained in:
parent
05db7b3652
commit
a85ae24c51
8 changed files with 237 additions and 174 deletions
|
@ -57,7 +57,7 @@ use traversal::PostorderNodeMutTraversal;
|
||||||
use url::Url;
|
use url::Url;
|
||||||
use util::linked_list;
|
use util::linked_list;
|
||||||
use util::opts;
|
use util::opts;
|
||||||
use wrapper::{PseudoElementType, TextContent, ThreadSafeLayoutNode};
|
use wrapper::{PseudoElementType, TextContent, ThreadSafeLayoutNode, TThreadSafeLayoutElement, TThreadSafeLayoutNode};
|
||||||
|
|
||||||
/// The results of flow construction for a DOM node.
|
/// The results of flow construction for a DOM node.
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
|
|
|
@ -58,7 +58,7 @@ use table_rowgroup::TableRowGroupFlow;
|
||||||
use table_wrapper::TableWrapperFlow;
|
use table_wrapper::TableWrapperFlow;
|
||||||
use util::geometry::ZERO_RECT;
|
use util::geometry::ZERO_RECT;
|
||||||
use util::logical_geometry::{LogicalRect, LogicalSize, WritingMode};
|
use util::logical_geometry::{LogicalRect, LogicalSize, WritingMode};
|
||||||
use wrapper::{PseudoElementType, ThreadSafeLayoutNode};
|
use wrapper::{PseudoElementType, ThreadSafeLayoutNode, TThreadSafeLayoutNode};
|
||||||
|
|
||||||
/// Virtual methods that make up a float context.
|
/// Virtual methods that make up a float context.
|
||||||
///
|
///
|
||||||
|
|
|
@ -50,7 +50,7 @@ use util::geometry::ZERO_POINT;
|
||||||
use util::logical_geometry::{LogicalMargin, LogicalRect, LogicalSize, WritingMode};
|
use util::logical_geometry::{LogicalMargin, LogicalRect, LogicalSize, WritingMode};
|
||||||
use util::range::*;
|
use util::range::*;
|
||||||
use util::str::slice_chars;
|
use util::str::slice_chars;
|
||||||
use wrapper::{PseudoElementType, ThreadSafeLayoutNode};
|
use wrapper::{PseudoElementType, ThreadSafeLayoutNode, TThreadSafeLayoutElement, TThreadSafeLayoutNode};
|
||||||
|
|
||||||
/// Fragments (`struct Fragment`) are the leaves of the layout tree. They cannot position
|
/// Fragments (`struct Fragment`) are the leaves of the layout tree. They cannot position
|
||||||
/// themselves. In general, fragments do not have a simple correspondence with CSS fragments in the
|
/// themselves. In general, fragments do not have a simple correspondence with CSS fragments in the
|
||||||
|
|
|
@ -73,7 +73,7 @@ use util::opts;
|
||||||
use util::task;
|
use util::task;
|
||||||
use util::task_state;
|
use util::task_state;
|
||||||
use util::workqueue::WorkQueue;
|
use util::workqueue::WorkQueue;
|
||||||
use wrapper::{LayoutDocument, LayoutElement, LayoutNode, ServoLayoutNode};
|
use wrapper::{LayoutDocument, LayoutElement, LayoutNode, ServoLayoutNode, TThreadSafeLayoutNode};
|
||||||
|
|
||||||
/// The number of screens of data we're allowed to generate display lists for in each direction.
|
/// The number of screens of data we're allowed to generate display lists for in each direction.
|
||||||
pub const DISPLAY_PORT_SIZE_FACTOR: i32 = 8;
|
pub const DISPLAY_PORT_SIZE_FACTOR: i32 = 8;
|
||||||
|
|
|
@ -31,7 +31,7 @@ use style::values::AuExtensionMethods;
|
||||||
use util::cursor::Cursor;
|
use util::cursor::Cursor;
|
||||||
use util::geometry::ZERO_POINT;
|
use util::geometry::ZERO_POINT;
|
||||||
use util::logical_geometry::WritingMode;
|
use util::logical_geometry::WritingMode;
|
||||||
use wrapper::{LayoutNode, ServoLayoutNode, ThreadSafeLayoutNode};
|
use wrapper::{LayoutNode, ServoLayoutNode, ThreadSafeLayoutNode, TThreadSafeLayoutNode};
|
||||||
|
|
||||||
pub struct LayoutRPCImpl(pub Arc<Mutex<LayoutTaskData>>);
|
pub struct LayoutRPCImpl(pub Arc<Mutex<LayoutTaskData>>);
|
||||||
|
|
||||||
|
|
|
@ -24,7 +24,7 @@ use style::properties::ComputedValues;
|
||||||
use table::InternalTable;
|
use table::InternalTable;
|
||||||
use table_row::{CollapsedBorder, CollapsedBorderProvenance};
|
use table_row::{CollapsedBorder, CollapsedBorderProvenance};
|
||||||
use util::logical_geometry::{LogicalMargin, LogicalRect, LogicalSize, WritingMode};
|
use util::logical_geometry::{LogicalMargin, LogicalRect, LogicalSize, WritingMode};
|
||||||
use wrapper::ThreadSafeLayoutNode;
|
use wrapper::{ThreadSafeLayoutNode, TThreadSafeLayoutNode};
|
||||||
|
|
||||||
/// A table formatting context.
|
/// A table formatting context.
|
||||||
#[derive(RustcEncodable)]
|
#[derive(RustcEncodable)]
|
||||||
|
|
|
@ -18,7 +18,7 @@ use std::mem;
|
||||||
use util::opts;
|
use util::opts;
|
||||||
use util::tid::tid;
|
use util::tid::tid;
|
||||||
use wrapper::{LayoutNode, ServoLayoutNode, layout_node_to_unsafe_layout_node};
|
use wrapper::{LayoutNode, ServoLayoutNode, layout_node_to_unsafe_layout_node};
|
||||||
use wrapper::{ThreadSafeLayoutNode, UnsafeLayoutNode};
|
use wrapper::{ThreadSafeLayoutNode, TThreadSafeLayoutNode, UnsafeLayoutNode};
|
||||||
|
|
||||||
/// Every time we do another layout, the old bloom filters are invalid. This is
|
/// Every time we do another layout, the old bloom filters are invalid. This is
|
||||||
/// detected by ticking a generation number every layout.
|
/// detected by ticking a generation number every layout.
|
||||||
|
|
|
@ -792,6 +792,163 @@ impl<T> PseudoElementType<T> {
|
||||||
|
|
||||||
/// A thread-safe version of `LayoutNode`, used during flow construction. This type of layout
|
/// A thread-safe version of `LayoutNode`, used during flow construction. This type of layout
|
||||||
/// node does not allow any parents or siblings of nodes to be accessed, to avoid races.
|
/// node does not allow any parents or siblings of nodes to be accessed, to avoid races.
|
||||||
|
|
||||||
|
pub trait TThreadSafeLayoutNode<'ln> : Clone + Copy + Sized {
|
||||||
|
type ConcreteThreadSafeLayoutElement: TThreadSafeLayoutElement<'ln>;
|
||||||
|
|
||||||
|
/// Converts self into an `OpaqueNode`.
|
||||||
|
fn opaque(&self) -> OpaqueNode;
|
||||||
|
|
||||||
|
/// Returns the type ID of this node.
|
||||||
|
/// Returns `None` if this is a pseudo-element; otherwise, returns `Some`.
|
||||||
|
fn type_id(&self) -> Option<NodeTypeId>;
|
||||||
|
|
||||||
|
fn debug_id(self) -> usize;
|
||||||
|
|
||||||
|
fn flow_debug_id(self) -> usize;
|
||||||
|
|
||||||
|
/// Returns an iterator over this node's children.
|
||||||
|
fn children(&self) -> ThreadSafeLayoutNodeChildrenIterator<'ln, Self>;
|
||||||
|
|
||||||
|
/// If this is an element, accesses the element data. Fails if this is not an element node.
|
||||||
|
#[inline]
|
||||||
|
fn as_element(&self) -> Self::ConcreteThreadSafeLayoutElement;
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn get_pseudo_element_type(&self) -> PseudoElementType<display::T>;
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn get_before_pseudo(&self) -> Option<Self>;
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn get_after_pseudo(&self) -> Option<Self>;
|
||||||
|
|
||||||
|
/// Borrows the layout data immutably. Fails on a conflicting borrow.
|
||||||
|
///
|
||||||
|
/// TODO(pcwalton): Make this private. It will let us avoid borrow flag checks in some cases.
|
||||||
|
#[inline(always)]
|
||||||
|
fn borrow_layout_data(&self) -> Ref<Option<LayoutDataWrapper>>;
|
||||||
|
|
||||||
|
/// Borrows the layout data mutably. Fails on a conflicting borrow.
|
||||||
|
///
|
||||||
|
/// TODO(pcwalton): Make this private. It will let us avoid borrow flag checks in some cases.
|
||||||
|
#[inline(always)]
|
||||||
|
fn mutate_layout_data(&self) -> RefMut<Option<LayoutDataWrapper>>;
|
||||||
|
|
||||||
|
/// Returns the style results for the given node. If CSS selector matching
|
||||||
|
/// has not yet been performed, fails.
|
||||||
|
#[inline]
|
||||||
|
fn style(&self) -> Ref<Arc<ComputedValues>> {
|
||||||
|
Ref::map(self.borrow_layout_data(), |layout_data_ref| {
|
||||||
|
let layout_data = layout_data_ref.as_ref().expect("no layout data");
|
||||||
|
let style = match self.get_pseudo_element_type() {
|
||||||
|
PseudoElementType::Before(_) => &layout_data.data.before_style,
|
||||||
|
PseudoElementType::After(_) => &layout_data.data.after_style,
|
||||||
|
PseudoElementType::Normal => &layout_data.shared_data.style,
|
||||||
|
};
|
||||||
|
style.as_ref().unwrap()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Removes the style from this node.
|
||||||
|
fn unstyle(self) {
|
||||||
|
let mut layout_data_ref = self.mutate_layout_data();
|
||||||
|
let layout_data = layout_data_ref.as_mut().expect("no layout data");
|
||||||
|
|
||||||
|
let style =
|
||||||
|
match self.get_pseudo_element_type() {
|
||||||
|
PseudoElementType::Before(_) => &mut layout_data.data.before_style,
|
||||||
|
PseudoElementType::After (_) => &mut layout_data.data.after_style,
|
||||||
|
PseudoElementType::Normal => &mut layout_data.shared_data.style,
|
||||||
|
};
|
||||||
|
|
||||||
|
*style = None;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn is_ignorable_whitespace(&self) -> bool;
|
||||||
|
|
||||||
|
/// Get the description of how to account for recent style changes.
|
||||||
|
/// This is a simple bitfield and fine to copy by value.
|
||||||
|
fn restyle_damage(self) -> RestyleDamage {
|
||||||
|
let layout_data_ref = self.borrow_layout_data();
|
||||||
|
layout_data_ref.as_ref().unwrap().data.restyle_damage
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Set the restyle damage field.
|
||||||
|
fn set_restyle_damage(self, damage: RestyleDamage) {
|
||||||
|
let mut layout_data_ref = self.mutate_layout_data();
|
||||||
|
match *layout_data_ref {
|
||||||
|
Some(ref mut layout_data) => layout_data.data.restyle_damage = damage,
|
||||||
|
_ => panic!("no layout data for this node"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns the layout data flags for this node.
|
||||||
|
fn flags(self) -> LayoutDataFlags;
|
||||||
|
|
||||||
|
/// Adds the given flags to this node.
|
||||||
|
fn insert_flags(self, new_flags: LayoutDataFlags) {
|
||||||
|
let mut layout_data_ref = self.mutate_layout_data();
|
||||||
|
match *layout_data_ref {
|
||||||
|
Some(ref mut layout_data) => layout_data.data.flags.insert(new_flags),
|
||||||
|
_ => panic!("no layout data for this node"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Removes the given flags from this node.
|
||||||
|
fn remove_flags(self, flags: LayoutDataFlags) {
|
||||||
|
let mut layout_data_ref = self.mutate_layout_data();
|
||||||
|
match *layout_data_ref {
|
||||||
|
Some(ref mut layout_data) => layout_data.data.flags.remove(flags),
|
||||||
|
_ => panic!("no layout data for this node"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns true if this node contributes content. This is used in the implementation of
|
||||||
|
/// `empty_cells` per CSS 2.1 § 17.6.1.1.
|
||||||
|
fn is_content(&self) -> bool {
|
||||||
|
match self.type_id() {
|
||||||
|
Some(NodeTypeId::Element(..)) | Some(NodeTypeId::CharacterData(CharacterDataTypeId::Text(..))) => true,
|
||||||
|
_ => false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// If this is a text node, generated content, or a form element, copies out
|
||||||
|
/// its content. Otherwise, panics.
|
||||||
|
///
|
||||||
|
/// FIXME(pcwalton): This might have too much copying and/or allocation. Profile this.
|
||||||
|
fn text_content(&self) -> TextContent;
|
||||||
|
|
||||||
|
/// If the insertion point is within this node, returns it. Otherwise, returns `None`.
|
||||||
|
fn insertion_point(&self) -> Option<CharIndex>;
|
||||||
|
|
||||||
|
/// If this is an image element, returns its URL. If this is not an image element, fails.
|
||||||
|
///
|
||||||
|
/// FIXME(pcwalton): Don't copy URLs.
|
||||||
|
fn image_url(&self) -> Option<Url>;
|
||||||
|
|
||||||
|
fn canvas_data(&self) -> Option<HTMLCanvasData>;
|
||||||
|
|
||||||
|
/// If this node is an iframe element, returns its pipeline ID. If this node is
|
||||||
|
/// not an iframe element, fails.
|
||||||
|
fn iframe_pipeline_id(&self) -> PipelineId;
|
||||||
|
|
||||||
|
fn get_colspan(&self) -> u32;
|
||||||
|
}
|
||||||
|
|
||||||
|
// These can violate the thread-safety and therefore are not public.
|
||||||
|
trait DangerousThreadSafeLayoutNode<'ln> : TThreadSafeLayoutNode<'ln> {
|
||||||
|
unsafe fn dangerous_first_child(&self) -> Option<Self>;
|
||||||
|
unsafe fn dangerous_next_sibling(&self) -> Option<Self>;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait TThreadSafeLayoutElement<'le> {
|
||||||
|
type ConcreteThreadSafeLayoutNode: TThreadSafeLayoutNode<'le>;
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn get_attr(&self, namespace: &Namespace, name: &Atom) -> Option<&'le str>;
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Copy, Clone)]
|
#[derive(Copy, Clone)]
|
||||||
pub struct ThreadSafeLayoutNode<'ln> {
|
pub struct ThreadSafeLayoutNode<'ln> {
|
||||||
/// The wrapped node.
|
/// The wrapped node.
|
||||||
|
@ -800,6 +957,17 @@ pub struct ThreadSafeLayoutNode<'ln> {
|
||||||
pseudo: PseudoElementType<display::T>,
|
pseudo: PseudoElementType<display::T>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<'ln> DangerousThreadSafeLayoutNode<'ln> for ThreadSafeLayoutNode<'ln> {
|
||||||
|
unsafe fn dangerous_first_child(&self) -> Option<Self> {
|
||||||
|
self.get_jsmanaged().first_child_ref()
|
||||||
|
.map(|node| self.new_with_this_lifetime(&node))
|
||||||
|
}
|
||||||
|
unsafe fn dangerous_next_sibling(&self) -> Option<Self> {
|
||||||
|
self.get_jsmanaged().next_sibling_ref()
|
||||||
|
.map(|node| self.new_with_this_lifetime(&node))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<'ln> ThreadSafeLayoutNode<'ln> {
|
impl<'ln> ThreadSafeLayoutNode<'ln> {
|
||||||
/// Creates a new layout node with the same lifetime as this layout node.
|
/// Creates a new layout node with the same lifetime as this layout node.
|
||||||
pub unsafe fn new_with_this_lifetime(&self, node: &LayoutJS<Node>) -> ThreadSafeLayoutNode<'ln> {
|
pub unsafe fn new_with_this_lifetime(&self, node: &LayoutJS<Node>) -> ThreadSafeLayoutNode<'ln> {
|
||||||
|
@ -832,14 +1000,23 @@ impl<'ln> ThreadSafeLayoutNode<'ln> {
|
||||||
self.node.get_jsmanaged()
|
self.node.get_jsmanaged()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Converts self into an `OpaqueNode`.
|
/// Borrows the layout data without checking.
|
||||||
pub fn opaque(&self) -> OpaqueNode {
|
#[inline(always)]
|
||||||
|
fn borrow_layout_data_unchecked(&self) -> *const Option<LayoutDataWrapper> {
|
||||||
|
unsafe {
|
||||||
|
self.node.borrow_layout_data_unchecked()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'ln> TThreadSafeLayoutNode<'ln> for ThreadSafeLayoutNode<'ln> {
|
||||||
|
type ConcreteThreadSafeLayoutElement = ThreadSafeLayoutElement<'ln>;
|
||||||
|
|
||||||
|
fn opaque(&self) -> OpaqueNode {
|
||||||
OpaqueNodeMethods::from_jsmanaged(unsafe { self.get_jsmanaged() })
|
OpaqueNodeMethods::from_jsmanaged(unsafe { self.get_jsmanaged() })
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the type ID of this node.
|
fn type_id(&self) -> Option<NodeTypeId> {
|
||||||
/// Returns `None` if this is a pseudo-element; otherwise, returns `Some`.
|
|
||||||
pub fn type_id(&self) -> Option<NodeTypeId> {
|
|
||||||
if self.pseudo != PseudoElementType::Normal {
|
if self.pseudo != PseudoElementType::Normal {
|
||||||
return None
|
return None
|
||||||
}
|
}
|
||||||
|
@ -847,22 +1024,19 @@ impl<'ln> ThreadSafeLayoutNode<'ln> {
|
||||||
Some(self.node.type_id())
|
Some(self.node.type_id())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn debug_id(self) -> usize {
|
fn debug_id(self) -> usize {
|
||||||
self.node.debug_id()
|
self.node.debug_id()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn flow_debug_id(self) -> usize {
|
fn flow_debug_id(self) -> usize {
|
||||||
self.node.flow_debug_id()
|
self.node.flow_debug_id()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns an iterator over this node's children.
|
fn children(&self) -> ThreadSafeLayoutNodeChildrenIterator<'ln, Self> {
|
||||||
pub fn children(&self) -> ThreadSafeLayoutNodeChildrenIterator<'ln> {
|
|
||||||
ThreadSafeLayoutNodeChildrenIterator::new(*self)
|
ThreadSafeLayoutNodeChildrenIterator::new(*self)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// If this is an element, accesses the element data. Fails if this is not an element node.
|
fn as_element(&self) -> ThreadSafeLayoutElement<'ln> {
|
||||||
#[inline]
|
|
||||||
pub fn as_element(&self) -> ThreadSafeLayoutElement<'ln> {
|
|
||||||
unsafe {
|
unsafe {
|
||||||
let element = match self.get_jsmanaged().downcast() {
|
let element = match self.get_jsmanaged().downcast() {
|
||||||
Some(e) => e.unsafe_get(),
|
Some(e) => e.unsafe_get(),
|
||||||
|
@ -876,13 +1050,11 @@ impl<'ln> ThreadSafeLayoutNode<'ln> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
fn get_pseudo_element_type(&self) -> PseudoElementType<display::T> {
|
||||||
pub fn get_pseudo_element_type(&self) -> PseudoElementType<display::T> {
|
|
||||||
self.pseudo
|
self.pseudo
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
fn get_before_pseudo(&self) -> Option<ThreadSafeLayoutNode<'ln>> {
|
||||||
pub fn get_before_pseudo(&self) -> Option<ThreadSafeLayoutNode<'ln>> {
|
|
||||||
let layout_data_ref = self.borrow_layout_data();
|
let layout_data_ref = self.borrow_layout_data();
|
||||||
let node_layout_data_wrapper = layout_data_ref.as_ref().unwrap();
|
let node_layout_data_wrapper = layout_data_ref.as_ref().unwrap();
|
||||||
node_layout_data_wrapper.data.before_style.as_ref().map(|style| {
|
node_layout_data_wrapper.data.before_style.as_ref().map(|style| {
|
||||||
|
@ -890,8 +1062,7 @@ impl<'ln> ThreadSafeLayoutNode<'ln> {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
fn get_after_pseudo(&self) -> Option<ThreadSafeLayoutNode<'ln>> {
|
||||||
pub fn get_after_pseudo(&self) -> Option<ThreadSafeLayoutNode<'ln>> {
|
|
||||||
let layout_data_ref = self.borrow_layout_data();
|
let layout_data_ref = self.borrow_layout_data();
|
||||||
let node_layout_data_wrapper = layout_data_ref.as_ref().unwrap();
|
let node_layout_data_wrapper = layout_data_ref.as_ref().unwrap();
|
||||||
node_layout_data_wrapper.data.after_style.as_ref().map(|style| {
|
node_layout_data_wrapper.data.after_style.as_ref().map(|style| {
|
||||||
|
@ -899,61 +1070,15 @@ impl<'ln> ThreadSafeLayoutNode<'ln> {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Borrows the layout data without checking.
|
fn borrow_layout_data(&self) -> Ref<Option<LayoutDataWrapper>> {
|
||||||
#[inline(always)]
|
|
||||||
fn borrow_layout_data_unchecked(&self) -> *const Option<LayoutDataWrapper> {
|
|
||||||
unsafe {
|
|
||||||
self.node.borrow_layout_data_unchecked()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Borrows the layout data immutably. Fails on a conflicting borrow.
|
|
||||||
///
|
|
||||||
/// TODO(pcwalton): Make this private. It will let us avoid borrow flag checks in some cases.
|
|
||||||
#[inline(always)]
|
|
||||||
pub fn borrow_layout_data(&self) -> Ref<Option<LayoutDataWrapper>> {
|
|
||||||
self.node.borrow_layout_data()
|
self.node.borrow_layout_data()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Borrows the layout data mutably. Fails on a conflicting borrow.
|
fn mutate_layout_data(&self) -> RefMut<Option<LayoutDataWrapper>> {
|
||||||
///
|
|
||||||
/// TODO(pcwalton): Make this private. It will let us avoid borrow flag checks in some cases.
|
|
||||||
#[inline(always)]
|
|
||||||
pub fn mutate_layout_data(&self) -> RefMut<Option<LayoutDataWrapper>> {
|
|
||||||
self.node.mutate_layout_data()
|
self.node.mutate_layout_data()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the style results for the given node. If CSS selector matching
|
fn is_ignorable_whitespace(&self) -> bool {
|
||||||
/// has not yet been performed, fails.
|
|
||||||
#[inline]
|
|
||||||
pub fn style(&self) -> Ref<Arc<ComputedValues>> {
|
|
||||||
Ref::map(self.borrow_layout_data(), |layout_data_ref| {
|
|
||||||
let layout_data = layout_data_ref.as_ref().expect("no layout data");
|
|
||||||
let style = match self.get_pseudo_element_type() {
|
|
||||||
PseudoElementType::Before(_) => &layout_data.data.before_style,
|
|
||||||
PseudoElementType::After(_) => &layout_data.data.after_style,
|
|
||||||
PseudoElementType::Normal => &layout_data.shared_data.style,
|
|
||||||
};
|
|
||||||
style.as_ref().unwrap()
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Removes the style from this node.
|
|
||||||
pub fn unstyle(self) {
|
|
||||||
let mut layout_data_ref = self.mutate_layout_data();
|
|
||||||
let layout_data = layout_data_ref.as_mut().expect("no layout data");
|
|
||||||
|
|
||||||
let style =
|
|
||||||
match self.get_pseudo_element_type() {
|
|
||||||
PseudoElementType::Before(_) => &mut layout_data.data.before_style,
|
|
||||||
PseudoElementType::After (_) => &mut layout_data.data.after_style,
|
|
||||||
PseudoElementType::Normal => &mut layout_data.shared_data.style,
|
|
||||||
};
|
|
||||||
|
|
||||||
*style = None;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn is_ignorable_whitespace(&self) -> bool {
|
|
||||||
unsafe {
|
unsafe {
|
||||||
let text: LayoutJS<Text> = match self.get_jsmanaged().downcast() {
|
let text: LayoutJS<Text> = match self.get_jsmanaged().downcast() {
|
||||||
Some(text) => text,
|
Some(text) => text,
|
||||||
|
@ -980,24 +1105,7 @@ impl<'ln> ThreadSafeLayoutNode<'ln> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get the description of how to account for recent style changes.
|
fn flags(self) -> LayoutDataFlags {
|
||||||
/// This is a simple bitfield and fine to copy by value.
|
|
||||||
pub fn restyle_damage(self) -> RestyleDamage {
|
|
||||||
let layout_data_ref = self.borrow_layout_data();
|
|
||||||
layout_data_ref.as_ref().unwrap().data.restyle_damage
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Set the restyle damage field.
|
|
||||||
pub fn set_restyle_damage(self, damage: RestyleDamage) {
|
|
||||||
let mut layout_data_ref = self.mutate_layout_data();
|
|
||||||
match *layout_data_ref {
|
|
||||||
Some(ref mut layout_data) => layout_data.data.restyle_damage = damage,
|
|
||||||
_ => panic!("no layout data for this node"),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns the layout data flags for this node.
|
|
||||||
pub fn flags(self) -> LayoutDataFlags {
|
|
||||||
unsafe {
|
unsafe {
|
||||||
match *self.borrow_layout_data_unchecked() {
|
match *self.borrow_layout_data_unchecked() {
|
||||||
None => panic!(),
|
None => panic!(),
|
||||||
|
@ -1006,38 +1114,7 @@ impl<'ln> ThreadSafeLayoutNode<'ln> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Adds the given flags to this node.
|
fn text_content(&self) -> TextContent {
|
||||||
pub fn insert_flags(self, new_flags: LayoutDataFlags) {
|
|
||||||
let mut layout_data_ref = self.mutate_layout_data();
|
|
||||||
match *layout_data_ref {
|
|
||||||
Some(ref mut layout_data) => layout_data.data.flags.insert(new_flags),
|
|
||||||
_ => panic!("no layout data for this node"),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Removes the given flags from this node.
|
|
||||||
pub fn remove_flags(self, flags: LayoutDataFlags) {
|
|
||||||
let mut layout_data_ref = self.mutate_layout_data();
|
|
||||||
match *layout_data_ref {
|
|
||||||
Some(ref mut layout_data) => layout_data.data.flags.remove(flags),
|
|
||||||
_ => panic!("no layout data for this node"),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns true if this node contributes content. This is used in the implementation of
|
|
||||||
/// `empty_cells` per CSS 2.1 § 17.6.1.1.
|
|
||||||
pub fn is_content(&self) -> bool {
|
|
||||||
match self.type_id() {
|
|
||||||
Some(NodeTypeId::Element(..)) | Some(NodeTypeId::CharacterData(CharacterDataTypeId::Text(..))) => true,
|
|
||||||
_ => false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// If this is a text node, generated content, or a form element, copies out
|
|
||||||
/// its content. Otherwise, panics.
|
|
||||||
///
|
|
||||||
/// FIXME(pcwalton): This might have too much copying and/or allocation. Profile this.
|
|
||||||
pub fn text_content(&self) -> TextContent {
|
|
||||||
if self.pseudo != PseudoElementType::Normal {
|
if self.pseudo != PseudoElementType::Normal {
|
||||||
let layout_data_ref = self.borrow_layout_data();
|
let layout_data_ref = self.borrow_layout_data();
|
||||||
let data = &layout_data_ref.as_ref().unwrap().data;
|
let data = &layout_data_ref.as_ref().unwrap().data;
|
||||||
|
@ -1074,8 +1151,7 @@ impl<'ln> ThreadSafeLayoutNode<'ln> {
|
||||||
panic!("not text!")
|
panic!("not text!")
|
||||||
}
|
}
|
||||||
|
|
||||||
/// If the insertion point is within this node, returns it. Otherwise, returns `None`.
|
fn insertion_point(&self) -> Option<CharIndex> {
|
||||||
pub fn insertion_point(&self) -> Option<CharIndex> {
|
|
||||||
let this = unsafe {
|
let this = unsafe {
|
||||||
self.get_jsmanaged()
|
self.get_jsmanaged()
|
||||||
};
|
};
|
||||||
|
@ -1094,10 +1170,7 @@ impl<'ln> ThreadSafeLayoutNode<'ln> {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
/// If this is an image element, returns its URL. If this is not an image element, fails.
|
fn image_url(&self) -> Option<Url> {
|
||||||
///
|
|
||||||
/// FIXME(pcwalton): Don't copy URLs.
|
|
||||||
pub fn image_url(&self) -> Option<Url> {
|
|
||||||
unsafe {
|
unsafe {
|
||||||
self.get_jsmanaged().downcast()
|
self.get_jsmanaged().downcast()
|
||||||
.expect("not an image!")
|
.expect("not an image!")
|
||||||
|
@ -1105,16 +1178,14 @@ impl<'ln> ThreadSafeLayoutNode<'ln> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn canvas_data(&self) -> Option<HTMLCanvasData> {
|
fn canvas_data(&self) -> Option<HTMLCanvasData> {
|
||||||
unsafe {
|
unsafe {
|
||||||
let canvas_element = self.get_jsmanaged().downcast();
|
let canvas_element = self.get_jsmanaged().downcast();
|
||||||
canvas_element.map(|canvas| canvas.data())
|
canvas_element.map(|canvas| canvas.data())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// If this node is an iframe element, returns its pipeline ID. If this node is
|
fn iframe_pipeline_id(&self) -> PipelineId {
|
||||||
/// not an iframe element, fails.
|
|
||||||
pub fn iframe_pipeline_id(&self) -> PipelineId {
|
|
||||||
use script::dom::htmliframeelement::HTMLIFrameElementLayoutMethods;
|
use script::dom::htmliframeelement::HTMLIFrameElementLayoutMethods;
|
||||||
unsafe {
|
unsafe {
|
||||||
let iframe_element = self.get_jsmanaged().downcast::<HTMLIFrameElement>()
|
let iframe_element = self.get_jsmanaged().downcast::<HTMLIFrameElement>()
|
||||||
|
@ -1123,65 +1194,56 @@ impl<'ln> ThreadSafeLayoutNode<'ln> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_colspan(&self) -> u32 {
|
fn get_colspan(&self) -> u32 {
|
||||||
unsafe {
|
unsafe {
|
||||||
self.get_jsmanaged().downcast::<Element>().unwrap().get_colspan()
|
self.get_jsmanaged().downcast::<Element>().unwrap().get_colspan()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct ThreadSafeLayoutNodeChildrenIterator<'a> {
|
pub struct ThreadSafeLayoutNodeChildrenIterator<'ln, ConcreteNode: TThreadSafeLayoutNode<'ln>> {
|
||||||
current_node: Option<ThreadSafeLayoutNode<'a>>,
|
current_node: Option<ConcreteNode>,
|
||||||
parent_node: ThreadSafeLayoutNode<'a>,
|
parent_node: ConcreteNode,
|
||||||
|
// Satisfy the compiler about the unused lifetime.
|
||||||
|
phantom: PhantomData<&'ln ()>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> ThreadSafeLayoutNodeChildrenIterator<'a> {
|
impl<'ln, ConcreteNode> ThreadSafeLayoutNodeChildrenIterator<'ln, ConcreteNode>
|
||||||
fn new(parent: ThreadSafeLayoutNode<'a>) -> ThreadSafeLayoutNodeChildrenIterator<'a> {
|
where ConcreteNode: DangerousThreadSafeLayoutNode<'ln> {
|
||||||
fn first_child(parent: ThreadSafeLayoutNode)
|
fn new(parent: ConcreteNode) -> Self {
|
||||||
-> Option<ThreadSafeLayoutNode> {
|
let first_child: Option<ConcreteNode> = match parent.get_pseudo_element_type() {
|
||||||
if parent.pseudo != PseudoElementType::Normal {
|
PseudoElementType::Normal => {
|
||||||
return None
|
parent.get_before_pseudo().or_else(|| {
|
||||||
}
|
unsafe { parent.dangerous_first_child() }
|
||||||
|
})
|
||||||
parent.get_before_pseudo().or_else(|| {
|
},
|
||||||
unsafe {
|
_ => None,
|
||||||
parent.get_jsmanaged().first_child_ref()
|
};
|
||||||
.map(|node| parent.new_with_this_lifetime(&node))
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
ThreadSafeLayoutNodeChildrenIterator {
|
ThreadSafeLayoutNodeChildrenIterator {
|
||||||
current_node: first_child(parent),
|
current_node: first_child,
|
||||||
parent_node: parent,
|
parent_node: parent,
|
||||||
|
phantom: PhantomData,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Iterator for ThreadSafeLayoutNodeChildrenIterator<'a> {
|
impl<'ln, ConcreteNode> Iterator for ThreadSafeLayoutNodeChildrenIterator<'ln, ConcreteNode>
|
||||||
type Item = ThreadSafeLayoutNode<'a>;
|
where ConcreteNode: DangerousThreadSafeLayoutNode<'ln> {
|
||||||
fn next(&mut self) -> Option<ThreadSafeLayoutNode<'a>> {
|
type Item = ConcreteNode;
|
||||||
|
fn next(&mut self) -> Option<ConcreteNode> {
|
||||||
let node = self.current_node.clone();
|
let node = self.current_node.clone();
|
||||||
|
|
||||||
if let Some(ref node) = node {
|
if let Some(ref node) = node {
|
||||||
self.current_node = match node.pseudo {
|
self.current_node = match node.get_pseudo_element_type() {
|
||||||
PseudoElementType::Before(_) => {
|
PseudoElementType::Before(_) => {
|
||||||
match unsafe { self.parent_node.get_jsmanaged().first_child_ref() } {
|
match unsafe { self.parent_node.dangerous_first_child() } {
|
||||||
Some(first) => {
|
Some(first) => Some(first),
|
||||||
Some(unsafe {
|
|
||||||
self.parent_node.new_with_this_lifetime(&first)
|
|
||||||
})
|
|
||||||
},
|
|
||||||
None => self.parent_node.get_after_pseudo(),
|
None => self.parent_node.get_after_pseudo(),
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
PseudoElementType::Normal => {
|
PseudoElementType::Normal => {
|
||||||
match unsafe { node.get_jsmanaged().next_sibling_ref() } {
|
match unsafe { node.dangerous_next_sibling() } {
|
||||||
Some(next) => {
|
Some(next) => Some(next),
|
||||||
Some(unsafe {
|
|
||||||
self.parent_node.new_with_this_lifetime(&next)
|
|
||||||
})
|
|
||||||
},
|
|
||||||
None => self.parent_node.get_after_pseudo(),
|
None => self.parent_node.get_after_pseudo(),
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -1201,9 +1263,10 @@ pub struct ThreadSafeLayoutElement<'le> {
|
||||||
element: &'le Element,
|
element: &'le Element,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'le> ThreadSafeLayoutElement<'le> {
|
impl<'le> TThreadSafeLayoutElement<'le> for ThreadSafeLayoutElement<'le> {
|
||||||
#[inline]
|
type ConcreteThreadSafeLayoutNode = ThreadSafeLayoutNode<'le>;
|
||||||
pub fn get_attr(&self, namespace: &Namespace, name: &Atom) -> Option<&'le str> {
|
|
||||||
|
fn get_attr(&self, namespace: &Namespace, name: &Atom) -> Option<&'le str> {
|
||||||
unsafe {
|
unsafe {
|
||||||
self.element.get_attr_val_for_layout(namespace, name)
|
self.element.get_attr_val_for_layout(namespace, name)
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue